-
Notifications
You must be signed in to change notification settings - Fork 2
/
expr.go
128 lines (108 loc) · 2.66 KB
/
expr.go
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
// Copyright (c) 2013 Ostap Cherkashin. You can use this source code
// under the terms of the MIT License found in the LICENSE file.
package main
import (
"bytes"
"fmt"
"strconv"
"sync/atomic"
)
type Expr struct {
Id int64
Name string
Code func() []Op
}
var BadExpr = Expr{0, "", nil}
var exprSeqNum int64 = 1
func nextEID() int64 {
return atomic.AddInt64(&exprSeqNum, 1)
}
func ExprLoad(name string, addr int) Expr {
return Expr{nextEID(), name, func() []Op {
return []Op{OpLoad(addr)}
}}
}
func ExprObject(fields []Expr) Expr {
name := new(bytes.Buffer)
fmt.Fprintf(name, "{")
for i, f := range fields {
if i != 0 {
fmt.Fprintf(name, ", ")
}
fmt.Fprintf(name, f.Name)
}
fmt.Fprintf(name, "}")
return Expr{nextEID(), name.String(), func() []Op {
code := []Op{OpObject(len(fields))}
for i, f := range fields {
for _, c := range f.Code() {
code = append(code, c)
}
code = append(code, OpSet(i))
}
return code
}}
}
func ExprList(elems []Expr) Expr {
// TODO: compose a name
return Expr{nextEID(), "", func() []Op {
code := []Op{OpList()}
for _, e := range elems {
for _, c := range e.Code() {
code = append(code, c)
}
code = append(code, OpAppend())
}
return code
}}
}
func ExprComp(loop *Loop, resAddr int) Expr {
// TODO: compose a name
return Expr{nextEID(), "", func() []Op {
return append(loop.Code(), OpLoad(resAddr))
}}
}
func (e Expr) Field(name string, pos *int) Expr {
return Expr{nextEID(), fmt.Sprintf("%v.%v", e.Name, name), func() []Op {
return append(e.Code(), OpGet(*pos))
}}
}
func (e Expr) Index(name string, pos *int) Expr {
return Expr{nextEID(), fmt.Sprintf("%v[%v]", e.Name, name), func() []Op {
return append(e.Code(), OpIndex(*pos))
}}
}
func (l Expr) Binary(r Expr, op Op, name string) Expr {
return Expr{nextEID(), fmt.Sprintf("%v %v %v", l.Name, name, r.Name), func() []Op {
lc := l.Code()
rc := r.Code()
code := make([]Op, len(rc)+len(lc)+1)
copy(code, rc)
copy(code[len(rc):], lc)
code[len(code)-1] = op
return code
}}
}
func (e Expr) Unary(op Op, name string) Expr {
return Expr{nextEID(), fmt.Sprintf("%v%v", name, e.Name), func() []Op {
return append(e.Code(), op)
}}
}
func (e Expr) Match(pattern string, re int) Expr {
name := fmt.Sprintf("%v =~ %v", e.Name, strconv.Quote(pattern))
return Expr{nextEID(), name, func() []Op {
return append(e.Code(), OpMatch(re))
}}
}
func ExprCall(fn int, args []Expr) Expr {
// TODO: compose a name
return Expr{nextEID(), "", func() []Op {
code := make([]Op, 0)
for i := len(args) - 1; i > -1; i-- {
for _, c := range args[i].Code() {
code = append(code, c)
}
}
return append(code, OpCall(fn))
}}
}