diff --git a/anselme/ast/ArgumentTuple.lua b/anselme/ast/ArgumentTuple.lua index 42d57bf..66b7803 100644 --- a/anselme/ast/ArgumentTuple.lua +++ b/anselme/ast/ArgumentTuple.lua @@ -35,7 +35,6 @@ ArgumentTuple = ast.abstract.Node { assert(not self.assignment) self.arity = self.arity + 1 self.assignment = val - self.format_priority = operator_priority["_=_"] end, _format = function(self, state, priority, ...) @@ -56,6 +55,13 @@ ArgumentTuple = ast.abstract.Node { end return s end, + _format_priority = function(self) + if self.assignment then + return operator_priority["_=_"] + else + return math.huge + end + end, traverse = function(self, fn, ...) for i=1, self.arity do diff --git a/anselme/ast/Assignment.lua b/anselme/ast/Assignment.lua index faeb5bf..b4b09a9 100644 --- a/anselme/ast/Assignment.lua +++ b/anselme/ast/Assignment.lua @@ -8,7 +8,6 @@ local Assignment = ast.abstract.Node { identifier = nil, expression = nil, - format_priority = operator_priority["_=_"], init = function(self, identifier, expression) self.identifier = identifier @@ -18,6 +17,9 @@ local Assignment = ast.abstract.Node { _format = function(self, ...) return self.identifier:format(...).." = "..self.expression:format_right(...) end, + _format_priority = function(self) + return operator_priority["_=_"] + end, traverse = function(self, fn, ...) fn(self.identifier, ...) diff --git a/anselme/ast/Call.lua b/anselme/ast/Call.lua index 8b6f918..090a51d 100644 --- a/anselme/ast/Call.lua +++ b/anselme/ast/Call.lua @@ -19,26 +19,10 @@ Call = ast.abstract.Node { func = nil, arguments = nil, -- ArgumentTuple - format_priority = infix["_!"], -- often overwritten in :init init = function(self, func, arguments) self.func = func self.arguments = arguments - - -- get priority: operators - if Identifier:is(self.func) then - local name, arity = self.func.name, self.arguments.arity - if infix[name] and arity == 2 then - self.format_priority = infix[name] - elseif prefix[name] and arity == 1 then - self.format_priority = prefix[name] - elseif suffix[name] and arity == 1 then - self.format_priority = suffix[name] - end - end - if self.arguments.assignment then - self.format_priority = operator_priority["_=_"] - end end, _format = function(self, ...) @@ -66,6 +50,22 @@ Call = ast.abstract.Node { return self.func:format(...)..self.arguments:format(...) -- no need for format_right, we already handle the assignment priority here end end, + _format_priority = function(self) + if Identifier:is(self.func) then + local name, arity = self.func.name, self.arguments.arity + if infix[name] and arity == 2 then + return infix[name] + elseif prefix[name] and arity == 1 then + return prefix[name] + elseif suffix[name] and arity == 1 then + return suffix[name] + end + end + if self.arguments.assignment then + return operator_priority["_=_"] + end + return operator_priority["_!"] + end, traverse = function(self, fn, ...) fn(self.func, ...) diff --git a/anselme/ast/Choice.lua b/anselme/ast/Choice.lua index 73e6eb1..c1bedd3 100644 --- a/anselme/ast/Choice.lua +++ b/anselme/ast/Choice.lua @@ -9,7 +9,6 @@ Choice = ast.abstract.Runtime { text = nil, func = nil, - format_priority = operator_priority["_|>_"], init = function(self, text, func) self.text = text @@ -24,6 +23,9 @@ Choice = ast.abstract.Runtime { _format = function(self, ...) return ("%s |> %s"):format(self.text:format(...), self.func:format_right(...)) end, + _format_priority = function(self) + return operator_priority["_|>_"] + end, build_event_data = function(self, state, event_buffer) local l = { diff --git a/anselme/ast/Definition.lua b/anselme/ast/Definition.lua index abd0dc9..8d33951 100644 --- a/anselme/ast/Definition.lua +++ b/anselme/ast/Definition.lua @@ -8,7 +8,6 @@ local Definition = ast.abstract.Node { symbol = nil, expression = nil, - format_priority = operator_priority["_=_"], init = function(self, symbol, expression) self.symbol = symbol @@ -18,6 +17,9 @@ local Definition = ast.abstract.Node { _format = function(self, ...) return self.symbol:format(...).." = "..self.expression:format_right(...) end, + _format_priority = function(self) + return operator_priority["_=_"] + end, traverse = function(self, fn, ...) fn(self.symbol, ...) diff --git a/anselme/ast/Environment.lua b/anselme/ast/Environment.lua index cf8b36f..4f36722 100644 --- a/anselme/ast/Environment.lua +++ b/anselme/ast/Environment.lua @@ -9,7 +9,6 @@ local VariableMetadata = ast.abstract.Runtime { symbol = nil, branched = nil, - format_priority = operator_priority["_=_"], init = function(self, state, symbol, value) self.symbol = symbol @@ -45,6 +44,10 @@ local VariableMetadata = ast.abstract.Runtime { _format = function(self, ...) return ("%s=%s"):format(self.symbol:format(...), self.branched:format(...)) end, + _format_priority = function(self) + return operator_priority["_=_"] + end, + traverse = function(self, fn, ...) fn(self.symbol, ...) fn(self.branched, ...) diff --git a/anselme/ast/Function.lua b/anselme/ast/Function.lua index 6d66bbb..cfed1e2 100644 --- a/anselme/ast/Function.lua +++ b/anselme/ast/Function.lua @@ -12,7 +12,6 @@ Function = Overloadable { parameters = nil, -- ParameterTuple expression = nil, - format_priority = operator_priority["$_"], exports = nil, -- { [sym] = exp, ... }, exctracted from expression during :prepare @@ -29,6 +28,9 @@ Function = Overloadable { return "$"..self.parameters:format(...).." "..self.expression:format_right(...) end end, + _format_priority = function(self) + return operator_priority["$_"] + end, traverse = function(self, fn, ...) fn(self.parameters, ...) diff --git a/anselme/ast/FunctionParameter.lua b/anselme/ast/FunctionParameter.lua index b71977c..5cc4fd8 100644 --- a/anselme/ast/FunctionParameter.lua +++ b/anselme/ast/FunctionParameter.lua @@ -13,11 +13,6 @@ FunctionParameter = ast.abstract.Node { self.identifier = identifier self.default = default self.type_check = type_check - if default then - self.format_priority = operator_priority["_=_"] - elseif type_check then -- type_check has higher prio than assignment in any case - self.format_priority = operator_priority["_::_"] - end end, _format = function(self, state, prio, ...) @@ -30,6 +25,15 @@ FunctionParameter = ast.abstract.Node { end return s end, + _format_priority = function(self) + if self.default then + return operator_priority["_=_"] + elseif self.type_check then -- type_check has higher prio than assignment in any case + return operator_priority["_::_"] + else + return math.huge + end + end, traverse = function(self, fn, ...) fn(self.identifier, ...) diff --git a/anselme/ast/List.lua b/anselme/ast/List.lua index 6c232a0..bdcc923 100644 --- a/anselme/ast/List.lua +++ b/anselme/ast/List.lua @@ -7,8 +7,6 @@ local List List = ast.abstract.Runtime { type = "list", - format_priority = operator_priority["*_"], - -- note: yeah technically this isn't mutable, only .branched is -- note: this a Branched of Tuple, and we *will* forcefully mutate the tuples, so make sure to not disseminate any reference to them outside the List @@ -23,6 +21,9 @@ List = ast.abstract.Runtime { _format = function(self, ...) return "*"..self.branched:format_right(...) end, + _format_priority = function(self) + return operator_priority["*_"] + end, traverse = function(self, fn, ...) fn(self.branched, ...) diff --git a/anselme/ast/LuaFunction.lua b/anselme/ast/LuaFunction.lua index 870b00f..5bdfd11 100644 --- a/anselme/ast/LuaFunction.lua +++ b/anselme/ast/LuaFunction.lua @@ -10,7 +10,6 @@ LuaFunction = ast.abstract.Runtime(Overloadable) { parameters = nil, -- ParameterTuple func = nil, -- lua function - format_priority = operator_priority["$_"], init = function(self, parameters, func) self.parameters = parameters @@ -28,6 +27,9 @@ LuaFunction = ast.abstract.Runtime(Overloadable) { return "$"..self.parameters:format(...).." " end end, + _format_priority = function(self) + return operator_priority["$_"] + end, compatible_with_arguments = function(self, state, args) return args:match_parameter_tuple(state, self.parameters) diff --git a/anselme/ast/Pair.lua b/anselme/ast/Pair.lua index ee87477..c4fa0a4 100644 --- a/anselme/ast/Pair.lua +++ b/anselme/ast/Pair.lua @@ -7,7 +7,6 @@ return ast.abstract.Runtime { name = nil, value = nil, - format_priority = operator_priority["_:_"], init = function(self, name, value) self.name = name @@ -22,4 +21,7 @@ return ast.abstract.Runtime { _format = function(self, ...) return ("%s:%s"):format(self.name:format(...), self.value:format(...)) end, + _format_priority = function(self) + return operator_priority["_:_"] + end, } diff --git a/anselme/ast/ParameterTuple.lua b/anselme/ast/ParameterTuple.lua index 258859b..2c771e0 100644 --- a/anselme/ast/ParameterTuple.lua +++ b/anselme/ast/ParameterTuple.lua @@ -27,7 +27,6 @@ ParameterTuple = ast.abstract.Node { insert_assignment = function(self, val) -- only for construction self:insert(val) self.assignment = true - self.format_priority = operator_priority["_=_"] end, _format = function(self, state, prio, ...) @@ -43,6 +42,12 @@ ParameterTuple = ast.abstract.Node { end return s end, + _format_priority = function(self) + if self.assignment then + return operator_priority["_=_"] + end + return math.huge + end, traverse = function(self, fn, ...) for _, e in ipairs(self.list) do diff --git a/anselme/ast/PartialScope.lua b/anselme/ast/PartialScope.lua index a412dc1..eb1976b 100644 --- a/anselme/ast/PartialScope.lua +++ b/anselme/ast/PartialScope.lua @@ -18,7 +18,6 @@ PartialScope = ast.abstract.Node { self.expression = expression self.definitions = {} self._identifiers = {} - self.format_priority = self.expression.format_priority end, define = function(self, symbol, value) -- for construction only assert(not self.definitions[symbol], ("%s already defined in partial layer"):format(symbol)) @@ -36,6 +35,9 @@ PartialScope = ast.abstract.Node { return self.expression:format(state, priority, indentation, ...) end end, + _format_priority = function(self) + return self.expression:format_priority() + end, traverse = function(self, fn, ...) fn(self.expression, ...) diff --git a/anselme/ast/Quote.lua b/anselme/ast/Quote.lua index 7d1bb9e..b7c9d36 100644 --- a/anselme/ast/Quote.lua +++ b/anselme/ast/Quote.lua @@ -15,12 +15,14 @@ Quote = ast.abstract.Node { init = function(self, expression) self.expression = expression - self.format_priority = expression.format_priority end, _format = function(self, ...) return self.expression:format(...) -- Quote is generated transparently by operators end, + _format_priority = function(self) + return self.expression:format_priority() + end, traverse = function(self, fn, ...) fn(self.expression, ...) diff --git a/anselme/ast/Return.lua b/anselme/ast/Return.lua index 7d41cd0..4880aa0 100644 --- a/anselme/ast/Return.lua +++ b/anselme/ast/Return.lua @@ -7,7 +7,6 @@ Return = ast.abstract.Node { type = "return", expression = nil, - format_priority = operator_priority["@_"], init = function(self, expression) self.expression = expression @@ -16,6 +15,9 @@ Return = ast.abstract.Node { _format = function(self, ...) return ("@%s"):format(self.expression:format_right(...)) end, + _format_priority = function(self) + return operator_priority["@_"] + end, traverse = function(self, fn, ...) fn(self.expression, ...) diff --git a/anselme/ast/ReturnBoundary.lua b/anselme/ast/ReturnBoundary.lua index 5bd5ba5..2740b44 100644 --- a/anselme/ast/ReturnBoundary.lua +++ b/anselme/ast/ReturnBoundary.lua @@ -10,12 +10,14 @@ local ReturnBoundary = ast.abstract.Node { init = function(self, expression) self.expression = expression - self.format_priority = self.expression.format_priority end, _format = function(self, ...) return self.expression:format(...) end, + _format_priority = function(self) + return self.expression:format_priority() + end, traverse = function(self, fn, ...) fn(self.expression, ...) diff --git a/anselme/ast/StringInterpolation.lua b/anselme/ast/StringInterpolation.lua index d9db8fc..4b80286 100644 --- a/anselme/ast/StringInterpolation.lua +++ b/anselme/ast/StringInterpolation.lua @@ -19,14 +19,14 @@ local StringInterpolation = ast.abstract.Node { end end, - _format = function(self, ...) + _format = function(self, state, prio, ...) local l = {} for _, e in ipairs(self.list) do if String:is(e) then local t = e.string:gsub("\\", "\\\\"):gsub("\n", "\\n"):gsub("\t", "\\t"):gsub("\"", "\\\"") table.insert(l, t) else - table.insert(l, ("{%s}"):format(e:format(...))) + table.insert(l, ("{%s}"):format(e:format(state, 0, ...))) end end return ("\"%s\""):format(table.concat(l)) diff --git a/anselme/ast/Symbol.lua b/anselme/ast/Symbol.lua index cbde7e6..189f626 100644 --- a/anselme/ast/Symbol.lua +++ b/anselme/ast/Symbol.lua @@ -24,9 +24,6 @@ Symbol = ast.abstract.Node { self.alias = modifiers.alias self.confined_to_branch = modifiers.confined_to_branch self.exported = modifiers.exported - if self.type_check then - self.format_priority = operator_priority["_::_"] - end end, _eval = function(self, state) @@ -66,6 +63,12 @@ Symbol = ast.abstract.Node { end return s end, + _format_priority = function(self) + if self.type_check then + return operator_priority["_::_"] + end + return math.huge + end, to_lua = function(self, state) return self.string diff --git a/anselme/ast/Table.lua b/anselme/ast/Table.lua index 4bbfceb..e3e2056 100644 --- a/anselme/ast/Table.lua +++ b/anselme/ast/Table.lua @@ -7,8 +7,6 @@ local Table Table = ast.abstract.Runtime { type = "table", - format_priority = operator_priority["*_"], - -- note: technically this isn't mutable, only .branched is -- note: this a Branched of Struct, and we *will* forcefully mutate the tuples, so make sure to not disseminate any reference to them outside the Table @@ -23,6 +21,9 @@ Table = ast.abstract.Runtime { _format = function(self, ...) return "*"..self.branched:format_right(...) end, + _format_priority = function(self) + return operator_priority["*_"] + end, traverse = function(self, fn, ...) fn(self.branched, ...) diff --git a/anselme/ast/TextInterpolation.lua b/anselme/ast/TextInterpolation.lua index 652e0c6..b93d2a5 100644 --- a/anselme/ast/TextInterpolation.lua +++ b/anselme/ast/TextInterpolation.lua @@ -21,14 +21,14 @@ local TextInterpolation = ast.abstract.Node { end end, - _format = function(self, ...) + _format = function(self, state, prio, ...) local l = {} for _, e in ipairs(self.list) do if String:is(e) then local t = e.string:gsub("\\", "\\\\"):gsub("\n", "\\n"):gsub("\t", "\\t"):gsub("\"", "\\\"") table.insert(l, t) else - table.insert(l, ("{%s}"):format(e:format(...))) + table.insert(l, ("{%s}"):format(e:format(state, 0, ...))) end end return ("| %s |"):format(table.concat(l)) diff --git a/anselme/ast/Translatable.lua b/anselme/ast/Translatable.lua index 3794ab9..c4d6505 100644 --- a/anselme/ast/Translatable.lua +++ b/anselme/ast/Translatable.lua @@ -7,7 +7,6 @@ local translation_manager local Translatable = ast.abstract.Node { type = "translatable", - format_priority = operator_priority["%_"], expression = nil, @@ -15,9 +14,6 @@ local Translatable = ast.abstract.Node { self.expression = expression self.context = ast.Struct:new() self.context:set(String:new("source"), String:new(self.expression.source)) - if TextInterpolation:is(self.expression) then - self.format_priority = expression.format_priority - end end, _format = function(self, ...) @@ -27,6 +23,13 @@ local Translatable = ast.abstract.Node { return "%"..self.expression:format_right(...) end end, + _format_priority = function(self) + if TextInterpolation:is(self.expression) then + return self.expression:format_priority() + else + return operator_priority["%_"] + end + end, traverse = function(self, fn, ...) fn(self.expression, ...) diff --git a/anselme/ast/abstract/Node.lua b/anselme/ast/abstract/Node.lua index 8ed7113..220f68e 100644 --- a/anselme/ast/abstract/Node.lua +++ b/anselme/ast/abstract/Node.lua @@ -257,9 +257,9 @@ Node = class { indentation_level = indentation_level or 0 parent_priority = parent_priority or 0 - local s = self:_format(state, self.format_priority, indentation_level) + local s = self:_format(state, self:format_priority(), indentation_level) - if self.format_priority < parent_priority then + if self:format_priority() < parent_priority then s = ("(%s)"):format(s) end @@ -273,9 +273,9 @@ Node = class { indentation_level = indentation_level or 0 parent_priority = parent_priority or 0 - local s = self:_format(state, self.format_priority, indentation_level) + local s = self:_format(state, self:format_priority(), indentation_level) - if self.format_priority <= parent_priority then + if self:format_priority() <= parent_priority then s = ("(%s)"):format(s) end @@ -288,9 +288,20 @@ Node = class { _format = function(self, state, self_priority, identation) error("format not implemented for "..self.type) end, - -- priority of the node that will be used in :format to add eventually needed parentheses. - -- should not be modified after object construction! - format_priority = math.huge, -- by default, assumes primary node, i.e. never wrap in parentheses + -- compute the priority of the node that will be used in :format to add eventually needed parentheses. + -- should alwaus return the same value after object construction (will be cached anyway) + -- redefine _format_priority, not this function + format_priority = function(self) + if not self._format_priority_cache then + self._format_priority_cache = self:_format_priority() + end + return self._format_priority_cache + end, + -- redefine this to compute the priority, see :format_priority + _format_priority = function(self) + return math.huge -- by default, assumes primary node, i.e. never wrap in parentheses + end, + _format_priority_cache = nil, -- cached priority -- return Lua value -- this should probably be only called on a Node that is already evaluated diff --git a/test/results/function separate variable from variants.ans b/test/results/function separate variable from variants.ans index edafc7f..334c360 100644 --- a/test/results/function separate variable from variants.ans +++ b/test/results/function separate variable from variants.ans @@ -5,8 +5,8 @@ • (c::($(x) ), s::($(x) )) = v: expected 3 arguments, received 2 • (c::($(x) ), s::($(x) )): type check failure for parameter c in function (c::($(x) ), s::($(x) )) ↳ from test/tests/function separate variable from variants.ans:10:4 in call: f . "a" - ↳ from test/tests/function separate variable from variants.ans:10:1 in text interpolation: | {(f . "a")} = 2 | - ↳ from test/tests/function separate variable from variants.ans:10:1 in translatable: | {(f . "a")} = 2 | + ↳ from test/tests/function separate variable from variants.ans:10:1 in text interpolation: | {f . "a"} = 2 | + ↳ from test/tests/function separate variable from variants.ans:10:1 in translatable: | {f . "a"} = 2 | ↳ from ? in block: :f = ($() _)… --# saved #-- {} \ No newline at end of file