1
0
Fork 0
mirror of https://github.com/Reuh/anselme.git synced 2025-10-27 16:49:31 +00:00

Rename type check to value check

This commit is contained in:
Étienne Fildadut 2024-01-09 16:57:43 +01:00
parent c027c87dc4
commit 5d000e2fec
16 changed files with 76 additions and 60 deletions

View file

@ -156,10 +156,10 @@ ArgumentTuple = ast.abstract.Node {
end end
-- not found -- not found
if not arg then return false, ("missing parameter %s"):format(param.identifier:format(state)) end if not arg then return false, ("missing parameter %s"):format(param.identifier:format(state)) end
-- type check (assume ok for default values) -- value check (assume ok for default values)
if param.type_check and arg ~= param.default then if param.value_check and arg ~= param.default then
local r = param.type_check:call(state, ArgumentTuple:new(arg)) local r = param.value_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 if not r:truthy() then return false, ("value check failure for parameter %s"):format(param.identifier:format(state)) end
if Number:is(r) then if Number:is(r) then
specificity = specificity + r.number specificity = specificity + r.number
else else

View file

@ -34,9 +34,9 @@ local VariableMetadata = ast.abstract.Runtime {
if self.symbol.constant then if self.symbol.constant then
error(("trying to change the value of constant %s"):format(self.symbol.string:format(state)), 0) error(("trying to change the value of constant %s"):format(self.symbol.string:format(state)), 0)
end end
if self.symbol.type_check then if self.symbol.value_check then
local r = self.symbol.type_check:call(state, ArgumentTuple:new(value)) local r = self.symbol.value_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 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 end
if self.symbol.alias then if self.symbol.alias then
local assign_args = ArgumentTuple:new() local assign_args = ArgumentTuple:new()

View file

@ -7,18 +7,18 @@ FunctionParameter = ast.abstract.Node {
identifier = nil, identifier = nil,
default = nil, -- can be 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.identifier = identifier
self.default = default self.default = default
self.type_check = type_check self.value_check = value_check
end, end,
_format = function(self, state, prio, ...) _format = function(self, state, prio, ...)
local s = self.identifier:format(state, prio, ...) local s = self.identifier:format(state, prio, ...)
if self.type_check then if self.value_check then
s = s .. "::" .. self.type_check:format_right(state, operator_priority["_::_"], ...) s = s .. "::" .. self.value_check:format_right(state, operator_priority["_::_"], ...)
end end
if self.default then if self.default then
s = s .. "=" .. self.default:format_right(state, operator_priority["_=_"], ...) s = s .. "=" .. self.default:format_right(state, operator_priority["_=_"], ...)
@ -28,7 +28,7 @@ FunctionParameter = ast.abstract.Node {
_format_priority = function(self) _format_priority = function(self)
if self.default then if self.default then
return operator_priority["_=_"] 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["_::_"] return operator_priority["_::_"]
else else
return math.huge return math.huge
@ -38,11 +38,11 @@ FunctionParameter = ast.abstract.Node {
traverse = function(self, fn, ...) traverse = function(self, fn, ...)
fn(self.identifier, ...) fn(self.identifier, ...)
if self.default then fn(self.default, ...) end 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, end,
_eval = function(self, state) _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 end
} }

View file

@ -9,10 +9,9 @@ Symbol = ast.abstract.Node {
string = nil, string = nil,
constant = nil, -- bool constant = nil, -- bool
type_check = nil, -- exp
alias = nil, -- bool alias = nil, -- bool
exported = nil, -- bool exported = nil, -- bool
value_check = nil, -- exp
confined_to_branch = nil, -- bool confined_to_branch = nil, -- bool
@ -20,21 +19,14 @@ Symbol = ast.abstract.Node {
modifiers = modifiers or {} modifiers = modifiers or {}
self.string = str self.string = str
self.constant = modifiers.constant self.constant = modifiers.constant
self.type_check = modifiers.type_check self.value_check = modifiers.value_check
self.alias = modifiers.alias self.alias = modifiers.alias
self.confined_to_branch = modifiers.confined_to_branch self.confined_to_branch = modifiers.confined_to_branch
self.exported = modifiers.exported self.exported = modifiers.exported
end, end,
_eval = function(self, state)
return self:with {
type_check = self.type_check and self.type_check:eval(state)
}
end,
with = function(self, modifiers) with = function(self, modifiers)
modifiers = modifiers or {} 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 if modifiers[k] == nil then
modifiers[k] = self[k] modifiers[k] = self[k]
end end
@ -42,8 +34,34 @@ Symbol = ast.abstract.Node {
return Symbol:new(self.string, modifiers) return Symbol:new(self.string, modifiers)
end, 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) _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, end,
_format = function(self, state, prio, ...) _format = function(self, state, prio, ...)
@ -58,13 +76,13 @@ Symbol = ast.abstract.Node {
s = s .. "@" s = s .. "@"
end end
s = s .. self.string s = s .. self.string
if self.type_check then if self.value_check then
s = s .. "::" .. self.type_check:format_right(state, operator_priority["_::_"], ...) s = s .. "::" .. self.value_check:format_right(state, operator_priority["_::_"], ...)
end end
return s return s
end, end,
_format_priority = function(self) _format_priority = function(self)
if self.type_check then if self.value_check then
return operator_priority["_::_"] return operator_priority["_::_"]
end end
return math.huge return math.huge

View file

@ -7,7 +7,7 @@ local FunctionParameter = ast.FunctionParameter
local operator_priority = require("anselme.common").operator_priority local operator_priority = require("anselme.common").operator_priority
local assignment_priority = operator_priority["_=_"] local assignment_priority = operator_priority["_=_"]
local type_check_priority = operator_priority["_::_"] local value_check_priority = operator_priority["_::_"]
return primary { return primary {
match = function(self, str) match = function(self, str)
@ -19,11 +19,11 @@ return primary {
-- name -- name
local ident, rem = identifier:parse(source, str) local ident, rem = identifier:parse(source, str)
-- type check -- value check
local type_check local value_check
if rem:match("^%s*::") then if rem:match("^%s*::") then
local scheck = source:consume(rem:match("^(%s*::%s*)(.*)$")) 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 end
-- default value -- default value
@ -35,6 +35,6 @@ return primary {
end end
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 end
} }

View file

@ -1,5 +1,5 @@
local primary = require("anselme.parser.expression.primary.primary") 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") local identifier = require("anselme.parser.expression.primary.identifier")
@ -16,7 +16,7 @@ return primary {
parse = function(self, source, str) parse = function(self, source, str)
local mod_const, mod_alias, mod_export, rem = source:consume(str:match("^(%:(:?)(&?)(@?))(.-)$")) 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 -- get modifier
if mod_const == ":" then constant = true end if mod_const == ":" then constant = true end
@ -27,14 +27,14 @@ return primary {
local ident local ident
ident, rem = identifier:parse(source, rem) ident, rem = identifier:parse(source, rem)
-- type check -- value check
local nil_val = Nil:new() 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 local exp
exp, rem = type_check:parse(source, rem, nil, 0, nil_val) exp, rem = value_check:parse(source, rem, nil, 0, nil_val)
type_check_exp = exp.arguments.positional[2] value_check_exp = exp.arguments.positional[2]
end 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 end
} }

View file

@ -27,14 +27,14 @@ local secondaries = {
r("infix.modulo"), r("infix.modulo"),
r("infix.implicit_multiplication"), r("infix.implicit_multiplication"),
r("infix.exponent"), r("infix.exponent"),
r("infix.type_check"), r("infix.value_check"),
r("infix.call"), r("infix.call"),
r("infix.index_identifier"), r("infix.index_identifier"),
r("infix.index"), r("infix.index"),
r("infix.assignment"), -- deported after equal r("infix.assignment"), -- deported after equal
r("infix.assignment_call"), r("infix.assignment_call"),
r("infix.definition"), r("infix.definition"),
r("infix.pair"), -- deported after type_check r("infix.pair"), -- deported after value_check
-- unary suffix operators -- unary suffix operators
r("suffix.semicolon"), r("suffix.semicolon"),

View file

@ -23,7 +23,7 @@ return function(main_state)
"conditionals", "conditionals",
"base", "base",
"typed", "typed",
"type check", "value check",
"number", "number",
"string", "string",
"symbol", "symbol",

View file

@ -9,7 +9,7 @@ return {
if r:truthy() then if r:truthy() then
return value return value
else 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
end end
}, },

View file

@ -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. 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. 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. 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 # Can be done later
Server API. Server API.
@ -83,7 +81,7 @@ Performance:
Assuming the filter functions are pure seems reasonable, so caching could be done. 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. 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. 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. * the recursive AST interpreter is also pretty meh, could do a bytecode VM.
This one seems like a lot more work. This one seems like a lot more work.
Could also compile to Lua and let LuaJIT deal with it. Or WASM, that sounds trendy. Could also compile to Lua and let LuaJIT deal with it. Or WASM, that sounds trendy.

View file

@ -4,7 +4,7 @@
--- text --- --- text ---
| {}"" {}"type(12, \"kg\")" {}"" | | {}"" {}"type(12, \"kg\")" {}"" |
--- error --- --- 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 test/tests/constrained variable assignement.ans:9:7 in assignment: weigh = 32
↳ from ? in block: :weigh::is("kg") = type(5, "kg")… ↳ from ? in block: :weigh::is("kg") = type(5, "kg")…
--# saved #-- --# saved #--

View file

@ -2,13 +2,13 @@
--- error --- --- error ---
can't call overload iter: no function match arguments (value), possible functions were: can't call overload iter: no function match arguments (value), possible functions were:
• $(table::is table) (from stdlib/for.ans:46:1): • $(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): • $(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): • $(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): • $(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:18 in call: iter(var)
↳ from stdlib/for.ans:3:12 in definition: :iterator = iter(var) ↳ from stdlib/for.ans:3:12 in definition: :iterator = iter(var)
↳ from stdlib/for.ans:2:1 in block: :iterator = iter(var)… ↳ from stdlib/for.ans:2:1 in block: :iterator = iter(var)…

View file

@ -6,9 +6,9 @@
--- error --- --- error ---
can't call overload a: no function match arguments (value), possible functions were: 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): • $(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): • $(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 test/tests/function custom type dispatch error.ans:14:2 in call: a(type(5, "nope"))
↳ from ? in block: :french name = "french name"… ↳ from ? in block: :french name = "french name"…
--# saved #-- --# saved #--

View file

@ -6,19 +6,19 @@
• $(s::is script, k::is string) = val (from stdlib/script.ans:43:1): • $(s::is script, k::is string) = val (from stdlib/script.ans:43:1):
expected 3 arguments, received 2 expected 3 arguments, received 2
• $(s::is script, k::is string) (from stdlib/script.ans:41:1): • $(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): • $(c::is function, s::is symbol) = v (from stdlib/for.ans:2:1):
expected 3 arguments, received 2 expected 3 arguments, received 2
• $(c::is function, s::is string) = v (from stdlib/for.ans:2:1): • $(c::is function, s::is string) = v (from stdlib/for.ans:2:1):
expected 3 arguments, received 2 expected 3 arguments, received 2
• $(c::is function, s::is string) (from stdlib/for.ans:2:1): • $(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): • $(c::is environment, s::is symbol) = v (from stdlib/for.ans:2:1):
expected 3 arguments, received 2 expected 3 arguments, received 2
• $(c::is environment, s::is string) = v (from stdlib/for.ans:2:1): • $(c::is environment, s::is string) = v (from stdlib/for.ans:2:1):
expected 3 arguments, received 2 expected 3 arguments, received 2
• $(c::is environment, s::is string) (from stdlib/for.ans:2:1): • $(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: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 text interpolation: | {f . "a"} = 2 |
↳ from ? in block: :f = ($() _)… ↳ from ? in block: :f = ($() _)…