aboutsummaryrefslogtreecommitdiff
path: root/lib/object.nom
blob: ddbb2b54072e83e2acfad515e7627334198d081b (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
#!/usr/bin/env nomsu -V2.5.5.5
#
    This file contains the implementation of an Object-Oriented programming system.

test:
    object "Dog":
        (class Dog).genus = "Canus"
        method [initialize %] (%.barks or= 0)
        method [bark, woof]:
            %barks = ("Bark!" for % in 1 to (me).barks)
            return (%barks joined with " ")
        
        method [get pissed off] ((me).barks += 1)
    
    %d = (new Dog {barks:2})
    as %d:
        assume ((me) == %d)
        assume ((me).barks == 2)
        assume ((bark) == "Bark! Bark!")
        assume ((woof) == "Bark! Bark!")
        get pissed off
        assume ((me).barks == 3)
        assume ((bark) == "Bark! Bark! Bark!")
        assume ((me).genus == "Canus")
    
    assume ("\(%d.class)" == "Dog")
    assume (%d.genus == "Canus")
    assume (%d.barks == 3)
    as (new Dog) (assume ((me).barks == 0) or barf "Default initializer failed")
    as (new Dog {barks:1}) (assume ((bark) == "Bark!"))
    action [foo] (as (new Dog {barks:23}) (return (me).barks))
    assume ((foo) == 23) or barf "Oops, \(foo) != 23"
    as (new Dog {barks:101}):
        try (as (new Dog {barks:8}) (barf)) and if it succeeds (barf)
        assume ((me).barks == 101) or barf ".."
            Error in nested 'as % %' failed to properly reset 'self'
    
    object "Corgi" extends (class Dog):
        method [sploot] "splooted"
        method [bark, woof]:
            %barks = ("Yip!" for % in 1 to (me).barks)
            return (%barks joined with " ")

    %corg = (new Corgi)
    assume (%corg.barks == 0)
    as (new Corgi {barks:1}):
        assume ((sploot) == "splooted") or barf "subclass method failed"
        assume ((bark) == "Yip!") or barf "inheritance failed"
        assume ((woof) == "Yip!")
    
    as (new Dog {barks:2}):
        assume ((bark) == "Bark! Bark!")

compile [@, me] to (Lua value "self")
compile [method %actions %body] to:
    %lua = (\(local action \[%actions.1] %body) as lua)
    declare locals in %lua
    for % in %actions:
        to %lua write "\n\(\%class as lua id).\(% as lua id) = \(%actions.1 as lua id)"
    %lua = (..)
        Lua ".."
            do -- Method: \(%actions.(1).stub)
                \%lua
            end
    return %lua

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

parse [as %instance %body] as (..)
    result of:
        %old_self = (me)
        (me) = %instance
        try %body and if it barfs %msg:
            (me) = %old_self
            barf %msg
        ..or if it succeeds: (me) = %old_self

compile [object %classname extends %parent %class_body] to:
    %class = (\%class as lua id)
    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 cls.A_initialize_1 then
                            cls.A_initialize_1(inst)
                        end
                        return inst
                    end,
                })
                _ENV["A"..string.as_lua_id("new "..\%class.name)] = \%class
                _ENV["A"..string.as_lua_id("new "..\%class.name.." 1")] = \%class
                _ENV["A"..string.as_lua_id("class "..\%class.name)] = function() return \%class end
                \%class.__index = \%class
                \%class.class = \%class
            
                \(%class_body as lua statements)
            
                \%class.__tostring = \%class["A"..string.as_lua_id("as text")] or function(inst)
                    return inst.name..getmetatable(dict{}).__tostring(inst)
                end
            end

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

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