From c847fefd39ad21f6885b5bd8a0a9f650d5a944b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20Reuh=20Fildadut?= Date: Sat, 5 Jun 2021 21:34:12 +0200 Subject: [PATCH] Parser only change state on success --- interpreter/common.lua | 1 + parser/postparser.lua | 5 +-- parser/preparser.lua | 69 +++++++++++++++++++++++++++++++++--------- 3 files changed, 59 insertions(+), 16 deletions(-) diff --git a/interpreter/common.lua b/interpreter/common.lua index 2544ab3..ed607ff 100644 --- a/interpreter/common.lua +++ b/interpreter/common.lua @@ -8,6 +8,7 @@ common = { local global_vars = state.interpreter.global_state.variables for var, value in pairs(state.variables) do global_vars[var] = value + state.variables[var] = nil end end, -- returns a variable's value, evaluating a pending expression if neccessary diff --git a/parser/postparser.lua b/parser/postparser.lua index c72a7ad..720ee2e 100644 --- a/parser/postparser.lua +++ b/parser/postparser.lua @@ -5,7 +5,8 @@ local parse_text -- * nil, error: in case of error local function parse(state) -- expression parsing - for _, l in ipairs(state.queued_lines) do + for i=#state.queued_lines, 1, -1 do + local l = state.queued_lines[i] local line, namespace = l.line, l.namespace -- default arguments and type annotation if line.type == "function" then @@ -60,8 +61,8 @@ local function parse(state) if err then return nil, ("%s; at %s"):format(err, line.source) end line.text = txt end + state.queued_lines[i] = nil end - state.queued_lines = {} return true end diff --git a/parser/preparser.lua b/parser/preparser.lua index a859f6a..6ff945a 100644 --- a/parser/preparser.lua +++ b/parser/preparser.lua @@ -57,9 +57,9 @@ local function parse_line(line, state, namespace) if r.type == "function" then r.remove_from_block_ast = true -- lua function - if state.link_next_function_definition_to_lua_function then - r.lua_function = state.link_next_function_definition_to_lua_function - state.link_next_function_definition_to_lua_function = nil + if state.global_state.link_next_function_definition_to_lua_function then + r.lua_function = state.global_state.link_next_function_definition_to_lua_function + state.global_state.link_next_function_definition_to_lua_function = nil end end -- get identifier @@ -164,10 +164,18 @@ local function parse_line(line, state, namespace) r.arity = { minarity, maxarity } r.signature = signature(r) r.pretty_signature = pretty_signature(r) + -- check for signature conflict with functions with the same fqm + if state.functions[fqm] then + for _, variant in ipairs(state.functions[fqm]) do + if r.signature == variant.signature then + return nil, ("trying to define %s %s, but another function with same signature %s exists; at %s"):format(r.type, r.pretty_signature, variant.pretty_signature, line.source) + end + end + end -- define variables if not line.children then line.children = {} end -- define 👁️ variable - local seen_alias = state.builtin_aliases["👁️"] + local seen_alias = state.global_state.builtin_aliases["👁️"] if seen_alias then table.insert(line.children, 1, { content = (":👁️:%s=0"):format(seen_alias), source = line.source }) else @@ -175,7 +183,7 @@ local function parse_line(line, state, namespace) end if r.type == "function" then -- define 🔖 variable - local checkpoint_alias = state.builtin_aliases["🔖"] + local checkpoint_alias = state.global_state.builtin_aliases["🔖"] if checkpoint_alias then table.insert(line.children, 1, { content = (":🔖:%s=\"\""):format(checkpoint_alias), source = line.source }) else @@ -183,7 +191,7 @@ local function parse_line(line, state, namespace) end elseif r.type == "checkpoint" then -- define 🏁 variable - local reached_alias = state.builtin_aliases["🏁"] + local reached_alias = state.global_state.builtin_aliases["🏁"] if reached_alias then table.insert(line.children, 1, { content = (":🏁:%s=0"):format(reached_alias), source = line.source }) else @@ -216,13 +224,6 @@ local function parse_line(line, state, namespace) state.functions[fqm] = { r } -- overloading else - -- check for signature conflict with functions with the same fqm - for _, variant in ipairs(state.functions[fqm]) do - if r.signature == variant.signature then - return nil, ("trying to define %s %s, but another function with same signature %s exists; at %s"):format(r.type, r.pretty_signature, variant.pretty_signature, line.source) - end - end - -- add table.insert(state.functions[fqm], r) end -- definition @@ -422,9 +423,49 @@ local function parse(state, s, name, source) end -- transform ast indented = transform_indented(indented) + -- build state proxy + local state_proxy = { + aliases = setmetatable({}, { __index = state.aliases }), + variables = setmetatable({}, { __index = state.aliases }), + functions = setmetatable({}, { + __index = function(self, key) + if state.functions[key] then + local t = {} -- need to copy to allow ipairs over variants + for k, v in ipairs(state.functions[key]) do + t[k] = v + end + self[key] = t + return t + end + return nil + end + }), + queued_lines = {}, + global_state = state + } -- parse - local root, err = parse_block(indented, state, "") + local root, err = parse_block(indented, state_proxy, "") if not root then return nil, err end + -- merge back state proxy into global state + for k,v in pairs(state_proxy.aliases) do + state.aliases[k] = v + end + for k,v in pairs(state_proxy.variables) do + state.variables[k] = v + end + for k,v in pairs(state_proxy.functions) do + if not state.functions[k] then + state.functions[k] = v + else + for i,w in ipairs(v) do + state.functions[k][i] = w + end + end + end + for _,l in ipairs(state_proxy.queued_lines) do + table.insert(state.queued_lines, l) + end + -- return block return root end