1
0
Fork 0
mirror of https://github.com/Reuh/anselme.git synced 2025-10-27 08:39:30 +00:00

Add object type, dot operator can return function references

This commit is contained in:
Étienne Fildadut 2022-06-09 17:07:58 +09:00
parent 69b9e17020
commit 47f95fc04a
18 changed files with 599 additions and 49 deletions

View file

@ -948,7 +948,7 @@ This only works on strings:
`a # b`: evaluates b, then evaluates a whith b added to the active tags. Returns a.
`a.b`: if a is a function reference, returns the variable named `b` in the referenced function namespace. When overloading this operator, if `b` is an identifier, the operator will interpret it as a string (and not returns the evaluated value of the variable eventually associated to the identifier).
`a.b`: if a is a function reference, returns the first found variable (or reference to a subfunction) named `b` in the referenced function namespace. When overloading this operator, if `b` is an identifier, the operator will interpret it as a string (instead of returning the evaluated value of the variable eventually associated to the identifier).
`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. Operator is named `()`.

View file

@ -577,8 +577,24 @@ local vm_mt = {
save = function(self)
local vars = {}
for k, v in pairs(self.state.variables) do
if should_keep_variable(self.state, k) then
vars[k] = v
if should_keep_variable(self.state, k, v) then
if v.type == "object" then -- filter object attributes
local attributes = {}
for kk, vv in pairs(v.value.attributes) do
if should_keep_variable(self.state, kk, vv) then
attributes[kk] = vv
end
end
vars[k] = {
type = "object",
value = {
class = v.value.class,
attributes = attributes
}
}
else
vars[k] = v
end
end
end
return {

View file

@ -189,9 +189,8 @@ common = {
end,
--- returns true if a variable should be persisted on save
-- will exclude: undefined variables, variables in scoped functions, internal anselme variables
should_keep_variable = function(state, name)
local v = state.variables[name]
return v.type ~= "undefined argument" and v.type ~= "pending definition" and name:match("^"..identifier_pattern.."$") and not name:match("^anselme%.")
should_keep_variable = function(state, name, value)
return value.type ~= "undefined argument" and value.type ~= "pending definition" and name:match("^"..identifier_pattern.."$") and not name:match("^anselme%.")
end,
--- check truthyness of an anselme value
truthy = function(val)

View file

@ -208,16 +208,10 @@ local function eval(state, exp)
local tried_function_error_messages = {}
local selected_variant = { depths = { assignment = nil }, variant = nil, args_to_set = nil }
for _, fn in ipairs(variants) do
-- checkpoint: no args, nothing to select on
if fn.type == "checkpoint" then
if not selected_variant.variant then
selected_variant.depths = {}
selected_variant.variant = fn
else
return nil, ("checkpoint call %q is ambigous; may be at least either:\n\t%s\n\t%s"):format(exp.called_name, fn.pretty_signature, selected_variant.variant.pretty_signature)
end
-- function
elseif fn.type == "function" then
if fn.type ~= "function" then
return nil, ("unknown function type %q"):format(fn.type)
-- functions
else
if not fn.assignment or exp.assignment then
local ok = true
-- get and set args
@ -342,18 +336,20 @@ local function eval(state, exp)
end
end
end
else
return nil, ("unknown function type %q"):format(fn.type)
end
end
-- function successfully selected: run
if selected_variant.variant then
local fn = selected_variant.variant
if fn.type == "checkpoint" then
if fn.type ~= "function" then
return nil, ("unknown function type %q"):format(fn.type)
-- checkpoint: no args and resume execution
elseif fn.subtype == "checkpoint" then
local r, e = run(state, fn.child, not paren_call)
if not r then return r, e end
return r
elseif fn.type == "function" then
-- other functions
else
local ret
-- push scope
-- NOTE: if error happens between here and scope:pop, will leave the stack a mess
@ -452,6 +448,28 @@ local function eval(state, exp)
type = "number",
value = seen.value + 1
})
-- for classes: build resulting object
if fn.subtype == "class" then
local object = {
type = "type",
value = {
{
type = "object",
value = {
class = fn.name,
attributes = {}
}
},
{
type = "function reference",
value = { fn.name }
}
}
}
if ret and ret.type == "nil" then
ret = object
end
end
-- pop scope
if fn.scoped then
scope:pop(state, fn)

View file

@ -111,7 +111,7 @@ run_line = function(state, line)
elseif line.type == "flush_events" then
local v, e = events:flush(state)
if not v then return v, ("%s; in event flush at %s"):format(e, line.source) end
elseif line.type == "checkpoint" then
elseif line.type == "function" and line.subtype == "checkpoint" then
local reached, reachede = get_variable(state, line.namespace.."🏁")
if not reached then return nil, reachede end
set_variable(state, line.namespace.."🏁", {
@ -150,9 +150,9 @@ run_block = function(state, block, resume_from_there, i, j)
i = i + 1
end
-- if we are exiting a checkpoint block, mark it as ran and update checkpoint
-- (when resuming from a checkpoint, execution is resumed from inside the checkpoint, the line.type=="checkpoint" check in run_line is never called)
-- (when resuming from a checkpoint, execution is resumed from inside the checkpoint, the line.subtype=="checkpoint" check in run_line is never called)
-- (and we want this to be done after executing the checkpoint block anyway)
if block.parent_line and block.parent_line.type == "checkpoint" then
if block.parent_line and block.parent_line.type == "function" and block.parent_line.subtype == "checkpoint" then
local parent_line = block.parent_line
local reached, reachede = get_variable(state, parent_line.namespace.."🏁")
if not reached then return nil, reachede end
@ -183,7 +183,7 @@ run_block = function(state, block, resume_from_there, i, j)
-- if parent is a choice, will ignore choices that belong to the same block (like the whole block was executed naturally from a higher parent)
-- if parent if a condition, will mark it as a success (skipping following else-conditions) (for the same reasons as for choices)
-- if parent pushed a tag, will pop it (tags from parents are added to the stack in run())
if resume_from_there and block.parent_line and block.parent_line.type ~= "function" then
if resume_from_there and block.parent_line and not block.parent_line.resume_boundary then
local parent_line = block.parent_line
if parent_line.type == "choice" then
state.interpreter.skip_choices_until_flush = true
@ -209,7 +209,7 @@ local function run(state, block, resume_from_there, i, j)
local tags_to_add = {}
-- go up in hierarchy in ascending order until function boundary
local parent_line = block.parent_line
while parent_line and parent_line.type ~= "function" do
while parent_line and not parent_line.resume_boundary do
if parent_line.type == "tag" then
local v, e = eval(state, parent_line.expression)
if not v then return v, ("%s; at %s"):format(e, parent_line.source) end

View file

@ -43,6 +43,8 @@ Reserved symbols that are still not used as a line type: `^+-=</[]*{}|\_!?.,;)"&
Broad goals and ideas that may never be implemented. Mostly used as personal post-it notes.
TODO: type system is not super nice to use
TODO: distinguish between list and argument list to confuse less pairs with named arguments
TODO: some sensible way to capture text event in string litterals (string interpolation)? -> meh, this means we can capture choice events, and choice events contain their code block, and we don't want to store code blocks in the save file (as code can be updated/translated/whatever)
@ -83,7 +85,7 @@ TODO: perform seen/reached/etc default variable not in interpreter but using par
TODO: no function call without () (reference to fn instead?). Fn could be stored in save but replaced with new versions on code reload... -> how to track these references?
if we make fn first class this means anonymous fn, is it ok?
TODO: make language simple enough to be able to reimplement it in, say, nim. Especially the interpreter (we could precompile a lot of stuff...)
TODO: make language simple enough to be able to reimplement it in, say, nim. Especially the AST interpreter (we could precompile a lot of stuff...)
TODO: test reacheability of script paths

View file

@ -54,24 +54,41 @@ local function parse_line(line, state, namespace, parent_function)
r.child = true
r.text = l:match("^>%s*(.-)$")
-- function & checkpoint
elseif l:match("^%$") or l:match("") then -- § is a 2-bytes caracter, DO NOT USE LUA PATTERN OPERATORS as they operate on single bytes
r.type = l:match("^%$") and "function" or "checkpoint"
elseif l:match("^%$") or l:match("") or l:match("^%%") then -- § is a 2-bytes caracter, DO NOT USE LUA PATTERN OPERATORS as they operate on single bytes
r.type = "function"
r.child = true
-- store parent function and run checkpoint when line is read
if r.type == "checkpoint" then
r.parent_function = parent_function
-- subtype options
local allow_params = true
local allow_assign = true
local keep_in_ast = false
if l:match("^%$") then
r.subtype = "function"
r.resume_boundary = true
elseif l:match("^%%") then
r.subtype = "class"
r.resume_boundary = true
allow_params = false
allow_assign = false
elseif l:match("") then
r.subtype = "checkpoint"
allow_params = false
allow_assign = false
keep_in_ast = true
r.parent_function = parent_function -- store parent function and run checkpoint when line is read
else
error("unknown function line type")
end
-- don't keep function node in block AST
if r.type == "function" then
if not keep_in_ast then
r.remove_from_block_ast = true
-- lua function
if state.global_state.link_next_function_definition_to_lua_function then
r.lua_function = state.global_state.link_next_function_definition_to_lua_function
state.global_state.link_next_function_definition_to_lua_function = nil
end
end
-- lua function
if r.subtype == "function" and state.global_state.link_next_function_definition_to_lua_function then
r.lua_function = state.global_state.link_next_function_definition_to_lua_function
state.global_state.link_next_function_definition_to_lua_function = nil
end
-- get identifier
local lc = l:match("^%$(.-)$") or l:match("^§(.-)$")
local lc = l:match("^[%$%%](.-)$") or l:match("^§(.-)$")
local identifier, rem = lc:match("^("..identifier_pattern..")(.-)$")
if not identifier then
for _, name in ipairs(special_functions_names) do
@ -80,7 +97,7 @@ local function parse_line(line, state, namespace, parent_function)
end
end
if not identifier then
return nil, ("no valid identifier in checkpoint/function definition line %q; at %s"):format(lc, line.source)
return nil, ("no valid identifier in function definition line %q; at %s"):format(lc, line.source)
end
-- format identifier
local fqm = ("%s%s"):format(namespace, format_identifier(identifier))
@ -101,7 +118,7 @@ local function parse_line(line, state, namespace, parent_function)
r.name = fqm
-- get params
r.params = {}
if r.type == "function" and rem:match("^%b()") then
if allow_params and rem:match("^%b()") then
r.scoped = true
local content
content, rem = rem:match("^(%b())%s*(.*)$")
@ -131,7 +148,7 @@ local function parse_line(line, state, namespace, parent_function)
end
end
-- get assignment param
if r.type == "function" and rem:match("^%:%=") then
if allow_assign and rem:match("^%:%=") then
local param = rem:match("^%:%=(.*)$")
-- get identifier
local param_identifier, param_rem = param:match("^("..identifier_pattern..")(.-)$")
@ -153,7 +170,7 @@ local function parse_line(line, state, namespace, parent_function)
-- add parameter
r.assignment = { name = param_identifier, alias = param_alias, full_name = param_fqm, type_annotation = type_annotation, default = nil, vararg = nil }
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 function definition line, but got %q; at %s"):format(rem, line.source)
end
-- calculate arity
local minarity, maxarity = #r.params, #r.params
@ -190,7 +207,7 @@ local function parse_line(line, state, namespace, parent_function)
else
table.insert(line.children, 1, { content = ":👁️=0", source = line.source })
end
if r.type == "function" then
if r.subtype ~= "checkpoint" then
-- define 🔖 variable
local checkpoint_alias = state.global_state.builtin_aliases["🔖"]
if checkpoint_alias then
@ -222,7 +239,7 @@ local function parse_line(line, state, namespace, parent_function)
end
end
end
elseif r.type == "checkpoint" then
elseif r.subtype == "checkpoint" then
-- define 🏁 variable
local reached_alias = state.global_state.builtin_aliases["🏁"]
if reached_alias then
@ -372,7 +389,7 @@ local function parse_block(indented, state, namespace, parent_function)
if not ast.child then
return nil, ("line %s (%s) can't have children"):format(ast.source, ast.type)
else
local r, e = parse_block(l.children, state, ast.namespace or namespace, ast.type == "function" and ast or parent_function)
local r, e = parse_block(l.children, state, ast.namespace or namespace, (ast.type == "function" and ast.subtype ~= "checkpoint") and ast or parent_function)
if not r then return r, e end
r.parent_line = ast
ast.child = r

View file

@ -8,6 +8,7 @@ return [[
:pair="pair"
:function reference="function reference"
:variable reference="variable reference"
:object="object"
:pi=3.1415926535898
]]

View file

@ -76,28 +76,37 @@ lua_functions = {
},
-- namespace
["_._(r::function reference, name::string)"] = {
mode = "raw",
mode = "untyped 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.interpreter.global_state.variables, ffqm..".", name)
local var, vfqm = find(state.aliases, state.interpreter.global_state.variables, "", ffqm.."."..name)
if var then
return get_variable(state, vfqm)
end
end
for _, ffqm in ipairs(rval) do
local fn, fnfqm = find(state.aliases, state.functions, "", ffqm.."."..name)
if fn then
return {
type = "function reference",
value = { fnfqm }
}
end
end
return nil, ("can't find variable %q in function reference (searched in namespaces: %s)"):format(name, table.concat(rval, ", "))
end
},
["_._(r::function reference, name::string) := v"] = {
mode = "raw",
mode = "untyped raw",
value = function(r, n, v)
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.interpreter.global_state.variables, ffqm..".", name)
local var, vfqm = find(state.aliases, state.interpreter.global_state.variables, "", ffqm.."."..name)
if var then
set_variable(state, vfqm, v)
return v
@ -106,6 +115,52 @@ lua_functions = {
return nil, ("can't find variable %q in function reference (searched in namespaces: %s)"):format(name, table.concat(rval, ", "))
end
},
["_._(r::object, name::string)"] = {
mode = "untyped raw",
value = function(r, n)
local state = anselme.running.state
local obj = r.value
local name = n.value
-- attribute already present in object
local var = find(state.aliases, obj.attributes, "", obj.class.."."..name)
if var then return var end
-- search for attribute in base class
local cvar, cvfqm = find(state.aliases, state.interpreter.global_state.variables, "", obj.class.."."..name)
if cvar then return get_variable(state, cvfqm) end
-- search for method in base class
local fn, fnfqm = find(state.aliases, state.functions, "", obj.class.."."..name)
if fn then
return {
type = "function reference",
value = { fnfqm }
}
end
return nil, ("can't find attribute %q in object"):format(name)
end
},
["_._(r::object, name::string) := v"] = {
mode = "untyped raw",
value = function(r, n, v)
local state = anselme.running.state
local obj = r.value
local name = n.value
-- attribute already present in object
local var, vfqm = find(state.aliases, obj.attributes, "", obj.class.."."..name)
if var then
obj.attributes[vfqm] = v
mark_as_modified(anselme.running.state, obj.attributes)
return v
end
-- search for attribute in base class
local cvar, cvfqm = find(state.aliases, state.interpreter.global_state.variables, "", obj.class.."."..name)
if cvar then
obj.attributes[cvfqm] = v
mark_as_modified(anselme.running.state, obj.attributes)
return v
end
return nil, ("can't find attribute %q in object"):format(name)
end
},
-- index
["()(l::list, i::number)"] = {
mode = "untyped raw",

View file

@ -166,6 +166,12 @@ types.anselme = {
end,
to_lua = nil
},
object = {
format = function(val)
return ("%%%s"):format(val.class)
end,
to_lua = nil
},
-- internal types
["event buffer"] = {
format = function(val) -- triggered from subtexts

View file

@ -0,0 +1,9 @@
$ f
$ a
@12
:x = &f
{x.a}
{x.a!}

View file

@ -0,0 +1,22 @@
local _={}
_[9]={}
_[8]={}
_[7]={tags=_[9],text="12"}
_[6]={tags=_[8],text="&function reference dot operator function.f.a"}
_[5]={_[7]}
_[4]={_[6]}
_[3]={"return"}
_[2]={"text",_[5]}
_[1]={"text",_[4]}
return {_[1],_[2],_[3]}
--[[
{ "text", { {
tags = {},
text = "&function reference dot operator function.f.a"
} } }
{ "text", { {
tags = {},
text = "12"
} } }
{ "return" }
]]--

View file

@ -0,0 +1,15 @@
% class
:a:b = "foo"
:c = "bar"
$ new(o::&class, x)
~ o.c := x
@o
:o = class
:p = class!new("hoho")
{o}, {p}
{o.c} == {class.c}
{p.c} != {class.c}

View file

@ -0,0 +1,57 @@
local _={}
_[23]={}
_[22]={}
_[21]={}
_[20]={}
_[19]={}
_[18]={}
_[17]={}
_[16]={}
_[15]={}
_[14]={tags=_[23],text="bar"}
_[13]={tags=_[22],text=" != "}
_[12]={tags=_[21],text="hoho"}
_[11]={tags=_[20],text="bar"}
_[10]={tags=_[19],text=" == "}
_[9]={tags=_[18],text="bar"}
_[8]={tags=_[17],text="%object constructor.class::&object constructor.class"}
_[7]={tags=_[16],text=", "}
_[6]={tags=_[15],text="%object constructor.class::&object constructor.class"}
_[5]={_[9],_[10],_[11],_[12],_[13],_[14]}
_[4]={_[6],_[7],_[8]}
_[3]={"return"}
_[2]={"text",_[5]}
_[1]={"text",_[4]}
return {_[1],_[2],_[3]}
--[[
{ "text", { {
tags = {},
text = "%object constructor.class::&object constructor.class"
}, {
tags = {},
text = ", "
}, {
tags = {},
text = "%object constructor.class::&object constructor.class"
} } }
{ "text", { {
tags = {},
text = "bar"
}, {
tags = {},
text = " == "
}, {
tags = {},
text = "bar"
}, {
tags = {},
text = "hoho"
}, {
tags = {},
text = " != "
}, {
tags = {},
text = "bar"
} } }
{ "return" }
]]--

View file

@ -0,0 +1,26 @@
% class
:a:b = "foo"
:c = "bar"
:o = class
:p = class
{o}, {p}
{o.a} == {class.a}
{o.b} == {class.b}
{p.a} == {class.a}
{p.b} == {class.b}
~ o.b := "haha"
{o.a} != {class.a}
{o.b} != {class.b}
{p.a} == {class.a}
{p.b} == {class.b}
{o.c} == {class.c}
{p.c} == {class.c}

View file

@ -0,0 +1,192 @@
local _={}
_[81]={}
_[80]={}
_[79]={}
_[78]={}
_[77]={}
_[76]={}
_[75]={}
_[74]={}
_[73]={}
_[72]={}
_[71]={}
_[70]={}
_[69]={}
_[68]={}
_[67]={}
_[66]={}
_[65]={}
_[64]={}
_[63]={}
_[62]={}
_[61]={}
_[60]={}
_[59]={}
_[58]={}
_[57]={}
_[56]={}
_[55]={}
_[54]={}
_[53]={}
_[52]={}
_[51]={}
_[50]={}
_[49]={}
_[48]={tags=_[81],text="bar"}
_[47]={tags=_[80],text=" == "}
_[46]={tags=_[79],text="bar"}
_[45]={tags=_[78],text="bar"}
_[44]={tags=_[77],text=" == "}
_[43]={tags=_[76],text="bar"}
_[42]={tags=_[75],text="foo"}
_[41]={tags=_[74],text=" == "}
_[40]={tags=_[73],text="foo"}
_[39]={tags=_[72],text="foo"}
_[38]={tags=_[71],text=" == "}
_[37]={tags=_[70],text="foo"}
_[36]={tags=_[69],text="foo"}
_[35]={tags=_[68],text=" != "}
_[34]={tags=_[67],text="haha"}
_[33]={tags=_[66],text="foo"}
_[32]={tags=_[65],text=" != "}
_[31]={tags=_[64],text="haha"}
_[30]={tags=_[63],text="foo"}
_[29]={tags=_[62],text=" == "}
_[28]={tags=_[61],text="foo"}
_[27]={tags=_[60],text="foo"}
_[26]={tags=_[59],text=" == "}
_[25]={tags=_[58],text="foo"}
_[24]={tags=_[57],text="foo"}
_[23]={tags=_[56],text=" == "}
_[22]={tags=_[55],text="foo"}
_[21]={tags=_[54],text="foo"}
_[20]={tags=_[53],text=" == "}
_[19]={tags=_[52],text="foo"}
_[18]={tags=_[51],text="%object several.class::&object several.class"}
_[17]={tags=_[50],text=", "}
_[16]={tags=_[49],text="%object several.class::&object several.class"}
_[15]={_[46],_[47],_[48]}
_[14]={_[43],_[44],_[45]}
_[13]={_[37],_[38],_[39],_[40],_[41],_[42]}
_[12]={_[31],_[32],_[33],_[34],_[35],_[36]}
_[11]={_[25],_[26],_[27],_[28],_[29],_[30]}
_[10]={_[19],_[20],_[21],_[22],_[23],_[24]}
_[9]={_[16],_[17],_[18]}
_[8]={"return"}
_[7]={"text",_[15]}
_[6]={"text",_[14]}
_[5]={"text",_[13]}
_[4]={"text",_[12]}
_[3]={"text",_[11]}
_[2]={"text",_[10]}
_[1]={"text",_[9]}
return {_[1],_[2],_[3],_[4],_[5],_[6],_[7],_[8]}
--[[
{ "text", { {
tags = {},
text = "%object several.class::&object several.class"
}, {
tags = {},
text = ", "
}, {
tags = {},
text = "%object several.class::&object several.class"
} } }
{ "text", { {
tags = {},
text = "foo"
}, {
tags = {},
text = " == "
}, {
tags = {},
text = "foo"
}, {
tags = {},
text = "foo"
}, {
tags = {},
text = " == "
}, {
tags = {},
text = "foo"
} } }
{ "text", { {
tags = {},
text = "foo"
}, {
tags = {},
text = " == "
}, {
tags = {},
text = "foo"
}, {
tags = {},
text = "foo"
}, {
tags = {},
text = " == "
}, {
tags = {},
text = "foo"
} } }
{ "text", { {
tags = {},
text = "haha"
}, {
tags = {},
text = " != "
}, {
tags = {},
text = "foo"
}, {
tags = {},
text = "haha"
}, {
tags = {},
text = " != "
}, {
tags = {},
text = "foo"
} } }
{ "text", { {
tags = {},
text = "foo"
}, {
tags = {},
text = " == "
}, {
tags = {},
text = "foo"
}, {
tags = {},
text = "foo"
}, {
tags = {},
text = " == "
}, {
tags = {},
text = "foo"
} } }
{ "text", { {
tags = {},
text = "bar"
}, {
tags = {},
text = " == "
}, {
tags = {},
text = "bar"
} } }
{ "text", { {
tags = {},
text = "bar"
}, {
tags = {},
text = " == "
}, {
tags = {},
text = "bar"
} } }
{ "return" }
]]--

View file

@ -0,0 +1,17 @@
% class
:a:b = "foo"
:c = "bar"
:o = class
{o}
{o.a} == {class.a}
{o.b} == {class.b}
~ o.b := "haha"
{o.a} != {class.a}
{o.b} != {class.b}
{o.c} == {class.c}

View file

@ -0,0 +1,98 @@
local _={}
_[41]={}
_[40]={}
_[39]={}
_[38]={}
_[37]={}
_[36]={}
_[35]={}
_[34]={}
_[33]={}
_[32]={}
_[31]={}
_[30]={}
_[29]={}
_[28]={}
_[27]={}
_[26]={}
_[25]={tags=_[41],text="bar"}
_[24]={tags=_[40],text=" == "}
_[23]={tags=_[39],text="bar"}
_[22]={tags=_[38],text="foo"}
_[21]={tags=_[37],text=" != "}
_[20]={tags=_[36],text="haha"}
_[19]={tags=_[35],text="foo"}
_[18]={tags=_[34],text=" != "}
_[17]={tags=_[33],text="haha"}
_[16]={tags=_[32],text="foo"}
_[15]={tags=_[31],text=" == "}
_[14]={tags=_[30],text="foo"}
_[13]={tags=_[29],text="foo"}
_[12]={tags=_[28],text=" == "}
_[11]={tags=_[27],text="foo"}
_[10]={tags=_[26],text="%object simple.class::&object simple.class"}
_[9]={_[23],_[24],_[25]}
_[8]={_[17],_[18],_[19],_[20],_[21],_[22]}
_[7]={_[11],_[12],_[13],_[14],_[15],_[16]}
_[6]={_[10]}
_[5]={"return"}
_[4]={"text",_[9]}
_[3]={"text",_[8]}
_[2]={"text",_[7]}
_[1]={"text",_[6]}
return {_[1],_[2],_[3],_[4],_[5]}
--[[
{ "text", { {
tags = {},
text = "%object simple.class::&object simple.class"
} } }
{ "text", { {
tags = {},
text = "foo"
}, {
tags = {},
text = " == "
}, {
tags = {},
text = "foo"
}, {
tags = {},
text = "foo"
}, {
tags = {},
text = " == "
}, {
tags = {},
text = "foo"
} } }
{ "text", { {
tags = {},
text = "haha"
}, {
tags = {},
text = " != "
}, {
tags = {},
text = "foo"
}, {
tags = {},
text = "haha"
}, {
tags = {},
text = " != "
}, {
tags = {},
text = "foo"
} } }
{ "text", { {
tags = {},
text = "bar"
}, {
tags = {},
text = " == "
}, {
tags = {},
text = "bar"
} } }
{ "return" }
]]--