aboutsummaryrefslogtreecommitdiff
path: root/lib/object.nom
blob: 67c6b73d5e546a565289b4000842705a9f859a8b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#!/usr/bin/env nomsu -V3.6.5.6
#
    This file contains the implementation of an Object-Oriented programming system.

test:
    object "Dog":
        (Dog).genus = "Canus"
        my action [set up]: %me.barks or= 0
        my action [bark, woof]:
            %barks = ("Bark!" for % in 1 to %me.barks)
            return (%barks joined with " ")
        
        my action [get pissed off]: %me.barks += 1
    
    %d = (new Dog {barks:2})
    assume (%d.barks == 2)
    assume ((%d::bark) == "Bark! Bark!")
    assume ((%d::woof) == "Bark! Bark!")
    %d::get pissed off
    assume (%d.barks == 3)
    assume ((%d::bark) == "Bark! Bark! Bark!")
    assume (%d.genus == "Canus")
    assume ("\(%d.class)" == "Dog")
    assume (%d.genus == "Canus")
    assume (%d.barks == 3)
    %d2 = (new Dog)
    assume (%d2.barks == 0) or barf "Default initializer failed"
    with {%d:new Dog {barks:1}}:
        assume ((%d::bark) == "Bark!")
    object "Corgi" extends (Dog):
        my action [sploot] "splooted"
        my action [bark, woof]:
            %barks = ("Yip!" for % in 1 to %me.barks)
            return (%barks joined with " ")
    
    %corg = (new Corgi)
    assume (%corg.barks == 0)
    with {%d:new Corgi {barks:1}}:
        assume ((%d::sploot) == "splooted") or barf "subclass method failed"
        assume ((%d::bark) == "Yip!") or barf "inheritance failed"
        assume ((%d::woof) == "Yip!")
    
    with {%d:new Dog {barks:2}}:
        assume ((%d::bark) == "Bark! Bark!")
compile [my action %actions %body] to:
    lua> ".."
        local fn_name = string.as_lua_id(\%actions[1].stub)
        local \%args = table.map(\%actions[1]:get_args(), function(a) return tostring(nomsu:compile(a)) end)
        table.insert(\%args, \(\%me as lua id))
        local lua = LuaCode(tree.source, "class.", fn_name, " = ", \(..)
            compile as (%args -> %body)
        ..)
        for i=2,#\%actions do
            local alias = \%actions[i]
            local alias_name = string.as_lua_id(alias.stub)
            local \%alias_args = table.map(alias:get_args(), function(a) return tostring(nomsu:compile(a)) end)
            table.insert(\%alias_args, \(\%me as lua id))
            lua:append("\\nclass.", alias_name, " = ")
            if utils.equivalent(\%args, \%alias_args) then
                lua:append("class.", fn_name)
            else
                lua:append("function(")
                lua:concat_append(\%alias_args, ", ")
                lua:append(")\\n    return class.", fn_name, "(")
                lua:concat_append(\%args, ", ")
                lua:append(")\\nend")
            end
        end
        return lua

compile [object %classname extends %parent %class_body] to:
    return (..)
        Lua ".."
            do
                local class = {name=\(%classname as lua expr)}
                setmetatable(class, {
                    __index=\(%parent as lua expr),
                    __tostring=function(cls) return cls.name end,
                    __call=function(cls, inst)
                        inst = setmetatable(inst or {}, cls)
                        if inst.set_up then
                            inst:set_up()
                        end
                        return inst
                    end,
                })
                nomsu["A_"..string.as_lua_id("new "..class.name)] = class
                nomsu["A_"..string.as_lua_id("new "..class.name.." 1")] = class
                nomsu["A_"..string.as_lua_id(class.name)] = function() return class end
                class.__index = class
                class.class = class
                class.__tostring = function(inst)
                    return inst.name..getmetatable(dict{}).__tostring(inst)
                end
            
                \(%class_body as lua statements)
            
                local metamethod_map = {["as text"]="__tostring", ["clean up"]="__gc",
                    ["+ 1"]="__add", ["- 1"]="__sub", ["* 1"]="__mul", ["/ 1"]="__div",
                    ["-"]="__unm", ["// 1"]="__idiv", ["mod 1"]="__mod", ["^ 1"]="__pow",
                    ["& 1"]="__band", ["| 1"]="__bor", ["~ 1"]="__bxor", ["~"]="__bnot",
                    ["<< 1"]="__bshl", [">> 1"]="__bshr", ["== 1"]="__eq", ["< 1"]="__lt",
                    ["<= 1"]="__le", ["set 1 = 2"]="__newindex", ["length"]="__len",
                    ["__ipairs"]="__ipairs", ["__pairs"]="__pairs",
                }
                for stub,metamethod in pairs(metamethod_map) do
                    class[metamethod] = class[string.as_lua_id(stub)]
                end
            end

parse [object %classname %class_body] as (..)
    object %classname extends (nil) %class_body