~ubuntu-branches/ubuntu/vivid/golang/vivid

« back to all changes in this revision

Viewing changes to doc/talks/io2010/eval1.go

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2013-08-20 14:06:23 UTC
  • mfrom: (14.1.23 saucy-proposed)
  • Revision ID: package-import@ubuntu.com-20130820140623-b414jfxi3m0qkmrq
Tags: 2:1.1.2-2ubuntu1
* Merge from Debian unstable (LP: #1211749, #1202027). Remaining changes:
  - 016-armhf-elf-header.patch: Use correct ELF header for armhf binaries.
  - d/control,control.cross: Update Breaks/Replaces for Ubuntu
    versions to ensure smooth upgrades, regenerate control file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// Copyright 2010 The Go Authors.  All rights reserved.
2
 
// Use of this source code is governed by a BSD-style
3
 
// license that can be found in the LICENSE file.
4
 
 
5
 
package main
6
 
 
7
 
import (
8
 
        "bufio"
9
 
        "fmt"
10
 
        "os"
11
 
        "strconv"
12
 
        "strings"
13
 
)
14
 
 
15
 
// Generic expression parser/evaluator
16
 
 
17
 
type Value interface {
18
 
        String() string
19
 
        BinaryOp(op string, y Value) Value
20
 
}
21
 
 
22
 
type Parser struct {
23
 
        precTab map[string]int
24
 
        newVal  func(string) Value
25
 
        src     string
26
 
        pos     int
27
 
        tok     string
28
 
}
29
 
 
30
 
const alphanum = "_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
31
 
 
32
 
func (p *Parser) stop(c uint8) bool {
33
 
        switch {
34
 
        case p.pos >= len(p.src):
35
 
                return true
36
 
        case c == '"':
37
 
                if p.src[p.pos] == '"' {
38
 
                        p.pos++
39
 
                        return true
40
 
                }
41
 
                return false
42
 
        case strings.IndexRune(alphanum, int(c)) >= 0:
43
 
                return strings.IndexRune(alphanum, int(p.src[p.pos])) < 0
44
 
        }
45
 
        return true
46
 
}
47
 
 
48
 
func (p *Parser) next() {
49
 
        // skip blanks
50
 
        for ; p.pos < len(p.src) && p.src[p.pos] <= ' '; p.pos++ {
51
 
        }
52
 
        if p.pos >= len(p.src) {
53
 
                p.tok = ""
54
 
                return
55
 
        }
56
 
        start := p.pos
57
 
        c := p.src[p.pos]
58
 
        for p.pos < len(p.src) {
59
 
                p.pos++
60
 
                if p.stop(c) {
61
 
                        break
62
 
                }
63
 
        }
64
 
        p.tok = p.src[start:p.pos]
65
 
}
66
 
 
67
 
func (p *Parser) binaryExpr(prec1 int) Value {
68
 
        x := p.newVal(p.tok)
69
 
        p.next()
70
 
        for prec := p.precTab[p.tok]; prec >= prec1; prec-- {
71
 
                for p.precTab[p.tok] == prec {
72
 
                        op := p.tok
73
 
                        p.next()
74
 
                        y := p.binaryExpr(prec + 1)
75
 
                        x = x.BinaryOp(op, y)
76
 
                }
77
 
        }
78
 
        return x
79
 
}
80
 
 
81
 
func Eval(precTab map[string]int, newVal func(string) Value, src string) Value {
82
 
        var p Parser
83
 
        p.precTab = precTab
84
 
        p.newVal = newVal
85
 
        p.src = src
86
 
        p.next()
87
 
        return p.binaryExpr(1)
88
 
}
89
 
 
90
 
// Command-line expression evaluator
91
 
 
92
 
func main() {
93
 
        r := bufio.NewReader(os.Stdin)
94
 
        for {
95
 
                fmt.Printf("> ")
96
 
                line, err := r.ReadString('\n')
97
 
                if err != nil {
98
 
                        break
99
 
                }
100
 
                fmt.Printf("%s\n", Eval(precTab, trace(newVal), line))
101
 
        }
102
 
}
103
 
 
104
 
// Custom grammar and values
105
 
 
106
 
var precTab = map[string]int{
107
 
        "&&": 1,
108
 
        "||": 2,
109
 
        "==": 3,
110
 
        "!=": 3,
111
 
        "<":  3,
112
 
        "<=": 3,
113
 
        ">":  3,
114
 
        ">=": 3,
115
 
        "+":  4,
116
 
        "-":  4,
117
 
        "*":  5,
118
 
        "/":  5,
119
 
        "%":  5,
120
 
}
121
 
 
122
 
func newVal(lit string) Value {
123
 
        x, err := strconv.Atoi(lit)
124
 
        if err == nil {
125
 
                return Int(x)
126
 
        }
127
 
        b, err := strconv.ParseBool(lit)
128
 
        if err == nil {
129
 
                return Bool(b)
130
 
        }
131
 
        return Error(fmt.Sprintf("illegal literal '%s'", lit))
132
 
}
133
 
 
134
 
type Error string
135
 
 
136
 
func (e Error) String() string                    { return string(e) }
137
 
func (e Error) BinaryOp(op string, y Value) Value { return e }
138
 
 
139
 
type Int int
140
 
 
141
 
func (x Int) String() string { return strconv.Itoa(int(x)) }
142
 
func (x Int) BinaryOp(op string, y Value) Value {
143
 
        switch y := y.(type) {
144
 
        case Error:
145
 
                return y
146
 
        case Int:
147
 
                switch op {
148
 
                case "+":
149
 
                        return x + y
150
 
                case "-":
151
 
                        return x - y
152
 
                case "*":
153
 
                        return x * y
154
 
                case "/":
155
 
                        return x / y
156
 
                case "%":
157
 
                        return x % y
158
 
                case "==":
159
 
                        return Bool(x == y)
160
 
                case "!=":
161
 
                        return Bool(x != y)
162
 
                case "<":
163
 
                        return Bool(x < y)
164
 
                case "<=":
165
 
                        return Bool(x <= y)
166
 
                case ">":
167
 
                        return Bool(x > y)
168
 
                case ">=":
169
 
                        return Bool(x >= y)
170
 
                }
171
 
        }
172
 
        return Error(fmt.Sprintf("illegal operation: '%v %s %v'", x, op, y))
173
 
}
174
 
 
175
 
type Bool bool
176
 
 
177
 
func (x Bool) String() string { return strconv.FormatBool(bool(x)) }
178
 
func (x Bool) BinaryOp(op string, y Value) Value {
179
 
        switch y := y.(type) {
180
 
        case Error:
181
 
                return y
182
 
        case Bool:
183
 
                switch op {
184
 
                case "&&":
185
 
                        return Bool(x && y)
186
 
                case "||":
187
 
                        return Bool(x || y)
188
 
                case "==":
189
 
                        return Bool(x == y)
190
 
                case "!=":
191
 
                        return Bool(x != y)
192
 
                }
193
 
        }
194
 
        return Error(fmt.Sprintf("illegal operation: '%v %s %v'", x, op, y))
195
 
}
196
 
 
197
 
func trace(newVal func(string) Value) func(string) Value {
198
 
        return func(s string) Value {
199
 
                v := newVal(s)
200
 
                fmt.Printf("\tnewVal(%q) = %s\n", s, fmtv(v))
201
 
                return &traceValue{v}
202
 
        }
203
 
}
204
 
 
205
 
type traceValue struct {
206
 
        Value
207
 
}
208
 
 
209
 
func (x *traceValue) BinaryOp(op string, y Value) Value {
210
 
        z := x.Value.BinaryOp(op, y.(*traceValue).Value)
211
 
        fmt.Printf("\t%s.BinaryOp(%q, %s) = %s\n", fmtv(x.Value), op, fmtv(y.(*traceValue).Value), fmtv(z))
212
 
        return &traceValue{z}
213
 
}
214
 
 
215
 
func (x *traceValue) String() string {
216
 
        s := x.Value.String()
217
 
        fmt.Printf("\t%s.String() = %#v\n", fmtv(x.Value), s)
218
 
        return s
219
 
}
220
 
 
221
 
func fmtv(v Value) string {
222
 
        t := fmt.Sprintf("%T", v)
223
 
        if i := strings.LastIndex(t, "."); i >= 0 { // strip package
224
 
                t = t[i+1:]
225
 
        }
226
 
        return fmt.Sprintf("%s(%#v)", t, v)
227
 
}