nomsu/lib/class.nom

105 lines
4.6 KiB
Plaintext

use "lib/core.nom"
compile [@%var] to
lua> ".."
local key_lua = repr(\%var.value);
local key_attr = (key_lua:match("'([a-zA-Z][a-zA-Z0-9]*)'")
or key_lua:match('"([a-zA-Z][a-zA-Z0-9]*)"'));
if key_attr then
return "_me."..key_attr;
elseif key_lua:sub(1,1) == "[" then
key_lua = " "..key_lua.." ";
end
return "_me["..key_lua.."]";
compile [@%var <- %val] to code
lua> ".."
local val_lua = \(%val as lua);
local key_lua = repr(\%var.value);
local key_attr = (key_lua:match("'([a-zA-Z][a-zA-Z0-9]*)'")
or key_lua:match('"([a-zA-Z][a-zA-Z0-9]*)"'));
if key_attr then
return "_me."..key_attr.." = "..val_lua..";";
elseif key_lua:sub(1,1) == "[" then
key_lua = " "..key_lua.." ";
end
return "_me["..key_lua.."] = "..val_lua..";";
compile [object %classname %class_body] to
%class_identifier <- (=lua "nomsu:var_to_lua_identifier(\(%classname as value)):sub(2,-1)")
if: %class_identifier is ""
%class_identifier <- "class"
%methods <- []
for %line in (%class_body's "value")
if: (%line's "type") is "Comment"
do next %line
assume (((%line's "type") == "FunctionCall") and ((%line's "stub") == "action % %"))
..or barf "Only action definitions are supported inside 'object % %', not \(%line's "src")"
lua> ".."
assert(\%line.value[3].type == "Block",
"Invalid type for action definition body. Expected Block, but got: "..tostring(\%line.value[3].type));
local names, args = nomsu:parse_spec(\%line.value[2]);
local stub = nomsu:get_stub(names[1]);
local body_lua = nomsu:tree_to_lua(\%line.value[3]);
body_lua = body_lua.statements or ("return "..body_lua.expr..";");
local arg_nomsus = {};
for i, arg in ipairs(args) do arg_nomsus[i] = "nomsu:tree_to_lua("..arg..").expr"; end
table.insert(\%methods, ([==[
%s[ %s] = function(%s)
%s
end
nomsu:define_compile_action(%s, %s, function(%s)
return {expr="("..nomsu:tree_to_lua(_me).expr..")[ "..%s.."]("..%s..")"};
end, %s);
ACTION_METADATA[%s[ %s]] = ACTION_METADATA[ACTIONS[ %s]];
]==]):format(
\%class_identifier, repr(stub), table.concat(args, ", "),
body_lua,
repr(names), repr(\%line:get_line_no()), table.concat(args, ", "),
repr(repr(stub)), table.concat(arg_nomsus, ".."),
repr(nomsu:dedent(\%line.src)),
\%class_identifier, repr(stub), repr(stub)));
return ".."
do -- \%class_identifier
-- Create the class object:
local \%class_identifier = setmetatable({
name=\(%classname as lua), instances=setmetatable({}, {__mode="k"}),
}, {
__tostring=function(c) return c.name; end,
__call=function(cls, inst)
inst = inst or {};
inst.id = tostring(inst):match('table: (.*)');
setmetatable(inst, cls.instance_metatable);
cls.instances[inst] = true;
if inst['set % up'] then
inst['set % up'](inst);
end
return inst;
end,
});
\%class_identifier.class = \%class_identifier;
-- Define the methods:
\(join %methods with "\n")
-- Define class methods for instantiating and accessing instances:
\%class_identifier.instance_metatable = {
__index=\%class_identifier,
__tostring=\%class_identifier['% as text'] or function(inst)
return "<"..inst.class.name..": "..inst.id..">";
end,
};
nomsu:define_action("instances of "..\%class_identifier.name, "lib/class.nom", function()
return utils.keys(\%class_identifier.instances);
end, "");
nomsu:define_action("new "..\%class_identifier.name.." %instance", "lib/class.nom", function(_instance)
return \%class_identifier(_instance);
end, "");
nomsu:define_action("new "..\%class_identifier.name, "lib/class.nom", function()
return \%class_identifier({});
end, "");
end -- End of definition of \%class_identifier
\("\n\n")