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

[language] replace constant symbols with a constant value check function

This commit is contained in:
Étienne Fildadut 2024-04-24 16:15:58 +02:00
parent b534a3c4a2
commit aaff625b6c
15 changed files with 31 additions and 37 deletions

View file

@ -31,12 +31,9 @@ local VariableMetadata = ast.abstract.Runtime {
return self.symbol return self.symbol
end, end,
set = function(self, state, value) set = function(self, state, value)
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.value_check then if self.symbol.value_check then
local r = self.symbol.value_check:call(state, ArgumentTuple:new(value)) 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 if not r:truthy() then error(("can not set %s = %s; %s value check failed"):format(self.symbol.string:format(state), value, self.symbol.value_check:format_short(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

@ -8,7 +8,6 @@ Symbol = ast.abstract.Node {
type = "symbol", type = "symbol",
string = nil, string = nil,
constant = nil, -- bool
alias = nil, -- bool alias = nil, -- bool
exported = nil, -- bool exported = nil, -- bool
value_check = nil, -- exp value_check = nil, -- exp
@ -18,7 +17,6 @@ Symbol = ast.abstract.Node {
init = function(self, str, modifiers) init = function(self, str, modifiers)
modifiers = modifiers or {} modifiers = modifiers or {}
self.string = str self.string = str
self.constant = modifiers.constant
self.value_check = modifiers.value_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
@ -26,7 +24,7 @@ Symbol = ast.abstract.Node {
end, end,
with = function(self, modifiers) with = function(self, modifiers)
modifiers = modifiers or {} modifiers = modifiers or {}
for _, k in ipairs{"constant", "value_check", "alias", "exported", "confined_to_branch"} do for _, k in ipairs{"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
@ -48,9 +46,6 @@ Symbol = ast.abstract.Node {
_hash = function(self) _hash = function(self)
local prefix = "" local prefix = ""
if self.constant then
prefix = prefix .. ":"
end
if self.alias then if self.alias then
prefix = prefix .. "&" prefix = prefix .. "&"
end end
@ -66,9 +61,6 @@ Symbol = ast.abstract.Node {
_format = function(self, state, prio, ...) _format = function(self, state, prio, ...)
local s = ":" local s = ":"
if self.constant then
s = s .. ":"
end
if self.alias then if self.alias then
s = s .. "&" s = s .. "&"
end end

View file

@ -159,19 +159,18 @@ end
return primary { return primary {
match = function(self, str) match = function(self, str)
return str:match("^%::?&?@?%$") return str:match("^%:&?@?%$")
end, end,
parse = function(self, source, options, str) parse = function(self, source, options, str)
local source_start = source:clone() local source_start = source:clone()
local mod_const, mod_alias, mod_exported, rem = source:consume(str:match("^(%:(:?)(&?)(@?)%$)(.-)$")) local mod_alias, mod_exported, rem = source:consume(str:match("^(%:(&?)(@?)%$)(.-)$"))
-- get modifiers -- get modifiers
local constant, exported, alias local exported, alias
if mod_const == ":" then constant = true end
if mod_alias == "&" then alias = true end if mod_alias == "&" then alias = true end
if mod_exported == "@" then exported = true end if mod_exported == "@" then exported = true end
local modifiers = { constant = constant, exported = exported, alias = alias } local modifiers = { exported = exported, alias = alias }
-- search for a valid signature -- search for a valid signature
local symbol, parameters local symbol, parameters

View file

@ -8,18 +8,17 @@ local Nil = ast.Nil
return primary { return primary {
match = function(self, str) match = function(self, str)
if str:match("^%::?&?@?") then if str:match("^%:&?@?") then
return identifier:match(str:match("^%::?&?@?(.-)$")) return identifier:match(str:match("^%::?&?@?(.-)$"))
end end
return false return false
end, end,
parse = function(self, source, options, str) parse = function(self, source, options, str)
local mod_const, mod_alias, mod_export, rem = source:consume(str:match("^(%:(:?)(&?)(@?))(.-)$")) local mod_alias, mod_export, rem = source:consume(str:match("^(%:(&?)(@?))(.-)$"))
local constant, alias, value_check_exp, exported local alias, value_check_exp, exported
-- get modifier -- get modifier
if mod_const == ":" then constant = true end
if mod_alias == "&" then alias = true end if mod_alias == "&" then alias = true end
if mod_export == "@" then exported = true end if mod_export == "@" then exported = true end
@ -35,6 +34,6 @@ return primary {
value_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, value_check = value_check_exp }:set_source(source), rem return ident:to_symbol{ alias = alias, exported = exported, value_check = value_check_exp }:set_source(source), rem
end end
} }

View file

@ -47,7 +47,7 @@ local ScopeStack = class {
-- for lua functions: define_lua("name", "(x, y, z=5)", function(x, y, z) ... end), where arguments and return values of the function are automatically converted between anselme and lua values -- for lua functions: define_lua("name", "(x, y, z=5)", function(x, y, z) ... end), where arguments and return values of the function are automatically converted between anselme and lua values
-- for other lua values: define_lua("name", value) -- for other lua values: define_lua("name", value)
-- for anselme AST: define_lua("name", value) -- for anselme AST: define_lua("name", value)
-- name can be prefixed with symbol modifiers, for example ":name" for a constant variable -- name can be prefixed with symbol modifiers, for example "@name" for an exported variable
-- if `raw_mode` is true, no anselme-to/from-lua conversion will be performed in the function -- if `raw_mode` is true, no anselme-to/from-lua conversion will be performed in the function
-- the function will receive the state followed by AST nodes as arguments, and is expected to return an AST node -- the function will receive the state followed by AST nodes as arguments, and is expected to return an AST node
define_lua = function(self, name, value, func, raw_mode) define_lua = function(self, name, value, func, raw_mode)

View file

@ -104,7 +104,7 @@ State = class {
-- * for other lua values: `define("name", value)` -- * for other lua values: `define("name", value)`
-- * for anselme AST: `define("name", value)` -- * for anselme AST: `define("name", value)`
-- --
-- `name` can be prefixed with symbol modifiers, for example ":name" for a constant variable. -- `name` can be prefixed with symbol modifiers, for example "@name" for an exported variable.
-- --
-- If `raw_mode` is true, no anselme-to/from-lua conversion will be performed in the function. -- If `raw_mode` is true, no anselme-to/from-lua conversion will be performed in the function.
-- The function will receive the state followed by AST nodes as arguments, and is expected to return an AST node. -- The function will receive the state followed by AST nodes as arguments, and is expected to return an AST node.

View file

@ -2,6 +2,13 @@ local ast = require("anselme.ast")
local Nil, Boolean, LuaCall, ParameterTuple, FunctionParameter, Identifier, Overloadable, Overload, Call, Quote = ast.Nil, ast.Boolean, ast.LuaCall, ast.ParameterTuple, ast.FunctionParameter, ast.Identifier, ast.abstract.Overloadable, ast.Overload, ast.Call, ast.Quote local Nil, Boolean, LuaCall, ParameterTuple, FunctionParameter, Identifier, Overloadable, Overload, Call, Quote = ast.Nil, ast.Boolean, ast.LuaCall, ast.ParameterTuple, ast.FunctionParameter, ast.Identifier, ast.abstract.Overloadable, ast.Overload, ast.Call, ast.Quote
return { return {
{
"constant", "(exp)",
function(state, exp)
return Boolean:new(false)
end
},
{ {
"is tuple", "(exp)", "is tuple", "(exp)",
function(state, exp) function(state, exp)

View file

@ -172,7 +172,7 @@ Define a value in the global scope, converting it from Lua to Anselme if needed.
* for other lua values: `define("name", value)` * for other lua values: `define("name", value)`
* for anselme AST: `define("name", value)` * for anselme AST: `define("name", value)`
`name` can be prefixed with symbol modifiers, for example ":name" for a constant variable. `name` can be prefixed with symbol modifiers, for example "@name" for an exported variable.
If `raw_mode` is true, no anselme-to/from-lua conversion will be performed in the function. If `raw_mode` is true, no anselme-to/from-lua conversion will be performed in the function.
The function will receive the state followed by AST nodes as arguments, and is expected to return an AST node. The function will receive the state followed by AST nodes as arguments, and is expected to return an AST node.

View file

@ -1,7 +1,7 @@
--# run #-- --# run #--
--- error --- --- error ---
trying to change the value of constant a can not set a = 52; constant value check failed
↳ from test/tests/constant variable.ans:5:3 in call: a = 52 ↳ from test/tests/constant variable.ans:5:3 in call: a = 52
↳ from test/tests/constant variable.ans:1:1 in block: ::a = 3… ↳ from test/tests/constant variable.ans:1:1 in block: :a::constant = 3…
--# saved #-- --# saved #--
{} {}

View file

@ -4,7 +4,7 @@
--- text --- --- text ---
| {}"" {}"type(12, \"kg\")" {}"" | | {}"" {}"type(12, \"kg\")" {}"" |
--- error --- --- error ---
value check failure for weigh; 32 does not satisfy $(x) type(x) == t can not set weigh = 32; $(x) type(x) == t value check failed
↳ from test/tests/constrained variable assignement.ans:9:7 in call: weigh = 32 ↳ from test/tests/constrained variable assignement.ans:9:7 in call: weigh = 32
↳ from test/tests/constrained variable assignement.ans:1:1 in block: :weigh::is("kg") = type(5, "kg")… ↳ from test/tests/constrained variable assignement.ans:1:1 in block: :weigh::is("kg") = type(5, "kg")…
--# saved #-- --# saved #--

View file

@ -5,7 +5,7 @@
--- text --- --- text ---
| {}"d=" {}"2" {}" (2)" | | {}"d=" {}"2" {}" (2)" |
--- error --- --- error ---
trying to change the value of constant d can not set d = 5; constant value check failed
↳ from test/tests/symbol alias constant.ans:12:3 in call: d = 5 ↳ from test/tests/symbol alias constant.ans:12:3 in call: d = 5
↳ from test/tests/symbol alias constant.ans:1:1 in block: :l = *[1, 2, 3]… ↳ from test/tests/symbol alias constant.ans:1:1 in block: :l = *[1, 2, 3]…
--# saved #-- --# saved #--

View file

@ -1,4 +1,4 @@
::a = *[3] :a::constant = *[3]
|{a} |{a}

View file

@ -1,4 +1,4 @@
::a = 3 :a::constant = 3
{a} {a}

View file

@ -1,4 +1,4 @@
::a = [1:2] :a::constant = [1:2]
|false = {a == [5:2]} |false = {a == [5:2]}
@ -6,7 +6,7 @@
|true = {a == [1:2]} |true = {a == [1:2]}
::b = [1,2,3] :b::constant = [1,2,3]
|false = {b == a} |false = {b == a}
@ -24,6 +24,6 @@
|true = {c!to tuple == b} |true = {c!to tuple == b}
::d = [1,2,3] :d::constant = [1,2,3]
|true = {d == b} |true = {d == b}

View file

@ -1,11 +1,11 @@
:l = *[1,2,3] :l = *[1,2,3]
::&c => l(2) :&c::constant => l(2)
| c={c} (2) | c={c} (2)
| l={l} (*[1,2,3]) | l={l} (*[1,2,3])
::&d = "{l(2)}" :&d::constant = "{l(2)}"
| d={c} (2) | d={c} (2)