nomsu/lib/object2.nom
2018-05-09 13:35:04 -07:00

176 lines
7.7 KiB
Plaintext

use "core"
compile [@] to: Lua value "self"
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 Lua.value(tree.source, "self."..key_attr);
elseif key_lua:sub(1,1) == "[" then
key_lua = " "..key_lua;
end
return Lua.Value(tree.source, "self["..key_lua.."]");
compile [@%var <- %val] to
lua> ".."
local val_lua = \(%val as lua expr);
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 Lua(tree.source, "self.", key_attr, " = ", val_lua, ";");
elseif key_lua:sub(1,1) == "[" then
key_lua = " "..key_lua.." ";
end
return Lua(tree.source, "self[", key_lua, "] = ", val_lua, ";");
compile [as %instance %body] to
%body_lua <- (%body as lua)
lua> "\%body_lua:convert_to_statements();"
return
Lua ".."
do
local self = \(%instance as lua expr);
local global_actions = ACTIONS;
local ACTIONS = setmetatable({}, {__index=function(_,key)
local method = self[key];
if method then return (function(...) return method(self, ...); end); end
return global_actions[key];
end});
\%body_lua
end
compile [define 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 <- []
%__index <- %class_identifier
%__newindex <- "nil"
for %line in (%class_body's "value")
if: (%line's "type") is "Comment"
do next %line
if: ((%line's "type") is "FunctionCall") and ((%line's stub) is "slots %")
%slot_index_clauses <- []
%slot_newindex_clauses <- []
%slots <- %line.value.2.value
for %slot_index = %slot_var in %slots
to %slot_index_clauses add ".."
if key == \(repr (%slot_var's "value")) or key == \(repr (%slot_var as lua expr)) then
return rawget(self, \%slot_index);
end
to %slot_newindex_clauses add ".."
if key == \(repr (%slot_var's "value")) or key == \(repr (%slot_var as lua expr)) or key == \%slot_index then
rawset(self, \%slot_index, value);
end
%__index <- ".."
function(self, key)
\(%slot_index_clauses joined with "\n")
return \%class_identifier[key];
end
%__newindex <- ".."
function(self, key, value)
\(%slot_newindex_clauses joined with "\n")
error("Attempt to store data in "..repr(key)..", which is not a valid slot on "..tostring(self.class));
end
do next %line
assume ((%line.type is "FunctionCall") and ((%line's stub) is "action % %"))
..or barf "Only action definitions are supported inside 'define object % %', not \(%line's "src")"
%actions <- %line.value.2
%body <- %line.value.3
lua> ".."
do
local stubs = {};
for i, action in ipairs(\%actions.value) do
stubs[i] = nomsu:tree_to_named_stub(action);
end
local args = {};
for i,tok in ipairs(\%actions.value[1].value) do
if tok.type == "Var" then args[#args+1] = nomsu:var_to_lua_identifier(tok.value); end
end
local arg_set = {};
for i, arg in ipairs(args) do arg_set[arg] = true; end
local body_lua = nomsu:tree_to_lua(\%body);
body_lua:convert_to_statements();
body_lua:declare_locals();
local lua_fn_args = table.concat({"self", unpack(args)}, ", ");
local def_tree = nomsu.compilestack[#nomsu.compilestack];
local compiled_args = {};
for i, arg in ipairs(args) do
compiled_args[i] = "nomsu:tree_to_lua("..arg..")";
end
compiled_args = table.concat(compiled_args, "..', '..");
table.insert(\%methods, ([==[
%s[ %s] = function(%s)
%s
end
]==]):format(
\%class_identifier, repr(stubs[1]), lua_fn_args,
body_lua));
end
return
Lua ".."
do -- \%class_identifier
-- Create the class object
local \%class_identifier = setmetatable({
name=\(%classname as lua expr), instances=setmetatable({}, {__mode="k"}),
}, {
__tostring=function(c) return c.name; end,
__call=function(cls, initial_values)
local inst = setmetatable({}, cls.instance_metatable);
for k,v in pairs(initial_values) do inst[k] = v; end
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
\(%methods joined with "\n")
-- Define class methods for instantiating and accessing instances
\%class_identifier.instance_metatable = {
__index=\%__index,
__newindex=\%__newindex,
__tostring=\%class_identifier['as text'] or function(inst)
return "<"..inst.class.name..": "..nomsu.ids[inst]..">";
end,
__len=\%class_identifier['size of'],
__unm=\%class_identifier['-'],
__add=\%class_identifier['+ %'],
__sub=\%class_identifier['- %'],
__mul=\%class_identifier['* %'],
__div=\%class_identifier['/ %'],
__mod=\%class_identifier['wrapped around %'],
__pow=\%class_identifier['^ %'],
__band=\%class_identifier['AND %'],
__bor=\%class_identifier['OR %'],
__bxor=\%class_identifier['XOR %'],
__bshl=\%class_identifier['<< %'],
__bshr=\%class_identifier['>> %'],
__eq=\%class_identifier['= %'],
__lt=\%class_identifier['< %'],
__le=\%class_identifier['<= %'],
};
nomsu:define_action("instances of "..\%class_identifier.name, "lib/class.nom", function(__callsite)
return utils.keys(\%class_identifier.instances);
end, "");
nomsu:define_action("new "..\%class_identifier.name.." %instance", "lib/class.nom", function(__callsite, _instance)
return \%class_identifier(_instance);
end, "");
nomsu:define_action("new "..\%class_identifier.name, "lib/class.nom", function(__callsite)
return \%class_identifier({});
end, "");
end -- End of definition of \%class_identifier
\("\n\n")