compiler: Build declaration names in checked storage

db1f48d4986315fd955b13f3d2101213372d33e307a529a26436a9b39b595415
Alexis Sellier committed ago 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 +
}