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
-- 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

View file

@ -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()

View file

@ -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
}

View file

@ -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

View file

@ -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
}

View file

@ -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
}

View file

@ -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"),

View file

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

View file

@ -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
},

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.
---
@ -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.

View file

@ -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 #--

View file

@ -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)…

View file

@ -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 #--

View file

@ -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 = ($() _)…