-
-
Notifications
You must be signed in to change notification settings - Fork 91
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement scoped lexical id generator
The new id generator creates identifier names based on a given name. The name is initially prefixed with "@" to avoid conflicts with ordinary variable names. Then, each time a scope is closed the name of generated variable is changed removing the "@" and ensuring that there is no conflicts with the variables in the scope.
- Loading branch information
Showing
3 changed files
with
90 additions
and
96 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,82 +1,50 @@ | ||
-- Create a two pass identifier generator. In the first pass the identifier are in the | ||
-- form "@<number>". Then all the lexical variables should be declared using "var_declare". | ||
-- In the final stage the function "normalize" is used to transform the temporary | ||
-- identifier, like "@2" into something like "__12". All this is to ensure that the | ||
-- * the identifier is a valid identifier string | ||
-- * there are no conflict with other local variables declared in the program | ||
local function create_genid_lexical(create_ident) | ||
local intervals = { {1, 2^32 - 1} } | ||
local longest = 1 | ||
local current = 0 | ||
|
||
local pending_idents = {} | ||
|
||
local function find_longest() | ||
local ilong, isize = 1, -1 | ||
for i = 1, #intervals do | ||
local size = intervals[i][2] - intervals[i][1] | ||
if size > isize then | ||
ilong, isize = i, size | ||
end | ||
local function unique_name(variables, name) | ||
if variables:lookup(name) ~= nil then | ||
local prefix, index = string.match(name, "^(.+)(%d+)$") | ||
if not prefix then | ||
prefix, index = name, 1 | ||
else | ||
index = tonumber(index) + 1 | ||
end | ||
longest = ilong | ||
end | ||
|
||
local function remove_id(n) | ||
for i = 1, #intervals do | ||
local a, b = intervals[i][1], intervals[i][2] | ||
if a <= n and n <= b then | ||
table.remove(intervals, i) | ||
if n > a then table.insert(intervals, i, {a, n - 1}) end | ||
if n < b then table.insert(intervals, i, {n + 1, b}) end | ||
if longest >= i then find_longest() end | ||
break | ||
end | ||
local test_name = prefix .. tostring(index) | ||
while variables:lookup(test_name) ~= nil do | ||
index = index + 1 | ||
test_name = prefix .. tostring(index) | ||
end | ||
return test_name | ||
else | ||
return name | ||
end | ||
end | ||
|
||
local function var_declare(name) | ||
local idn = string.match(name, "^__(%d+)$") | ||
if idn then | ||
remove_id(tonumber(idn)) | ||
end | ||
end | ||
local function pseudo(name) | ||
return '@' .. name | ||
end | ||
|
||
local function normal_name(n) | ||
local name = intervals[longest][1] + (n - 1) | ||
assert(name <= intervals[longest][2], "cannot generate new identifier") | ||
return "__" .. name | ||
end | ||
local function pseudo_match(pseudo_name) | ||
return string.match(pseudo_name, "^@(.+)$") | ||
end | ||
|
||
local function normalize(raw_name) | ||
local n = tonumber(string.match(raw_name, "^@(%d+)$")) | ||
return normal_name(n) | ||
end | ||
local function genid(variables, name) | ||
local pname = pseudo(name or "_") | ||
local uname = unique_name(variables, pname) | ||
return variables:declare(uname) | ||
end | ||
|
||
local function new_ident() | ||
current = current + 1 | ||
local id | ||
if pending_idents then -- Create a temporary name. | ||
id = create_ident("@" .. current) | ||
pending_idents[#pending_idents+1] = id | ||
else -- Generate the final name. | ||
local name = normal_name(current) | ||
id = create_ident(name) | ||
end | ||
return id | ||
end | ||
local function normalize(variables, raw_name) | ||
local name = pseudo_match(raw_name) | ||
local uname = unique_name(variables, name) | ||
return uname | ||
end | ||
|
||
-- When called this means that all the lexical variables have been | ||
-- declared with "var_declare". | ||
local function close_lexical() | ||
for i = 1, #pending_idents do | ||
local id = pending_idents[i] | ||
id.name = normalize(id.name) | ||
local function close_gen_variables(variables) | ||
local vars = variables.current.vars | ||
for i = 1, #vars do | ||
local id = vars[i] | ||
if pseudo_match(id.name) then | ||
id.name = normalize(variables, id.name) | ||
end | ||
pending_idents = nil | ||
end | ||
|
||
return { new_ident = new_ident, var_declare = var_declare, close_lexical = close_lexical } | ||
end | ||
|
||
return { create = create_genid_simple, lexical = create_genid_lexical } | ||
return { genid = genid, close_gen_variables = close_gen_variables } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters