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

Rename overloaded operators (add underscores)

* add suffix unary operators
* add _! operator
* _._ and _&_ operator overloading
* allow calling function references with _! and access variables with _._
* rename . method operator to !
* various cleaning & improvements

Documentation will follow at some point.
This commit is contained in:
Étienne Fildadut 2021-12-06 01:45:19 +01:00
parent d5b1a9f225
commit 9bd9759115
16 changed files with 350 additions and 178 deletions

View file

@ -164,10 +164,15 @@ local function eval(state, exp)
end end
-- function reference: call the referenced function -- function reference: call the referenced function
local variants = exp.variants local variants = exp.variants
if exp.called_name == "()" and args[1].type == "function reference" then local paren_call = exp.paren_call
if args[1] and args[1].type == "function reference" and (exp.called_name == "()" or exp.called_name == "_!") then
-- remove func ref as first arg -- remove func ref as first arg
local refv = args[1].value local refv = args[1].value
table.remove(args, 1) table.remove(args, 1)
-- set paren_call for _!
if exp.called_name == "_!" then
paren_call = false
end
-- get variants of the referenced function -- get variants of the referenced function
variants = {} variants = {}
for _, ffqm in ipairs(refv) do for _, ffqm in ipairs(refv) do
@ -333,7 +338,7 @@ local function eval(state, exp)
if selected_variant.variant then if selected_variant.variant then
local fn = selected_variant.variant local fn = selected_variant.variant
if fn.type == "checkpoint" then if fn.type == "checkpoint" then
local r, e = run(state, fn.child, not exp.explicit_call) local r, e = run(state, fn.child, not paren_call)
if not r then return r, e end if not r then return r, e end
return r return r
elseif fn.type == "function" then elseif fn.type == "function" then
@ -361,9 +366,14 @@ local function eval(state, exp)
final_args[#final_args+1] = v final_args[#final_args+1] = v
end end
-- execute function -- execute function
-- raw mode: pass raw anselme values to the Lua function -- raw mode: pass raw anselme values to the Lua function; support return nil, err in case of error
if lua_fn.mode == "raw" then if lua_fn.mode == "raw" then
ret = lua_fn.value(unpack(final_args)) local r, e = lua_fn.value(unpack(final_args))
if r then
ret = r
else
return nil, ("%s; in Lua function %q"):format(e, exp.called_name)
end
-- untyped raw mode: same as raw, but strips custom types from the arguments -- untyped raw mode: same as raw, but strips custom types from the arguments
elseif lua_fn.mode == "untyped raw" then elseif lua_fn.mode == "untyped raw" then
-- extract value from custom types -- extract value from custom types
@ -372,7 +382,12 @@ local function eval(state, exp)
final_args[i] = arg.value[1] final_args[i] = arg.value[1]
end end
end end
ret = lua_fn.value(unpack(final_args)) local r, e = lua_fn.value(unpack(final_args))
if r then
ret = r
else
return nil, ("%s; in Lua function %q"):format(e, exp.called_name)
end
-- normal mode: convert args to Lua and convert back Lua value to Anselme -- normal mode: convert args to Lua and convert back Lua value to Anselme
elseif lua_fn.mode == nil then elseif lua_fn.mode == nil then
local l_lua = {} local l_lua = {}
@ -397,7 +412,7 @@ local function eval(state, exp)
else else
local e local e
-- eval function from start -- eval function from start
if exp.explicit_call or checkpoint.value == "" then if paren_call or checkpoint.value == "" then
ret, e = run(state, fn.child) ret, e = run(state, fn.child)
-- resume at last checkpoint -- resume at last checkpoint
else else

View file

@ -25,20 +25,28 @@ common = {
identifier_pattern = "%s*[^0-9%s"..disallowed_set.."][^"..disallowed_set.."]*", identifier_pattern = "%s*[^0-9%s"..disallowed_set.."][^"..disallowed_set.."]*",
-- names allowed for a function that aren't valid identifiers, mainly for overloading operators -- names allowed for a function that aren't valid identifiers, mainly for overloading operators
special_functions_names = { special_functions_names = {
-- operators not included here: -- operators not included here and why:
-- * assignment operators (:=, +=, -=, //=, /=, *=, %=, ^=): handled with its own syntax (function assignment) -- * assignment operators (:=, +=, -=, //=, /=, *=, %=, ^=): handled with its own syntax (function assignment)
-- * list operator (,): is used when calling every functions, sounds like more trouble than it's worth -- * list operator (,): is used when calling every functions, sounds like more trouble than it's worth
-- * |, & and ~ operators: are lazy and don't behave like regular functions -- * |, & and ~ operators: are lazy and don't behave like regular functions
-- * # operator: need to set tag state before evaluating the left arg -- * # operator: need to set tag state _before_ evaluating the left arg
-- * . operator: don't behave like regular functions either
";", -- prefix unop
"!=", "==", ">=", "<=", "<", ">", "-_", "!_",
"+", "-", "&_",
"*", "//", "/", "%", -- binop
"::", ":", "_;_",
"!", "_!=_", "_==_", "_>=_", "_<=_", "_<_", "_>_",
"^", "_+_", "_-_",
"()", "{}" "_*_", "_//_", "_/_", "_%_",
"_::_", "_:_",
"_^_",
"_._", "_!_",
-- suffix unop
"_!",
-- special
"()",
"{}"
}, },
-- escapement code and their value in strings -- escapement code and their value in strings
-- I don't think there's a point in supporting form feed, carriage return, and other printer and terminal related codes -- I don't think there's a point in supporting form feed, carriage return, and other printer and terminal related codes
@ -248,7 +256,7 @@ common = {
--- same as find_function_variant_from_fqm, but will search every function from the current namespace and up using find --- same as find_function_variant_from_fqm, but will search every function from the current namespace and up using find
-- returns directly a function expression in case of success -- returns directly a function expression in case of success
-- return nil, err otherwise -- return nil, err otherwise
find_function = function(state, namespace, name, arg, explicit_call) find_function = function(state, namespace, name, arg, paren_call, implicit_call)
local variants = {} local variants = {}
local err = ("compatible function %q variant not found"):format(name) local err = ("compatible function %q variant not found"):format(name)
local l = common.find_all(state.aliases, state.functions, namespace, name) local l = common.find_all(state.aliases, state.functions, namespace, name)
@ -264,9 +272,10 @@ common = {
if #variants > 0 then if #variants > 0 then
return { return {
type = "function call", type = "function call",
called_name = name, called_name = name, -- name of the called function
explicit_call = explicit_call, paren_call = paren_call, -- was call with parantheses?
variants = variants, implicit_call = implicit_call, -- was call implicitely (no ! or parentheses)?
variants = variants, -- list of potential variants
argument = { -- wrap everything in a list literal to simplify later things (otherwise may be nil, single value, list constructor) argument = { -- wrap everything in a list literal to simplify later things (otherwise may be nil, single value, list constructor)
type = "list_brackets", type = "list_brackets",
expression = arg expression = arg

View file

@ -1,4 +1,4 @@
local identifier_pattern, format_identifier, find, escape, find_function, parse_text, find_all local identifier_pattern, format_identifier, find, escape, find_function, parse_text, find_all, split
--- binop priority --- binop priority
local binops_prio = { local binops_prio = {
@ -12,10 +12,11 @@ local binops_prio = {
[8] = { "::", ":" }, [8] = { "::", ":" },
[9] = {}, -- unary operators [9] = {}, -- unary operators
[10] = { "^" }, [10] = { "^" },
[11] = { "." } [11] = { ".", "!" },
[12] = {}
} }
-- unop priority -- unop priority
local unops_prio = { local prefix_unops_prio = {
[1] = {}, [1] = {},
[2] = {}, [2] = {},
[3] = {}, [3] = {},
@ -27,6 +28,21 @@ local unops_prio = {
[9] = { "-", "!" }, [9] = { "-", "!" },
[10] = {}, [10] = {},
[11] = {}, [11] = {},
[12] = { "&" }
}
local suffix_unops_prio = {
[1] = {},
[2] = {},
[3] = {},
[4] = {},
[5] = {},
[6] = {},
[7] = {},
[8] = {},
[9] = {},
[10] = {},
[11] = { "!" },
[12] = {}
} }
local function get_text_in_litteral(s, start_pos) local function get_text_in_litteral(s, start_pos)
@ -132,33 +148,30 @@ local function expression(s, state, namespace, current_priority, operating_on)
right = val right = val
} }
-- find compatible variant -- find compatible variant
local variant, err = find_function(state, namespace, ":", args, true) local variant, err = find_function(state, namespace, "_:_", args, true)
if not variant then return variant, err end if not variant then return variant, err end
return expression(r, state, namespace, current_priority, variant) return expression(r, state, namespace, current_priority, variant)
end end
-- variables -- variables
local var, vfqm = find(state.aliases, state.variables, namespace, name) -- if name isn't a valid variable, suffix call: detect if a prefix is valid variable, suffix _._ call is handled in the binop section below
if var then local nl = split(name)
return expression(r, state, namespace, current_priority, { for i=#nl, 1, -1 do
type = "variable", local name_prefix = table.concat(nl, ".", 1, i)
name = vfqm local var, vfqm = find(state.aliases, state.variables, namespace, name_prefix)
}) if var then
end if i < #nl then
-- suffix call: detect if prefix is valid variable, suffix call is handled in the binop section below r = "."..table.concat(nl, ".", i+1, #nl)..r
local sname, suffix = name:match("^(.*)(%."..identifier_pattern..")$") end
if sname then return expression(r, state, namespace, current_priority, {
local svar, svfqm = find(state.aliases, state.variables, namespace, sname)
if svar then
return expression(suffix..r, state, namespace, current_priority, {
type = "variable", type = "variable",
name = svfqm name = vfqm
}) })
end end
end end
-- function call -- function call
local args, explicit_call local args, paren_call, implicit_call
if r:match("^%b()") then if r:match("^%b()") then
explicit_call = true paren_call = true
local content, rem = r:match("^(%b())(.*)$") local content, rem = r:match("^(%b())(.*)$")
content = content:gsub("^%(", ""):gsub("%)$", "") content = content:gsub("^%(", ""):gsub("%)$", "")
r = rem r = rem
@ -169,38 +182,50 @@ local function expression(s, state, namespace, current_priority, operating_on)
if not args then return args, err end if not args then return args, err end
if err:match("[^%s]") then return nil, ("unexpected %q at end of argument list"):format(err) end if err:match("[^%s]") then return nil, ("unexpected %q at end of argument list"):format(err) end
end end
elseif r:match("^%!") then -- optional, to call with no arg, no explicit call else -- implicit call; will be changed if there happens to be a ! after in the suffix operator code
r = r:match("^%!(.*)$") implicit_call = true
end end
-- find compatible variant -- find compatible variant
local variant, err = find_function(state, namespace, name, args, explicit_call) local variant, err = find_function(state, namespace, name, args, paren_call, implicit_call)
if not variant then return variant, err end if not variant then return variant, err end
return expression(r, state, namespace, current_priority, variant) return expression(r, state, namespace, current_priority, variant)
-- function reference
elseif s:match("^%&"..identifier_pattern) then
local name, r = s:match("^%&("..identifier_pattern..")(.-)$")
name = format_identifier(name)
-- get all functions this name can reference
local lfnqm = find_all(state.aliases, state.functions, namespace, name)
if #lfnqm > 0 then
return expression(r, state, namespace, current_priority, {
type = "function reference",
names = lfnqm
})
end
return nil, ("can't find function %q to reference"):format(name)
end end
-- unops -- prefix unops
for prio, oplist in ipairs(unops_prio) do for prio, oplist in ipairs(prefix_unops_prio) do
for _, op in ipairs(oplist) do for _, op in ipairs(oplist) do
local escaped = escape(op) local escaped = escape(op)
if s:match("^"..escaped) then if s:match("^"..escaped) then
local right, r = expression(s:match("^"..escaped.."(.*)$"), state, namespace, prio) local sright = s:match("^"..escaped.."(.*)$")
if not right then return nil, ("invalid expression after unop %q: %s"):format(op, r) end -- function reference
-- find variant if op == "&" and sright:match("^"..identifier_pattern) then
local variant, err = find_function(state, namespace, op, right, true) local name, r = sright:match("^("..identifier_pattern..")(.-)$")
if not variant then return variant, err end name = format_identifier(name)
return expression(r, state, namespace, current_priority, variant) -- get all functions this name can reference
-- try prefixes until we find a valid function name
local nl = split(name)
for i=#nl, 1, -1 do
local name_prefix = table.concat(nl, ".", 1, i)
local lfnqm = find_all(state.aliases, state.functions, namespace, name_prefix)
if #lfnqm > 0 then
if i < #nl then
r = "."..table.concat(nl, ".", i+1, #nl)..r
end
return expression(r, state, namespace, current_priority, {
type = "function reference",
names = lfnqm
})
end
end
return nil, ("can't find function %q to reference"):format(name)
-- normal prefix unop
else
local right, r = expression(sright, state, namespace, prio)
if not right then return nil, ("invalid expression after unop %q: %s"):format(op, r) end
-- find variant
local variant, err = find_function(state, namespace, op.."_", right, true)
if not variant then return variant, err end
return expression(r, state, namespace, current_priority, variant)
end
end end
end end
end end
@ -214,12 +239,12 @@ local function expression(s, state, namespace, current_priority, operating_on)
if s:match("^"..escaped) then if s:match("^"..escaped) then
local sright = s:match("^"..escaped.."(.*)$") local sright = s:match("^"..escaped.."(.*)$")
-- suffix call -- suffix call
if op == "." and sright:match("^"..identifier_pattern) then if op == "!" and sright:match("^"..identifier_pattern) then
local name, r = sright:match("^("..identifier_pattern..")(.-)$") local name, r = sright:match("^("..identifier_pattern..")(.-)$")
name = format_identifier(name) name = format_identifier(name)
local args, explicit_call local args, paren_call
if r:match("^%b()") then if r:match("^%b()") then
explicit_call = true paren_call = true
local content, rem = r:match("^(%b())(.*)$") local content, rem = r:match("^(%b())(.*)$")
content = content:gsub("^%(", ""):gsub("%)$", "") content = content:gsub("^%(", ""):gsub("%)$", "")
r = rem r = rem
@ -242,101 +267,127 @@ local function expression(s, state, namespace, current_priority, operating_on)
} }
end end
-- find compatible variant -- find compatible variant
local variant, err = find_function(state, namespace, name, args, explicit_call) local variant, err = find_function(state, namespace, name, args, paren_call)
if not variant then return variant, err end
return expression(r, state, namespace, current_priority, variant)
-- namespace
elseif op == "." and sright:match("^"..identifier_pattern) then
local name, r = sright:match("^("..identifier_pattern..")(.-)$")
name = format_identifier(name)
-- find variant
local args = {
type = "list",
left = operating_on,
right = { type = "string", text = { name } }
}
local variant, err = find_function(state, namespace, "_._", args, true)
if not variant then return variant, err end if not variant then return variant, err end
return expression(r, state, namespace, current_priority, variant) return expression(r, state, namespace, current_priority, variant)
-- other binops -- other binops
else else
local right, r = expression(sright, state, namespace, prio) local right, r = expression(sright, state, namespace, prio)
if not right then return nil, ("invalid expression after binop %q: %s"):format(op, r) end if right then
-- list constructor -- list constructor (can't do this through a function call since we need to build a list for its arguments)
if op == "," then if op == "," then
return expression(r, state, namespace, current_priority, { return expression(r, state, namespace, current_priority, {
type = "list", type = "list",
left = operating_on, left = operating_on,
right = right right = right
}) })
-- special binops -- special binops
elseif op == ":=" or op == "+=" or op == "-=" or op == "//=" or op == "/=" or op == "*=" or op == "%=" or op == "^=" then elseif op == ":=" or op == "+=" or op == "-=" or op == "//=" or op == "/=" or op == "*=" or op == "%=" or op == "^=" then
-- rewrite assignment + arithmetic operators into a normal assignment -- rewrite assignment + arithmetic operators into a normal assignment
if op ~= ":=" then if op ~= ":=" then
local args = {
type = "list",
left = operating_on,
right = right
}
local variant, err = find_function(state, namespace, "_"..op:match("^(.*)%=$").."_", args, true)
if not variant then return variant, err end
right = variant
end
-- assign to a function
if operating_on.type == "function call" then
-- remove non-assignment functions
for i=#operating_on.variants, 1, -1 do
if not operating_on.variants[i].assignment then
table.remove(operating_on.variants, i)
end
end
if #operating_on.variants == 0 then
return nil, ("trying to perform assignment on function %s with no compatible assignment variant"):format(operating_on.called_name)
end
-- rewrite function to perform assignment
operating_on.assignment = right
return expression(r, state, namespace, current_priority, operating_on)
elseif operating_on.type ~= "variable" then
return nil, ("trying to perform assignment on a %s expression"):format(operating_on.type)
end
-- assign to a variable
return expression(r, state, namespace, current_priority, {
type = ":=",
left = operating_on,
right = right
})
elseif op == "&" or op == "|" or op == "~" or op == "#" then
return expression(r, state, namespace, current_priority, {
type = op,
left = operating_on,
right = right
})
-- normal binop
else
-- find variant
local args = { local args = {
type = "list", type = "list",
left = operating_on, left = operating_on,
right = right right = right
} }
local variant, err = find_function(state, namespace, op:match("^(.*)%=$"), args, true) local variant, err = find_function(state, namespace, "_"..op.."_", args, true)
if not variant then return variant, err end if not variant then return variant, err end
right = variant return expression(r, state, namespace, current_priority, variant)
end end
-- assign to a function
if operating_on.type == "function call" then
-- remove non-assignment functions
for i=#operating_on.variants, 1, -1 do
if not operating_on.variants[i].assignment then
table.remove(operating_on.variants, i)
end
end
if #operating_on.variants == 0 then
return nil, ("trying to perform assignment on function %s with no compatible assignment variant"):format(operating_on.called_name)
end
-- rewrite function to perform assignment
operating_on.assignment = right
return expression(r, state, namespace, current_priority, operating_on)
elseif operating_on.type ~= "variable" then
return nil, ("trying to perform assignment on a %s expression"):format(operating_on.type)
end
-- assign to a variable
return expression(r, state, namespace, current_priority, {
type = ":=",
left = operating_on,
right = right
})
elseif op == "&" or op == "|" or op == "~" or op == "#" then
return expression(r, state, namespace, current_priority, {
type = op,
left = operating_on,
right = right
})
-- normal binop
else
-- find variant
local args = {
type = "list",
left = operating_on,
right = right
}
local variant, err = find_function(state, namespace, op, args, true)
if not variant then return variant, err end
return expression(r, state, namespace, current_priority, variant)
end end
end end
end end
end end
end end
end end
-- index / call -- suffix unop
if s:match("^%b()") or s:match("^%!") then for prio, oplist in ipairs(suffix_unops_prio) do
local args = operating_on if prio > current_priority then
local explicit_call, r for _, op in ipairs(oplist) do
-- call with args, explicit call local escaped = escape(op)
if s:match("^%b()") then if s:match("^"..escaped) then
explicit_call = true local r = s:match("^"..escaped.."(.*)$")
local content -- remove ! after a previously-assumed implicit function call
content, r = s:match("^(%b())(.*)$") if op == "!" and operating_on.type == "function call" and operating_on.implicit_call then
content = content:gsub("^%(", ""):gsub("%)$", "") operating_on.implicit_call = false
-- get arguments return expression(r, state, namespace, current_priority, operating_on)
if content:match("[^%s]") then -- normal suffix unop
local right, r_paren = expression(content, state, namespace) else
if not right then return right, r_paren end local variant, err = find_function(state, namespace, "_"..op, operating_on, true)
if r_paren:match("[^%s]") then return nil, ("unexpected %q at end of index/call expression"):format(r_paren) end if not variant then return variant, err end
args = { type = "list", left = args, right = right } return expression(r, state, namespace, current_priority, variant)
end
end
end end
-- call with no arg, no explicit call
elseif s:match("^%!") then
r = s:match("^%!(.*)$")
end end
local variant, err = find_function(state, namespace, "()", args, explicit_call) end
-- index / call
if s:match("^%b()") then
local args = operating_on
local content, r = s:match("^(%b())(.*)$")
content = content:gsub("^%(", ""):gsub("%)$", "")
-- get arguments
if content:match("[^%s]") then
local right, r_paren = expression(content, state, namespace)
if not right then return right, r_paren end
if r_paren:match("[^%s]") then return nil, ("unexpected %q at end of index/call expression"):format(r_paren) end
args = { type = "list", left = args, right = right }
end
local variant, err = find_function(state, namespace, "()", args, true)
if not variant then return variant, err end if not variant then return variant, err end
return expression(r, state, namespace, current_priority, variant) return expression(r, state, namespace, current_priority, variant)
end end
@ -347,6 +398,6 @@ end
package.loaded[...] = expression package.loaded[...] = expression
local common = require((...):gsub("expression$", "common")) local common = require((...):gsub("expression$", "common"))
identifier_pattern, format_identifier, find, escape, find_function, parse_text, find_all = common.identifier_pattern, common.format_identifier, common.find, common.escape, common.find_function, common.parse_text, common.find_all identifier_pattern, format_identifier, find, escape, find_function, parse_text, find_all, split = common.identifier_pattern, common.format_identifier, common.find, common.escape, common.find_function, common.parse_text, common.find_all, common.split
return expression return expression

View file

@ -29,7 +29,7 @@ local function parse(state)
end end
param.default = default_exp param.default = default_exp
-- extract type annotation from default value -- extract type annotation from default value
if default_exp.type == "function call" and default_exp.called_name == "::" then if default_exp.type == "function call" and default_exp.called_name == "_::_" then
param.type_annotation = default_exp.argument.expression.right param.type_annotation = default_exp.argument.expression.right
end end
end end

View file

@ -1,14 +1,14 @@
local truthy, anselme, compare, is_of_type, identifier_pattern, format_identifier local truthy, anselme, compare, is_of_type, identifier_pattern, format_identifier, find, get_variable
local functions local functions
functions = { functions = {
-- discard left -- discard left
[";(a, b)"] = { ["_;_(a, b)"] = {
mode = "raw", mode = "raw",
value = function(a, b) return b end value = function(a, b) return b end
}, },
-- comparaison -- comparaison
["==(a, b)"] = { ["_==_(a, b)"] = {
mode = "raw", mode = "raw",
value = function(a, b) value = function(a, b)
return { return {
@ -17,7 +17,7 @@ functions = {
} }
end end
}, },
["!=(a, b)"] = { ["_!=_(a, b)"] = {
mode = "raw", mode = "raw",
value = function(a, b) value = function(a, b)
return { return {
@ -26,21 +26,21 @@ functions = {
} }
end end
}, },
[">(a::number, b::number)"] = function(a, b) return a > b end, ["_>_(a::number, b::number)"] = function(a, b) return a > b end,
["<(a::number, b::number)"] = function(a, b) return a < b end, ["_<_(a::number, b::number)"] = function(a, b) return a < b end,
[">=(a::number, b::number)"] = function(a, b) return a >= b end, ["_>=_(a::number, b::number)"] = function(a, b) return a >= b end,
["<=(a::number, b::number)"] = function(a, b) return a <= b end, ["_<=_(a::number, b::number)"] = function(a, b) return a <= b end,
-- arithmetic -- arithmetic
["+(a::number, b::number)"] = function(a, b) return a + b end, ["_+_(a::number, b::number)"] = function(a, b) return a + b end,
["+(a::string, b::string)"] = function(a, b) return a .. b end, ["_+_(a::string, b::string)"] = function(a, b) return a .. b end,
["-(a::number, b::number)"] = function(a, b) return a - b end, ["_-_(a::number, b::number)"] = function(a, b) return a - b end,
["-(a::number)"] = function(a) return -a end, ["-_(a::number)"] = function(a) return -a end,
["*(a::number, b::number)"] = function(a, b) return a * b end, ["_*_(a::number, b::number)"] = function(a, b) return a * b end,
["/(a::number, b::number)"] = function(a, b) return a / b end, ["_/_(a::number, b::number)"] = function(a, b) return a / b end,
["//(a::number, b::number)"] = function(a, b) return math.floor(a / b) end, ["_//_(a::number, b::number)"] = function(a, b) return math.floor(a / b) end,
["^(a::number, b::number)"] = function(a, b) return a ^ b end, ["_^_(a::number, b::number)"] = function(a, b) return a ^ b end,
-- boolean -- boolean
["!(a)"] = { ["!_(a)"] = {
mode = "raw", mode = "raw",
value = function(a) value = function(a)
return { return {
@ -50,7 +50,7 @@ functions = {
end end
}, },
-- pair -- pair
[":(a, b)"] = { ["_:_(a, b)"] = {
mode = "raw", mode = "raw",
value = function(a, b) value = function(a, b)
return { return {
@ -60,7 +60,7 @@ functions = {
end end
}, },
-- type -- type
["::(a, b)"] = { ["_::_(a, b)"] = {
mode = "raw", mode = "raw",
value = function(a, b) value = function(a, b)
return { return {
@ -69,6 +69,22 @@ functions = {
} }
end end
}, },
-- namespace
["_._(r::function reference, name::string)"] = {
mode = "raw",
value = function(r, n)
local state = anselme.running.state
local rval = r.value
local name = n.value
for _, ffqm in ipairs(rval) do
local var, vfqm = find(state.aliases, state.variables, ffqm..".", name)
if var then
return get_variable(state, vfqm)
end
end
return nil, ("can't find variable %q in function reference (searched in namespaces: %s)"):format(name, table.concat(rval, ", "))
end
},
-- index -- index
["()(l::list, i::number)"] = { ["()(l::list, i::number)"] = {
mode = "untyped raw", mode = "untyped raw",
@ -122,6 +138,9 @@ functions = {
["()(fn::function reference, l...)"] = { ["()(fn::function reference, l...)"] = {
-- bypassed, this case is manually handled in the expression interpreter -- bypassed, this case is manually handled in the expression interpreter
}, },
["_!(fn::function reference, l...)"] = {
-- bypassed, this case is manually handled in the expression interpreter
},
-- format -- format
["{}(v)"] = { ["{}(v)"] = {
mode = "raw", mode = "raw",
@ -281,7 +300,7 @@ functions = {
package.loaded[...] = functions package.loaded[...] = functions
local icommon = require((...):gsub("stdlib%.functions$", "interpreter.common")) local icommon = require((...):gsub("stdlib%.functions$", "interpreter.common"))
truthy, compare, is_of_type = icommon.truthy, icommon.compare, icommon.is_of_type truthy, compare, is_of_type, get_variable = icommon.truthy, icommon.compare, icommon.is_of_type, icommon.get_variable
local pcommon = require((...):gsub("stdlib%.functions$", "parser.common")) local pcommon = require((...):gsub("stdlib%.functions$", "parser.common"))
identifier_pattern, format_identifier = pcommon.identifier_pattern, pcommon.format_identifier identifier_pattern, format_identifier, find = pcommon.identifier_pattern, pcommon.format_identifier, pcommon.find
anselme = require((...):gsub("stdlib%.functions$", "anselme")) anselme = require((...):gsub("stdlib%.functions$", "anselme"))

View file

@ -0,0 +1,6 @@
return [[
(Built-in variables)
:alias 👁 = "seen"
:alias 🔖 = "checkpoint"
:alias 🏁 = "reached"
]]

View file

@ -1,7 +1,7 @@
$ -(a, b) $ _-_(a, b)
@"generic minus" @"generic minus"
$ -(a::string, b::string) $ _-_(a::string, b::string)
@a + " minus " + b @a + " minus " + b
{2-5} {2-5}

View file

@ -0,0 +1,7 @@
:c = 1
{c}
~ c += 2
{c}

View file

@ -0,0 +1,22 @@
local _={}
_[9]={}
_[8]={}
_[7]={tags=_[9],text="3"}
_[6]={tags=_[8],text="1"}
_[5]={_[7]}
_[4]={_[6]}
_[3]={"return"}
_[2]={"text",_[5]}
_[1]={"text",_[4]}
return {_[1],_[2],_[3]}
--[[
{ "text", { {
tags = {},
text = "1"
} } }
{ "text", { {
tags = {},
text = "3"
} } }
{ "return" }
]]--

View file

@ -4,19 +4,19 @@
1,2: {l} 1,2: {l}
~ l.insert(3) ~ l!insert(3)
1,2,3: {l} 1,2,3: {l}
§ a § a
~ l.insert(4) ~ l!insert(4)
1,2,3,4: {l} 1,2,3,4: {l}
§ b § b
~ l.insert(5) ~ l!insert(5)
1,2,3,4,5: {l} 1,2,3,4,5: {l}

View file

@ -0,0 +1,13 @@
$ fn
@1
$ add(x)
@x+2
:c = &fn
{c!}
{fn!add}
{c!!add}

View file

@ -0,0 +1,30 @@
local _={}
_[13]={}
_[12]={}
_[11]={}
_[10]={text="3",tags=_[13]}
_[9]={text="3",tags=_[12]}
_[8]={text="1",tags=_[11]}
_[7]={_[10]}
_[6]={_[9]}
_[5]={_[8]}
_[4]={"return"}
_[3]={"text",_[7]}
_[2]={"text",_[6]}
_[1]={"text",_[5]}
return {_[1],_[2],_[3],_[4]}
--[[
{ "text", { {
tags = {},
text = "1"
} } }
{ "text", { {
tags = {},
text = "3"
} } }
{ "text", { {
tags = {},
text = "3"
} } }
{ "return" }
]]--

View file

@ -1,6 +1,6 @@
$ f(a) $ f(a)
{a} {a}
~ "ok".f ~ "ok"!f
~ "ok".f() ~ "ok"!f()

View file

@ -1,4 +1,4 @@
$ f(a, b) $ f(a, b)
{a}{b} {a}{b}
~ "o".f("k") ~ "o"!f("k")

View file

@ -1,8 +1,8 @@
$ f(l...) $ f(l...)
~ l.len ~ l!len
:a = 0 :a = 0
~ a := l(1) ~ a := l(1)
~ l.remove(1) ~ l!remove(1)
@a + f(l=l) @a + f(l=l)
~~ ~~
@0 @0

View file

@ -1,7 +1,7 @@
$ -(f) $ -_(f)
@"generic minus" @"generic minus"
$ -(f::string) $ -_(f::string)
@"minus "+f @"minus "+f
{-5} {-5}