mirror of
https://github.com/Reuh/anselme.git
synced 2025-10-27 16:49:31 +00:00
Add default and named arguments, rename equality operator to ==, shortcut for string pairs
This commit is contained in:
parent
17751c5c59
commit
151c70ed26
28 changed files with 396 additions and 146 deletions
70
README.md
70
README.md
|
|
@ -98,16 +98,16 @@ $ main
|
||||||
|
|
||||||
~ var := 2
|
~ var := 2
|
||||||
|
|
||||||
before: {var}=2, because the value has been changed in the current execution context
|
before: {var}==2, because the value has been changed in the current execution context
|
||||||
|
|
||||||
(But if we run the script "parallel" in parallel at this point, it will still think var=5)
|
(But if we run the script "parallel" in parallel at this point, it will still think var==5)
|
||||||
|
|
||||||
§ foo
|
§ foo
|
||||||
But the variable will be merged with the global state on a checkpoint
|
But the variable will be merged with the global state on a checkpoint
|
||||||
|
|
||||||
after: {var}=2, still, as expected
|
after: {var}==2, still, as expected
|
||||||
|
|
||||||
(And if we run the script "parallel" in parallel at this point, it will now think var=2)
|
(And if we run the script "parallel" in parallel at this point, it will now think var==2)
|
||||||
|
|
||||||
$ parallel
|
$ parallel
|
||||||
parallel: {main.var}
|
parallel: {main.var}
|
||||||
|
|
@ -150,7 +150,7 @@ There's different types of lines, depending on their first character(s) (after i
|
||||||
|
|
||||||
~ 0
|
~ 0
|
||||||
This is never run.
|
This is never run.
|
||||||
~~ 1 = 0
|
~~ 1 == 0
|
||||||
This neither.
|
This neither.
|
||||||
~~
|
~~
|
||||||
This is.
|
This is.
|
||||||
|
|
@ -168,13 +168,14 @@ There's different types of lines, depending on their first character(s) (after i
|
||||||
|
|
||||||
The function body is not executed when the line is reached; it must be explicitely called in an expression. See [expressions](#function-calls) to see the different ways of calling a function.
|
The function body is not executed when the line is reached; it must be explicitely called in an expression. See [expressions](#function-calls) to see the different ways of calling a function.
|
||||||
|
|
||||||
A parameter list can be optionally given after the identifier. Parameter names are identifiers, with eventually an alias. It is enclosed with paranthesis and contain a comma-separated list of identifiers:
|
A parameter list can be optionally given after the identifier. Parameter names are identifiers, with eventually an alias (after a `:`) and a default value (after a `=`). It is enclosed with paranthesis and contain a comma-separated list of identifiers:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ f(a, b, c)
|
$ f(a, b: alias for b, c="default for c", d: alias for d = "default for d")
|
||||||
first argument: {a}
|
first argument: {a}
|
||||||
second argument: {b}
|
second argument: {b}
|
||||||
third argument: {c}
|
third argument: {c}
|
||||||
|
fourth argument: {d}
|
||||||
```
|
```
|
||||||
|
|
||||||
Functions can also have a variable number of arguments. By adding `...` after the last argument identifier, it will be considered a variable length argument ("vararg"), and will contain a list of every extraneous argument.
|
Functions can also have a variable number of arguments. By adding `...` after the last argument identifier, it will be considered a variable length argument ("vararg"), and will contain a list of every extraneous argument.
|
||||||
|
|
@ -274,7 +275,7 @@ $ f
|
||||||
@2
|
@2
|
||||||
|
|
||||||
(f will return 2 since the choice is run after the @2 line)
|
(f will return 2 since the choice is run after the @2 line)
|
||||||
~ f = 2
|
~ f == 2
|
||||||
|
|
||||||
Yes.
|
Yes.
|
||||||
|
|
||||||
|
|
@ -442,7 +443,7 @@ Var1 in the current namespace = 1: {var1}
|
||||||
Var1 in the fn1 namespace = 2: {fn1.var1}
|
Var1 in the fn1 namespace = 2: {fn1.var1}
|
||||||
|
|
||||||
(Weird, but valid, and also the reason I'm not talking of scoping:)
|
(Weird, but valid, and also the reason I'm not talking of scoping:)
|
||||||
~ fn1.var1 = 3
|
~ fn1.var1 == 3
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Aliases
|
#### Aliases
|
||||||
|
|
@ -495,7 +496,7 @@ Default types are:
|
||||||
|
|
||||||
* `list`: a list of values. Types can be mixed. Can be defined between square brackets and use comma as a separator '[1,2,3,4]'.
|
* `list`: a list of values. Types can be mixed. Can be defined between square brackets and use comma as a separator '[1,2,3,4]'.
|
||||||
|
|
||||||
* `pair`: a couple of values. Types can be mixed. Can be defined using colon `"key":5`.
|
* `pair`: a couple of values. Types can be mixed. Can be defined using colon `"key":5`. Pairs named by a string that is also a valid identifier can be created using the `key=5` shorthand syntax.
|
||||||
|
|
||||||
How conversions are handled from Anselme to Lua:
|
How conversions are handled from Anselme to Lua:
|
||||||
|
|
||||||
|
|
@ -507,7 +508,7 @@ How conversions are handled from Anselme to Lua:
|
||||||
|
|
||||||
* `list` -> `table`. Pair elements in the list will be assigned as a key-value pair in the Lua list and its index skipped in the sequential part, e.g. `[1,2,"key":"value",3]` -> `{1,2,3,key="value"}`.
|
* `list` -> `table`. Pair elements in the list will be assigned as a key-value pair in the Lua list and its index skipped in the sequential part, e.g. `[1,2,"key":"value",3]` -> `{1,2,3,key="value"}`.
|
||||||
|
|
||||||
* `pair` -> `table`, with a signle key-value pair.
|
* `pair` -> `table`, with a single key-value pair.
|
||||||
|
|
||||||
How conservions are handled from Lua to Anselme:
|
How conservions are handled from Lua to Anselme:
|
||||||
|
|
||||||
|
|
@ -584,6 +585,49 @@ $ f
|
||||||
this is text: {f}
|
this is text: {f}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Functions can also have default arguments. Defaults values can be any expression and are re-evaluated each time the function is called:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ f(a, b=1)
|
||||||
|
@a+b
|
||||||
|
|
||||||
|
{f(1)} = 2
|
||||||
|
|
||||||
|
$ g(a, b=a)
|
||||||
|
@a+b
|
||||||
|
|
||||||
|
{g(1)} = 2
|
||||||
|
{g(2)} = 4
|
||||||
|
```
|
||||||
|
|
||||||
|
Arguments can also be passed by naming them instead of their position. These syntaxes can be mixed:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ f(a, b, c)
|
||||||
|
@a + b + c
|
||||||
|
|
||||||
|
{f(1,2,3)} = {f(c=3,b=2,a=1)} = {f(1,2,c=3)}
|
||||||
|
```
|
||||||
|
|
||||||
|
Anselme actually treat argument list are regular lists; named arguments are actually pairs.
|
||||||
|
|
||||||
|
This means that pairs can't be passed directly as arguments to a function (as they will be considered named arguments). If you want to use pairs, always wrap them in a list.
|
||||||
|
|
||||||
|
Functions can have a variable number of arguments. Additional arguments are added in a list:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ f(a, b...)
|
||||||
|
{a}
|
||||||
|
|
||||||
|
{b}
|
||||||
|
|
||||||
|
{f(1, 2, 3, 4, 5)}
|
||||||
|
|
||||||
|
(Will print:)
|
||||||
|
1
|
||||||
|
[2,3,4,5]
|
||||||
|
```
|
||||||
|
|
||||||
#### Checkpoint calls
|
#### Checkpoint calls
|
||||||
|
|
||||||
Most of the time, you should'nt need to call checkpoints yourself - they will be automatically be set as the active checkpoint when the interperter reach their line, and they will be automatically called when resuming its parent function.
|
Most of the time, you should'nt need to call checkpoints yourself - they will be automatically be set as the active checkpoint when the interperter reach their line, and they will be automatically called when resuming its parent function.
|
||||||
|
|
@ -647,7 +691,7 @@ Built-in operators:
|
||||||
|
|
||||||
##### Comparaison
|
##### Comparaison
|
||||||
|
|
||||||
`a = b`: returns `1` if a and b have the same value (will recursively compare list and pairs), `0` otherwise
|
`a == b`: returns `1` if a and b have the same value (will recursively compare list and pairs), `0` otherwise
|
||||||
|
|
||||||
`a != b`: returns `1` if a and b do not have the same value, `0` otherwise
|
`a != b`: returns `1` if a and b do not have the same value, `0` otherwise
|
||||||
|
|
||||||
|
|
@ -685,7 +729,7 @@ This only works on strings:
|
||||||
|
|
||||||
`a : b`: evaluate a and b, returns a new pair with a as key and b as value.
|
`a : b`: evaluate a and b, returns a new pair with a as key and b as value.
|
||||||
|
|
||||||
`a(b)`: evaluate b (number), returns the value with this index in a (list). Use 1-based indexing.
|
`a(b)`: evaluate b (number), returns the value with this index in a (list). Use 1-based indexing. If b is a string, will search the first pair in the list with this string as its name.
|
||||||
|
|
||||||
#### Built-in functions
|
#### Built-in functions
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
-- anselme module
|
-- anselme module
|
||||||
local anselme = {
|
local anselme = {
|
||||||
-- version
|
-- version
|
||||||
version = "0.13.1",
|
-- major.minor.fix
|
||||||
|
-- saves files are incompatible between major versions
|
||||||
|
-- scripts files may break between minor versions
|
||||||
|
version = "0.14.0",
|
||||||
--- currently running interpreter
|
--- currently running interpreter
|
||||||
running = nil
|
running = nil
|
||||||
}
|
}
|
||||||
|
|
@ -399,7 +402,7 @@ return setmetatable(anselme, {
|
||||||
functions = {
|
functions = {
|
||||||
-- [":="] = {
|
-- [":="] = {
|
||||||
-- {
|
-- {
|
||||||
-- arity = {3,42}, type = { [1] = "variable" }, check = function, rewrite = function, vararg = 2, mode = "custom",
|
-- arity = {3,42}, type = { [1] = "variable" }, check = function, rewrite = function, mode = "custom",
|
||||||
-- value = function(state, exp)
|
-- value = function(state, exp)
|
||||||
-- end -- or checkpoint, function, line
|
-- end -- or checkpoint, function, line
|
||||||
-- }
|
-- }
|
||||||
|
|
|
||||||
|
|
@ -33,12 +33,13 @@ local function eval(state, exp)
|
||||||
elseif exp.type == "parentheses" then
|
elseif exp.type == "parentheses" then
|
||||||
return eval(state, exp.expression)
|
return eval(state, exp.expression)
|
||||||
-- list parentheses
|
-- list parentheses
|
||||||
elseif exp.type == "list_parentheses" then
|
elseif exp.type == "list_brackets" then
|
||||||
if exp.expression then
|
if exp.expression then
|
||||||
local v, e = eval(state, exp.expression)
|
local v, e = eval(state, exp.expression)
|
||||||
if not v then return v, e end
|
if not v then return v, e end
|
||||||
if v.type == "list" then
|
if exp.expression.type == "list" then
|
||||||
return v
|
return v
|
||||||
|
-- contained a single element, wrap in list manually
|
||||||
else
|
else
|
||||||
return {
|
return {
|
||||||
type = "list",
|
type = "list",
|
||||||
|
|
@ -78,24 +79,12 @@ local function eval(state, exp)
|
||||||
if fn.mode == "custom" then
|
if fn.mode == "custom" then
|
||||||
return fn.value(state, exp)
|
return fn.value(state, exp)
|
||||||
else
|
else
|
||||||
-- eval args: same as list, but only put vararg arguments in a separate list
|
-- eval args: list_brackets
|
||||||
local l = {}
|
local args = {}
|
||||||
if exp.argument then
|
if exp.argument then
|
||||||
local vararg = fn.vararg or math.huge
|
local arg, arge = eval(state, exp.argument)
|
||||||
local i, ast = 1, exp.argument
|
if not arg then return arg, arge end
|
||||||
while ast.type == "list" and i < vararg do
|
args = arg.value
|
||||||
local left, lefte = eval(state, ast.left)
|
|
||||||
if not left then return left, lefte end
|
|
||||||
table.insert(l, left)
|
|
||||||
ast = ast.right
|
|
||||||
i = i + 1
|
|
||||||
end
|
|
||||||
local right, righte = eval(state, ast)
|
|
||||||
if not right then return right, righte end
|
|
||||||
table.insert(l, right)
|
|
||||||
end
|
|
||||||
if fn.vararg and #l < fn.vararg then -- empty list vararg
|
|
||||||
table.insert(l, { type = "list", value = {} })
|
|
||||||
end
|
end
|
||||||
-- anselme function
|
-- anselme function
|
||||||
if type(fn.value) == "table" then
|
if type(fn.value) == "table" then
|
||||||
|
|
@ -106,9 +95,40 @@ local function eval(state, exp)
|
||||||
return r
|
return r
|
||||||
-- function
|
-- function
|
||||||
elseif fn.value.type == "function" then
|
elseif fn.value.type == "function" then
|
||||||
-- set args
|
-- map named arguments
|
||||||
|
for _, arg in ipairs(args) do
|
||||||
|
if arg.type == "pair" and arg.value[1].type == "string" then
|
||||||
|
args[arg.value[1].value] = arg.value[2]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- get and set args
|
||||||
for j, param in ipairs(fn.value.params) do
|
for j, param in ipairs(fn.value.params) do
|
||||||
state.variables[param] = l[j]
|
local val
|
||||||
|
-- named
|
||||||
|
if param.alias and args[param.alias] then
|
||||||
|
val = args[param.alias]
|
||||||
|
elseif args[param.name] then
|
||||||
|
val = args[param.name]
|
||||||
|
-- vararg
|
||||||
|
elseif param.vararg then
|
||||||
|
val = { type = "list", value = {} }
|
||||||
|
for k=j, #args do
|
||||||
|
table.insert(val.value, args[k])
|
||||||
|
end
|
||||||
|
-- positional
|
||||||
|
elseif args[j] and args[j].type ~= "pair" then
|
||||||
|
val = args[j]
|
||||||
|
-- default
|
||||||
|
elseif param.default then
|
||||||
|
local v, e = eval(state, param.default)
|
||||||
|
if not v then return v, e end
|
||||||
|
val = v
|
||||||
|
end
|
||||||
|
if val then
|
||||||
|
state.variables[param.full_name] = val
|
||||||
|
else
|
||||||
|
return nil, ("missing mandatory argument %q in function %q call"):format(param.name, fn.value.name)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
-- eval function
|
-- eval function
|
||||||
local r, e
|
local r, e
|
||||||
|
|
@ -130,12 +150,13 @@ local function eval(state, exp)
|
||||||
return nil, ("unknown function type %q"):format(fn.value.type)
|
return nil, ("unknown function type %q"):format(fn.value.type)
|
||||||
end
|
end
|
||||||
-- lua functions
|
-- lua functions
|
||||||
|
-- TODO: handle named and default arguments
|
||||||
else
|
else
|
||||||
if fn.mode == "raw" then
|
if fn.mode == "raw" then
|
||||||
return fn.value(unpack(l))
|
return fn.value(unpack(args))
|
||||||
else
|
else
|
||||||
local l_lua = {}
|
local l_lua = {}
|
||||||
for _, v in ipairs(l) do
|
for _, v in ipairs(args) do
|
||||||
table.insert(l_lua, to_lua(v))
|
table.insert(l_lua, to_lua(v))
|
||||||
end
|
end
|
||||||
local r, e
|
local r, e
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,9 @@ common = {
|
||||||
for _, variant in ipairs(func) do
|
for _, variant in ipairs(func) do
|
||||||
local ok = true
|
local ok = true
|
||||||
local return_type = variant.return_type
|
local return_type = variant.return_type
|
||||||
|
-- arity check
|
||||||
|
-- note: because named args can't be predicted in advance (pairs need to be evaluated), this arity check isn't enough to guarantee a compatible function
|
||||||
|
-- (e.g., if there's 3 required args but only provide 3 optional arg in a call, will pass)
|
||||||
if variant.arity then
|
if variant.arity then
|
||||||
local min, max
|
local min, max
|
||||||
if type(variant.arity) == "table" then
|
if type(variant.arity) == "table" then
|
||||||
|
|
@ -123,6 +126,7 @@ common = {
|
||||||
ok = false
|
ok = false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
-- custom check
|
||||||
if ok and variant.check then
|
if ok and variant.check then
|
||||||
local s, e = variant.check(state, args)
|
local s, e = variant.check(state, args)
|
||||||
if not s then
|
if not s then
|
||||||
|
|
@ -131,6 +135,7 @@ common = {
|
||||||
end
|
end
|
||||||
return_type = s == true and return_type or s
|
return_type = s == true and return_type or s
|
||||||
end
|
end
|
||||||
|
-- type check
|
||||||
if ok and variant.types then
|
if ok and variant.types then
|
||||||
for j, t in pairs(variant.types) do
|
for j, t in pairs(variant.types) do
|
||||||
if args[j] and args[j].return_type and args[j].return_type ~= t then
|
if args[j] and args[j].return_type and args[j].return_type ~= t then
|
||||||
|
|
@ -139,6 +144,7 @@ common = {
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
-- done
|
||||||
if ok then
|
if ok then
|
||||||
if variant.rewrite then
|
if variant.rewrite then
|
||||||
local r, e = variant.rewrite(fqm, state, arg, explicit_call)
|
local r, e = variant.rewrite(fqm, state, arg, explicit_call)
|
||||||
|
|
@ -156,7 +162,11 @@ common = {
|
||||||
name = fqm,
|
name = fqm,
|
||||||
explicit_call = explicit_call,
|
explicit_call = explicit_call,
|
||||||
variant = variant,
|
variant = variant,
|
||||||
argument = arg
|
argument = { -- wrap everything in a list literal to simply later things (otherwise may be nil, single value, list constructor)
|
||||||
|
type = "list_brackets",
|
||||||
|
return_type = "list",
|
||||||
|
expression = arg
|
||||||
|
}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ local binops_prio = {
|
||||||
[2] = { ":=", "+=", "-=", "//=", "/=", "*=", "%=", "^=" },
|
[2] = { ":=", "+=", "-=", "//=", "/=", "*=", "%=", "^=" },
|
||||||
[3] = { "," },
|
[3] = { "," },
|
||||||
[4] = { "|", "&" },
|
[4] = { "|", "&" },
|
||||||
[5] = { "!=", "=", ">=", "<=", "<", ">" },
|
[5] = { "!=", "==", ">=", "<=", "<", ">" },
|
||||||
[6] = { "+", "-" },
|
[6] = { "+", "-" },
|
||||||
[7] = { "*", "//", "/", "%" },
|
[7] = { "*", "//", "/", "%" },
|
||||||
[8] = {}, -- unary operators
|
[8] = {}, -- unary operators
|
||||||
|
|
@ -89,7 +89,7 @@ local function expression(s, state, namespace, currentPriority, operatingOn)
|
||||||
if r_paren:match("[^%s]") then return nil, ("unexpected %q at end of list parenthesis expression"):format(r_paren) end
|
if r_paren:match("[^%s]") then return nil, ("unexpected %q at end of list parenthesis expression"):format(r_paren) end
|
||||||
end
|
end
|
||||||
return expression(r, state, namespace, currentPriority, {
|
return expression(r, state, namespace, currentPriority, {
|
||||||
type = "list_parentheses",
|
type = "list_brackets",
|
||||||
return_type = "list",
|
return_type = "list",
|
||||||
expression = exp
|
expression = exp
|
||||||
})
|
})
|
||||||
|
|
@ -97,6 +97,26 @@ local function expression(s, state, namespace, currentPriority, operatingOn)
|
||||||
elseif s:match("^"..identifier_pattern) then
|
elseif s:match("^"..identifier_pattern) then
|
||||||
local name, r = s:match("^("..identifier_pattern..")(.-)$")
|
local name, r = s:match("^("..identifier_pattern..")(.-)$")
|
||||||
name = format_identifier(name)
|
name = format_identifier(name)
|
||||||
|
-- string:value pair shorthand using =
|
||||||
|
if r:match("^=[^=]") then
|
||||||
|
local val
|
||||||
|
val, r = expression(r:match("^=(.*)$"), state, namespace, 9)
|
||||||
|
if not val then return val, r end
|
||||||
|
local args = {
|
||||||
|
type = "list",
|
||||||
|
return_type = "list",
|
||||||
|
left = {
|
||||||
|
type = "string",
|
||||||
|
return_type = "string",
|
||||||
|
value = { name }
|
||||||
|
},
|
||||||
|
right = val
|
||||||
|
}
|
||||||
|
-- find compatible variant
|
||||||
|
local variant, err = find_function_variant(":", state, args, true)
|
||||||
|
if not variant then return variant, err end
|
||||||
|
return expression(r, state, namespace, currentPriority, variant)
|
||||||
|
end
|
||||||
-- variables
|
-- variables
|
||||||
local var, vfqm = find(state.aliases, state.variables, namespace, name)
|
local var, vfqm = find(state.aliases, state.variables, namespace, name)
|
||||||
if var then
|
if var then
|
||||||
|
|
@ -132,6 +152,7 @@ local function expression(s, state, namespace, currentPriority, operatingOn)
|
||||||
local err
|
local err
|
||||||
args, err = expression(content, state, namespace)
|
args, err = expression(content, state, namespace)
|
||||||
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
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- find compatible variant
|
-- find compatible variant
|
||||||
|
|
@ -181,6 +202,7 @@ local function expression(s, state, namespace, currentPriority, operatingOn)
|
||||||
local err
|
local err
|
||||||
args, err = expression(content, state, namespace)
|
args, err = expression(content, state, namespace)
|
||||||
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
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- add first argument
|
-- add first argument
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,21 @@ local parse_text
|
||||||
local function parse(state)
|
local function parse(state)
|
||||||
for _, l in ipairs(state.queued_lines) do
|
for _, l in ipairs(state.queued_lines) do
|
||||||
local line, namespace = l.line, l.namespace
|
local line, namespace = l.line, l.namespace
|
||||||
|
-- default arguments
|
||||||
|
if line.type == "function" then
|
||||||
|
for i, param in ipairs(line.params) do
|
||||||
|
if param.default then
|
||||||
|
local exp, rem = expression(param.default, state, namespace)
|
||||||
|
if not exp then return nil, ("%s; at %s"):format(rem, line.source) end
|
||||||
|
if rem:match("[^%s]") then return nil, ("expected end of expression before %q; at %s"):format(rem, line.source) end
|
||||||
|
param.default = exp
|
||||||
|
-- complete type information
|
||||||
|
if exp.return_type then
|
||||||
|
line.variant.types[i] = exp.return_type
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
-- expressions
|
-- expressions
|
||||||
if line.expression then
|
if line.expression then
|
||||||
local exp, rem = expression(line.expression, state, namespace)
|
local exp, rem = expression(line.expression, state, namespace)
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,28 @@ local expression
|
||||||
local format_identifier, identifier_pattern
|
local format_identifier, identifier_pattern
|
||||||
local eval
|
local eval
|
||||||
|
|
||||||
|
-- try to define an alias using rem, the text that follows the identifier
|
||||||
|
-- returns true, new_rem, alias_name in case of success
|
||||||
|
-- returns true, rem in case of no alias and no error
|
||||||
|
-- returns nil, err in case of alias and error
|
||||||
|
local function maybe_alias(rem, fqm, namespace, line, state)
|
||||||
|
local alias
|
||||||
|
if rem:match("^%:") then
|
||||||
|
local param_content = rem:sub(2)
|
||||||
|
alias, rem = param_content:match("^("..identifier_pattern..")(.-)$")
|
||||||
|
if not alias then return nil, ("expected an identifier in alias, but got %q; at %s"):format(param_content, line.source) end
|
||||||
|
alias = format_identifier(alias)
|
||||||
|
-- format alias
|
||||||
|
local aliasfqm = ("%s%s"):format(namespace, alias)
|
||||||
|
-- define alias
|
||||||
|
if state.aliases[aliasfqm] ~= nil and state.aliases[aliasfqm] ~= fqm then
|
||||||
|
return nil, ("trying to define alias %q for %q, but already exist and refer to %q; at %s"):format(aliasfqm, fqm, state.aliases[aliasfqm], line.source)
|
||||||
|
end
|
||||||
|
state.aliases[aliasfqm] = fqm
|
||||||
|
end
|
||||||
|
return true, rem, alias
|
||||||
|
end
|
||||||
|
|
||||||
-- * ast: if success
|
-- * ast: if success
|
||||||
-- * nil, error: in case of error
|
-- * nil, error: in case of error
|
||||||
local function parse_line(line, state, namespace)
|
local function parse_line(line, state, namespace)
|
||||||
|
|
@ -9,12 +31,6 @@ local function parse_line(line, state, namespace)
|
||||||
local r = {
|
local r = {
|
||||||
source = line.source
|
source = line.source
|
||||||
}
|
}
|
||||||
-- comment
|
|
||||||
if l:match("^%(") then
|
|
||||||
r.type = "comment"
|
|
||||||
r.remove_from_block_ast = true
|
|
||||||
return r
|
|
||||||
end
|
|
||||||
-- else-condition & condition
|
-- else-condition & condition
|
||||||
if l:match("^~~?") then
|
if l:match("^~~?") then
|
||||||
r.type = l:match("^~~") and "else-condition" or "condition"
|
r.type = l:match("^~~") and "else-condition" or "condition"
|
||||||
|
|
@ -42,19 +58,9 @@ local function parse_line(line, state, namespace)
|
||||||
-- format identifier
|
-- format identifier
|
||||||
local fqm = ("%s%s"):format(namespace, format_identifier(identifier))
|
local fqm = ("%s%s"):format(namespace, format_identifier(identifier))
|
||||||
-- get alias
|
-- get alias
|
||||||
if rem:match("^%:") then
|
local ok_alias
|
||||||
local content = rem:sub(2)
|
ok_alias, rem = maybe_alias(rem, fqm, namespace, line, state)
|
||||||
local alias
|
if not ok_alias then return ok_alias, rem end
|
||||||
alias, rem = content:match("^("..identifier_pattern..")(.-)$")
|
|
||||||
if not alias then return nil, ("expected an identifier in alias in checkpoint/function definition line, but got %q; at %s"):format(content, line.source) end
|
|
||||||
-- format alias
|
|
||||||
local aliasfqm = ("%s%s"):format(namespace, format_identifier(alias))
|
|
||||||
-- define alias
|
|
||||||
if state.aliases[aliasfqm] ~= nil and state.aliases[aliasfqm] ~= fqm then
|
|
||||||
return nil, ("trying to define alias %q for checkpoint/function %q, but already exist and refer to %q; at %s"):format(aliasfqm, fqm, state.aliases[aliasfqm], line.source)
|
|
||||||
end
|
|
||||||
state.aliases[aliasfqm] = fqm
|
|
||||||
end
|
|
||||||
-- get params
|
-- get params
|
||||||
r.params = {}
|
r.params = {}
|
||||||
if r.type == "function" and rem:match("^%b()$") then
|
if r.type == "function" and rem:match("^%b()$") then
|
||||||
|
|
@ -63,36 +69,39 @@ local function parse_line(line, state, namespace)
|
||||||
-- get identifier
|
-- get identifier
|
||||||
local param_identifier, param_rem = param:match("^("..identifier_pattern..")(.-)$")
|
local param_identifier, param_rem = param:match("^("..identifier_pattern..")(.-)$")
|
||||||
if not identifier then return nil, ("no valid identifier in function parameter %q; at %s"):format(param, line.source) end
|
if not identifier then return nil, ("no valid identifier in function parameter %q; at %s"):format(param, line.source) end
|
||||||
|
param_identifier = format_identifier(param_identifier)
|
||||||
-- format identifier
|
-- format identifier
|
||||||
local param_fqm = ("%s.%s"):format(fqm, format_identifier(param_identifier))
|
local param_fqm = ("%s.%s"):format(fqm, param_identifier)
|
||||||
-- get alias
|
-- get alias
|
||||||
if param_rem:match("^%:") then
|
local ok_param_alias, param_alias
|
||||||
local param_content = param_rem:sub(2)
|
ok_param_alias, param_rem, param_alias = maybe_alias(param_rem, param_fqm, fqm..".", line, state)
|
||||||
local alias
|
if not ok_param_alias then return ok_param_alias, param_rem end
|
||||||
alias, param_rem = param_content:match("^("..identifier_pattern..")(.-)$")
|
-- get default value
|
||||||
if not alias then return nil, ("expected an identifier in alias in parameter, but got %q; at %s"):format(param_content, line.source) end
|
local default
|
||||||
-- format alias
|
if param_rem:match("^=") then
|
||||||
local aliasfqm = ("%s.%s"):format(fqm, format_identifier(alias))
|
default = param_rem:match("^=(.*)$")
|
||||||
-- define alias
|
elseif param_rem:match("[^%s]") then
|
||||||
if state.aliases[aliasfqm] ~= nil and state.aliases[aliasfqm] ~= param_fqm then
|
|
||||||
return nil, ("trying to define alias %q for parameter %q, but already exist and refer to %q; at %s"):format(aliasfqm, param_fqm, state.aliases[aliasfqm], line.source)
|
|
||||||
end
|
|
||||||
state.aliases[aliasfqm] = param_fqm
|
|
||||||
end
|
|
||||||
if param_rem:match("[^%s]") then
|
|
||||||
return nil, ("unexpected characters after parameter %q: %q; at %s"):format(param_fqm, param_rem, line.source)
|
return nil, ("unexpected characters after parameter %q: %q; at %s"):format(param_fqm, param_rem, line.source)
|
||||||
end
|
end
|
||||||
-- add parameter
|
-- add parameter
|
||||||
table.insert(r.params, param_fqm)
|
table.insert(r.params, { name = param_identifier, alias = param_alias, full_name = param_fqm, default = default })
|
||||||
end
|
end
|
||||||
elseif rem:match("[^%s]") then
|
elseif rem:match("[^%s]") then
|
||||||
return nil, ("expected end-of-line at end of checkpoint/function definition line, but got %q; at %s"):format(rem, line.source)
|
return nil, ("expected end-of-line at end of checkpoint/function definition line, but got %q; at %s"):format(rem, line.source)
|
||||||
end
|
end
|
||||||
local arity, vararg = #r.params, nil
|
-- calculate arity
|
||||||
if arity > 0 and r.params[arity]:match("%.%.%.$") then -- varargs
|
local minarity, maxarity = #r.params, #r.params
|
||||||
r.params[arity] = r.params[arity]:match("^(.*)%.%.%.$")
|
for _, param in ipairs(r.params) do -- params with default values
|
||||||
vararg = arity
|
if param.default then
|
||||||
arity = { arity-1, math.huge }
|
minarity = minarity - 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if maxarity > 0 and r.params[maxarity].full_name:match("%.%.%.$") then -- varargs
|
||||||
|
r.params[maxarity].name = r.params[maxarity].name:match("^(.*)%.%.%.$")
|
||||||
|
r.params[maxarity].full_name = r.params[maxarity].full_name:match("^(.*)%.%.%.$")
|
||||||
|
r.params[maxarity].vararg = true
|
||||||
|
minarity = minarity - 1
|
||||||
|
maxarity = math.huge
|
||||||
end
|
end
|
||||||
-- store parent function and run checkpoint when line is read
|
-- store parent function and run checkpoint when line is read
|
||||||
if r.type == "checkpoint" then
|
if r.type == "checkpoint" then
|
||||||
|
|
@ -107,9 +116,8 @@ local function parse_line(line, state, namespace)
|
||||||
r.name = fqm
|
r.name = fqm
|
||||||
if state.variables[fqm] then return nil, ("trying to define %s %s, but a variable with the same name exists; at %s"):format(r.type, fqm, line.source) end
|
if state.variables[fqm] then return nil, ("trying to define %s %s, but a variable with the same name exists; at %s"):format(r.type, fqm, line.source) end
|
||||||
r.variant = {
|
r.variant = {
|
||||||
arity = arity,
|
arity = { minarity, maxarity },
|
||||||
types = {},
|
types = {},
|
||||||
vararg = vararg,
|
|
||||||
value = r
|
value = r
|
||||||
}
|
}
|
||||||
-- new function (no overloading yet)
|
-- new function (no overloading yet)
|
||||||
|
|
@ -191,13 +199,13 @@ local function parse_line(line, state, namespace)
|
||||||
end
|
end
|
||||||
-- define args and set type check information
|
-- define args and set type check information
|
||||||
for i, param in ipairs(r.params) do
|
for i, param in ipairs(r.params) do
|
||||||
if not state.variables[param] then
|
if not state.variables[param.full_name] then
|
||||||
state.variables[param] = {
|
state.variables[param.full_name] = {
|
||||||
type = "undefined argument",
|
type = "undefined argument",
|
||||||
value = { r.variant, i }
|
value = { r.variant, i }
|
||||||
}
|
}
|
||||||
elseif state.variables[param].type ~= "undefined argument" then
|
elseif state.variables[param.full_name].type ~= "undefined argument" then
|
||||||
r.variant.types[i] = state.variables[param].type
|
r.variant.types[i] = state.variables[param.full_name].type
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- definition
|
-- definition
|
||||||
|
|
@ -208,25 +216,17 @@ local function parse_line(line, state, namespace)
|
||||||
local exp, rem = expression(l:match("^:(.*)$"), state, namespace) -- expression parsing is done directly to get type information
|
local exp, rem = expression(l:match("^:(.*)$"), state, namespace) -- expression parsing is done directly to get type information
|
||||||
if not exp then return nil, ("%s; at %s"):format(rem, line.source) end
|
if not exp then return nil, ("%s; at %s"):format(rem, line.source) end
|
||||||
-- get identifier
|
-- get identifier
|
||||||
local identifier, rem2 = rem:match("^("..identifier_pattern..")(.-)$")
|
local identifier
|
||||||
|
identifier, rem = rem:match("^("..identifier_pattern..")(.-)$")
|
||||||
if not identifier then return nil, ("no valid identifier after expression in definition line %q; at %s"):format(rem, line.source) end
|
if not identifier then return nil, ("no valid identifier after expression in definition line %q; at %s"):format(rem, line.source) end
|
||||||
-- format identifier
|
-- format identifier
|
||||||
local fqm = ("%s%s"):format(namespace, format_identifier(identifier))
|
local fqm = ("%s%s"):format(namespace, format_identifier(identifier))
|
||||||
-- get alias
|
-- get alias
|
||||||
if rem2:match("^%:") then
|
local ok_alias
|
||||||
local content = rem2:sub(2)
|
ok_alias, rem = maybe_alias(rem, fqm, namespace, line, state)
|
||||||
local alias, rem3 = content:match("^("..identifier_pattern..")(.-)$")
|
if not ok_alias then return ok_alias, rem end
|
||||||
if not alias then return nil, ("expected an identifier in alias in definition line, but got %q; at %s"):format(content, line.source) end
|
if rem:match("[^%s]") then
|
||||||
if rem3:match("[^%s]") then return nil, ("expected end-of-line after identifier in alias in definition line, but got %q; at %s"):format(rem3, line.source) end
|
return nil, ("expected end-of-line after identifier in definition line, but got %q; at %s"):format(rem, line.source)
|
||||||
-- format alias
|
|
||||||
local aliasfqm = ("%s%s"):format(namespace, format_identifier(alias))
|
|
||||||
-- define alias
|
|
||||||
if state.aliases[aliasfqm] ~= nil and state.aliases[aliasfqm] ~= fqm then
|
|
||||||
return nil, ("trying to define alias %s for variable %s, but already exist and refer to different variable %s; at %s"):format(aliasfqm, fqm, state.aliases[aliasfqm], line.source)
|
|
||||||
end
|
|
||||||
state.aliases[aliasfqm] = fqm
|
|
||||||
elseif rem2:match("[^%s]") then
|
|
||||||
return nil, ("expected end-of-line after identifier in definition line, but got %q; at %s"):format(rem2, line.source)
|
|
||||||
end
|
end
|
||||||
-- define identifier
|
-- define identifier
|
||||||
if state.functions[fqm] then return nil, ("trying to define variable %s, but a function with the same name exists; at %s"):format(fqm, line.source) end
|
if state.functions[fqm] then return nil, ("trying to define variable %s, but a function with the same name exists; at %s"):format(fqm, line.source) end
|
||||||
|
|
@ -297,8 +297,8 @@ local function parse_block(indented, state, namespace, parent_function)
|
||||||
-- queue in expression evalution
|
-- queue in expression evalution
|
||||||
table.insert(state.queued_lines, { namespace = ast.namespace or namespace, line = ast })
|
table.insert(state.queued_lines, { namespace = ast.namespace or namespace, line = ast })
|
||||||
|
|
||||||
-- indented block (ignore block comments)
|
-- indented block
|
||||||
if l.children and ast.type ~= "comment" then
|
if l.children then
|
||||||
if not ast.child then
|
if not ast.child then
|
||||||
return nil, ("line %s (%s) can't have children"):format(ast.source, ast.type)
|
return nil, ("line %s (%s) can't have children"):format(ast.source, ast.type)
|
||||||
else
|
else
|
||||||
|
|
@ -317,31 +317,35 @@ local function transform_indented(indented)
|
||||||
local i = 1
|
local i = 1
|
||||||
while i <= #indented do
|
while i <= #indented do
|
||||||
local l = indented[i]
|
local l = indented[i]
|
||||||
|
-- comment
|
||||||
-- condition decorator
|
if l.content:match("^%(") then
|
||||||
if l.content:match("^.-%s*[^~]%~[^#~$]-$") then
|
table.remove(indented, i)
|
||||||
local decorator
|
|
||||||
l.content, decorator = l.content:match("^(..-)%s*(%~[^#~$]-)$")
|
|
||||||
indented[i] = { content = decorator, source = l.source, children = { l } }
|
|
||||||
-- tag decorator
|
|
||||||
elseif l.content:match("^..-%s*%#[^#~$]-$") then
|
|
||||||
local decorator
|
|
||||||
l.content, decorator = l.content:match("^(..-)%s*(%#[^#~$]-)$")
|
|
||||||
indented[i] = { content = decorator, source = l.source, children = { l } }
|
|
||||||
-- function decorator
|
|
||||||
elseif l.content:match("^..-%s*%$[^#~$]-$") then
|
|
||||||
local name
|
|
||||||
l.content, name = l.content:match("^(..-)%s*%$([^#~$]-)$")
|
|
||||||
indented[i] = { content = "~"..name, source = l.source }
|
|
||||||
table.insert(indented, i+1, { content = "$"..name, source = l.source, children = { l } })
|
|
||||||
i = i + 1 -- $ line should not contain any decorator anymore
|
|
||||||
else
|
else
|
||||||
i = i + 1 -- only increment when no decorator, as there may be several decorators per line
|
-- condition decorator
|
||||||
end
|
if l.content:match("^.-%s*[^~]%~[^#~$]-$") then
|
||||||
|
local decorator
|
||||||
|
l.content, decorator = l.content:match("^(..-)%s*(%~[^#~$]-)$")
|
||||||
|
indented[i] = { content = decorator, source = l.source, children = { l } }
|
||||||
|
-- tag decorator
|
||||||
|
elseif l.content:match("^..-%s*%#[^#~$]-$") then
|
||||||
|
local decorator
|
||||||
|
l.content, decorator = l.content:match("^(..-)%s*(%#[^#~$]-)$")
|
||||||
|
indented[i] = { content = decorator, source = l.source, children = { l } }
|
||||||
|
-- function decorator
|
||||||
|
elseif l.content:match("^..-%s*%$[^#~$]-$") then
|
||||||
|
local name
|
||||||
|
l.content, name = l.content:match("^(..-)%s*%$([^#~$]-)$")
|
||||||
|
indented[i] = { content = "~"..name, source = l.source }
|
||||||
|
table.insert(indented, i+1, { content = "$"..name, source = l.source, children = { l } })
|
||||||
|
i = i + 1 -- $ line should not contain any decorator anymore
|
||||||
|
else
|
||||||
|
i = i + 1 -- only increment when no decorator, as there may be several decorators per line
|
||||||
|
end
|
||||||
|
|
||||||
-- indented block
|
-- indented block
|
||||||
if l.children then
|
if l.children then
|
||||||
transform_indented(l.children)
|
transform_indented(l.children)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return indented
|
return indented
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ functions = {
|
||||||
return right.return_type or true
|
return right.return_type or true
|
||||||
end,
|
end,
|
||||||
value = function(state, exp)
|
value = function(state, exp)
|
||||||
local arg = exp.argument
|
local arg = exp.argument.expression
|
||||||
local name = arg.left.name
|
local name = arg.left.name
|
||||||
local right, righte = eval(state, arg.right)
|
local right, righte = eval(state, arg.right)
|
||||||
if not right then return right, righte end
|
if not right then return right, righte end
|
||||||
|
|
@ -84,7 +84,7 @@ functions = {
|
||||||
{ rewrite = rewrite_assignement }
|
{ rewrite = rewrite_assignement }
|
||||||
},
|
},
|
||||||
-- comparaison
|
-- comparaison
|
||||||
["="] = {
|
["=="] = {
|
||||||
{
|
{
|
||||||
arity = 2, return_type = "number", mode = "raw",
|
arity = 2, return_type = "number", mode = "raw",
|
||||||
value = function(a, b)
|
value = function(a, b)
|
||||||
|
|
@ -193,7 +193,7 @@ functions = {
|
||||||
{
|
{
|
||||||
arity = 2, return_type = "number", mode = "custom",
|
arity = 2, return_type = "number", mode = "custom",
|
||||||
value = function(state, exp)
|
value = function(state, exp)
|
||||||
local arg = exp.argument
|
local arg = exp.argument.expression
|
||||||
local left, lefte = eval(state, arg.left)
|
local left, lefte = eval(state, arg.left)
|
||||||
if not left then return left, lefte end
|
if not left then return left, lefte end
|
||||||
if truthy(left) then
|
if truthy(left) then
|
||||||
|
|
@ -217,7 +217,7 @@ functions = {
|
||||||
{
|
{
|
||||||
arity = 2, return_type = "number", mode = "custom",
|
arity = 2, return_type = "number", mode = "custom",
|
||||||
value = function(state, exp)
|
value = function(state, exp)
|
||||||
local arg = exp.argument
|
local arg = exp.argument.expression
|
||||||
local left, lefte = eval(state, arg.left)
|
local left, lefte = eval(state, arg.left)
|
||||||
if not left then return left, lefte end
|
if not left then return left, lefte end
|
||||||
if truthy(left) then
|
if truthy(left) then
|
||||||
|
|
@ -254,6 +254,17 @@ functions = {
|
||||||
value = function(a, b)
|
value = function(a, b)
|
||||||
return a.value[b.value] or { type = "nil", value = nil }
|
return a.value[b.value] or { type = "nil", value = nil }
|
||||||
end
|
end
|
||||||
|
},
|
||||||
|
{
|
||||||
|
arity = 2, types = { "list", "string" }, mode = "raw",
|
||||||
|
value = function(a, b)
|
||||||
|
for _,v in ipairs(a.value) do
|
||||||
|
if v.type == "pair" and compare(v.value[1], b) then
|
||||||
|
return v.value[2]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return { type = "nil", value = nil }
|
||||||
|
end
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
-- list methods
|
-- list methods
|
||||||
|
|
|
||||||
4
test/tests/argument alias.ans
Normal file
4
test/tests/argument alias.ans
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
$ f(str: foo)
|
||||||
|
@str + foo
|
||||||
|
|
||||||
|
{f("bi")} = {f(foo="bi")}
|
||||||
14
test/tests/argument alias.lua
Normal file
14
test/tests/argument alias.lua
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
local _={}
|
||||||
|
_[5]={}
|
||||||
|
_[4]={data="bibi = bibi",tags=_[5]}
|
||||||
|
_[3]={_[4]}
|
||||||
|
_[2]={"return"}
|
||||||
|
_[1]={"text",_[3]}
|
||||||
|
return {_[1],_[2]}
|
||||||
|
--[[
|
||||||
|
{ "text", { {
|
||||||
|
data = "bibi = bibi",
|
||||||
|
tags = {}
|
||||||
|
} } }
|
||||||
|
{ "return" }
|
||||||
|
]]--
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
:5 a
|
:5 a
|
||||||
|
|
||||||
~ a = 2
|
~ a == 2
|
||||||
ko
|
ko
|
||||||
~~
|
~~
|
||||||
ok
|
ok
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
:5 a
|
:5 a
|
||||||
|
|
||||||
~ a = 5
|
~ a == 5
|
||||||
ok
|
ok
|
||||||
~~
|
~~
|
||||||
ko
|
ko
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
:5 a
|
:5 a
|
||||||
|
|
||||||
~ a = 2
|
~ a == 2
|
||||||
ko
|
ko
|
||||||
~~ 0
|
~~ 0
|
||||||
ko
|
ko
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
:5 a
|
:5 a
|
||||||
|
|
||||||
~ a = 2
|
~ a == 2
|
||||||
ko
|
ko
|
||||||
~~ 1
|
~~ 1
|
||||||
ok
|
ok
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
:5 a
|
:5 a
|
||||||
|
|
||||||
~ a = 2
|
~ a == 2
|
||||||
ko
|
ko
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
:5 a
|
:5 a
|
||||||
|
|
||||||
~ a = 5
|
~ a == 5
|
||||||
ok
|
ok
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,19 @@
|
||||||
:(1:2) a
|
:(1:2) a
|
||||||
|
|
||||||
0 = {a = (5:2)}
|
0 = {a == (5:2)}
|
||||||
|
|
||||||
0 = {a = (1:3)}
|
0 = {a == (1:3)}
|
||||||
|
|
||||||
1 = {a = (1:2)}
|
1 = {a == (1:2)}
|
||||||
|
|
||||||
:[1,2,3] b
|
:[1,2,3] b
|
||||||
|
|
||||||
0 = {b = a}
|
0 = {b == a}
|
||||||
|
|
||||||
0 = {b = []}
|
0 = {b == []}
|
||||||
|
|
||||||
0 = {b = [3,1,2]}
|
0 = {b == [3,1,2]}
|
||||||
|
|
||||||
0 = {b = [1,2,3,4]}
|
0 = {b == [1,2,3,4]}
|
||||||
|
|
||||||
1 = {b = [1,2,3]}
|
1 = {b == [1,2,3]}
|
||||||
|
|
|
||||||
9
test/tests/function alias.ans
Normal file
9
test/tests/function alias.ans
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
$ f : test
|
||||||
|
@"ok"
|
||||||
|
|
||||||
|
{f} = {test}
|
||||||
|
|
||||||
|
$ g : bis(a)
|
||||||
|
@a
|
||||||
|
|
||||||
|
{g("ye")} = {bis("ye")}
|
||||||
22
test/tests/function alias.lua
Normal file
22
test/tests/function alias.lua
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
local _={}
|
||||||
|
_[9]={}
|
||||||
|
_[8]={}
|
||||||
|
_[7]={data="ye = ye",tags=_[9]}
|
||||||
|
_[6]={data="ok = ok",tags=_[8]}
|
||||||
|
_[5]={_[7]}
|
||||||
|
_[4]={_[6]}
|
||||||
|
_[3]={"return"}
|
||||||
|
_[2]={"text",_[5]}
|
||||||
|
_[1]={"text",_[4]}
|
||||||
|
return {_[1],_[2],_[3]}
|
||||||
|
--[[
|
||||||
|
{ "text", { {
|
||||||
|
data = "ok = ok",
|
||||||
|
tags = {}
|
||||||
|
} } }
|
||||||
|
{ "text", { {
|
||||||
|
data = "ye = ye",
|
||||||
|
tags = {}
|
||||||
|
} } }
|
||||||
|
{ "return" }
|
||||||
|
]]--
|
||||||
4
test/tests/named arguments.ans
Normal file
4
test/tests/named arguments.ans
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
$ f(a, b, c)
|
||||||
|
@a + b + c
|
||||||
|
|
||||||
|
{f("a", "b", "c")} = {f(a="a", b="b", c="c")} = {f(c="c", a="a", b="b")}
|
||||||
14
test/tests/named arguments.lua
Normal file
14
test/tests/named arguments.lua
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
local _={}
|
||||||
|
_[5]={}
|
||||||
|
_[4]={tags=_[5],data="abc = abc = abc"}
|
||||||
|
_[3]={_[4]}
|
||||||
|
_[2]={"return"}
|
||||||
|
_[1]={"text",_[3]}
|
||||||
|
return {_[1],_[2]}
|
||||||
|
--[[
|
||||||
|
{ "text", { {
|
||||||
|
data = "abc = abc = abc",
|
||||||
|
tags = {}
|
||||||
|
} } }
|
||||||
|
{ "return" }
|
||||||
|
]]--
|
||||||
4
test/tests/optional arguments.ans
Normal file
4
test/tests/optional arguments.ans
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
$ f(a, b, c="c")
|
||||||
|
@a + b + c
|
||||||
|
|
||||||
|
{f("a", "b")} = {f("a", "b", "c")} = {f(b="b", a="a")}
|
||||||
14
test/tests/optional arguments.lua
Normal file
14
test/tests/optional arguments.lua
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
local _={}
|
||||||
|
_[5]={}
|
||||||
|
_[4]={tags=_[5],data="abc = abc = abc"}
|
||||||
|
_[3]={_[4]}
|
||||||
|
_[2]={"return"}
|
||||||
|
_[1]={"text",_[3]}
|
||||||
|
return {_[1],_[2]}
|
||||||
|
--[[
|
||||||
|
{ "text", { {
|
||||||
|
data = "abc = abc = abc",
|
||||||
|
tags = {}
|
||||||
|
} } }
|
||||||
|
{ "return" }
|
||||||
|
]]--
|
||||||
4
test/tests/paragraph alias.ans
Normal file
4
test/tests/paragraph alias.ans
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
§ f : test
|
||||||
|
@"ok"
|
||||||
|
|
||||||
|
{f} = {test}
|
||||||
14
test/tests/paragraph alias.lua
Normal file
14
test/tests/paragraph alias.lua
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
local _={}
|
||||||
|
_[5]={}
|
||||||
|
_[4]={tags=_[5],data="ok = ok"}
|
||||||
|
_[3]={_[4]}
|
||||||
|
_[2]={"return"}
|
||||||
|
_[1]={"text",_[3]}
|
||||||
|
return {_[1],_[2]}
|
||||||
|
--[[
|
||||||
|
{ "text", { {
|
||||||
|
data = "ok = ok",
|
||||||
|
tags = {}
|
||||||
|
} } }
|
||||||
|
{ "return" }
|
||||||
|
]]--
|
||||||
|
|
@ -5,6 +5,6 @@ $ f
|
||||||
y
|
y
|
||||||
@2
|
@2
|
||||||
|
|
||||||
~ f = 2
|
~ f == 2
|
||||||
~ choose(1)
|
~ choose(1)
|
||||||
Yes.
|
Yes.
|
||||||
|
|
|
||||||
3
test/tests/variable alias.ans
Normal file
3
test/tests/variable alias.ans
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
:42 a : b
|
||||||
|
|
||||||
|
{a} = {b}
|
||||||
14
test/tests/variable alias.lua
Normal file
14
test/tests/variable alias.lua
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
local _={}
|
||||||
|
_[5]={}
|
||||||
|
_[4]={data="42 = 42",tags=_[5]}
|
||||||
|
_[3]={_[4]}
|
||||||
|
_[2]={"return"}
|
||||||
|
_[1]={"text",_[3]}
|
||||||
|
return {_[1],_[2]}
|
||||||
|
--[[
|
||||||
|
{ "text", { {
|
||||||
|
data = "42 = 42",
|
||||||
|
tags = {}
|
||||||
|
} } }
|
||||||
|
{ "return" }
|
||||||
|
]]--
|
||||||
Loading…
Add table
Add a link
Reference in a new issue