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:
cron 2020-12-10 04:34:48 +00:00 committed by Schmappie Eldress
parent a4b2aca647
commit 42a253cc71
4 changed files with 154 additions and 31 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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