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:
parent
c027c87dc4
commit
5d000e2fec
16 changed files with 76 additions and 60 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"),
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ return function(main_state)
|
|||
"conditionals",
|
||||
"base",
|
||||
"typed",
|
||||
"type check",
|
||||
"value check",
|
||||
"number",
|
||||
"string",
|
||||
"symbol",
|
||||
|
|
|
|||
|
|
@ -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
|
||||
},
|
||||
|
|
|
|||
6
ideas.md
6
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.
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
--- text ---
|
||||
| {}"" {}"type(12, \"kg\")" {}"" |
|
||||
--- error ---
|
||||
[0m[31m[0m[31mtype check failure for weigh; 32 does not satisfy $(x) type(x) == t[0m
|
||||
[0m[31m[0m[31mvalue check failure for weigh; 32 does not satisfy $(x) type(x) == t[0m
|
||||
↳ from [4mtest/tests/constrained variable assignement.ans:9:7[0m in assignment: [2mweigh = 32[0m[0m
|
||||
↳ from [4m?[0m in block: [2m:weigh::is("kg") = type(5, "kg")…[0m
|
||||
--# saved #--
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@
|
|||
--- error ---
|
||||
[0m[31m[0m[31m[0m[31m[0m[31m[0m[31m[0m[31mcan'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[0m
|
||||
value check failure for parameter s[0m
|
||||
↳ from [4mstdlib/for.ans:3:18[0m in call: [2miter(var)[0m[0m
|
||||
↳ from [4mstdlib/for.ans:3:12[0m in definition: [2m:iterator = iter(var)[0m[0m
|
||||
↳ from [4mstdlib/for.ans:2:1[0m in block: [2m:iterator = iter(var)…[0m[0m
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@
|
|||
--- error ---
|
||||
[0m[31m[0m[31mcan'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[0m
|
||||
value check failure for parameter name[0m
|
||||
↳ from [4mtest/tests/function custom type dispatch error.ans:14:2[0m in call: [2ma(type(5, "nope"))[0m[0m
|
||||
↳ from [4m?[0m in block: [2m:french name = "french name"…[0m
|
||||
--# saved #--
|
||||
|
|
|
|||
|
|
@ -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[0m
|
||||
value check failure for parameter c[0m
|
||||
↳ from [4mtest/tests/function separate variable from variants.ans:10:4[0m in call: [2mf . "a"[0m[0m
|
||||
↳ from [4mtest/tests/function separate variable from variants.ans:10:1[0m in text interpolation: [2m| {f . "a"} = 2 |[0m[0m
|
||||
↳ from [4m?[0m in block: [2m:f = ($() _)…[0m
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue