From 5d000e2fec1d4f7ad77dba7586c51f02119d1a89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20Reuh=20Fildadut?= Date: Tue, 9 Jan 2024 16:57:43 +0100 Subject: [PATCH] Rename type check to value check --- anselme/ast/ArgumentTuple.lua | 8 ++-- anselme/ast/Environment.lua | 6 +-- anselme/ast/FunctionParameter.lua | 16 +++---- anselme/ast/Symbol.lua | 48 +++++++++++++------ .../contextual/function_parameter.lua | 10 ++-- anselme/parser/expression/primary/symbol.lua | 14 +++--- .../infix/{type_check.lua => value_check.lua} | 0 anselme/parser/expression/secondary/init.lua | 4 +- anselme/stdlib/init.lua | 2 +- anselme/stdlib/typed.lua | 2 +- .../{type check.lua => value check.lua} | 0 ideas.md | 6 +-- .../constrained variable assignement.ans | 2 +- test/results/for invalid iterator.ans | 8 ++-- .../function custom type dispatch error.ans | 4 +- ...nction separate variable from variants.ans | 6 +-- 16 files changed, 76 insertions(+), 60 deletions(-) rename anselme/parser/expression/secondary/infix/{type_check.lua => value_check.lua} (100%) rename anselme/stdlib/{type check.lua => value check.lua} (100%) diff --git a/anselme/ast/ArgumentTuple.lua b/anselme/ast/ArgumentTuple.lua index 41219db..b2141fc 100644 --- a/anselme/ast/ArgumentTuple.lua +++ b/anselme/ast/ArgumentTuple.lua @@ -156,10 +156,10 @@ ArgumentTuple = ast.abstract.Node { end -- not found if not arg then return false, ("missing parameter %s"):format(param.identifier:format(state)) end - -- type check (assume ok for default values) - if param.type_check and arg ~= param.default then - local r = param.type_check:call(state, ArgumentTuple:new(arg)) - if not r:truthy() then return false, ("type check failure for parameter %s"):format(param.identifier:format(state)) end + -- value check (assume ok for default values) + if param.value_check and arg ~= param.default then + local r = param.value_check:call(state, ArgumentTuple:new(arg)) + if not r:truthy() then return false, ("value check failure for parameter %s"):format(param.identifier:format(state)) end if Number:is(r) then specificity = specificity + r.number else diff --git a/anselme/ast/Environment.lua b/anselme/ast/Environment.lua index 681a288..ad44153 100644 --- a/anselme/ast/Environment.lua +++ b/anselme/ast/Environment.lua @@ -34,9 +34,9 @@ local VariableMetadata = ast.abstract.Runtime { if self.symbol.constant then error(("trying to change the value of constant %s"):format(self.symbol.string:format(state)), 0) end - if self.symbol.type_check then - local r = self.symbol.type_check:call(state, ArgumentTuple:new(value)) - if not r:truthy() then error(("type check failure for %s; %s does not satisfy %s"):format(self.symbol.string:format(state), value, self.symbol.type_check:format(state)), 0) end + if self.symbol.value_check then + local r = self.symbol.value_check:call(state, ArgumentTuple:new(value)) + if not r:truthy() then error(("value check failure for %s; %s does not satisfy %s"):format(self.symbol.string:format(state), value, self.symbol.value_check:format(state)), 0) end end if self.symbol.alias then local assign_args = ArgumentTuple:new() diff --git a/anselme/ast/FunctionParameter.lua b/anselme/ast/FunctionParameter.lua index 5cc4fd8..64dff99 100644 --- a/anselme/ast/FunctionParameter.lua +++ b/anselme/ast/FunctionParameter.lua @@ -7,18 +7,18 @@ FunctionParameter = ast.abstract.Node { identifier = nil, default = nil, -- can be nil - type_check = nil, -- can be nil + value_check = nil, -- can be nil - init = function(self, identifier, default, type_check) + init = function(self, identifier, default, value_check) self.identifier = identifier self.default = default - self.type_check = type_check + self.value_check = value_check end, _format = function(self, state, prio, ...) local s = self.identifier:format(state, prio, ...) - if self.type_check then - s = s .. "::" .. self.type_check:format_right(state, operator_priority["_::_"], ...) + if self.value_check then + s = s .. "::" .. self.value_check:format_right(state, operator_priority["_::_"], ...) end if self.default then s = s .. "=" .. self.default:format_right(state, operator_priority["_=_"], ...) @@ -28,7 +28,7 @@ FunctionParameter = ast.abstract.Node { _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 + elseif self.value_check then -- value_check has higher prio than assignment in any case return operator_priority["_::_"] else return math.huge @@ -38,11 +38,11 @@ FunctionParameter = ast.abstract.Node { traverse = function(self, fn, ...) fn(self.identifier, ...) if self.default then fn(self.default, ...) end - if self.type_check then fn(self.type_check, ...) end + if self.value_check then fn(self.value_check, ...) end end, _eval = function(self, state) - return FunctionParameter:new(self.identifier, self.default, self.type_check and self.type_check:eval(state)) + return FunctionParameter:new(self.identifier, self.default, self.value_check and self.value_check:eval(state)) end } diff --git a/anselme/ast/Symbol.lua b/anselme/ast/Symbol.lua index 189f626..0cc25d1 100644 --- a/anselme/ast/Symbol.lua +++ b/anselme/ast/Symbol.lua @@ -9,10 +9,9 @@ Symbol = ast.abstract.Node { string = nil, constant = nil, -- bool - type_check = nil, -- exp - alias = nil, -- bool exported = nil, -- bool + value_check = nil, -- exp confined_to_branch = nil, -- bool @@ -20,21 +19,14 @@ Symbol = ast.abstract.Node { modifiers = modifiers or {} self.string = str self.constant = modifiers.constant - self.type_check = modifiers.type_check + self.value_check = modifiers.value_check self.alias = modifiers.alias self.confined_to_branch = modifiers.confined_to_branch self.exported = modifiers.exported end, - - _eval = function(self, state) - return self:with { - type_check = self.type_check and self.type_check:eval(state) - } - end, - with = function(self, modifiers) modifiers = modifiers or {} - for _, k in ipairs{"constant", "type_check", "alias", "exported", "confined_to_branch"} do + for _, k in ipairs{"constant", "value_check", "alias", "exported", "confined_to_branch"} do if modifiers[k] == nil then modifiers[k] = self[k] end @@ -42,8 +34,34 @@ Symbol = ast.abstract.Node { return Symbol:new(self.string, modifiers) end, + traverse = function(self, fn, ...) + if self.value_check then + fn(self.value_check, ...) + end + end, + + _eval = function(self, state) + return self:with { + value_check = self.value_check and self.value_check:eval(state) + } + end, + _hash = function(self) - return ("symbol<%q>"):format(self.string) + local prefix = "" + if self.constant then + prefix = prefix .. ":" + end + if self.alias then + prefix = prefix .. "&" + end + if self.exported then + prefix = prefix .. "@" + end + if self.value_check then + return ("symbol<%s%q;%s>"):format(prefix, self.string, self.value_check:hash()) + else + return ("symbol<%s%q>"):format(prefix, self.string) + end end, _format = function(self, state, prio, ...) @@ -58,13 +76,13 @@ Symbol = ast.abstract.Node { s = s .. "@" end s = s .. self.string - if self.type_check then - s = s .. "::" .. self.type_check:format_right(state, operator_priority["_::_"], ...) + if self.value_check then + s = s .. "::" .. self.value_check:format_right(state, operator_priority["_::_"], ...) end return s end, _format_priority = function(self) - if self.type_check then + if self.value_check then return operator_priority["_::_"] end return math.huge diff --git a/anselme/parser/expression/contextual/function_parameter.lua b/anselme/parser/expression/contextual/function_parameter.lua index 28df941..5e01a75 100644 --- a/anselme/parser/expression/contextual/function_parameter.lua +++ b/anselme/parser/expression/contextual/function_parameter.lua @@ -7,7 +7,7 @@ local FunctionParameter = ast.FunctionParameter local operator_priority = require("anselme.common").operator_priority local assignment_priority = operator_priority["_=_"] -local type_check_priority = operator_priority["_::_"] +local value_check_priority = operator_priority["_::_"] return primary { match = function(self, str) @@ -19,11 +19,11 @@ return primary { -- name local ident, rem = identifier:parse(source, str) - -- type check - local type_check + -- value check + local value_check if rem:match("^%s*::") then local scheck = source:consume(rem:match("^(%s*::%s*)(.*)$")) - type_check, rem = expression_to_ast(source, scheck, limit_pattern, type_check_priority) + value_check, rem = expression_to_ast(source, scheck, limit_pattern, value_check_priority) end -- default value @@ -35,6 +35,6 @@ return primary { end end - return FunctionParameter:new(ident, default, type_check):set_source(source_param), rem + return FunctionParameter:new(ident, default, value_check):set_source(source_param), rem end } diff --git a/anselme/parser/expression/primary/symbol.lua b/anselme/parser/expression/primary/symbol.lua index e74e25a..92215e0 100644 --- a/anselme/parser/expression/primary/symbol.lua +++ b/anselme/parser/expression/primary/symbol.lua @@ -1,5 +1,5 @@ local primary = require("anselme.parser.expression.primary.primary") -local type_check = require("anselme.parser.expression.secondary.infix.type_check") +local value_check = require("anselme.parser.expression.secondary.infix.value_check") local identifier = require("anselme.parser.expression.primary.identifier") @@ -16,7 +16,7 @@ return primary { parse = function(self, source, str) local mod_const, mod_alias, mod_export, rem = source:consume(str:match("^(%:(:?)(&?)(@?))(.-)$")) - local constant, alias, type_check_exp, exported + local constant, alias, value_check_exp, exported -- get modifier if mod_const == ":" then constant = true end @@ -27,14 +27,14 @@ return primary { local ident ident, rem = identifier:parse(source, rem) - -- type check + -- value check local nil_val = Nil:new() - if type_check:match(rem, 0, nil_val) then + if value_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.positional[2] + exp, rem = value_check:parse(source, rem, nil, 0, nil_val) + value_check_exp = exp.arguments.positional[2] end - return ident:to_symbol{ constant = constant, alias = alias, exported = exported, type_check = type_check_exp }:set_source(source), rem + return ident:to_symbol{ constant = constant, alias = alias, exported = exported, value_check = value_check_exp }:set_source(source), rem end } diff --git a/anselme/parser/expression/secondary/infix/type_check.lua b/anselme/parser/expression/secondary/infix/value_check.lua similarity index 100% rename from anselme/parser/expression/secondary/infix/type_check.lua rename to anselme/parser/expression/secondary/infix/value_check.lua diff --git a/anselme/parser/expression/secondary/init.lua b/anselme/parser/expression/secondary/init.lua index cc4d412..c3cb5de 100644 --- a/anselme/parser/expression/secondary/init.lua +++ b/anselme/parser/expression/secondary/init.lua @@ -27,14 +27,14 @@ local secondaries = { r("infix.modulo"), r("infix.implicit_multiplication"), r("infix.exponent"), - r("infix.type_check"), + r("infix.value_check"), r("infix.call"), r("infix.index_identifier"), r("infix.index"), r("infix.assignment"), -- deported after equal r("infix.assignment_call"), r("infix.definition"), - r("infix.pair"), -- deported after type_check + r("infix.pair"), -- deported after value_check -- unary suffix operators r("suffix.semicolon"), diff --git a/anselme/stdlib/init.lua b/anselme/stdlib/init.lua index e4c238e..16bd409 100644 --- a/anselme/stdlib/init.lua +++ b/anselme/stdlib/init.lua @@ -23,7 +23,7 @@ return function(main_state) "conditionals", "base", "typed", - "type check", + "value check", "number", "string", "symbol", diff --git a/anselme/stdlib/typed.lua b/anselme/stdlib/typed.lua index 999e7da..3df406d 100644 --- a/anselme/stdlib/typed.lua +++ b/anselme/stdlib/typed.lua @@ -9,7 +9,7 @@ return { if r:truthy() then return value else - error(("type check failure: %s does not satisfy %s"):format(value:format(state), check:format(state)), 0) + error(("value check failure: %s does not satisfy %s"):format(value:format(state), check:format(state)), 0) end end }, diff --git a/anselme/stdlib/type check.lua b/anselme/stdlib/value check.lua similarity index 100% rename from anselme/stdlib/type check.lua rename to anselme/stdlib/value check.lua diff --git a/ideas.md b/ideas.md index 7c871fa..d808405 100644 --- a/ideas.md +++ b/ideas.md @@ -24,7 +24,7 @@ Standard library. --- -Default arguments and initial variables values should pass the type check associated with the variable / parameter. +Default arguments and initial variables values should pass the value check associated with the variable / parameter. Issue: dispatch is decided before evaluating default values. --- @@ -43,8 +43,6 @@ Syntax modifications: Could interpret the left operand as a string when it is an identifier, like how _._ works. Would feel good to have less nodes. But because we can doesn't mean we should. Also Assignment is reused in a few other places. -* remove operators if possible, i'd like to avoid the code looking like a bunch of sigils. Could be replaced by functions: _|>_, _::_ - # Can be done later Server API. @@ -83,7 +81,7 @@ Performance: Assuming the filter functions are pure seems reasonable, so caching could be done. Could also hardcode some shortcut paths for the simple type equality check case. Or track function/expression purity and cache/precompute the results. Not sure how to do that with multiple dispatch though. - (note for future reference: once a function is first evaluated into a closure, its parameters are fixed, including the type check overloads) + (note for future reference: once a function is first evaluated into a closure, its parameters are fixed, including the value check callable) * the recursive AST interpreter is also pretty meh, could do a bytecode VM. This one seems like a lot more work. Could also compile to Lua and let LuaJIT deal with it. Or WASM, that sounds trendy. diff --git a/test/results/constrained variable assignement.ans b/test/results/constrained variable assignement.ans index 87f10fc..83284dd 100644 --- a/test/results/constrained variable assignement.ans +++ b/test/results/constrained variable assignement.ans @@ -4,7 +4,7 @@ --- text --- | {}"" {}"type(12, \"kg\")" {}"" | --- error --- -type check failure for weigh; 32 does not satisfy $(x) type(x) == t +value check failure for weigh; 32 does not satisfy $(x) type(x) == t ↳ from test/tests/constrained variable assignement.ans:9:7 in assignment: weigh = 32 ↳ from ? in block: :weigh::is("kg") = type(5, "kg")… --# saved #-- diff --git a/test/results/for invalid iterator.ans b/test/results/for invalid iterator.ans index 1a6ded7..04066e7 100644 --- a/test/results/for invalid iterator.ans +++ b/test/results/for invalid iterator.ans @@ -2,13 +2,13 @@ --- error --- can't call overload iter: no function match arguments (value), possible functions were: • $(table::is table) (from stdlib/for.ans:46:1): - type check failure for parameter table + value check failure for parameter table • $(tuple::is sequence) (from stdlib/for.ans:37:1): - type check failure for parameter tuple + value check failure for parameter tuple • $(range::is range) (from stdlib/for.ans:19:1): - type check failure for parameter range + value check failure for parameter range • $(s::is struct) (from stdlib/for.ans:2:1): - type check failure for parameter s + value check failure for parameter s ↳ from stdlib/for.ans:3:18 in call: iter(var) ↳ from stdlib/for.ans:3:12 in definition: :iterator = iter(var) ↳ from stdlib/for.ans:2:1 in block: :iterator = iter(var)… diff --git a/test/results/function custom type dispatch error.ans b/test/results/function custom type dispatch error.ans index 249c64f..1b30443 100644 --- a/test/results/function custom type dispatch error.ans +++ b/test/results/function custom type dispatch error.ans @@ -6,9 +6,9 @@ --- error --- can't call overload a: no function match arguments (value), possible functions were: • $(name::($(x) type(x) == t)) (from test/tests/function custom type dispatch error.ans:7:1): - type check failure for parameter name + value check failure for parameter name • $(name::($(x) type(x) == t)) (from test/tests/function custom type dispatch error.ans:4:1): - type check failure for parameter name + value check failure for parameter name ↳ from test/tests/function custom type dispatch error.ans:14:2 in call: a(type(5, "nope")) ↳ from ? in block: :french name = "french name"… --# saved #-- diff --git a/test/results/function separate variable from variants.ans b/test/results/function separate variable from variants.ans index 565f02c..237ae1b 100644 --- a/test/results/function separate variable from variants.ans +++ b/test/results/function separate variable from variants.ans @@ -6,19 +6,19 @@ • $(s::is script, k::is string) = val (from stdlib/script.ans:43:1): expected 3 arguments, received 2 • $(s::is script, k::is string) (from stdlib/script.ans:41:1): - type check failure for parameter s + value check failure for parameter s • $(c::is function, s::is symbol) = v (from stdlib/for.ans:2:1): expected 3 arguments, received 2 • $(c::is function, s::is string) = v (from stdlib/for.ans:2:1): expected 3 arguments, received 2 • $(c::is function, s::is string) (from stdlib/for.ans:2:1): - type check failure for parameter c + value check failure for parameter c • $(c::is environment, s::is symbol) = v (from stdlib/for.ans:2:1): expected 3 arguments, received 2 • $(c::is environment, s::is string) = v (from stdlib/for.ans:2:1): expected 3 arguments, received 2 • $(c::is environment, s::is string) (from stdlib/for.ans:2:1): - type check failure for parameter c + value check failure for parameter c ↳ 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 ? in block: :f = ($() _)…