compiler: Build declaration names in checked storage
db1f48d4986315fd955b13f3d2101213372d33e307a529a26436a9b39b595415
1 parent
2911781f
lib/std/lang/lower.rad
+16 -33
| 1852 | 1852 | return nil; |
|
| 1853 | 1853 | } |
|
| 1854 | 1854 | ||
| 1855 | 1855 | /// Compose a segmented symbol name from a list of path segments. |
|
| 1856 | 1856 | /// Example: `["func", "nominal", "VALUE"]` -> `func$nominal$VALUE`. |
|
| 1857 | - | unsafe fn buildSegmentedName 'arena 'phase ( |
|
| 1858 | - | self: &mut Lowerer 'arena 'phase, |
|
| 1859 | - | segments: &[*[u8]] |
|
| 1860 | - | ) -> *[u8] throws (LowerError) where 'arena: 'phase { |
|
| 1857 | + | fn buildSegmentedName(segments: &[*[u8]], allocator: alloc::Allocator) -> *[u8] { |
|
| 1861 | 1858 | assert segments.len > 0; |
|
| 1862 | - | ||
| 1863 | - | let mut totalLen: u32 = 0; |
|
| 1864 | - | for segment in segments { |
|
| 1865 | - | set totalLen += segment.len; |
|
| 1866 | - | } |
|
| 1867 | - | if segments.len > 1 { |
|
| 1868 | - | set totalLen += segments.len - 1; |
|
| 1869 | - | } |
|
| 1870 | - | let buf = try! alloc::allocSlice(self.arena, 1, 1, totalLen) as *mut [u8]; |
|
| 1871 | - | let mut pos: u32 = 0; |
|
| 1872 | - | ||
| 1859 | + | let mut buf: *mut [u8] = &mut []; |
|
| 1873 | 1860 | for segment, i in segments { |
|
| 1874 | - | set pos += try! mem::copy(&mut buf[pos..], segment); |
|
| 1861 | + | for byte in segment { |
|
| 1862 | + | buf.append(byte, allocator); |
|
| 1863 | + | } |
|
| 1875 | 1864 | if i + 1 <> segments.len { |
|
| 1876 | - | set buf[pos] = '$'; |
|
| 1877 | - | set pos += 1; |
|
| 1865 | + | buf.append('$', allocator); |
|
| 1878 | 1866 | } |
|
| 1879 | 1867 | } |
|
| 1880 | - | assert pos == totalLen; |
|
| 1881 | - | ||
| 1882 | - | return &buf[..totalLen]; |
|
| 1868 | + | return buf; |
|
| 1883 | 1869 | } |
|
| 1884 | 1870 | ||
| 1885 | 1871 | /// Generate a unique name for declaration-local backing data entries. |
|
| 1886 | - | unsafe fn nextDeclDataName 'arena 'phase ( |
|
| 1887 | - | self: &mut Lowerer 'arena 'phase, |
|
| 1872 | + | fn nextDeclDataName( |
|
| 1888 | 1873 | prefix: *[u8], |
|
| 1889 | 1874 | count: u32, |
|
| 1890 | - | namespace: *[u8] |
|
| 1891 | - | ) -> *[u8] throws (LowerError) where 'arena: 'phase { |
|
| 1892 | - | let mut digits: [u8; fmt::U32_STR_LEN] = [0; fmt::U32_STR_LEN]; |
|
| 1893 | - | let start = fmt::formatU32(count, &mut digits[..]); |
|
| 1894 | - | let suffix = try! alloc::allocSlice(self.arena, 1, 1, digits.len - start) as *mut [u8]; |
|
| 1895 | - | try! mem::copy(suffix, &digits[start..]); |
|
| 1875 | + | namespace: *[u8], |
|
| 1876 | + | allocator: alloc::Allocator, |
|
| 1877 | + | ) -> *[u8] { |
|
| 1878 | + | let suffix = labelWithSuffix("", count, allocator); |
|
| 1896 | 1879 | let segments = [prefix, namespace, suffix]; |
|
| 1897 | 1880 | ||
| 1898 | - | return try buildSegmentedName(self, &segments[..]); |
|
| 1881 | + | return buildSegmentedName(&segments[..], allocator); |
|
| 1899 | 1882 | } |
|
| 1900 | 1883 | ||
| 1901 | 1884 | /// Append a data entry using a function-local literal namespace (`prefix$literal$N`). |
|
| 1902 | 1885 | unsafe fn pushDeclData 'arena 'phase ( |
|
| 1903 | 1886 | self: &mut Lowerer 'arena 'phase, |
| 1906 | 1889 | readOnly: bool, |
|
| 1907 | 1890 | values: *[il::DataValue], |
|
| 1908 | 1891 | dataPrefix: *[u8] |
|
| 1909 | 1892 | ) -> *[u8] throws (LowerError) where 'arena: 'phase { |
|
| 1910 | 1893 | let dataCount = self.data.len; |
|
| 1911 | - | let name = try nextDeclDataName(self, dataPrefix, dataCount, "literal"); |
|
| 1894 | + | let name = nextDeclDataName(dataPrefix, dataCount, "literal", alloc::arenaAllocator(self.arena)); |
|
| 1912 | 1895 | self.data.append(il::Data { |
|
| 1913 | 1896 | name, |
|
| 1914 | 1897 | size, |
|
| 1915 | 1898 | alignment, |
|
| 1916 | 1899 | readOnly, |
| 2060 | 2043 | /// Generate a unique data name for inline literals, eg. `fnName$literal$N`. |
|
| 2061 | 2044 | unsafe fn nextDataName 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function) -> *[u8] throws (LowerError) where 'arena: 'phase, 'phase: 'function { |
|
| 2062 | 2045 | let counter = self.dataCounter; |
|
| 2063 | 2046 | set self.dataCounter += 1; |
|
| 2064 | 2047 | let fnName = self.fnName; |
|
| 2065 | - | return try nextDeclDataName(self.low, fnName, counter, "literal"); |
|
| 2048 | + | return nextDeclDataName(fnName, counter, "literal", alloc::arenaAllocator(self.low.arena)); |
|
| 2066 | 2049 | } |
|
| 2067 | 2050 | ||
| 2068 | 2051 | /// Assign a unique function-local data symbol name. |
|
| 2069 | 2052 | unsafe fn registerLocalDataDeclName 'arena 'phase 'function (self: &mut FnLowerer 'arena 'phase 'function, node: *ast::Node) throws (LowerError) where 'arena: 'phase, 'phase: 'function { |
|
| 2070 | 2053 | let sym = resolver::symbolFor(self.low.resolver, node) |
|
| 2071 | 2054 | else throw LowerError::MissingSymbol(node); |
|
| 2072 | 2055 | ||
| 2073 | 2056 | let prefix = self.fnName; |
|
| 2074 | 2057 | let segments = [prefix, "nominal", sym.name]; |
|
| 2075 | - | let name = try buildSegmentedName(self.low, &segments[..]); |
|
| 2058 | + | let name = buildSegmentedName(&segments[..], alloc::arenaAllocator(self.low.arena)); |
|
| 2076 | 2059 | ||
| 2077 | 2060 | let qualified = qualifyName(self.low, nil, name); |
|
| 2078 | 2061 | registerSymbolName(&mut self.low.symbolNames, sym, qualified, alloc::arenaAllocator(self.low.arena)); |
|
| 2079 | 2062 | } |
|
| 2080 | 2063 |
test/tests/const.backing.names.rad
added
+22 -0
| 1 | + | //! returns: 0 |
|
| 2 | + | ||
| 3 | + | /// Distinct backing strings with multi-digit generated suffixes. |
|
| 4 | + | constant WORDS: [*[u8]; 12] = ["a", "bb", "ccc", "dddd", "eeeee", "ffffff", "ggggggg", "hhhhhhhh", "iiiiiiiii", "jjjjjjjjjj", "kkkkkkkkkkk", "llllllllllll"]; |
|
| 5 | + | ||
| 6 | + | /// A separate declaration with some identical string contents. |
|
| 7 | + | constant OTHER: [*[u8]; 3] = ["ccc", "a", "bb"]; |
|
| 8 | + | ||
| 9 | + | /// Check that generated names retain the correct backing bytes. |
|
| 10 | + | @default fn main() -> u32 { |
|
| 11 | + | for index in 0..WORDS.len { |
|
| 12 | + | let word = WORDS[index]; |
|
| 13 | + | assert word.len == index + 1; |
|
| 14 | + | for byte in word { |
|
| 15 | + | assert byte as u32 == 97 + index; |
|
| 16 | + | } |
|
| 17 | + | } |
|
| 18 | + | assert OTHER[0] == WORDS[2]; |
|
| 19 | + | assert OTHER[1] == WORDS[0]; |
|
| 20 | + | assert OTHER[2] == WORDS[1]; |
|
| 21 | + | return 0; |
|
| 22 | + | } |