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:
parent
b534a3c4a2
commit
aaff625b6c
15 changed files with 31 additions and 37 deletions
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
--# run #--
|
--# run #--
|
||||||
--- error ---
|
--- error ---
|
||||||
[0m[31m[0m[31mtrying to change the value of constant a[0m
|
[0m[31m[0m[31mcan not set a = 52; constant value check failed[0m
|
||||||
↳ from [4mtest/tests/constant variable.ans:5:3[0m in call: [2ma = 52[0m[0m
|
↳ from [4mtest/tests/constant variable.ans:5:3[0m in call: [2ma = 52[0m[0m
|
||||||
↳ from [4mtest/tests/constant variable.ans:1:1[0m in block: [2m::a = 3…[0m
|
↳ from [4mtest/tests/constant variable.ans:1:1[0m in block: [2m:a::constant = 3…[0m
|
||||||
--# saved #--
|
--# saved #--
|
||||||
{}
|
{}
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
--- text ---
|
--- text ---
|
||||||
| {}"" {}"type(12, \"kg\")" {}"" |
|
| {}"" {}"type(12, \"kg\")" {}"" |
|
||||||
--- error ---
|
--- error ---
|
||||||
[0m[31m[0m[31mvalue check failure for weigh; 32 does not satisfy $(x) type(x) == t[0m
|
[0m[31m[0m[31mcan not set weigh = 32; $(x) type(x) == t value check failed[0m
|
||||||
↳ from [4mtest/tests/constrained variable assignement.ans:9:7[0m in call: [2mweigh = 32[0m[0m
|
↳ from [4mtest/tests/constrained variable assignement.ans:9:7[0m in call: [2mweigh = 32[0m[0m
|
||||||
↳ from [4mtest/tests/constrained variable assignement.ans:1:1[0m in block: [2m:weigh::is("kg") = type(5, "kg")…[0m
|
↳ from [4mtest/tests/constrained variable assignement.ans:1:1[0m in block: [2m:weigh::is("kg") = type(5, "kg")…[0m
|
||||||
--# saved #--
|
--# saved #--
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
--- text ---
|
--- text ---
|
||||||
| {}"d=" {}"2" {}" (2)" |
|
| {}"d=" {}"2" {}" (2)" |
|
||||||
--- error ---
|
--- error ---
|
||||||
[0m[31m[0m[31mtrying to change the value of constant d[0m
|
[0m[31m[0m[31mcan not set d = 5; constant value check failed[0m
|
||||||
↳ from [4mtest/tests/symbol alias constant.ans:12:3[0m in call: [2md = 5[0m[0m
|
↳ from [4mtest/tests/symbol alias constant.ans:12:3[0m in call: [2md = 5[0m[0m
|
||||||
↳ from [4mtest/tests/symbol alias constant.ans:1:1[0m in block: [2m:l = *[1, 2, 3]…[0m
|
↳ from [4mtest/tests/symbol alias constant.ans:1:1[0m in block: [2m:l = *[1, 2, 3]…[0m
|
||||||
--# saved #--
|
--# saved #--
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
::a = *[3]
|
:a::constant = *[3]
|
||||||
|
|
||||||
|{a}
|
|{a}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
::a = 3
|
:a::constant = 3
|
||||||
|
|
||||||
{a}
|
{a}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue