mirror of
https://github.com/Reuh/anselme.git
synced 2025-10-27 16:49:31 +00:00
ArgumentTuple cleanup
This commit is contained in:
parent
fe351b5ca4
commit
ffadc0dd69
12 changed files with 88 additions and 105 deletions
|
|
@ -7,51 +7,48 @@ local ArgumentTuple
|
|||
ArgumentTuple = ast.abstract.Node {
|
||||
type = "argument tuple",
|
||||
|
||||
list = nil, -- list of expr
|
||||
named = nil, -- { [string] = expr, ... }
|
||||
assignment = nil, -- expr
|
||||
arity = 0,
|
||||
arguments = nil,
|
||||
|
||||
positional = nil, -- list of expr - can be sparse! but for each hole there should be an associated named arg
|
||||
named = nil, -- { [string name] = arg1, [pos number] = string name, ... }
|
||||
assignment = nil, -- expr; always the last argument if set
|
||||
arity = 0, -- number of arguments, i.e. number of positional+named+assignment arguments
|
||||
|
||||
init = function(self, ...)
|
||||
self.list = { ... }
|
||||
self.positional = { ... }
|
||||
self.named = {}
|
||||
self.arity = #self.list
|
||||
self.arity = #self.positional
|
||||
end,
|
||||
insert_positional = function(self, position, val) -- only for construction
|
||||
local l = {}
|
||||
for k, v in pairs(self.list) do
|
||||
if k >= position then l[k+1] = v
|
||||
else l[k] = v end
|
||||
end
|
||||
l[position] = val
|
||||
self.list = l
|
||||
add_positional = function(self, val) -- only for construction
|
||||
assert(not (self.positional[self.arity+1]) or self.assignment)
|
||||
self.arity = self.arity + 1
|
||||
self.positional[self.arity] = val
|
||||
end,
|
||||
set_positional = function(self, position, val) -- only for construction
|
||||
assert(not self.list[position])
|
||||
self.list[position] = val
|
||||
self.arity = self.arity + 1
|
||||
end,
|
||||
set_named = function(self, identifier, val) -- only for construction
|
||||
add_named = function(self, identifier, val) -- only for construction
|
||||
local name = identifier.name
|
||||
assert(not self.named[name])
|
||||
assert(not (self.named[name] or self.assignment))
|
||||
self.arity = self.arity + 1
|
||||
self.named[name] = val
|
||||
self.arity = self.arity + 1
|
||||
self.named[self.arity] = name
|
||||
end,
|
||||
set_assignment = function(self, val) -- only for construction
|
||||
add_assignment = function(self, val) -- only for construction
|
||||
assert(not self.assignment)
|
||||
self.assignment = val
|
||||
self.arity = self.arity + 1
|
||||
self.assignment = val
|
||||
self.format_priority = operator_priority["_=_"]
|
||||
end,
|
||||
|
||||
_format = function(self, state, priority, ...)
|
||||
local l = {}
|
||||
for _, e in pairs(self.list) do
|
||||
table.insert(l, e:format(state, operator_priority["_,_"], ...))
|
||||
for i=1, self.arity do
|
||||
if self.positional[i] then
|
||||
table.insert(l, self.positional[i]:format(state, operator_priority["_,_"], ...))
|
||||
elseif self.named[i] then
|
||||
local name = self.named[i]
|
||||
table.insert(l, name.."="..self.named[name]:format_right(state, operator_priority["_=_"], ...))
|
||||
else
|
||||
break
|
||||
end
|
||||
for n, e in pairs(self.named) do
|
||||
table.insert(l, n.."="..e:format_right(state, operator_priority["_=_"], ...))
|
||||
end
|
||||
local s = ("(%s)"):format(table.concat(l, ", "))
|
||||
if self.assignment then
|
||||
|
|
@ -61,59 +58,43 @@ ArgumentTuple = ast.abstract.Node {
|
|||
end,
|
||||
|
||||
traverse = function(self, fn, ...)
|
||||
for _, e in pairs(self.list) do
|
||||
fn(e, ...)
|
||||
end
|
||||
for _, e in pairs(self.named) do
|
||||
fn(e, ...)
|
||||
end
|
||||
if self.assignment then
|
||||
for i=1, self.arity do
|
||||
if self.positional[i] then
|
||||
fn(self.positional[i], ...)
|
||||
elseif self.named[i] then
|
||||
fn(self.named[self.named[i]], ...)
|
||||
else
|
||||
fn(self.assignment, ...)
|
||||
end
|
||||
end,
|
||||
|
||||
-- need to redefine hash to include a table.sort as pairs() in :traverse is non-deterministic
|
||||
-- as well as doesn't account for named arguments names
|
||||
_hash = function(self)
|
||||
local t = {}
|
||||
for _, e in pairs(self.list) do
|
||||
table.insert(t, e:hash())
|
||||
end
|
||||
for n, e in pairs(self.named) do
|
||||
table.insert(t, ("%s=%s"):format(n, e:hash()))
|
||||
end
|
||||
if self.assignment then
|
||||
table.insert(t, self.assignment:hash())
|
||||
end
|
||||
table.sort(t)
|
||||
return ("%s<%s>"):format(self.type, table.concat(t, ";"))
|
||||
end,
|
||||
|
||||
_eval = function(self, state)
|
||||
local r = ArgumentTuple:new()
|
||||
for i, e in pairs(self.list) do
|
||||
r:set_positional(i, e:eval(state))
|
||||
for i=1, self.arity do
|
||||
if self.positional[i] then
|
||||
r:add_positional(self.positional[i]:eval(state))
|
||||
elseif self.named[i] then
|
||||
r:add_named(Identifier:new(self.named[i]), self.named[self.named[i]]:eval(state))
|
||||
else
|
||||
r:add_assignment(self.assignment:eval(state))
|
||||
end
|
||||
for n, e in pairs(self.named) do
|
||||
r:set_named(Identifier:new(n), e:eval(state))
|
||||
end
|
||||
if self.assignment then
|
||||
r:set_assignment(self.assignment:eval(state))
|
||||
end
|
||||
return r
|
||||
end,
|
||||
|
||||
-- recreate new argumenttuple with a first positional argument added
|
||||
with_first_argument = function(self, first)
|
||||
local r = ArgumentTuple:new()
|
||||
r:set_positional(1, first)
|
||||
for i, e in pairs(self.list) do
|
||||
r:set_positional(i+1, e)
|
||||
r:add_positional(first)
|
||||
for i=1, self.arity do
|
||||
if self.positional[i] then
|
||||
r:add_positional(self.positional[i])
|
||||
elseif self.named[i] then
|
||||
r:add_named(Identifier:new(self.named[i]), self.named[self.named[i]])
|
||||
else
|
||||
r:add_assignment(self.assignment)
|
||||
end
|
||||
for n, e in pairs(self.named) do
|
||||
r:set_named(Identifier:new(n), e)
|
||||
end
|
||||
if self.assignment then
|
||||
r:set_assignment(self.assignment)
|
||||
end
|
||||
return r
|
||||
end,
|
||||
|
|
@ -140,9 +121,9 @@ ArgumentTuple = ast.abstract.Node {
|
|||
for i, param in ipairs(params.list) do
|
||||
-- search in args
|
||||
local arg
|
||||
if self.list[i] then
|
||||
if self.positional[i] then
|
||||
used_list[i] = true
|
||||
arg = self.list[i]
|
||||
arg = self.positional[i]
|
||||
elseif self.named[param.identifier.name] then
|
||||
used_named[param.identifier.name] = true
|
||||
arg = self.named[param.identifier.name]
|
||||
|
|
@ -166,14 +147,17 @@ ArgumentTuple = ast.abstract.Node {
|
|||
end
|
||||
end
|
||||
-- check for unused arguments
|
||||
for i in pairs(self.list) do
|
||||
for i=1, self.arity do
|
||||
if self.positional[i] then
|
||||
if not used_list[i] then
|
||||
return false, ("%sth positional argument is unused"):format(i)
|
||||
end
|
||||
elseif self.named[i] then
|
||||
if not used_named[self.named[i]] then
|
||||
return false, ("named argument %s is unused"):format(self.named[i])
|
||||
end
|
||||
for n in pairs(self.named) do
|
||||
if not used_named[n] then
|
||||
return false, ("named argument %s is unused"):format(n)
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
if self.assignment and not used_assignment then
|
||||
|
|
@ -186,8 +170,8 @@ ArgumentTuple = ast.abstract.Node {
|
|||
-- assume :match_parameter_tuple was already called and returned true
|
||||
bind_parameter_tuple = function(self, state, params)
|
||||
for i, arg in ipairs(params.list) do
|
||||
if self.list[i] then
|
||||
state.scope:define(arg.identifier:to_symbol(), self.list[i])
|
||||
if self.positional[i] then
|
||||
state.scope:define(arg.identifier:to_symbol(), self.positional[i])
|
||||
elseif self.named[arg.identifier.name] then
|
||||
state.scope:define(arg.identifier:to_symbol(), self.named[arg.identifier.name])
|
||||
elseif i == params.max_arity and params.assignment then
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
local ast = require("ast")
|
||||
local Identifier, Quote
|
||||
|
||||
local attached_block_identifier
|
||||
local attached_block_identifier, attached_block_symbol
|
||||
|
||||
local AttachBlock = ast.abstract.Node {
|
||||
type = "attach block",
|
||||
|
|
@ -26,7 +26,7 @@ local AttachBlock = ast.abstract.Node {
|
|||
|
||||
_eval = function(self, state)
|
||||
state.scope:push_partial(attached_block_identifier)
|
||||
state.scope:define(attached_block_identifier:to_symbol(), Quote:new(self.block)) -- _ is always wrapped in a Call when it appears
|
||||
state.scope:define(attached_block_symbol, Quote:new(self.block)) -- _ is always wrapped in a Call when it appears
|
||||
local exp = self.expression:eval(state)
|
||||
state.scope:pop()
|
||||
|
||||
|
|
@ -35,7 +35,7 @@ local AttachBlock = ast.abstract.Node {
|
|||
|
||||
_prepare = function(self, state)
|
||||
state.scope:push_partial(attached_block_identifier)
|
||||
state.scope:define(attached_block_identifier:to_symbol(), Quote:new(self.block))
|
||||
state.scope:define(attached_block_symbol, Quote:new(self.block))
|
||||
self.expression:prepare(state)
|
||||
state.scope:pop()
|
||||
end
|
||||
|
|
@ -45,5 +45,6 @@ package.loaded[...] = AttachBlock
|
|||
Identifier, Quote = ast.Identifier, ast.Quote
|
||||
|
||||
attached_block_identifier = Identifier:new("_")
|
||||
attached_block_symbol = attached_block_identifier:to_symbol()
|
||||
|
||||
return AttachBlock
|
||||
|
|
|
|||
|
|
@ -52,14 +52,14 @@ Call = ast.abstract.Node {
|
|||
if Identifier:is(self.func) then
|
||||
local name, arity = self.func.name, self.arguments.arity
|
||||
if infix[name] and arity == 2 then
|
||||
local left = self.arguments.list[1]:format(...)
|
||||
local right = self.arguments.list[2]:format_right(...)
|
||||
local left = self.arguments.positional[1]:format(...)
|
||||
local right = self.arguments.positional[2]:format_right(...)
|
||||
return ("%s %s %s"):format(left, name:match("^_(.*)_$"), right)
|
||||
elseif prefix[name] and arity == 1 then
|
||||
local right = self.arguments.list[1]:format_right(...)
|
||||
local right = self.arguments.positional[1]:format_right(...)
|
||||
return ("%s%s"):format(name:match("^(.*)_$"), right)
|
||||
elseif suffix[name] and arity == 1 then
|
||||
local left = self.arguments.list[1]:format(...)
|
||||
local left = self.arguments.positional[1]:format(...)
|
||||
return ("%s%s"):format(left, name:match("^_(.*)$"))
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
-- prevent an expression from being immediately evaluated, and instead only evaluate it when the node is explicitely called
|
||||
-- it can be used to evaluate the expression on demand, as if the quote call AST was simply replaced by the unevaluated associated expression AST (like a macro)
|
||||
-- it can be used to evaluate the expression on demand, as if the quote call AST was simply replaced by the unevaluated associated expression AST.
|
||||
-- kinda like a function, but no parameters, no closure and no new scope
|
||||
-- keep in mind that this thus bypass any scoping rule, closure, etc.
|
||||
--
|
||||
-- used for infix operators where the evaluation of the right term depends of the left one (lazy boolean operators, conditionals, etc.)
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ return Runtime(AutoCall, Event) {
|
|||
for _, e in ipairs(self.list) do
|
||||
table.insert(t, ("%s%s"):format(e[2]:format(...), e[1]:format(...)))
|
||||
end
|
||||
return ("| %s |"):format(table.concat(t, " "))
|
||||
return ("| %s|"):format(table.concat(t, " "))
|
||||
end,
|
||||
|
||||
-- Text comes from TextInterpolation which already evals the contents
|
||||
|
|
|
|||
|
|
@ -190,7 +190,7 @@ Node = class {
|
|||
end,
|
||||
|
||||
-- return a pretty string representation of the node.
|
||||
-- for non-runtime nodes (what was generated by a parse without any evaluation), this should return valid Anselme code that is functionnally equivalent to the parsed code. note that it currently does not preserve comment.
|
||||
-- for non-runtime nodes (what was generated by a parse without any evaluation), this should return valid Anselme code that is functionnally equivalent to the parsed code. note that it currently does not preserve comment. the returned code should additionally always be the same given the same non-runtime input.
|
||||
-- redefine _format, not this - note that _format is a mandary method for all nodes.
|
||||
-- state is optional and should only be relevant for runtime nodes; if specified, only show what is relevant for the current branch.
|
||||
-- indentation_level and parent_priority are optional value that respectively keep track in nester :format calls of the indentation level (number) and parent operator priority (number); if the node has a strictly lower priority than the parent node, parentheses will be added
|
||||
|
|
|
|||
|
|
@ -70,9 +70,9 @@ local function add_to_set(set, val)
|
|||
end
|
||||
|
||||
--# class creation logic #--
|
||||
local new_class, class_mt
|
||||
local class_mt
|
||||
|
||||
new_class = function(...)
|
||||
local function new_class(...)
|
||||
local class = {}
|
||||
local include = {...}
|
||||
for i=1, #include do
|
||||
|
|
|
|||
|
|
@ -2,10 +2,8 @@
|
|||
|
||||
local primary = require("parser.expression.primary.primary")
|
||||
|
||||
local StringInterpolation = require("ast.StringInterpolation")
|
||||
|
||||
local ast = require("ast")
|
||||
local String = ast.String
|
||||
local String, StringInterpolation = ast.String, ast.StringInterpolation
|
||||
|
||||
local expression_to_ast = require("parser.expression.to_ast")
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ return primary {
|
|||
if type_check:match(rem, 0, nil_val) then
|
||||
local exp
|
||||
exp, rem = type_check:parse(source, rem, nil, 0, nil_val)
|
||||
type_check_exp = exp.arguments.list[2]
|
||||
type_check_exp = exp.arguments.positional[2]
|
||||
end
|
||||
|
||||
return ident:to_symbol{ constant = constant, persistent = persistent, exported = exported, type_check = type_check_exp }:set_source(source), rem
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ return infix {
|
|||
end,
|
||||
|
||||
build_ast = function(self, left, right)
|
||||
left.arguments:set_assignment(right)
|
||||
left.arguments:add_assignment(right)
|
||||
return Call:new(left.func, left.arguments) -- recreate Call since we modified left.arguments
|
||||
end,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,8 +19,7 @@ return infix {
|
|||
|
||||
build_ast = function(self, left, right)
|
||||
if Call:is(right) then
|
||||
right.arguments:insert_positional(1, left)
|
||||
return right
|
||||
return Call:new(right.func, right.arguments:with_first_argument(left))
|
||||
else
|
||||
return Call:new(right, ArgumentTuple:new(left))
|
||||
end
|
||||
|
|
|
|||
|
|
@ -27,11 +27,11 @@ return secondary {
|
|||
exp = Tuple:new(exp)
|
||||
end
|
||||
|
||||
for i, v in ipairs(exp.list) do
|
||||
for _, v in ipairs(exp.list) do
|
||||
if Assignment:is(v) then
|
||||
args:set_named(v.identifier, v.expression)
|
||||
args:add_named(v.identifier, v.expression)
|
||||
else
|
||||
args:set_positional(i, v)
|
||||
args:add_positional(v)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue