From a212dd7fd175af1acdc9d7fb6dba73ac84140fe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20Reuh=20Fildadut?= Date: Thu, 4 Jan 2024 20:45:23 +0100 Subject: [PATCH] stdlib cleanup --- anselme/stdlib/attached block.lua | 39 ++++++ anselme/stdlib/base.lua | 44 +------ anselme/stdlib/boolean.lua | 3 + anselme/stdlib/{boot_script.lua => boot.lua} | 0 anselme/stdlib/closure.lua | 122 ------------------ anselme/stdlib/conditionals.lua | 15 +++ anselme/stdlib/function.lua | 53 ++++++++ anselme/stdlib/init.lua | 24 ++-- anselme/stdlib/number.lua | 4 +- anselme/stdlib/pair.lua | 5 + anselme/stdlib/{checkpoint.lua => resume.lua} | 4 +- .../stdlib/{script_script.lua => script.lua} | 14 +- anselme/stdlib/{type_check.lua => types.lua} | 41 +++++- anselme/stdlib/wrap.lua | 28 ++++ .../merge nested mutable error bis.ans | 2 +- test/results/merge nested mutable error.ans | 2 +- test/tests/resume anchors.ans | 2 +- 17 files changed, 212 insertions(+), 190 deletions(-) create mode 100644 anselme/stdlib/attached block.lua rename anselme/stdlib/{boot_script.lua => boot.lua} (100%) delete mode 100644 anselme/stdlib/closure.lua create mode 100644 anselme/stdlib/function.lua rename anselme/stdlib/{checkpoint.lua => resume.lua} (90%) rename anselme/stdlib/{script_script.lua => script.lua} (85%) rename anselme/stdlib/{type_check.lua => types.lua} (64%) create mode 100644 anselme/stdlib/wrap.lua diff --git a/anselme/stdlib/attached block.lua b/anselme/stdlib/attached block.lua new file mode 100644 index 0000000..fa4babf --- /dev/null +++ b/anselme/stdlib/attached block.lua @@ -0,0 +1,39 @@ +local ast = require("anselme.ast") +local Function, ParameterTuple, Identifier = ast.Function, ast.ParameterTuple, ast.Identifier + +local calling_environment_manager = require("anselme.state.calling_environment_manager") + +local block_identifier = Identifier:new("_") + +return { + { + "attached block", "(level::number=1, keep return=false)", + function(state, level, keep_return) + -- level 2: env of the function that called the function that called attached block + local env = calling_environment_manager:get_level(state, level:to_lua(state)+1) + local r = env:get(state, block_identifier) + if keep_return:truthy() then + return Function:new(ParameterTuple:new(), r.expression):eval(state) + else + return Function:with_return_boundary(ParameterTuple:new(), r.expression):eval(state) + end + end + }, + { + "attached block", "(level::number=1, keep return=false, default)", + function(state, level, keep_return, default) + -- level 2: env of the function that called the function that called attached block + local env = calling_environment_manager:get_level(state, level:to_lua(state)+1) + if env:defined(state, block_identifier) then + local r = env:get(state, block_identifier) + if keep_return:truthy() then + return Function:new(ParameterTuple:new(), r.expression):eval(state) + else + return Function:with_return_boundary(ParameterTuple:new(), r.expression):eval(state) + end + else + return default + end + end + }, +} diff --git a/anselme/stdlib/base.lua b/anselme/stdlib/base.lua index 81f2925..d6e2844 100644 --- a/anselme/stdlib/base.lua +++ b/anselme/stdlib/base.lua @@ -1,21 +1,10 @@ local ast = require("anselme.ast") -local Pair, ArgumentTuple, Nil, String, Typed, Boolean = ast.Pair, ast.ArgumentTuple, ast.Nil, ast.String, ast.Typed, ast.Boolean +local Nil, String = ast.Nil, ast.String return { { "_;_", "(left, right)", function(state, left, right) return right end }, { "_;", "(left)", function(state, left) return Nil:new() end }, - { "_:_", "(name, value)", function(state, a, b) return Pair:new(a,b) end }, - { - "_::_", "(value, check)", - function(state, value, check) - local r = check:call(state, ArgumentTuple:new(value)) - if r:truthy() then - return value - else - error(("type check failure: %s does not satisfy %s"):format(value:format(state), check:format(state)), 0) - end - end - }, + { "print", "(a)", function(state, a) @@ -29,35 +18,6 @@ return { return String:new(a:hash()) end }, - { - "type", "(value)", - function(state, v) - if v.type == "typed" then - return v.type_expression - else - return String:new(v.type) - end - end - }, - { - "value", "(value)", - function(state, v) - if v.type == "typed" then - return v.expression - else - return v - end - end - }, - { - "type", "(value, type)", - function(state, v, t) - return Typed:new(v, t) - end - }, - { "true", Boolean:new(true) }, - { "false", Boolean:new(false) }, - { "error", "(message=\"error\")", function(state, message) diff --git a/anselme/stdlib/boolean.lua b/anselme/stdlib/boolean.lua index 03fb242..4812986 100644 --- a/anselme/stdlib/boolean.lua +++ b/anselme/stdlib/boolean.lua @@ -2,6 +2,9 @@ local ast = require("anselme.ast") local Boolean, ArgumentTuple = ast.Boolean, ast.ArgumentTuple return { + { "true", Boolean:new(true) }, + { "false", Boolean:new(false) }, + { "_==_", "(a, b)", function(state, a, b) diff --git a/anselme/stdlib/boot_script.lua b/anselme/stdlib/boot.lua similarity index 100% rename from anselme/stdlib/boot_script.lua rename to anselme/stdlib/boot.lua diff --git a/anselme/stdlib/closure.lua b/anselme/stdlib/closure.lua deleted file mode 100644 index 7265c80..0000000 --- a/anselme/stdlib/closure.lua +++ /dev/null @@ -1,122 +0,0 @@ -local ast = require("anselme.ast") -local Nil, Boolean, Definition, Call, Function, ParameterTuple, FunctionParameter, Identifier, Overload, Assignment, Return = ast.Nil, ast.Boolean, ast.Definition, ast.Call, ast.Function, ast.ParameterTuple, ast.FunctionParameter, ast.Identifier, ast.Overload, ast.Assignment, ast.Return -local assert0 = require("anselme.common").assert0 - -local calling_environment_manager = require("anselme.state.calling_environment_manager") - -local block_identifier = Identifier:new("_") - -return { - { - "defined", "(c::function, s::string)", - function(state, c, s) - return Boolean:new(c.scope:defined_in_current(state, s:to_identifier())) - end - }, - { - "has upvalue", "(c::function, s::string)", - function(state, c, s) - return Boolean:new(c.scope:defined(state, s:to_identifier())) - end - }, - { - "_._", "(c::function, s::string)", - function(state, c, s) - local identifier = s:to_identifier() - assert0(c.scope:defined(state, identifier), ("no variable %q defined in closure"):format(s.string)) - return c.scope:get(state, identifier) - end - }, - { - "_._", "(c::function, s::string) = v", - function(state, c, s, v) - local identifier = s:to_identifier() - assert0(c.scope:defined(state, identifier), ("no variable %q defined in closure"):format(s.string)) - c.scope:set(state, identifier, v) - return Nil:new() - end - }, - { - "_._", "(c::function, s::symbol) = v", - function(state, c, s, v) - state.scope:push(c.scope) - local r = Definition:new(s, v):eval(state) - state.scope:pop() - return r - end - }, - { - ">_", "(q::is(\"quote\"))", - function(state, q) - local exp = q.expression - local get = Function:with_return_boundary(ParameterTuple:new(), exp):eval(state) - - local set_exp - if Call:is(exp) then - set_exp = Call:new(exp.func, exp.arguments:with_assignment(Identifier:new("value"))) - elseif Identifier:is(exp) then - set_exp = Assignment:new(exp, Identifier:new("value")) - end - - if set_exp then - local set_param = ParameterTuple:new() - set_param:insert_assignment(FunctionParameter:new(Identifier:new("value"))) - local set = Function:with_return_boundary(set_param, set_exp):eval(state) - return Overload:new(get, set) - else - return get - end - end - }, - { - "return", "(value=())", - function(state, val) - if Return:is(val) then val = val.expression end - return Return:new(val) - end - }, - { - "break", "(value=())", - function(state, val) - if Return:is(val) then val = val.expression end - return Return:new(val, "break") - end - }, - { - "continue", "(value=())", - function(state, val) - if Return:is(val) then val = val.expression end - return Return:new(val, "continue") - end - }, - { - "attached block", "(level::number=1, keep return=false)", - function(state, level, keep_return) - -- level 2: env of the function that called the function that called attached block - local env = calling_environment_manager:get_level(state, level:to_lua(state)+1) - local r = env:get(state, block_identifier) - if keep_return:truthy() then - return Function:new(ParameterTuple:new(), r.expression):eval(state) - else - return Function:with_return_boundary(ParameterTuple:new(), r.expression):eval(state) - end - end - }, - { - "attached block", "(level::number=1, keep return=false, default)", - function(state, level, keep_return, default) - -- level 2: env of the function that called the function that called attached block - local env = calling_environment_manager:get_level(state, level:to_lua(state)+1) - if env:defined(state, block_identifier) then - local r = env:get(state, block_identifier) - if keep_return:truthy() then - return Function:new(ParameterTuple:new(), r.expression):eval(state) - else - return Function:with_return_boundary(ParameterTuple:new(), r.expression):eval(state) - end - else - return default - end - end - }, -} diff --git a/anselme/stdlib/conditionals.lua b/anselme/stdlib/conditionals.lua index b39056a..bdfeca8 100644 --- a/anselme/stdlib/conditionals.lua +++ b/anselme/stdlib/conditionals.lua @@ -66,6 +66,7 @@ return { end end }, + { "while", "(condition, expression=attached block(keep return=true))", function(state, condition, expression) @@ -94,4 +95,18 @@ return { return r end }, + { + "break", "(value=())", + function(state, val) + if Return:is(val) then val = val.expression end + return Return:new(val, "break") + end + }, + { + "continue", "(value=())", + function(state, val) + if Return:is(val) then val = val.expression end + return Return:new(val, "continue") + end + }, } diff --git a/anselme/stdlib/function.lua b/anselme/stdlib/function.lua new file mode 100644 index 0000000..6ad0633 --- /dev/null +++ b/anselme/stdlib/function.lua @@ -0,0 +1,53 @@ +local ast = require("anselme.ast") +local Nil, Boolean, Definition, Return = ast.Nil, ast.Boolean, ast.Definition, ast.Return +local assert0 = require("anselme.common").assert0 + +return { + { + "defined", "(c::function, s::string)", + function(state, c, s) + return Boolean:new(c.scope:defined_in_current(state, s:to_identifier())) + end + }, + { + "has upvalue", "(c::function, s::string)", + function(state, c, s) + return Boolean:new(c.scope:defined(state, s:to_identifier())) + end + }, + + { + "_._", "(c::function, s::string)", + function(state, c, s) + local identifier = s:to_identifier() + assert0(c.scope:defined(state, identifier), ("no variable %q defined in closure"):format(s.string)) + return c.scope:get(state, identifier) + end + }, + { + "_._", "(c::function, s::string) = v", + function(state, c, s, v) + local identifier = s:to_identifier() + assert0(c.scope:defined(state, identifier), ("no variable %q defined in closure"):format(s.string)) + c.scope:set(state, identifier, v) + return Nil:new() + end + }, + { + "_._", "(c::function, s::symbol) = v", + function(state, c, s, v) + state.scope:push(c.scope) + local r = Definition:new(s, v):eval(state) + state.scope:pop() + return r + end + }, + + { + "return", "(value=())", + function(state, val) + if Return:is(val) then val = val.expression end + return Return:new(val) + end + }, +} diff --git a/anselme/stdlib/init.lua b/anselme/stdlib/init.lua index f31330c..cf8f700 100644 --- a/anselme/stdlib/init.lua +++ b/anselme/stdlib/init.lua @@ -7,7 +7,12 @@ local function define_lua(state, list) end local function load(state, l) for _, m in ipairs(l) do - define_lua(state, require("anselme.stdlib."..m)) + local mod = require("anselme.stdlib."..m) + if type(mod) == "string" then + parser(mod, m..".ans"):eval(state) + else + define_lua(state, mod) + end end end @@ -17,21 +22,18 @@ return function(main_state) "tag", "conditionals", "base", - "type_check" - }) - - parser(require("anselme.stdlib.boot_script"), "boot.ans"):eval(main_state) - - load(main_state, { + "types", + "boot", "number", "string", "text", "pair", "structures", - "closure", - "checkpoint", + "wrap", + "attached block", + "function", + "resume", "persist", + "script" }) - - parser(require("anselme.stdlib.script_script"), "script.ans"):eval(main_state) end diff --git a/anselme/stdlib/number.lua b/anselme/stdlib/number.lua index d3b5877..d5700ea 100644 --- a/anselme/stdlib/number.lua +++ b/anselme/stdlib/number.lua @@ -2,6 +2,8 @@ local ast = require("anselme.ast") local Boolean, Number = ast.Boolean, ast.Number return { + { "pi", Number:new(math.pi) }, + { "_<_", "(a::number, b::number)", function(state, a, b) @@ -64,6 +66,4 @@ return { end end }, - - { "pi", Number:new(math.pi) } } diff --git a/anselme/stdlib/pair.lua b/anselme/stdlib/pair.lua index 68a877b..71ee328 100644 --- a/anselme/stdlib/pair.lua +++ b/anselme/stdlib/pair.lua @@ -1,4 +1,9 @@ +local ast = require("anselme.ast") +local Pair = ast.Pair + return { + { "_:_", "(name, value)", function(state, a, b) return Pair:new(a,b) end }, + { "name", "(pair::pair)", function(state, pair) diff --git a/anselme/stdlib/checkpoint.lua b/anselme/stdlib/resume.lua similarity index 90% rename from anselme/stdlib/checkpoint.lua rename to anselme/stdlib/resume.lua index 19e2912..fd74218 100644 --- a/anselme/stdlib/checkpoint.lua +++ b/anselme/stdlib/resume.lua @@ -6,13 +6,13 @@ local calling_environment_manager = require("anselme.state.calling_environment_m return { { - "resume", "(function::function, anchor::anchor)", + "from", "(function::function, anchor::anchor)", function(state, func, anchor) return func:resume(state, anchor) end }, { - "resume", "(function::function, anchor::nil)", + "from", "(function::function, anchor::nil)", function(state, func) return func:call(state, ArgumentTuple:new()) end diff --git a/anselme/stdlib/script_script.lua b/anselme/stdlib/script.lua similarity index 85% rename from anselme/stdlib/script_script.lua rename to anselme/stdlib/script.lua index 8fe0b68..8d2a76d 100644 --- a/anselme/stdlib/script_script.lua +++ b/anselme/stdlib/script.lua @@ -4,30 +4,30 @@ return [[ fn.:&reached => "{name}.reached"!persist(*{}) fn.:&run => "{name}.run"!persist(0) - :resumed from = () + :resume target = () fn.:check = $(anchor::anchor) fn.reached(anchor) = (fn.reached(anchor) | 0) + 1 fn.:checkpoint = $(anchor::anchor, on resume=attached block(default=())) if(on resume) fn.current checkpoint = anchor - if(resumed from == anchor | resuming(4)) + if(resume target == anchor | resuming(4)) on resume! else! fn.reached(anchor) = (fn.reached(anchor) | 0) + 1 merge branch! else! fn.current checkpoint = anchor - if(resumed from != anchor) + if(resume target != anchor) fn.reached(anchor) = (fn.reached(anchor) | 0) + 1 merge branch! :f = $ if(fn.current checkpoint) - resumed from = fn.current checkpoint - fn!resume(fn.current checkpoint) + resume target = fn.current checkpoint + fn!from(fn.current checkpoint) else! - resumed from = () + resume target = () fn! fn.run += 1 @@ -52,7 +52,7 @@ return [[ s.current checkpoint = () return(s!) -/*Additionnal helpers*/ +/* Additionnal helpers */ :@$ cycle(l::tuple) :i = 2 while($i <= l!len) diff --git a/anselme/stdlib/type_check.lua b/anselme/stdlib/types.lua similarity index 64% rename from anselme/stdlib/type_check.lua rename to anselme/stdlib/types.lua index 1e07655..660dd69 100644 --- a/anselme/stdlib/type_check.lua +++ b/anselme/stdlib/types.lua @@ -1,7 +1,46 @@ local ast = require("anselme.ast") -local Boolean = ast.Boolean +local ArgumentTuple, Boolean, String, Typed = ast.ArgumentTuple, ast.Boolean, ast.String, ast.Typed return { + { + "_::_", "(value, check)", + function(state, value, check) + local r = check:call(state, ArgumentTuple:new(value)) + if r:truthy() then + return value + else + error(("type check failure: %s does not satisfy %s"):format(value:format(state), check:format(state)), 0) + end + end + }, + + { + "type", "(value)", + function(state, v) + if v.type == "typed" then + return v.type_expression + else + return String:new(v.type) + end + end + }, + { + "type", "(value, type)", + function(state, v, t) + return Typed:new(v, t) + end + }, + { + "value", "(value)", + function(state, v) + if v.type == "typed" then + return v.expression + else + return v + end + end + }, + { "nil", "(x)", function(state, x) return Boolean:new(x.type == "nil") end }, { "number", "(x)", function(state, x) return Boolean:new(x.type == "number") end }, { "string", "(x)", function(state, x) return Boolean:new(x.type == "string") end }, diff --git a/anselme/stdlib/wrap.lua b/anselme/stdlib/wrap.lua new file mode 100644 index 0000000..9c64d4e --- /dev/null +++ b/anselme/stdlib/wrap.lua @@ -0,0 +1,28 @@ +local ast = require("anselme.ast") +local Call, Function, ParameterTuple, FunctionParameter, Identifier, Overload, Assignment = ast.Call, ast.Function, ast.ParameterTuple, ast.FunctionParameter, ast.Identifier, ast.Overload, ast.Assignment + +return { + { + ">_", "(q::is(\"quote\"))", + function(state, q) + local exp = q.expression + local get = Function:with_return_boundary(ParameterTuple:new(), exp):eval(state) + + local set_exp + if Call:is(exp) then + set_exp = Call:new(exp.func, exp.arguments:with_assignment(Identifier:new("value"))) + elseif Identifier:is(exp) then + set_exp = Assignment:new(exp, Identifier:new("value")) + end + + if set_exp then + local set_param = ParameterTuple:new() + set_param:insert_assignment(FunctionParameter:new(Identifier:new("value"))) + local set = Function:with_return_boundary(set_param, set_exp):eval(state) + return Overload:new(get, set) + else + return get + end + end + }, +} diff --git a/test/results/merge nested mutable error bis.ans b/test/results/merge nested mutable error bis.ans index c6501ca..6873006 100644 --- a/test/results/merge nested mutable error bis.ans +++ b/test/results/merge nested mutable error bis.ans @@ -5,7 +5,7 @@ ↳ from test/tests/merge nested mutable error bis.ans:3:1 in block: insert(a, b)… ↳ from test/tests/merge nested mutable error bis.ans:3:18 in call: _ ↳ from script.ans:30:6 in call: fn! - ↳ from script.ans:28:3 in block: resumed from = ()… + ↳ from script.ans:28:3 in block: resume target = ()… ↳ from script.ans:28:7 in call: else! ↳ from script.ans:24:2 in block: if(fn . "current checkpoint")… ↳ from script.ans:24:9 in call: _ diff --git a/test/results/merge nested mutable error.ans b/test/results/merge nested mutable error.ans index 71120a5..7e3dbfd 100644 --- a/test/results/merge nested mutable error.ans +++ b/test/results/merge nested mutable error.ans @@ -5,7 +5,7 @@ ↳ from test/tests/merge nested mutable error.ans:3:1 in block: insert(a, b)… ↳ from test/tests/merge nested mutable error.ans:3:18 in call: _ ↳ from script.ans:30:6 in call: fn! - ↳ from script.ans:28:3 in block: resumed from = ()… + ↳ from script.ans:28:3 in block: resume target = ()… ↳ from script.ans:28:7 in call: else! ↳ from script.ans:24:2 in block: if(fn . "current checkpoint")… ↳ from script.ans:24:9 in call: _ diff --git a/test/tests/resume anchors.ans b/test/tests/resume anchors.ans index 57cda80..8857583 100644 --- a/test/tests/resume anchors.ans +++ b/test/tests/resume anchors.ans @@ -8,7 +8,7 @@ :f = $(anchor=()) :x = 8 - ($_)!resume(anchor) + ($_)!from(anchor) |a | A |> | b