aboutsummaryrefslogtreecommitdiff
path: root/lib/object2.nom
diff options
context:
space:
mode:
Diffstat (limited to 'lib/object2.nom')
-rw-r--r--lib/object2.nom135
1 files changed, 135 insertions, 0 deletions
diff --git a/lib/object2.nom b/lib/object2.nom
new file mode 100644
index 0000000..5e77a05
--- /dev/null
+++ b/lib/object2.nom
@@ -0,0 +1,135 @@
+use "core"
+
+compile [@] to {expr:"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 {expr="self."..key_attr};
+ elseif key_lua:sub(1,1) == "[" then
+ key_lua = " "..key_lua.." ";
+ end
+ return {expr="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 {statements="self."..key_attr.." = "..val_lua..";"};
+ elseif key_lua:sub(1,1) == "[" then
+ key_lua = " "..key_lua.." ";
+ end
+ return {statements="self["..key_lua.."] = "..val_lua..";"};
+
+compile [as %instance %body] to:
+ %body_lua <- (%body as lua)
+ return {..}
+ statements: ".."
+ do
+ local self = \(%instance as lua expr);
+ local global_actions = ACTION;
+ local ACTION = 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's "statements") or "\(%body_lua's "expr");")
+ end
+ locals: %body_lua's "locals"
+
+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 <- []
+ 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 'define object % %', not \(%line's "src")"
+ %actions <- (2nd in (%line's "value"))
+ %body <- (3rd in (%line's "value"))
+ lua> ".."
+ local signature = {};
+ for i, action in ipairs(\%actions.value) do signature[i] = action:get_src(); end
+ local stubs = nomsu:get_stubs_from_signature(signature);
+ local stub_args = nomsu:get_args_from_signature(signature);
+ local arg_set = {};
+ for i, arg in ipairs(stub_args[1]) do arg_set[arg] = true; end
+ local body_lua = nomsu:tree_to_lua(\%body);
+ local body_code = body_lua.statements or ("return "..body_lua.expr..";");
+ local undeclared_locals = {};
+ for i, body_local in ipairs(body_lua.locals or {}) do
+ if not arg_set[body_local] then
+ table.insert(undeclared_locals, body_local);
+ end
+ end
+ if #undeclared_locals > 0 then
+ body_code = "local "..table.concat(undeclared_locals, ", ")..";\\n"..body_code;
+ end
+ local lua_fn_args = table.concat({"self", unpack(stub_args[1])}, ", ");
+ local def_tree = nomsu.compilestack[#nomsu.compilestack];
+ local code_location = ("%s:%s,%s"):format(def_tree.filename, def_tree.start, def_tree.stop);
+
+ local compiled_args = {};
+ for i, arg in ipairs(stub_args[1]) do
+ compiled_args[i] = "nomsu:tree_to_lua("..arg..").expr";
+ 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_code));
+
+ return {..}
+ statements:".."
+ 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, 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:
+ \(%methods joined 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")
+