mirror of
https://github.com/Reuh/anselme.git
synced 2025-10-27 16:49:31 +00:00
Show source file in error messages
This commit is contained in:
parent
b233d7fa1e
commit
a6c4eee4b3
14 changed files with 84 additions and 71 deletions
14
anselme.lua
14
anselme.lua
|
|
@ -7,6 +7,12 @@ local anselme = {
|
||||||
}
|
}
|
||||||
package.loaded[...] = anselme
|
package.loaded[...] = anselme
|
||||||
|
|
||||||
|
-- TODO: for type checking functions:
|
||||||
|
-- pour éliminer totalement les undefined
|
||||||
|
-- ne type checker/compiler les fonctions que lorsqu'elles sont apppelées, en déterminant leur type à ce moment là selon les arguments donnés
|
||||||
|
-- (du coup la surcharge ne se fera que selon l'arité. Mais ça sera 100% type checké)
|
||||||
|
-- PB: les listes ont des types mixés (cf les varargs) + afficher des warnings dans le selecteur de variante lorsqu'un type de retour manque
|
||||||
|
|
||||||
-- load libs
|
-- load libs
|
||||||
local preparse = require((...):gsub("anselme$", "parser.preparser"))
|
local preparse = require((...):gsub("anselme$", "parser.preparser"))
|
||||||
local postparse = require((...):gsub("anselme$", "parser.postparser"))
|
local postparse = require((...):gsub("anselme$", "parser.postparser"))
|
||||||
|
|
@ -60,7 +66,7 @@ local interpreter_methods = {
|
||||||
local namespace = self:current_namespace()
|
local namespace = self:current_namespace()
|
||||||
-- replace state with interrupted state
|
-- replace state with interrupted state
|
||||||
local exp, err = expression(expr, self.state.interpreter.global_state, namespace or "")
|
local exp, err = expression(expr, self.state.interpreter.global_state, namespace or "")
|
||||||
if not exp then return "error", ("%s; during interrupt %q at line %s"):format(err, expr, line and line.line or 0) end
|
if not exp then return "error", ("%s; during interrupt %q at %s"):format(err, expr, line and line.source or "unknown") end
|
||||||
local r, e = self.vm:run(exp)
|
local r, e = self.vm:run(exp)
|
||||||
if not r then return "error", e end
|
if not r then return "error", e end
|
||||||
self.state = r.state
|
self.state = r.state
|
||||||
|
|
@ -157,15 +163,15 @@ local vm_mt = {
|
||||||
--- load code
|
--- load code
|
||||||
-- return self in case of success
|
-- return self in case of success
|
||||||
-- returns nil, err in case of error
|
-- returns nil, err in case of error
|
||||||
loadstring = function(self, str, name)
|
loadstring = function(self, str, name, source)
|
||||||
local s, e = preparse(self.state, str, name or "")
|
local s, e = preparse(self.state, str, name or "", source)
|
||||||
if not s then return s, e end
|
if not s then return s, e end
|
||||||
return self
|
return self
|
||||||
end,
|
end,
|
||||||
loadfile = function(self, path, name)
|
loadfile = function(self, path, name)
|
||||||
local f, e = io.open(path, "r")
|
local f, e = io.open(path, "r")
|
||||||
if not f then return f, e end
|
if not f then return f, e end
|
||||||
local s, err = self:loadstring(f:read("*a"), name or "")
|
local s, err = self:loadstring(f:read("*a"), name, path)
|
||||||
f:close()
|
f:close()
|
||||||
if not s then return s, err end
|
if not s then return s, err end
|
||||||
return self
|
return self
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ local flush_state, to_lua, from_lua, eval_text
|
||||||
|
|
||||||
local run, run_block
|
local run, run_block
|
||||||
|
|
||||||
|
local unpack = table.unpack or unpack
|
||||||
|
|
||||||
--- evaluate an expression
|
--- evaluate an expression
|
||||||
-- returns evaluated value if success
|
-- returns evaluated value if success
|
||||||
-- returns nil, error if error
|
-- returns nil, error if error
|
||||||
|
|
|
||||||
|
|
@ -41,21 +41,21 @@ local function run_line(state, line)
|
||||||
local skipped = false
|
local skipped = false
|
||||||
if line.condition then
|
if line.condition then
|
||||||
local v, e = eval(state, line.condition)
|
local v, e = eval(state, line.condition)
|
||||||
if not v then return v, ("%s; at line %s"):format(e, line.line) end
|
if not v then return v, ("%s; at %s"):format(e, line.source) end
|
||||||
skipped = not truthy(v)
|
skipped = not truthy(v)
|
||||||
end
|
end
|
||||||
if not skipped then
|
if not skipped then
|
||||||
-- tag decorator
|
-- tag decorator
|
||||||
if line.tag then
|
if line.tag then
|
||||||
local v, e = eval(state, line.tag)
|
local v, e = eval(state, line.tag)
|
||||||
if not v then return v, ("%s; in tag decorator at line %s"):format(e, line.line) end
|
if not v then return v, ("%s; in tag decorator at %s"):format(e, line.source) end
|
||||||
tags:push(state, v)
|
tags:push(state, v)
|
||||||
end
|
end
|
||||||
-- line types
|
-- line types
|
||||||
if line.type == "condition" then
|
if line.type == "condition" then
|
||||||
state.interpreter.last_condition_success = nil
|
state.interpreter.last_condition_success = nil
|
||||||
local v, e = eval(state, line.expression)
|
local v, e = eval(state, line.expression)
|
||||||
if not v then return v, ("%s; at line %s"):format(e, line.line) end
|
if not v then return v, ("%s; at %s"):format(e, line.source) end
|
||||||
if truthy(v) then
|
if truthy(v) then
|
||||||
state.interpreter.last_condition_success = true
|
state.interpreter.last_condition_success = true
|
||||||
v, e = run_block(state, line.child)
|
v, e = run_block(state, line.child)
|
||||||
|
|
@ -65,7 +65,7 @@ local function run_line(state, line)
|
||||||
elseif line.type == "else-condition" then
|
elseif line.type == "else-condition" then
|
||||||
if not state.interpreter.last_condition_success then
|
if not state.interpreter.last_condition_success then
|
||||||
local v, e = eval(state, line.expression)
|
local v, e = eval(state, line.expression)
|
||||||
if not v then return v, ("%s; at line %s"):format(e, line.line) end
|
if not v then return v, ("%s; at %s"):format(e, line.source) end
|
||||||
if truthy(v) then
|
if truthy(v) then
|
||||||
state.interpreter.last_condition_success = true
|
state.interpreter.last_condition_success = true
|
||||||
v, e = run_block(state, line.child)
|
v, e = run_block(state, line.child)
|
||||||
|
|
@ -81,7 +81,7 @@ local function run_line(state, line)
|
||||||
elseif line.type == "tag" then
|
elseif line.type == "tag" then
|
||||||
if line.expression then
|
if line.expression then
|
||||||
local v, e = eval(state, line.expression)
|
local v, e = eval(state, line.expression)
|
||||||
if not v then return v, ("%s; at line %s"):format(e, line.line) end
|
if not v then return v, ("%s; at %s"):format(e, line.source) end
|
||||||
tags:push(state, v)
|
tags:push(state, v)
|
||||||
end
|
end
|
||||||
local v, e = run_block(state, line.child)
|
local v, e = run_block(state, line.child)
|
||||||
|
|
@ -92,12 +92,12 @@ local function run_line(state, line)
|
||||||
local v, e
|
local v, e
|
||||||
if line.expression then
|
if line.expression then
|
||||||
v, e = eval(state, line.expression)
|
v, e = eval(state, line.expression)
|
||||||
if not v then return v, ("%s; at line %s"):format(e, line.line) end
|
if not v then return v, ("%s; at %s"):format(e, line.source) end
|
||||||
end
|
end
|
||||||
return v
|
return v
|
||||||
elseif line.type == "text" then
|
elseif line.type == "text" then
|
||||||
local t, er = eval_text(state, line.text)
|
local t, er = eval_text(state, line.text)
|
||||||
if not t then return t, ("%s; at line %s"):format(er, line.line) end
|
if not t then return t, ("%s; at %s"):format(er, line.source) end
|
||||||
write_event(state, "text", t)
|
write_event(state, "text", t)
|
||||||
elseif line.type == "flush_events" then
|
elseif line.type == "flush_events" then
|
||||||
while state.interpreter.event_buffer do
|
while state.interpreter.event_buffer do
|
||||||
|
|
@ -122,7 +122,7 @@ local function run_line(state, line)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif line.type ~= "paragraph" then
|
elseif line.type ~= "paragraph" then
|
||||||
return nil, ("unknown line type %q; line %s"):format(line.type, line.line)
|
return nil, ("unknown line type %q; at %s"):format(line.type, line.source)
|
||||||
end
|
end
|
||||||
-- tag decorator
|
-- tag decorator
|
||||||
if line.tag then
|
if line.tag then
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ local escapeCache = {}
|
||||||
local common
|
local common
|
||||||
common = {
|
common = {
|
||||||
--- valid identifier pattern
|
--- valid identifier pattern
|
||||||
identifier_pattern = "[^%%%/%*%+%-%(%)%!%&%|%=%$%?%>%<%:%{%}%[%]%,]+",
|
identifier_pattern = "[^%%%/%*%+%-%(%)%!%&%|%=%$%?%>%<%:%{%}%[%]%,%\"]+",
|
||||||
--- escape a string to be used as an exact match pattern
|
--- escape a string to be used as an exact match pattern
|
||||||
escape = function(str)
|
escape = function(str)
|
||||||
if not escapeCache[str] then
|
if not escapeCache[str] then
|
||||||
|
|
|
||||||
|
|
@ -91,27 +91,6 @@ local function expression(s, state, namespace, currentPriority, operatingOn)
|
||||||
elseif s:match("^"..identifier_pattern) then
|
elseif s:match("^"..identifier_pattern) then
|
||||||
local name, r = s:match("^("..identifier_pattern..")(.-)$")
|
local name, r = s:match("^("..identifier_pattern..")(.-)$")
|
||||||
name = format_identifier(name, state)
|
name = format_identifier(name, state)
|
||||||
-- functions
|
|
||||||
local funcs, ffqm = find(state.functions, namespace, name)
|
|
||||||
if funcs then
|
|
||||||
local args, explicit_call
|
|
||||||
if r:match("^%b()") then
|
|
||||||
explicit_call = true
|
|
||||||
local content, rem = r:match("^(%b())(.*)$")
|
|
||||||
content = content:gsub("^%(", ""):gsub("%)$", "")
|
|
||||||
r = rem
|
|
||||||
-- get arguments
|
|
||||||
if content:match("[^%s]") then
|
|
||||||
local err
|
|
||||||
args, err = expression(content, state, namespace)
|
|
||||||
if not args then return args, err end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- find compatible variant
|
|
||||||
local variant, err = find_function_variant(ffqm, state, args, explicit_call)
|
|
||||||
if not variant then return variant, err end
|
|
||||||
return expression(r, state, namespace, currentPriority, variant)
|
|
||||||
end
|
|
||||||
-- variables
|
-- variables
|
||||||
local var, vfqm = find(state.variables, namespace, name)
|
local var, vfqm = find(state.variables, namespace, name)
|
||||||
if var then
|
if var then
|
||||||
|
|
@ -133,6 +112,27 @@ local function expression(s, state, namespace, currentPriority, operatingOn)
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
-- functions
|
||||||
|
local funcs, ffqm = find(state.functions, namespace, name)
|
||||||
|
if funcs then
|
||||||
|
local args, explicit_call
|
||||||
|
if r:match("^%b()") then
|
||||||
|
explicit_call = true
|
||||||
|
local content, rem = r:match("^(%b())(.*)$")
|
||||||
|
content = content:gsub("^%(", ""):gsub("%)$", "")
|
||||||
|
r = rem
|
||||||
|
-- get arguments
|
||||||
|
if content:match("[^%s]") then
|
||||||
|
local err
|
||||||
|
args, err = expression(content, state, namespace)
|
||||||
|
if not args then return args, err end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- find compatible variant
|
||||||
|
local variant, err = find_function_variant(ffqm, state, args, explicit_call)
|
||||||
|
if not variant then return variant, err end
|
||||||
|
return expression(r, state, namespace, currentPriority, variant)
|
||||||
|
end
|
||||||
return nil, ("unknown identifier %q"):format(name)
|
return nil, ("unknown identifier %q"):format(name)
|
||||||
end
|
end
|
||||||
-- unops
|
-- unops
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,8 @@ local function parse(state)
|
||||||
if line.condition then
|
if line.condition then
|
||||||
if line.condition:match("[^%s]") then
|
if line.condition:match("[^%s]") then
|
||||||
local exp, rem = expression(line.condition, state, namespace)
|
local exp, rem = expression(line.condition, state, namespace)
|
||||||
if not exp then return nil, ("%s; at line %s"):format(rem, line.line) end
|
if not exp then return nil, ("%s; at %s"):format(rem, line.source) end
|
||||||
if rem:match("[^%s]") then return nil, ("expected end of expression before %q in condition decorator; at line %s"):format(rem, line.line) end
|
if rem:match("[^%s]") then return nil, ("expected end of expression before %q in condition decorator; at %s"):format(rem, line.source) end
|
||||||
line.condition = exp
|
line.condition = exp
|
||||||
else
|
else
|
||||||
line.condition = nil
|
line.condition = nil
|
||||||
|
|
@ -20,8 +20,8 @@ local function parse(state)
|
||||||
if line.tag then
|
if line.tag then
|
||||||
if line.tag:match("[^%s]") then
|
if line.tag:match("[^%s]") then
|
||||||
local exp, rem = expression(line.tag, state, namespace)
|
local exp, rem = expression(line.tag, state, namespace)
|
||||||
if not exp then return nil, ("%s; at line %s"):format(rem, line.line) end
|
if not exp then return nil, ("%s; at %s"):format(rem, line.source) end
|
||||||
if rem:match("[^%s]") then return nil, ("expected end of expression before %q in condition decorator; at line %s"):format(rem, line.line) end
|
if rem:match("[^%s]") then return nil, ("expected end of expression before %q in condition decorator; at %s"):format(rem, line.source) end
|
||||||
line.tag = exp
|
line.tag = exp
|
||||||
else
|
else
|
||||||
line.tag = nil
|
line.tag = nil
|
||||||
|
|
@ -31,8 +31,8 @@ local function parse(state)
|
||||||
if line.expression then
|
if line.expression then
|
||||||
if line.expression:match("[^%s]") then
|
if line.expression:match("[^%s]") then
|
||||||
local exp, rem = expression(line.expression, state, namespace)
|
local exp, rem = expression(line.expression, state, namespace)
|
||||||
if not exp then return nil, ("%s; at line %s"):format(rem, line.line) end
|
if not exp then return nil, ("%s; at %s"):format(rem, line.source) end
|
||||||
if rem:match("[^%s]") then return nil, ("expected end of expression before %q; at line %s"):format(rem, line.line) end
|
if rem:match("[^%s]") then return nil, ("expected end of expression before %q; at %s"):format(rem, line.source) end
|
||||||
line.expression = exp
|
line.expression = exp
|
||||||
else
|
else
|
||||||
line.expression = nil
|
line.expression = nil
|
||||||
|
|
@ -45,7 +45,7 @@ local function parse(state)
|
||||||
if not variant.return_type then
|
if not variant.return_type then
|
||||||
variant.return_type = return_type
|
variant.return_type = return_type
|
||||||
elseif variant.return_type ~= return_type then
|
elseif variant.return_type ~= return_type then
|
||||||
return nil, ("trying to return a %s in a function that returns a %s; at line %s"):format(return_type, variant.return_type, line.line)
|
return nil, ("trying to return a %s in a function that returns a %s; at %s"):format(return_type, variant.return_type, line.source)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -53,7 +53,7 @@ local function parse(state)
|
||||||
-- text
|
-- text
|
||||||
if line.text then
|
if line.text then
|
||||||
local txt, err = parse_text(line.text, state, namespace)
|
local txt, err = parse_text(line.text, state, namespace)
|
||||||
if err then return nil, ("%s; at line %s"):format(err, line.line) end
|
if err then return nil, ("%s; at %s"):format(err, line.source) end
|
||||||
line.text = txt
|
line.text = txt
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ local eval
|
||||||
local function parse_line(line, state, namespace)
|
local function parse_line(line, state, namespace)
|
||||||
local l = line.content
|
local l = line.content
|
||||||
local r = {
|
local r = {
|
||||||
line = line.line
|
source = line.source
|
||||||
}
|
}
|
||||||
-- comment
|
-- comment
|
||||||
if l:match("^%(") then
|
if l:match("^%(") then
|
||||||
|
|
@ -113,7 +113,7 @@ local function parse_line(line, state, namespace)
|
||||||
-- define function and variables
|
-- define function and variables
|
||||||
r.namespace = fqm.."."
|
r.namespace = fqm.."."
|
||||||
r.name = fqm
|
r.name = fqm
|
||||||
if state.variables[fqm] then return nil, ("trying to define %s %s, but a variable with the same name exists; at line %s"):format(r.type, fqm, line.line) end
|
if state.variables[fqm] then return nil, ("trying to define %s %s, but a variable with the same name exists; at %s"):format(r.type, fqm, line.source) end
|
||||||
r.variant = {
|
r.variant = {
|
||||||
arity = arity,
|
arity = arity,
|
||||||
types = {},
|
types = {},
|
||||||
|
|
@ -144,13 +144,13 @@ local function parse_line(line, state, namespace)
|
||||||
min, max = variant.arity, r.variant.arity
|
min, max = variant.arity, r.variant.arity
|
||||||
end
|
end
|
||||||
if min == vmin and max == vmax then
|
if min == vmin and max == vmax then
|
||||||
return nil, ("trying to define %s %s with arity [%s;%s], but another function with the arity exist; at line %s"):format(r.type, fqm, min, max, line.line)
|
return nil, ("trying to define %s %s with arity [%s;%s], but another function with the arity exist; at %s"):format(r.type, fqm, min, max, line.source)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- add
|
-- add
|
||||||
table.insert(state.functions[fqm], r.variant)
|
table.insert(state.functions[fqm], r.variant)
|
||||||
end
|
end
|
||||||
-- set type check information
|
-- define args and set type check information
|
||||||
for i, param in ipairs(r.params) do
|
for i, param in ipairs(r.params) do
|
||||||
if not state.variables[param] then
|
if not state.variables[param] then
|
||||||
state.variables[param] = {
|
state.variables[param] = {
|
||||||
|
|
@ -166,9 +166,9 @@ local function parse_line(line, state, namespace)
|
||||||
r.type = "definition"
|
r.type = "definition"
|
||||||
r.remove_from_block_ast = true
|
r.remove_from_block_ast = true
|
||||||
local exp, rem = expression(l:match("^:(.*)$"), state, namespace) -- expression parsing is done directly to get type information
|
local exp, rem = expression(l:match("^:(.*)$"), state, namespace) -- expression parsing is done directly to get type information
|
||||||
if not exp then return nil, ("%s; at line %s"):format(rem, line.line) end
|
if not exp then return nil, ("%s; at %s"):format(rem, line.source) end
|
||||||
local fqm = ("%s%s"):format(namespace, format_identifier(rem, state))
|
local fqm = ("%s%s"):format(namespace, format_identifier(rem, state))
|
||||||
if state.functions[fqm] then return nil, ("trying to define variable %s, but a function with the same name exists; at line %s"):format(fqm, line.line) end
|
if state.functions[fqm] then return nil, ("trying to define variable %s, but a function with the same name exists; at %s"):format(fqm, line.source) end
|
||||||
if not state.variables[fqm] or state.variables[fqm].type == "undefined argument" then
|
if not state.variables[fqm] or state.variables[fqm].type == "undefined argument" then
|
||||||
local v, e = eval(state, exp)
|
local v, e = eval(state, exp)
|
||||||
if not v then return v, e end
|
if not v then return v, e end
|
||||||
|
|
@ -179,7 +179,7 @@ local function parse_line(line, state, namespace)
|
||||||
end
|
end
|
||||||
state.variables[fqm] = v
|
state.variables[fqm] = v
|
||||||
elseif state.variables[fqm].type ~= exp.type then
|
elseif state.variables[fqm].type ~= exp.type then
|
||||||
return nil, ("trying to define variable %s of type %s but a it is already defined with type %s; at line %s"):format(fqm, exp.type, state.variables[fqm].type, line.line)
|
return nil, ("trying to define variable %s of type %s but a it is already defined with type %s; at %s"):format(fqm, exp.type, state.variables[fqm].type, line.source)
|
||||||
end
|
end
|
||||||
-- tag
|
-- tag
|
||||||
elseif l:match("^%#") then
|
elseif l:match("^%#") then
|
||||||
|
|
@ -200,7 +200,7 @@ local function parse_line(line, state, namespace)
|
||||||
else
|
else
|
||||||
r.type = "flush_events"
|
r.type = "flush_events"
|
||||||
end
|
end
|
||||||
if not r.type then return nil, ("unknown line %s type"):format(line.line) end
|
if not r.type then return nil, ("unknown line %s type"):format(line.source) end
|
||||||
return r
|
return r
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -224,7 +224,7 @@ local function parse_block(indented, state, namespace, parent_function, last_eve
|
||||||
if ast.type == "flush" then last_event = nil end
|
if ast.type == "flush" then last_event = nil end
|
||||||
if ast.push_event then
|
if ast.push_event then
|
||||||
if last_event and ast.push_event ~= last_event then
|
if last_event and ast.push_event ~= last_event then
|
||||||
table.insert(block, { line = l.line, type = "flush_events" })
|
table.insert(block, { source = l.source, type = "flush_events" })
|
||||||
end
|
end
|
||||||
last_event = ast.push_event
|
last_event = ast.push_event
|
||||||
end
|
end
|
||||||
|
|
@ -232,9 +232,9 @@ local function parse_block(indented, state, namespace, parent_function, last_eve
|
||||||
ast.parent_position = #block+1
|
ast.parent_position = #block+1
|
||||||
if ast.replace_with then
|
if ast.replace_with then
|
||||||
if indented[i+1].content then
|
if indented[i+1].content then
|
||||||
table.insert(indented, i+1, { content = ast.replace_with, line = l.line })
|
table.insert(indented, i+1, { content = ast.replace_with, source = l.source })
|
||||||
else
|
else
|
||||||
table.insert(indented, i+2, { content = ast.replace_with, line = l.line }) -- if line has children
|
table.insert(indented, i+2, { content = ast.replace_with, source = l.source }) -- if line has children
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
table.insert(block, ast)
|
table.insert(block, ast)
|
||||||
|
|
@ -247,7 +247,7 @@ local function parse_block(indented, state, namespace, parent_function, last_eve
|
||||||
-- indented (ignore block comments)
|
-- indented (ignore block comments)
|
||||||
elseif lastLine.type ~= "comment" then
|
elseif lastLine.type ~= "comment" then
|
||||||
if not lastLine.child then
|
if not lastLine.child then
|
||||||
return nil, ("line %s (%s) can't have children"):format(lastLine.line, lastLine.type)
|
return nil, ("line %s (%s) can't have children"):format(lastLine.source, lastLine.type)
|
||||||
else
|
else
|
||||||
local r, e = parse_block(l, state, lastLine.namespace or namespace, lastLine.type == "function" and lastLine or parent_function, last_event)
|
local r, e = parse_block(l, state, lastLine.namespace or namespace, lastLine.type == "function" and lastLine or parent_function, last_event)
|
||||||
if not r then return r, e end
|
if not r then return r, e end
|
||||||
|
|
@ -262,7 +262,7 @@ end
|
||||||
--- returns the nested list of lines {content="", line=1}, grouped by indentation
|
--- returns the nested list of lines {content="", line=1}, grouped by indentation
|
||||||
-- multiple empty lines are merged
|
-- multiple empty lines are merged
|
||||||
-- * list, last line
|
-- * list, last line
|
||||||
local function parse_indent(lines, i, indentLevel, insert_empty_line)
|
local function parse_indent(lines, source, i, indentLevel, insert_empty_line)
|
||||||
i = i or 1
|
i = i or 1
|
||||||
indentLevel = indentLevel or 0
|
indentLevel = indentLevel or 0
|
||||||
local indented = {}
|
local indented = {}
|
||||||
|
|
@ -271,13 +271,13 @@ local function parse_indent(lines, i, indentLevel, insert_empty_line)
|
||||||
local indent, line = lines[i]:match("^(%s*)(.*)$")
|
local indent, line = lines[i]:match("^(%s*)(.*)$")
|
||||||
if #indent == indentLevel then
|
if #indent == indentLevel then
|
||||||
if insert_empty_line then
|
if insert_empty_line then
|
||||||
table.insert(indented, { content = "", line = insert_empty_line })
|
table.insert(indented, { content = "", source = ("%s:%s"):format(source, insert_empty_line) })
|
||||||
insert_empty_line = false
|
insert_empty_line = false
|
||||||
end
|
end
|
||||||
table.insert(indented, { content = line, line = i })
|
table.insert(indented, { content = line, source = ("%s:%s"):format(source, i) })
|
||||||
elseif #indent > indentLevel then
|
elseif #indent > indentLevel then
|
||||||
local t
|
local t
|
||||||
t, i = parse_indent(lines, i, #indent, insert_empty_line)
|
t, i = parse_indent(lines, source, i, #indent, insert_empty_line)
|
||||||
table.insert(indented, t)
|
table.insert(indented, t)
|
||||||
else
|
else
|
||||||
return indented, i-1
|
return indented, i-1
|
||||||
|
|
@ -303,17 +303,17 @@ end
|
||||||
-- (wait for other files to be parsed before doing this with postparse)
|
-- (wait for other files to be parsed before doing this with postparse)
|
||||||
-- * state: in case of success
|
-- * state: in case of success
|
||||||
-- * nil, err: in case of error
|
-- * nil, err: in case of error
|
||||||
local function parse(state, s, name)
|
local function parse(state, s, name, source)
|
||||||
-- parse lines
|
-- parse lines
|
||||||
local lines = parse_lines(s)
|
local lines = parse_lines(s)
|
||||||
local indented = parse_indent(lines)
|
local indented = parse_indent(lines, source or name)
|
||||||
-- wrap in named function if neccessary
|
-- wrap in named function if neccessary
|
||||||
if name ~= "" then
|
if name ~= "" then
|
||||||
if not name:match("^"..identifier_pattern.."$") then
|
if not name:match("^"..identifier_pattern.."$") then
|
||||||
return nil, ("invalid function name %q"):format(name)
|
return nil, ("invalid function name %q"):format(name)
|
||||||
end
|
end
|
||||||
indented = {
|
indented = {
|
||||||
{ content = "$ "..name, line = 0 },
|
{ content = "$ "..name, source = ("%s:%s"):format(source or name, 0) },
|
||||||
indented
|
indented
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
|
||||||
3
test.ans
3
test.ans
|
|
@ -1,3 +1,6 @@
|
||||||
$ f(a, b)
|
$ f(a, b)
|
||||||
|
|
||||||
$ f(x)
|
$ f(x)
|
||||||
|
kk {x+1}
|
||||||
|
|
||||||
|
~ f(6)
|
||||||
|
|
@ -182,6 +182,7 @@ else
|
||||||
print(inspect(result))
|
print(inspect(result))
|
||||||
print("is not equal to")
|
print("is not equal to")
|
||||||
print(inspect(output))
|
print(inspect(output))
|
||||||
|
print("")
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
success = success + 1
|
success = success + 1
|
||||||
|
|
@ -192,6 +193,7 @@ else
|
||||||
print(e)
|
print(e)
|
||||||
print("result was:")
|
print("result was:")
|
||||||
print(inspect(result))
|
print(inspect(result))
|
||||||
|
print("")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
local _={}
|
local _={}
|
||||||
_[1]={"error","trying to define variable define override function.a, but a function with the same name exists; at line 3"}
|
_[1]={"error","trying to define variable define override function.a, but a function with the same name exists; at test/tests/define override function.ans:3"}
|
||||||
return {_[1]}
|
return {_[1]}
|
||||||
--[[
|
--[[
|
||||||
{ "error", "trying to define variable define override function.a, but a function with the same name exists; at line 3" }
|
{ "error", "trying to define variable define override function.a, but a function with the same name exists; at test/tests/define override function.ans:3" }
|
||||||
]]--
|
]]--
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
local _={}
|
local _={}
|
||||||
_[1]={"error","trying to define function define override variable.a, but a variable with the same name exists; at line 3"}
|
_[1]={"error","trying to define function define override variable.a, but a variable with the same name exists; at test/tests/define override variable.ans:3"}
|
||||||
return {_[1]}
|
return {_[1]}
|
||||||
--[[
|
--[[
|
||||||
{ "error", "trying to define function define override variable.a, but a variable with the same name exists; at line 3" }
|
{ "error", "trying to define function define override variable.a, but a variable with the same name exists; at test/tests/define override variable.ans:3" }
|
||||||
]]--
|
]]--
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
local _={}
|
local _={}
|
||||||
_[1]={"error","function \"function args arity check fail.f\" expected 2 arguments but received 1; at line 4"}
|
_[1]={"error","function \"function args arity check fail.f\" expected 2 arguments but received 1; at test/tests/function args arity check fail.ans:4"}
|
||||||
return {_[1]}
|
return {_[1]}
|
||||||
--[[
|
--[[
|
||||||
{ "error", 'function "function args arity check fail.f" expected 2 arguments but received 1; at line 4' }
|
{ "error", 'function "function args arity check fail.f" expected 2 arguments but received 1; at test/tests/function args arity check fail.ans:4' }
|
||||||
]]--
|
]]--
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
local _={}
|
local _={}
|
||||||
_[1]={"error","trying to define function function arity conflict.f with arity [2;2], but another function with the arity exist; at line 5"}
|
_[1]={"error","trying to define function function arity conflict.f with arity [2;2], but another function with the arity exist; at test/tests/function arity conflict.ans:5"}
|
||||||
return {_[1]}
|
return {_[1]}
|
||||||
--[[
|
--[[
|
||||||
{ "error", "trying to define function function arity conflict.f with arity [2;2], but another function with the arity exist; at line 5" }
|
{ "error", "trying to define function function arity conflict.f with arity [2;2], but another function with the arity exist; at test/tests/function arity conflict.ans:5" }
|
||||||
]]--
|
]]--
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
local _={}
|
local _={}
|
||||||
_[1]={"error","unknown identifier \"b\"; at line 4"}
|
_[1]={"error","unknown identifier \"b\"; at test/tests/function scope wrong.ans:4"}
|
||||||
return {_[1]}
|
return {_[1]}
|
||||||
--[[
|
--[[
|
||||||
{ "error", 'unknown identifier "b"; at line 4' }
|
{ "error", 'unknown identifier "b"; at test/tests/function scope wrong.ans:4' }
|
||||||
]]--
|
]]--
|
||||||
Loading…
Add table
Add a link
Reference in a new issue