turtle/tlang: add . map indexing
var.key pushes the value indexed by key in var onto the stack quotes also work for assignment numerical keys do not work yet
This commit is contained in:
parent
a4b2aca647
commit
42a253cc71
@ -68,10 +68,13 @@ function tlang.get_state(code)
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
locals = {{
|
locals = {{
|
||||||
pc = {sg = 1, pos = "__ast__", elem = 1},
|
pc = {sg = 1, pos = {"__ast__"}, elem = 1},
|
||||||
v__src__ = tlang.value_to_tlang(code),
|
vars = {
|
||||||
v__lex__ = tlang.value_to_tlang(lexed),
|
__src__ = tlang.value_to_tlang(code),
|
||||||
v__ast__ = {type = "code", value = parsed}}},
|
__lex__ = tlang.value_to_tlang(lexed),
|
||||||
|
__ast__ = {type = "code", value = parsed}
|
||||||
|
}
|
||||||
|
}},
|
||||||
stack = {},
|
stack = {},
|
||||||
code_stack = {},
|
code_stack = {},
|
||||||
builtins = tlang.builtins
|
builtins = tlang.builtins
|
||||||
@ -87,6 +90,45 @@ function tlang.pretty_pc(pc)
|
|||||||
return tostring(pc.sg) .. ";" .. tostring(pc.pos) .. ";" .. tostring(pc.elem)
|
return tostring(pc.sg) .. ";" .. tostring(pc.pos) .. ";" .. tostring(pc.elem)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function tlang.format_table(t, depth, maxdepth)
|
||||||
|
depth = depth or 0
|
||||||
|
maxdepth = maxdepth or -1
|
||||||
|
|
||||||
|
if depth == maxdepth then
|
||||||
|
return "{...}"
|
||||||
|
end
|
||||||
|
|
||||||
|
local out = {}
|
||||||
|
out[1] = "{\n"
|
||||||
|
|
||||||
|
for k, v in pairs(t) do
|
||||||
|
local idx = k
|
||||||
|
if type(k) == "string" then
|
||||||
|
idx = '"' .. k .. '"'
|
||||||
|
elseif type(k) == "table" then
|
||||||
|
idx = "{...}"
|
||||||
|
end
|
||||||
|
|
||||||
|
out[#out + 1] = string.rep("\t", depth + 1) .. "[" .. idx .. "] = "
|
||||||
|
|
||||||
|
if type(v) == "table" then
|
||||||
|
out[#out + 1] = tlang.format_table(v, depth + 1, maxdepth)
|
||||||
|
elseif type(v) == "string" then
|
||||||
|
out[#out + 1] = '"' .. v .. '"'
|
||||||
|
else
|
||||||
|
out[#out + 1] = tostring(v)
|
||||||
|
end
|
||||||
|
|
||||||
|
out[#out + 1] = ",\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
out[#out + 1] = string.rep("\t", depth) .. "}"
|
||||||
|
return table.concat(out)
|
||||||
|
end
|
||||||
|
|
||||||
|
function tlang.print_table(t, maxdepth)
|
||||||
|
print(tlang.format_table(t, nil, maxdepth))
|
||||||
|
end
|
||||||
|
|
||||||
local function test()
|
local function test()
|
||||||
local complex = [[{dup *} `square =
|
local complex = [[{dup *} `square =
|
||||||
@ -185,7 +227,25 @@ local function test()
|
|||||||
|
|
||||||
local paren_test = "('works' print) 'out' print"
|
local paren_test = "('works' print) 'out' print"
|
||||||
|
|
||||||
tlang.exec(paren_test)
|
local mapdot_test = [[
|
||||||
|
[1 a:5 b:[a:2 b:3] ] `a =
|
||||||
|
4 `a.a =
|
||||||
|
a.a print
|
||||||
|
a.b.b print
|
||||||
|
]]
|
||||||
|
|
||||||
|
local stackdot_test = [[
|
||||||
|
[a:1 b:2]
|
||||||
|
.b print
|
||||||
|
6 `.a =
|
||||||
|
.a print
|
||||||
|
]]
|
||||||
|
|
||||||
|
local test = stackdot_test
|
||||||
|
|
||||||
|
--tlang.print_table(tlang.lex(test))
|
||||||
|
--tlang.print_table(tlang.parse(tlang.lex(test)))
|
||||||
|
tlang.exec(test)
|
||||||
end
|
end
|
||||||
|
|
||||||
if minetest == nil then
|
if minetest == nil then
|
||||||
|
@ -131,16 +131,12 @@ local function lex_identifier_raw(state, top)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return table.concat(identifier)
|
return {table.concat(identifier)}
|
||||||
end
|
end
|
||||||
|
|
||||||
local function lex_identifier(state)
|
local function lex_identifier(state)
|
||||||
local id = lex_identifier_raw(state, true)
|
local id = lex_identifier_raw(state, true)
|
||||||
if type(id) == "string" then
|
return {type = "literal", subtype = "identifier", value = id}
|
||||||
return {type = "literal", subtype = "identifier", value = id}
|
|
||||||
elseif type(id) == "table" then
|
|
||||||
return {type = "literal", subtype = "mapid", value = id}
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- `identifier
|
-- `identifier
|
||||||
|
@ -13,6 +13,8 @@ symbol
|
|||||||
|
|
||||||
local tlang = {}
|
local tlang = {}
|
||||||
|
|
||||||
|
local internal = {}
|
||||||
|
|
||||||
local function sublist(list, istart, iend, inclusive)
|
local function sublist(list, istart, iend, inclusive)
|
||||||
local o = {}
|
local o = {}
|
||||||
local oi = 1
|
local oi = 1
|
||||||
@ -35,8 +37,6 @@ local function sublist(list, istart, iend, inclusive)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--tlang.parse = function(lexed) end
|
|
||||||
|
|
||||||
local function parse_peek(state)
|
local function parse_peek(state)
|
||||||
return state.lexed[state.position]
|
return state.lexed[state.position]
|
||||||
end
|
end
|
||||||
@ -69,15 +69,19 @@ local function parse_map(state)
|
|||||||
local key = n.value
|
local key = n.value
|
||||||
local mr = parse_peek(state)
|
local mr = parse_peek(state)
|
||||||
|
|
||||||
|
if type(key) == "table" then
|
||||||
|
key = key[1]
|
||||||
|
end
|
||||||
|
|
||||||
if mr.type == "map_relation" then
|
if mr.type == "map_relation" then
|
||||||
parse_next(state)
|
parse_next(state)
|
||||||
local nval = tlang.parse({parse_next(state)})
|
local nval = internal.parse_step(state)
|
||||||
|
|
||||||
if nval == nil then
|
if nval == nil then
|
||||||
return nil -- ERROR
|
return nil -- ERROR
|
||||||
end
|
end
|
||||||
|
|
||||||
map[key] = nval[1]
|
map[key] = nval
|
||||||
skip = true
|
skip = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -126,7 +130,7 @@ local function parse_code(state, open, close)
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
local function parse_step(state)
|
function internal.parse_step(state)
|
||||||
local n = parse_peek(state)
|
local n = parse_peek(state)
|
||||||
|
|
||||||
if n == nil then
|
if n == nil then
|
||||||
@ -171,7 +175,7 @@ function tlang.parse(lexed)
|
|||||||
local treei = 1
|
local treei = 1
|
||||||
|
|
||||||
while true do
|
while true do
|
||||||
local n = parse_step(state)
|
local n = internal.parse_step(state)
|
||||||
|
|
||||||
if n == nil then
|
if n == nil then
|
||||||
if state.position <= #state.lexed then
|
if state.position <= #state.lexed then
|
||||||
|
@ -106,7 +106,7 @@ function tlang.call(state, target)
|
|||||||
target.pos = #state.code_stack
|
target.pos = #state.code_stack
|
||||||
end
|
end
|
||||||
|
|
||||||
state.locals[#state.locals + 1] = {pc = target}
|
state.locals[#state.locals + 1] = {vars = {}, pc = target}
|
||||||
end
|
end
|
||||||
|
|
||||||
function tlang.call_tos(state)
|
function tlang.call_tos(state)
|
||||||
@ -151,7 +151,7 @@ local function find_var_pos(state, name)
|
|||||||
|
|
||||||
for i = 1, slen do
|
for i = 1, slen do
|
||||||
local v = state.locals[slen + 1 - i]
|
local v = state.locals[slen + 1 - i]
|
||||||
if in_keys("v" .. name, v) then
|
if in_keys(name, v.vars) then
|
||||||
return slen + 1 - i
|
return slen + 1 - i
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -160,24 +160,82 @@ end
|
|||||||
function tlang.near_access(state, name)
|
function tlang.near_access(state, name)
|
||||||
local n = find_var_pos(state, name)
|
local n = find_var_pos(state, name)
|
||||||
if n then
|
if n then
|
||||||
return state.locals[n]["v" .. name]
|
return state.locals[n].vars[name]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function tlang.map_access_assign(state, index, start, assign)
|
||||||
|
local container
|
||||||
|
local curtab
|
||||||
|
|
||||||
|
if start then
|
||||||
|
container = start
|
||||||
|
elseif index[1] == "" and #index > 1 then
|
||||||
|
curtab = state.stack[#state.stack].value
|
||||||
|
else
|
||||||
|
local pos = find_var_pos(state, index[1])
|
||||||
|
-- assignments can go at the current scope
|
||||||
|
if assign then
|
||||||
|
pos = pos or #state.locals
|
||||||
|
end
|
||||||
|
|
||||||
|
container = state.locals[pos].vars
|
||||||
|
end
|
||||||
|
|
||||||
|
if not container and not curtab then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if #index == 1 then
|
||||||
|
if assign then
|
||||||
|
container[index[1]] = assign
|
||||||
|
return
|
||||||
|
else
|
||||||
|
return container[index[1]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
curtab = curtab or container[index[1]].value
|
||||||
|
|
||||||
|
for idx = 2, #index - 1 do
|
||||||
|
curtab = curtab[index[idx]]
|
||||||
|
|
||||||
|
if not curtab then
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
curtab = curtab.value
|
||||||
|
end
|
||||||
|
|
||||||
|
if assign then
|
||||||
|
curtab[index[#index]] = assign
|
||||||
|
else
|
||||||
|
return curtab[index[#index]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function tlang.near_access_indexed(state, index)
|
||||||
|
return tlang.map_access_assign(state, index)
|
||||||
|
end
|
||||||
|
|
||||||
|
function tlang.near_assign_indexed(state, index, value)
|
||||||
|
tlang.map_access_assign(state, index, nil, value)
|
||||||
|
end
|
||||||
|
|
||||||
function tlang.global_assign(state, name, value)
|
function tlang.global_assign(state, name, value)
|
||||||
state.locals[0]["v" .. name] = value
|
state.locals[0].vars[name] = value
|
||||||
end
|
end
|
||||||
|
|
||||||
function tlang.local_assign(state, name, value)
|
function tlang.local_assign(state, name, value)
|
||||||
state.locals[#state.locals]["v" .. name] = value
|
state.locals[#state.locals].vars[name] = value
|
||||||
end
|
end
|
||||||
|
|
||||||
function tlang.near_assign(state, name, value)
|
function tlang.near_assign(state, name, value)
|
||||||
local n = find_var_pos(state, name)
|
local n = find_var_pos(state, name)
|
||||||
if n then
|
if n then
|
||||||
state.locals[n]["v" .. name] = value
|
state.locals[n].vars[name] = value
|
||||||
else
|
else
|
||||||
state.locals[#state.locals]["v" .. name] = value
|
state.locals[#state.locals].vars[name] = value
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -190,7 +248,7 @@ local function accesspc(state, pc)
|
|||||||
if pc.sg == 0 then -- stack
|
if pc.sg == 0 then -- stack
|
||||||
code = state.code_stack[pc.pos]
|
code = state.code_stack[pc.pos]
|
||||||
elseif pc.sg == 1 then -- global
|
elseif pc.sg == 1 then -- global
|
||||||
code = tlang.near_access(state, pc.pos)
|
code = tlang.near_access_indexed(state, pc.pos)
|
||||||
end
|
end
|
||||||
|
|
||||||
if code then
|
if code then
|
||||||
@ -315,7 +373,7 @@ tlang.builtins["="] = function(state)
|
|||||||
local name = statepop_type(state, "quote")
|
local name = statepop_type(state, "quote")
|
||||||
local value = tlang.pop_raw(state)
|
local value = tlang.pop_raw(state)
|
||||||
|
|
||||||
tlang.near_assign(state, name.value, value)
|
tlang.near_assign_indexed(state, name.value, value)
|
||||||
end
|
end
|
||||||
|
|
||||||
function tlang.unary(func)
|
function tlang.unary(func)
|
||||||
@ -325,7 +383,7 @@ function tlang.unary(func)
|
|||||||
statepush_num(state, func(tos.value))
|
statepush_num(state, func(tos.value))
|
||||||
elseif tos.type == "quote" then
|
elseif tos.type == "quote" then
|
||||||
local n = tlang.near_access(state, tos.value)
|
local n = tlang.near_access(state, tos.value)
|
||||||
tlang.near_assign(state, tos.value, {type = "number", value = func(n.value)})
|
tlang.near_assign_indexed(state, tos.value, {type = "number", value = func(n.value)})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -657,13 +715,18 @@ function tlang.step(state)
|
|||||||
if in_list(cur.type, literals) then
|
if in_list(cur.type, literals) then
|
||||||
state.stack[#state.stack + 1] = cur
|
state.stack[#state.stack + 1] = cur
|
||||||
elseif cur.type == "identifier" or cur.type == "symbol" then
|
elseif cur.type == "identifier" or cur.type == "symbol" then
|
||||||
if in_keys(cur.value, state.builtins) then
|
local strname = cur.value
|
||||||
local f = state.builtins[cur.value]
|
if type(cur.value) == "table" then
|
||||||
|
strname = cur.value[1]
|
||||||
|
end
|
||||||
|
|
||||||
|
if in_keys(strname, state.builtins) then
|
||||||
|
local f = state.builtins[strname]
|
||||||
f(state)
|
f(state)
|
||||||
else
|
else
|
||||||
local var = tlang.near_access(state, cur.value)
|
local var = tlang.near_access_indexed(state, cur.value)
|
||||||
if var == nil then
|
if var == nil then
|
||||||
return "Undefined identifier: " .. cur.value
|
return "Undefined identifier: " .. table.concat(cur.value, ".")
|
||||||
elseif var.type == "code" then
|
elseif var.type == "code" then
|
||||||
tlang.call_var(state, cur.value)
|
tlang.call_var(state, cur.value)
|
||||||
else
|
else
|
||||||
|
Loading…
x
Reference in New Issue
Block a user