aboutsummaryrefslogtreecommitdiff
path: root/notes/union_sum_types.txt
blob: 61f1675f3ee3ac2357d914fb22c3d4f0dcc9bd67 (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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133

Union/Sum types
===============

How about allowing multiple `data` blocks with names:

For example, in file `Expr.slul`:

    # Common data
    data
        int line
        int column
    end

    data Unary
        Expr op
    end

    data Binary
        Expr op1
        Expr op2
    end

    data IntegerLiteral
        bool negative
        uint64 value
    end

    data StringLiteral
        # some kind of duplicate handling is necessary.
        # maybe there should be a single identifier tree,
        # and then a subtree if it's a union field.
        # perhaps use (fieldname,union-index) as the key in the ident tree?
        String value
    end

    func print
        PrintWriter pw
        int indent
    # is this necessary? can't we just assume that all non-functions are
    # instance variables?
    #   * in that case, maybe typeidents would need to be prefixed?
    #   * or, just require that fields are declared before functions
    accesses
        Unary.operand
        Binary.operand1
        Binary.operand2
        IntegerLiteral.negative
        IntegerLiteral.value
        StringLiteral.value
    code
        print_indent pw indent
        switch this.kind
        case Unary
            pw.print "unary("
            op.print pw (indent+1)
        case Binary
            pw.print "binary("
            op1.print pw (indent+1)
            op2.print pw (indent+1)
        case IntegerLiteral
            pw.print "int_literal("
            pw.print (switch negative [true "-"] [false ""]) number.to_str
        case StringLiteral
            pw.print "string_literal("
            pw.string "\"" value.c_string_escape() "\""
        end
        pw.println ")"
        # it could also be (would look nicer in this case, but if only
        # printing from one function then it will not align as nicely)
        ")".println pw
        # or, have some kind of special coroutine that yields stuff to print?
        yield "unary("
        yield (op.to_str (indent+1))
        yield .newline
        # alternatively, one could simply use different names:
        pw.print "unary("
        op.dump pw (indent+1)
        # or
        pw.print "unary("
        op.print_to pw (indent+1)
    end


More compact syntax:

    data
        int line
        int column
    case Unary
        Expr op
    case Binary
        Expr op1
        Expr op2
    case IntegerLiteral
        bool negative
        uint64 value
    case StringLiteral
        # some kind of duplicate handling is necessary.
        # maybe there should be a single identifier tree,
        # and then a subtree if it's a union field.
        # perhaps use (fieldname,union-index) as the key in the ident tree?
        String value
    end

    func dump
        io PrintWriter pw
        int indent
    code
        dump_indent pw indent
        specific
        pw.println
    case Unary
        pw.print "unary("
        op.print pw (indent+1)
    case Binary
        pw.print "binary("
        op1.print pw (indent+1)
        op2.print pw (indent+1)
    case IntegerLiteral
        pw.print "int_literal("
        pw.print (switch negative [true "-"] [false ""]) number.to_str
    case StringLiteral
        pw.print "string_literal("
        pw.string "\"" value.c_string_escape() "\""
    end

Keyword
-------

* case
* only
* subtype
* when