├── .gitignore ├── .travis.yml ├── LICENSE ├── Makefile ├── README.md ├── bench_test.go ├── bytecode ├── Frame.go ├── Op.go ├── OpAdd.go ├── OpDiv.go ├── OpInvoke.go ├── OpMul.go ├── OpPushFalse.go ├── OpPushInt.go ├── OpPushStr.go ├── OpPushTrue.go ├── OpPushVector.go ├── OpSub.go ├── Program.go ├── Version.go └── proto.fbs ├── cmd └── expr │ └── main.go ├── compiler └── compiler.go ├── delegate ├── delegator.go ├── registry.go ├── tracing.go └── tracing_test.go ├── example_test.go ├── exec ├── errors.go ├── globals.go ├── stack.go ├── vm.go └── vm_test.go ├── go.mod ├── go.sum ├── lexer ├── ast.go ├── init.go ├── lexer.go ├── lexer.go.rl ├── lexer_test.go ├── node.go └── nvec.go ├── memory ├── addr.go ├── addr_test.go ├── grid.go ├── heap.go ├── memory.go ├── memory_test.go ├── type.go └── type_test.go └── stdlib ├── compare.go ├── compare_test.go ├── strings.go └── strings_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | expr.test 2 | coverage.txt 3 | cpu.out 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - tip 5 | - stable 6 | 7 | jobs: 8 | allow_failures: 9 | - go: tip 10 | 11 | script: 12 | - go test -race -coverprofile=coverage.txt -covermode=atomic ./... 13 | 14 | after_success: 15 | - bash <(curl -s https://codecov.io/bash) 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Anthony Regeda 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: gen-fbs gen-lexer test bench bench-report escape-analysis 2 | 3 | default: test 4 | 5 | gen-fbs: 6 | @rm -f bytecode/*.go 7 | @flatc -g -o . bytecode/proto.fbs 8 | 9 | gen-lexer: 10 | @ragel -Z -G2 lexer/lexer.go.rl -o lexer/lexer.go 11 | @goimports -w lexer/lexer.go 12 | 13 | test: gen-fbs gen-lexer 14 | @go test -v -cover ./... 15 | 16 | bench: test 17 | @go test -v -bench=. -run=- -benchmem -cpuprofile cpu.out 18 | 19 | bench-report: bench 20 | @go tool pprof -web cpu.out 21 | 22 | escape-analysis: ; @go test -gcflags="-m" ./... 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Expr – a tiny stack-based virtual machine written in Go 2 | 3 | [![Build Status](https://travis-ci.com/regeda/expr.svg?branch=main)](https://travis-ci.com/regeda/expr) 4 | [![codecov](https://codecov.io/gh/regeda/expr/branch/main/graph/badge.svg?token=99QXNC2IAO)](https://codecov.io/gh/regeda/expr) 5 | [![Go Reference](https://pkg.go.dev/badge/gihub.com/regeda/expr.svg)](https://pkg.go.dev/github.com/regeda/expr) 6 | 7 | The executor is designed to interpret **a simple expression language** and it's useful in delegating decision enforcement to user scripts. 8 | 9 | User scripts can produce scalar or array variables. 10 | 11 | You can easily embed the toolchain in your Go application. 12 | 13 | The executor is blazingly fast and it makes no memory allocation. 14 | 15 | You can add custom functions to the executor empowering your application. 16 | 17 | ## Syntax 18 | 19 | ### Data types 20 | 21 | *integer* (64 bit) 22 | ```js 23 | -9223372036854775808 .. 9223372036854775807 24 | ``` 25 | 26 | *string* (wrapped by double quote) 27 | ```js 28 | "Hello Expr!" 29 | "Welcome \"Alice\" and \"Bob\"" 30 | ``` 31 | 32 | *boolean* 33 | ```js 34 | true, false 35 | ``` 36 | 37 | *array* (a vector of elements) 38 | ```js 39 | [1, true, "text"] 40 | [["hello"], "world!"] 41 | ``` 42 | 43 | ### Operators 44 | 45 | The virtual machine supports basic math operators `+-*/`. A math expression might be surrounded by parentheses. 46 | Examples: 47 | ``` 48 | 1 + -1 49 | 1 * (2 + 3) 50 | ``` 51 | 52 | ### Delegators 53 | 54 | In general, delegators are functions implemented by the hosted application. 55 | 56 | Helpfully, this toolchain is equipped with an own standard library to handle basic operation on its data types. 57 | 58 | #### stdlib 59 | 60 | ###### `concat(string, ...)` 61 | returns a concatenated string 62 | ```js 63 | concat("a", "b", "c") // "abc" 64 | ``` 65 | 66 | ###### `join(string, [string, ...])` 67 | returns a concatenated string with a separator 68 | ```js 69 | join(", ", ["a", "b", "c"]) // "a, b, c" 70 | ``` 71 | 72 | ###### `equals(string, string)` 73 | ###### `equals(int64, int64)` 74 | ###### `equals([string, ...], [string, ...])` 75 | ###### `equals([int64, ...], [int64, ...])` 76 | returns `true` if both arguments are equal 77 | ```js 78 | equals(1, 1) // true 79 | equals(1, 0) // false 80 | equals("foo", "foo") // true 81 | equals("foo", "bar") // false 82 | equals(["foo", 1], ["foo", 1]) // true 83 | equals(["foo"], ["bar"]) // false 84 | ``` 85 | 86 | ###### `intersects([string, ...], [string, ...])` 87 | ###### `intersects([int64, ...], [int64, ...])` 88 | returns `true` if both arrays share the same item 89 | ```js 90 | intersects([1, 2, 3], [3, 4]) // true 91 | intersects([1, 2, 3], [4, 5]) // false 92 | ``` 93 | 94 | ###### `contains([string, ...], string)` 95 | ###### `contains([int64, ...], int64)` 96 | returns `true` if the value exists in the array 97 | ```js 98 | contains([1, 2, 3], 1) // true 99 | contains([1, 2, 3], 4) // false 100 | ``` 101 | 102 | ## Architecture 103 | 104 | The architecture consists of 3 components: 105 | 1. Lexer 106 | 2. Compiler 107 | 3. Virtual Machine 108 | 109 | **The lexer** parses the input text: 110 | ``` 111 | join(",", ["a", "b"]) 112 | ``` 113 | and generates a syntax tree: 114 | ``` 115 | STR "," 116 | STR "a" 117 | STR "b" 118 | ARR 2 119 | INVOKE join 2 120 | ``` 121 | > The lexer is implemented using [Ragel State Machine Compiler](https://www.colm.net/open-source/ragel/). 122 | 123 | **The compiler** makes a bytecode from the syntax tree to make it executable by **a stack-based virtual machine**. 124 | > The bytecode is described by [Flatbuffers](https://google.github.io/flatbuffers/flatbuffers_guide_use_go.html) to achieve high-throughput with low memory consumption. 125 | 126 | ## Usage 127 | 128 | Compilation: 129 | ```go 130 | import ( 131 | "github.com/regeda/expr/compiler" 132 | "github.com/regeda/expr/lexer" 133 | ) 134 | 135 | code := `join(",", ["a", "b"])` 136 | 137 | tokens, err := lexer.Parse([]byte(code)) 138 | if err != nil { 139 | panic(err) 140 | } 141 | 142 | bytecode := compiler.Compile(tokens) 143 | 144 | // save `bytecode` to be executed by the virtual machine 145 | ``` 146 | 147 | Running: 148 | ```go 149 | import ( 150 | "github.com/regeda/expr/delegate" 151 | "github.com/regeda/expr/exec" 152 | "github.com/regeda/expr/stdlib" 153 | ) 154 | 155 | bytecode := ... // read []byte 156 | 157 | ex := exec.New( 158 | exec.WithRegistry(delegate.Import(stdlib.Compare, stdlib.Strings)), 159 | ) 160 | addr, err := ex.Exec(bytecode) 161 | if err != nil { 162 | panic(err) 163 | } 164 | // `addr` contains the result, see github.com/regeda/expr/memory.Addr 165 | ``` 166 | > `Exec` is **not designed** to be run in the concurrent environment. However, you can define a pool of executors to consume them in the safe mode. 167 | 168 | ## Benchmark 169 | 170 | The benchmark executes a compiled bytecode of the following statement: 171 | ```js 172 | equals("foo,bar,baz", join(",", ["foo", "bar", "baz"])) 173 | ``` 174 | ``` 175 | cpu: Intel(R) Core(TM) i5-8259U CPU @ 2.30GHz 176 | BenchmarkExec 177 | BenchmarkExec-8 1635091 746.7 ns/op 0 B/op 0 allocs/op 178 | ``` 179 | -------------------------------------------------------------------------------- /bench_test.go: -------------------------------------------------------------------------------- 1 | package expr_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/regeda/expr/compiler" 7 | "github.com/regeda/expr/delegate" 8 | "github.com/regeda/expr/exec" 9 | "github.com/regeda/expr/lexer" 10 | "github.com/regeda/expr/memory" 11 | "github.com/regeda/expr/stdlib" 12 | ) 13 | 14 | func BenchmarkExec(b *testing.B) { 15 | var comp compiler.Compiler 16 | 17 | ex := exec.New( 18 | exec.WithRegistry(delegate.Import(stdlib.Compare, stdlib.Strings)), 19 | exec.WithStackSize(0xff), 20 | exec.WithMemory( 21 | memory.New( 22 | memory.PreallocHeap(0xff), 23 | memory.PreallocGrid(0xff), 24 | ), 25 | ), 26 | ) 27 | 28 | bcode := comp.Compile([]lexer.Node{ 29 | {Typ: lexer.TypStr, DatS: "foo,bar,baz"}, 30 | {Typ: lexer.TypStr, DatS: ","}, 31 | {Typ: lexer.TypStr, DatS: "foo"}, 32 | {Typ: lexer.TypStr, DatS: "bar"}, 33 | {Typ: lexer.TypStr, DatS: "baz"}, 34 | {Typ: lexer.TypVector, Cap: 3}, 35 | {Typ: lexer.TypInvoke, DatS: "join", Cap: 2}, 36 | {Typ: lexer.TypInvoke, DatS: "equals", Cap: 2}, 37 | }) 38 | 39 | b.ResetTimer() 40 | 41 | for i := 0; i < b.N; i++ { 42 | _, err := ex.Exec(bcode) 43 | if err != nil { 44 | b.FailNow() 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /bytecode/Frame.go: -------------------------------------------------------------------------------- 1 | // Code generated by the FlatBuffers compiler. DO NOT EDIT. 2 | 3 | package bytecode 4 | 5 | import ( 6 | flatbuffers "github.com/google/flatbuffers/go" 7 | ) 8 | 9 | type Frame struct { 10 | _tab flatbuffers.Table 11 | } 12 | 13 | func GetRootAsFrame(buf []byte, offset flatbuffers.UOffsetT) *Frame { 14 | n := flatbuffers.GetUOffsetT(buf[offset:]) 15 | x := &Frame{} 16 | x.Init(buf, n+offset) 17 | return x 18 | } 19 | 20 | func (rcv *Frame) Init(buf []byte, i flatbuffers.UOffsetT) { 21 | rcv._tab.Bytes = buf 22 | rcv._tab.Pos = i 23 | } 24 | 25 | func (rcv *Frame) Table() flatbuffers.Table { 26 | return rcv._tab 27 | } 28 | 29 | func (rcv *Frame) OpType() Op { 30 | o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) 31 | if o != 0 { 32 | return Op(rcv._tab.GetByte(o + rcv._tab.Pos)) 33 | } 34 | return 0 35 | } 36 | 37 | func (rcv *Frame) MutateOpType(n Op) bool { 38 | return rcv._tab.MutateByteSlot(4, byte(n)) 39 | } 40 | 41 | func (rcv *Frame) Op(obj *flatbuffers.Table) bool { 42 | o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) 43 | if o != 0 { 44 | rcv._tab.Union(obj, o) 45 | return true 46 | } 47 | return false 48 | } 49 | 50 | func FrameStart(builder *flatbuffers.Builder) { 51 | builder.StartObject(2) 52 | } 53 | func FrameAddOpType(builder *flatbuffers.Builder, opType Op) { 54 | builder.PrependByteSlot(0, byte(opType), 0) 55 | } 56 | func FrameAddOp(builder *flatbuffers.Builder, op flatbuffers.UOffsetT) { 57 | builder.PrependUOffsetTSlot(1, flatbuffers.UOffsetT(op), 0) 58 | } 59 | func FrameEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { 60 | return builder.EndObject() 61 | } 62 | -------------------------------------------------------------------------------- /bytecode/Op.go: -------------------------------------------------------------------------------- 1 | // Code generated by the FlatBuffers compiler. DO NOT EDIT. 2 | 3 | package bytecode 4 | 5 | import "strconv" 6 | 7 | type Op byte 8 | 9 | const ( 10 | OpNONE Op = 0 11 | OpOpPushStr Op = 1 12 | OpOpPushInt Op = 2 13 | OpOpPushTrue Op = 3 14 | OpOpPushFalse Op = 4 15 | OpOpPushVector Op = 5 16 | OpOpInvoke Op = 6 17 | OpOpAdd Op = 7 18 | OpOpSub Op = 8 19 | OpOpMul Op = 9 20 | OpOpDiv Op = 10 21 | ) 22 | 23 | var EnumNamesOp = map[Op]string{ 24 | OpNONE: "NONE", 25 | OpOpPushStr: "OpPushStr", 26 | OpOpPushInt: "OpPushInt", 27 | OpOpPushTrue: "OpPushTrue", 28 | OpOpPushFalse: "OpPushFalse", 29 | OpOpPushVector: "OpPushVector", 30 | OpOpInvoke: "OpInvoke", 31 | OpOpAdd: "OpAdd", 32 | OpOpSub: "OpSub", 33 | OpOpMul: "OpMul", 34 | OpOpDiv: "OpDiv", 35 | } 36 | 37 | var EnumValuesOp = map[string]Op{ 38 | "NONE": OpNONE, 39 | "OpPushStr": OpOpPushStr, 40 | "OpPushInt": OpOpPushInt, 41 | "OpPushTrue": OpOpPushTrue, 42 | "OpPushFalse": OpOpPushFalse, 43 | "OpPushVector": OpOpPushVector, 44 | "OpInvoke": OpOpInvoke, 45 | "OpAdd": OpOpAdd, 46 | "OpSub": OpOpSub, 47 | "OpMul": OpOpMul, 48 | "OpDiv": OpOpDiv, 49 | } 50 | 51 | func (v Op) String() string { 52 | if s, ok := EnumNamesOp[v]; ok { 53 | return s 54 | } 55 | return "Op(" + strconv.FormatInt(int64(v), 10) + ")" 56 | } 57 | -------------------------------------------------------------------------------- /bytecode/OpAdd.go: -------------------------------------------------------------------------------- 1 | // Code generated by the FlatBuffers compiler. DO NOT EDIT. 2 | 3 | package bytecode 4 | 5 | import ( 6 | flatbuffers "github.com/google/flatbuffers/go" 7 | ) 8 | 9 | type OpAdd struct { 10 | _tab flatbuffers.Table 11 | } 12 | 13 | func GetRootAsOpAdd(buf []byte, offset flatbuffers.UOffsetT) *OpAdd { 14 | n := flatbuffers.GetUOffsetT(buf[offset:]) 15 | x := &OpAdd{} 16 | x.Init(buf, n+offset) 17 | return x 18 | } 19 | 20 | func (rcv *OpAdd) Init(buf []byte, i flatbuffers.UOffsetT) { 21 | rcv._tab.Bytes = buf 22 | rcv._tab.Pos = i 23 | } 24 | 25 | func (rcv *OpAdd) Table() flatbuffers.Table { 26 | return rcv._tab 27 | } 28 | 29 | func OpAddStart(builder *flatbuffers.Builder) { 30 | builder.StartObject(0) 31 | } 32 | func OpAddEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { 33 | return builder.EndObject() 34 | } 35 | -------------------------------------------------------------------------------- /bytecode/OpDiv.go: -------------------------------------------------------------------------------- 1 | // Code generated by the FlatBuffers compiler. DO NOT EDIT. 2 | 3 | package bytecode 4 | 5 | import ( 6 | flatbuffers "github.com/google/flatbuffers/go" 7 | ) 8 | 9 | type OpDiv struct { 10 | _tab flatbuffers.Table 11 | } 12 | 13 | func GetRootAsOpDiv(buf []byte, offset flatbuffers.UOffsetT) *OpDiv { 14 | n := flatbuffers.GetUOffsetT(buf[offset:]) 15 | x := &OpDiv{} 16 | x.Init(buf, n+offset) 17 | return x 18 | } 19 | 20 | func (rcv *OpDiv) Init(buf []byte, i flatbuffers.UOffsetT) { 21 | rcv._tab.Bytes = buf 22 | rcv._tab.Pos = i 23 | } 24 | 25 | func (rcv *OpDiv) Table() flatbuffers.Table { 26 | return rcv._tab 27 | } 28 | 29 | func OpDivStart(builder *flatbuffers.Builder) { 30 | builder.StartObject(0) 31 | } 32 | func OpDivEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { 33 | return builder.EndObject() 34 | } 35 | -------------------------------------------------------------------------------- /bytecode/OpInvoke.go: -------------------------------------------------------------------------------- 1 | // Code generated by the FlatBuffers compiler. DO NOT EDIT. 2 | 3 | package bytecode 4 | 5 | import ( 6 | flatbuffers "github.com/google/flatbuffers/go" 7 | ) 8 | 9 | type OpInvoke struct { 10 | _tab flatbuffers.Table 11 | } 12 | 13 | func GetRootAsOpInvoke(buf []byte, offset flatbuffers.UOffsetT) *OpInvoke { 14 | n := flatbuffers.GetUOffsetT(buf[offset:]) 15 | x := &OpInvoke{} 16 | x.Init(buf, n+offset) 17 | return x 18 | } 19 | 20 | func (rcv *OpInvoke) Init(buf []byte, i flatbuffers.UOffsetT) { 21 | rcv._tab.Bytes = buf 22 | rcv._tab.Pos = i 23 | } 24 | 25 | func (rcv *OpInvoke) Table() flatbuffers.Table { 26 | return rcv._tab 27 | } 28 | 29 | func (rcv *OpInvoke) Args() uint16 { 30 | o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) 31 | if o != 0 { 32 | return rcv._tab.GetUint16(o + rcv._tab.Pos) 33 | } 34 | return 0 35 | } 36 | 37 | func (rcv *OpInvoke) MutateArgs(n uint16) bool { 38 | return rcv._tab.MutateUint16Slot(4, n) 39 | } 40 | 41 | func (rcv *OpInvoke) Name() []byte { 42 | o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) 43 | if o != 0 { 44 | return rcv._tab.ByteVector(o + rcv._tab.Pos) 45 | } 46 | return nil 47 | } 48 | 49 | func OpInvokeStart(builder *flatbuffers.Builder) { 50 | builder.StartObject(2) 51 | } 52 | func OpInvokeAddArgs(builder *flatbuffers.Builder, args uint16) { 53 | builder.PrependUint16Slot(0, args, 0) 54 | } 55 | func OpInvokeAddName(builder *flatbuffers.Builder, name flatbuffers.UOffsetT) { 56 | builder.PrependUOffsetTSlot(1, flatbuffers.UOffsetT(name), 0) 57 | } 58 | func OpInvokeEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { 59 | return builder.EndObject() 60 | } 61 | -------------------------------------------------------------------------------- /bytecode/OpMul.go: -------------------------------------------------------------------------------- 1 | // Code generated by the FlatBuffers compiler. DO NOT EDIT. 2 | 3 | package bytecode 4 | 5 | import ( 6 | flatbuffers "github.com/google/flatbuffers/go" 7 | ) 8 | 9 | type OpMul struct { 10 | _tab flatbuffers.Table 11 | } 12 | 13 | func GetRootAsOpMul(buf []byte, offset flatbuffers.UOffsetT) *OpMul { 14 | n := flatbuffers.GetUOffsetT(buf[offset:]) 15 | x := &OpMul{} 16 | x.Init(buf, n+offset) 17 | return x 18 | } 19 | 20 | func (rcv *OpMul) Init(buf []byte, i flatbuffers.UOffsetT) { 21 | rcv._tab.Bytes = buf 22 | rcv._tab.Pos = i 23 | } 24 | 25 | func (rcv *OpMul) Table() flatbuffers.Table { 26 | return rcv._tab 27 | } 28 | 29 | func OpMulStart(builder *flatbuffers.Builder) { 30 | builder.StartObject(0) 31 | } 32 | func OpMulEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { 33 | return builder.EndObject() 34 | } 35 | -------------------------------------------------------------------------------- /bytecode/OpPushFalse.go: -------------------------------------------------------------------------------- 1 | // Code generated by the FlatBuffers compiler. DO NOT EDIT. 2 | 3 | package bytecode 4 | 5 | import ( 6 | flatbuffers "github.com/google/flatbuffers/go" 7 | ) 8 | 9 | type OpPushFalse struct { 10 | _tab flatbuffers.Table 11 | } 12 | 13 | func GetRootAsOpPushFalse(buf []byte, offset flatbuffers.UOffsetT) *OpPushFalse { 14 | n := flatbuffers.GetUOffsetT(buf[offset:]) 15 | x := &OpPushFalse{} 16 | x.Init(buf, n+offset) 17 | return x 18 | } 19 | 20 | func (rcv *OpPushFalse) Init(buf []byte, i flatbuffers.UOffsetT) { 21 | rcv._tab.Bytes = buf 22 | rcv._tab.Pos = i 23 | } 24 | 25 | func (rcv *OpPushFalse) Table() flatbuffers.Table { 26 | return rcv._tab 27 | } 28 | 29 | func OpPushFalseStart(builder *flatbuffers.Builder) { 30 | builder.StartObject(0) 31 | } 32 | func OpPushFalseEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { 33 | return builder.EndObject() 34 | } 35 | -------------------------------------------------------------------------------- /bytecode/OpPushInt.go: -------------------------------------------------------------------------------- 1 | // Code generated by the FlatBuffers compiler. DO NOT EDIT. 2 | 3 | package bytecode 4 | 5 | import ( 6 | flatbuffers "github.com/google/flatbuffers/go" 7 | ) 8 | 9 | type OpPushInt struct { 10 | _tab flatbuffers.Table 11 | } 12 | 13 | func GetRootAsOpPushInt(buf []byte, offset flatbuffers.UOffsetT) *OpPushInt { 14 | n := flatbuffers.GetUOffsetT(buf[offset:]) 15 | x := &OpPushInt{} 16 | x.Init(buf, n+offset) 17 | return x 18 | } 19 | 20 | func (rcv *OpPushInt) Init(buf []byte, i flatbuffers.UOffsetT) { 21 | rcv._tab.Bytes = buf 22 | rcv._tab.Pos = i 23 | } 24 | 25 | func (rcv *OpPushInt) Table() flatbuffers.Table { 26 | return rcv._tab 27 | } 28 | 29 | func (rcv *OpPushInt) Val() int64 { 30 | o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) 31 | if o != 0 { 32 | return rcv._tab.GetInt64(o + rcv._tab.Pos) 33 | } 34 | return 0 35 | } 36 | 37 | func (rcv *OpPushInt) MutateVal(n int64) bool { 38 | return rcv._tab.MutateInt64Slot(4, n) 39 | } 40 | 41 | func OpPushIntStart(builder *flatbuffers.Builder) { 42 | builder.StartObject(1) 43 | } 44 | func OpPushIntAddVal(builder *flatbuffers.Builder, val int64) { 45 | builder.PrependInt64Slot(0, val, 0) 46 | } 47 | func OpPushIntEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { 48 | return builder.EndObject() 49 | } 50 | -------------------------------------------------------------------------------- /bytecode/OpPushStr.go: -------------------------------------------------------------------------------- 1 | // Code generated by the FlatBuffers compiler. DO NOT EDIT. 2 | 3 | package bytecode 4 | 5 | import ( 6 | flatbuffers "github.com/google/flatbuffers/go" 7 | ) 8 | 9 | type OpPushStr struct { 10 | _tab flatbuffers.Table 11 | } 12 | 13 | func GetRootAsOpPushStr(buf []byte, offset flatbuffers.UOffsetT) *OpPushStr { 14 | n := flatbuffers.GetUOffsetT(buf[offset:]) 15 | x := &OpPushStr{} 16 | x.Init(buf, n+offset) 17 | return x 18 | } 19 | 20 | func (rcv *OpPushStr) Init(buf []byte, i flatbuffers.UOffsetT) { 21 | rcv._tab.Bytes = buf 22 | rcv._tab.Pos = i 23 | } 24 | 25 | func (rcv *OpPushStr) Table() flatbuffers.Table { 26 | return rcv._tab 27 | } 28 | 29 | func (rcv *OpPushStr) Val() []byte { 30 | o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) 31 | if o != 0 { 32 | return rcv._tab.ByteVector(o + rcv._tab.Pos) 33 | } 34 | return nil 35 | } 36 | 37 | func OpPushStrStart(builder *flatbuffers.Builder) { 38 | builder.StartObject(1) 39 | } 40 | func OpPushStrAddVal(builder *flatbuffers.Builder, val flatbuffers.UOffsetT) { 41 | builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(val), 0) 42 | } 43 | func OpPushStrEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { 44 | return builder.EndObject() 45 | } 46 | -------------------------------------------------------------------------------- /bytecode/OpPushTrue.go: -------------------------------------------------------------------------------- 1 | // Code generated by the FlatBuffers compiler. DO NOT EDIT. 2 | 3 | package bytecode 4 | 5 | import ( 6 | flatbuffers "github.com/google/flatbuffers/go" 7 | ) 8 | 9 | type OpPushTrue struct { 10 | _tab flatbuffers.Table 11 | } 12 | 13 | func GetRootAsOpPushTrue(buf []byte, offset flatbuffers.UOffsetT) *OpPushTrue { 14 | n := flatbuffers.GetUOffsetT(buf[offset:]) 15 | x := &OpPushTrue{} 16 | x.Init(buf, n+offset) 17 | return x 18 | } 19 | 20 | func (rcv *OpPushTrue) Init(buf []byte, i flatbuffers.UOffsetT) { 21 | rcv._tab.Bytes = buf 22 | rcv._tab.Pos = i 23 | } 24 | 25 | func (rcv *OpPushTrue) Table() flatbuffers.Table { 26 | return rcv._tab 27 | } 28 | 29 | func OpPushTrueStart(builder *flatbuffers.Builder) { 30 | builder.StartObject(0) 31 | } 32 | func OpPushTrueEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { 33 | return builder.EndObject() 34 | } 35 | -------------------------------------------------------------------------------- /bytecode/OpPushVector.go: -------------------------------------------------------------------------------- 1 | // Code generated by the FlatBuffers compiler. DO NOT EDIT. 2 | 3 | package bytecode 4 | 5 | import ( 6 | flatbuffers "github.com/google/flatbuffers/go" 7 | ) 8 | 9 | type OpPushVector struct { 10 | _tab flatbuffers.Table 11 | } 12 | 13 | func GetRootAsOpPushVector(buf []byte, offset flatbuffers.UOffsetT) *OpPushVector { 14 | n := flatbuffers.GetUOffsetT(buf[offset:]) 15 | x := &OpPushVector{} 16 | x.Init(buf, n+offset) 17 | return x 18 | } 19 | 20 | func (rcv *OpPushVector) Init(buf []byte, i flatbuffers.UOffsetT) { 21 | rcv._tab.Bytes = buf 22 | rcv._tab.Pos = i 23 | } 24 | 25 | func (rcv *OpPushVector) Table() flatbuffers.Table { 26 | return rcv._tab 27 | } 28 | 29 | func (rcv *OpPushVector) Elems() uint16 { 30 | o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) 31 | if o != 0 { 32 | return rcv._tab.GetUint16(o + rcv._tab.Pos) 33 | } 34 | return 0 35 | } 36 | 37 | func (rcv *OpPushVector) MutateElems(n uint16) bool { 38 | return rcv._tab.MutateUint16Slot(4, n) 39 | } 40 | 41 | func OpPushVectorStart(builder *flatbuffers.Builder) { 42 | builder.StartObject(1) 43 | } 44 | func OpPushVectorAddElems(builder *flatbuffers.Builder, elems uint16) { 45 | builder.PrependUint16Slot(0, elems, 0) 46 | } 47 | func OpPushVectorEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { 48 | return builder.EndObject() 49 | } 50 | -------------------------------------------------------------------------------- /bytecode/OpSub.go: -------------------------------------------------------------------------------- 1 | // Code generated by the FlatBuffers compiler. DO NOT EDIT. 2 | 3 | package bytecode 4 | 5 | import ( 6 | flatbuffers "github.com/google/flatbuffers/go" 7 | ) 8 | 9 | type OpSub struct { 10 | _tab flatbuffers.Table 11 | } 12 | 13 | func GetRootAsOpSub(buf []byte, offset flatbuffers.UOffsetT) *OpSub { 14 | n := flatbuffers.GetUOffsetT(buf[offset:]) 15 | x := &OpSub{} 16 | x.Init(buf, n+offset) 17 | return x 18 | } 19 | 20 | func (rcv *OpSub) Init(buf []byte, i flatbuffers.UOffsetT) { 21 | rcv._tab.Bytes = buf 22 | rcv._tab.Pos = i 23 | } 24 | 25 | func (rcv *OpSub) Table() flatbuffers.Table { 26 | return rcv._tab 27 | } 28 | 29 | func OpSubStart(builder *flatbuffers.Builder) { 30 | builder.StartObject(0) 31 | } 32 | func OpSubEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { 33 | return builder.EndObject() 34 | } 35 | -------------------------------------------------------------------------------- /bytecode/Program.go: -------------------------------------------------------------------------------- 1 | // Code generated by the FlatBuffers compiler. DO NOT EDIT. 2 | 3 | package bytecode 4 | 5 | import ( 6 | flatbuffers "github.com/google/flatbuffers/go" 7 | ) 8 | 9 | type Program struct { 10 | _tab flatbuffers.Table 11 | } 12 | 13 | func GetRootAsProgram(buf []byte, offset flatbuffers.UOffsetT) *Program { 14 | n := flatbuffers.GetUOffsetT(buf[offset:]) 15 | x := &Program{} 16 | x.Init(buf, n+offset) 17 | return x 18 | } 19 | 20 | func (rcv *Program) Init(buf []byte, i flatbuffers.UOffsetT) { 21 | rcv._tab.Bytes = buf 22 | rcv._tab.Pos = i 23 | } 24 | 25 | func (rcv *Program) Table() flatbuffers.Table { 26 | return rcv._tab 27 | } 28 | 29 | func (rcv *Program) Ver(obj *Version) *Version { 30 | o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) 31 | if o != 0 { 32 | x := o + rcv._tab.Pos 33 | if obj == nil { 34 | obj = new(Version) 35 | } 36 | obj.Init(rcv._tab.Bytes, x) 37 | return obj 38 | } 39 | return nil 40 | } 41 | 42 | func (rcv *Program) Frames(obj *Frame, j int) bool { 43 | o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) 44 | if o != 0 { 45 | x := rcv._tab.Vector(o) 46 | x += flatbuffers.UOffsetT(j) * 4 47 | x = rcv._tab.Indirect(x) 48 | obj.Init(rcv._tab.Bytes, x) 49 | return true 50 | } 51 | return false 52 | } 53 | 54 | func (rcv *Program) FramesLength() int { 55 | o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) 56 | if o != 0 { 57 | return rcv._tab.VectorLen(o) 58 | } 59 | return 0 60 | } 61 | 62 | func ProgramStart(builder *flatbuffers.Builder) { 63 | builder.StartObject(2) 64 | } 65 | func ProgramAddVer(builder *flatbuffers.Builder, ver flatbuffers.UOffsetT) { 66 | builder.PrependStructSlot(0, flatbuffers.UOffsetT(ver), 0) 67 | } 68 | func ProgramAddFrames(builder *flatbuffers.Builder, frames flatbuffers.UOffsetT) { 69 | builder.PrependUOffsetTSlot(1, flatbuffers.UOffsetT(frames), 0) 70 | } 71 | func ProgramStartFramesVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { 72 | return builder.StartVector(4, numElems, 4) 73 | } 74 | func ProgramEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { 75 | return builder.EndObject() 76 | } 77 | -------------------------------------------------------------------------------- /bytecode/Version.go: -------------------------------------------------------------------------------- 1 | // Code generated by the FlatBuffers compiler. DO NOT EDIT. 2 | 3 | package bytecode 4 | 5 | import ( 6 | flatbuffers "github.com/google/flatbuffers/go" 7 | ) 8 | 9 | type Version struct { 10 | _tab flatbuffers.Struct 11 | } 12 | 13 | func (rcv *Version) Init(buf []byte, i flatbuffers.UOffsetT) { 14 | rcv._tab.Bytes = buf 15 | rcv._tab.Pos = i 16 | } 17 | 18 | func (rcv *Version) Table() flatbuffers.Table { 19 | return rcv._tab.Table 20 | } 21 | 22 | func (rcv *Version) Minor() byte { 23 | return rcv._tab.GetByte(rcv._tab.Pos + flatbuffers.UOffsetT(0)) 24 | } 25 | func (rcv *Version) MutateMinor(n byte) bool { 26 | return rcv._tab.MutateByte(rcv._tab.Pos+flatbuffers.UOffsetT(0), n) 27 | } 28 | 29 | func (rcv *Version) Major() byte { 30 | return rcv._tab.GetByte(rcv._tab.Pos + flatbuffers.UOffsetT(1)) 31 | } 32 | func (rcv *Version) MutateMajor(n byte) bool { 33 | return rcv._tab.MutateByte(rcv._tab.Pos+flatbuffers.UOffsetT(1), n) 34 | } 35 | 36 | func CreateVersion(builder *flatbuffers.Builder, minor byte, major byte) flatbuffers.UOffsetT { 37 | builder.Prep(1, 2) 38 | builder.PrependByte(major) 39 | builder.PrependByte(minor) 40 | return builder.Offset() 41 | } 42 | -------------------------------------------------------------------------------- /bytecode/proto.fbs: -------------------------------------------------------------------------------- 1 | namespace bytecode; 2 | 3 | table OpPushStr { 4 | val:string; 5 | } 6 | 7 | table OpPushInt { 8 | val:long; 9 | } 10 | 11 | table OpPushTrue { 12 | } 13 | 14 | table OpPushFalse { 15 | } 16 | 17 | table OpPushVector { 18 | elems:ushort; 19 | } 20 | 21 | table OpInvoke { 22 | args:ushort; 23 | name:string; 24 | } 25 | 26 | table OpAdd { 27 | } 28 | 29 | table OpSub { 30 | } 31 | 32 | table OpMul { 33 | } 34 | 35 | table OpDiv { 36 | } 37 | 38 | union Op { 39 | OpPushStr, 40 | OpPushInt, 41 | OpPushTrue, 42 | OpPushFalse, 43 | OpPushVector, 44 | OpInvoke, 45 | OpAdd, 46 | OpSub, 47 | OpMul, 48 | OpDiv, 49 | } 50 | 51 | struct Version { 52 | minor:ubyte; 53 | major:ubyte; 54 | } 55 | 56 | table Frame { 57 | op:Op; 58 | } 59 | 60 | table Program { 61 | ver:Version; 62 | frames:[Frame]; 63 | } 64 | 65 | root_type Program; 66 | -------------------------------------------------------------------------------- /cmd/expr/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "log" 7 | "os" 8 | 9 | "github.com/regeda/expr/compiler" 10 | "github.com/regeda/expr/delegate" 11 | "github.com/regeda/expr/exec" 12 | "github.com/regeda/expr/lexer" 13 | "github.com/regeda/expr/stdlib" 14 | ) 15 | 16 | func main() { 17 | bytes, err := io.ReadAll(os.Stdin) 18 | if err != nil { 19 | log.Fatal(err) 20 | } 21 | 22 | tokens, err := lexer.Parse(bytes) 23 | if err != nil { 24 | panic(err) 25 | } 26 | 27 | bcode := compiler.Compile(tokens) 28 | 29 | ex := exec.New( 30 | exec.WithRegistry(delegate.Import(stdlib.Compare, stdlib.Strings)), 31 | ) 32 | 33 | addr, err := ex.Exec(bcode) 34 | if err != nil { 35 | log.Fatal(err) 36 | } 37 | 38 | addr.Print(os.Stdout) 39 | fmt.Fprintln(os.Stdout) 40 | } 41 | -------------------------------------------------------------------------------- /compiler/compiler.go: -------------------------------------------------------------------------------- 1 | package compiler 2 | 3 | import ( 4 | "fmt" 5 | 6 | flatbuffers "github.com/google/flatbuffers/go" 7 | "github.com/regeda/expr/bytecode" 8 | "github.com/regeda/expr/lexer" 9 | ) 10 | 11 | const ( 12 | MinorVersion byte = 2 13 | MajorVersion byte = 0 14 | ) 15 | 16 | var Default = Compiler{} 17 | 18 | func Compile(nodes []lexer.Node) []byte { 19 | return Default.Compile(nodes) 20 | } 21 | 22 | type Compiler struct { 23 | b flatbuffers.Builder 24 | frames []flatbuffers.UOffsetT 25 | } 26 | 27 | func (c *Compiler) Compile(nodes []lexer.Node) []byte { 28 | c.reset() 29 | 30 | c.b.Finish(c.writeProgram( 31 | c.writeFrames(nodes), 32 | )) 33 | 34 | return c.b.FinishedBytes() 35 | } 36 | 37 | func (c *Compiler) reset() { 38 | c.b.Reset() 39 | c.frames = c.frames[:0] 40 | } 41 | 42 | func (c *Compiler) writeVersion(major, minor byte) flatbuffers.UOffsetT { 43 | return bytecode.CreateVersion(&c.b, minor, major) 44 | } 45 | 46 | func (c *Compiler) writeProgram(frames flatbuffers.UOffsetT) flatbuffers.UOffsetT { 47 | bytecode.ProgramStart(&c.b) 48 | bytecode.ProgramAddVer(&c.b, c.writeVersion(MajorVersion, MinorVersion)) 49 | bytecode.ProgramAddFrames(&c.b, frames) 50 | return bytecode.ProgramEnd(&c.b) 51 | } 52 | 53 | func (c *Compiler) writeOpPushInt(v int64) flatbuffers.UOffsetT { 54 | bytecode.OpPushIntStart(&c.b) 55 | bytecode.OpPushIntAddVal(&c.b, v) 56 | return bytecode.OpPushIntEnd(&c.b) 57 | } 58 | 59 | func (c *Compiler) writeOpPushTrue() flatbuffers.UOffsetT { 60 | bytecode.OpPushTrueStart(&c.b) 61 | return bytecode.OpPushTrueEnd(&c.b) 62 | } 63 | 64 | func (c *Compiler) writeOpPushFalse() flatbuffers.UOffsetT { 65 | bytecode.OpPushFalseStart(&c.b) 66 | return bytecode.OpPushFalseEnd(&c.b) 67 | } 68 | 69 | func (c *Compiler) writeOpAdd() flatbuffers.UOffsetT { 70 | bytecode.OpAddStart(&c.b) 71 | return bytecode.OpAddEnd(&c.b) 72 | } 73 | 74 | func (c *Compiler) writeOpSub() flatbuffers.UOffsetT { 75 | bytecode.OpSubStart(&c.b) 76 | return bytecode.OpSubEnd(&c.b) 77 | } 78 | 79 | func (c *Compiler) writeOpMul() flatbuffers.UOffsetT { 80 | bytecode.OpMulStart(&c.b) 81 | return bytecode.OpMulEnd(&c.b) 82 | } 83 | 84 | func (c *Compiler) writeOpDiv() flatbuffers.UOffsetT { 85 | bytecode.OpDivStart(&c.b) 86 | return bytecode.OpDivEnd(&c.b) 87 | } 88 | 89 | func (c *Compiler) writeOpPushStr(v string) flatbuffers.UOffsetT { 90 | offset := c.b.CreateSharedString(v) 91 | 92 | bytecode.OpPushStrStart(&c.b) 93 | bytecode.OpPushStrAddVal(&c.b, offset) 94 | return bytecode.OpPushStrEnd(&c.b) 95 | } 96 | 97 | func (c *Compiler) writeOpPushVector(elems uint) flatbuffers.UOffsetT { 98 | bytecode.OpPushVectorStart(&c.b) 99 | bytecode.OpPushVectorAddElems(&c.b, uint16(elems)) 100 | return bytecode.OpPushVectorEnd(&c.b) 101 | } 102 | 103 | func (c *Compiler) writeOpInvoke(fn string, args uint) flatbuffers.UOffsetT { 104 | fnOffset := c.b.CreateSharedString(fn) 105 | 106 | bytecode.OpInvokeStart(&c.b) 107 | bytecode.OpInvokeAddArgs(&c.b, uint16(args)) 108 | bytecode.OpInvokeAddName(&c.b, fnOffset) 109 | return bytecode.OpInvokeEnd(&c.b) 110 | } 111 | 112 | func (c *Compiler) writeFrames(nodes []lexer.Node) flatbuffers.UOffsetT { 113 | c.discoverFrames(nodes) 114 | 115 | num := len(c.frames) 116 | bytecode.ProgramStartFramesVector(&c.b, num) 117 | for i := num - 1; i >= 0; i-- { 118 | c.b.PrependUOffsetT(c.frames[i]) 119 | } 120 | return c.b.EndVector(num) 121 | } 122 | 123 | func (c *Compiler) writeFrame(offset flatbuffers.UOffsetT, op bytecode.Op) flatbuffers.UOffsetT { 124 | bytecode.FrameStart(&c.b) 125 | bytecode.FrameAddOpType(&c.b, op) 126 | bytecode.FrameAddOp(&c.b, offset) 127 | return bytecode.FrameEnd(&c.b) 128 | } 129 | 130 | func (c *Compiler) pushFrame(f flatbuffers.UOffsetT) { 131 | c.frames = append(c.frames, f) 132 | } 133 | 134 | func (c *Compiler) discoverFrames(nodes []lexer.Node) { 135 | for _, node := range nodes { 136 | switch node.Typ { 137 | case lexer.TypInvoke: 138 | c.pushFrame(c.writeFrame( 139 | c.writeOpInvoke(node.DatS, node.Cap), 140 | bytecode.OpOpInvoke, 141 | )) 142 | case lexer.TypStr: 143 | c.pushFrame(c.writeFrame( 144 | c.writeOpPushStr(node.DatS), 145 | bytecode.OpOpPushStr, 146 | )) 147 | case lexer.TypInt: 148 | c.pushFrame(c.writeFrame( 149 | c.writeOpPushInt(node.DatN), 150 | bytecode.OpOpPushInt, 151 | )) 152 | case lexer.TypTrue: 153 | c.pushFrame(c.writeFrame( 154 | c.writeOpPushTrue(), 155 | bytecode.OpOpPushTrue, 156 | )) 157 | case lexer.TypFalse: 158 | c.pushFrame(c.writeFrame( 159 | c.writeOpPushFalse(), 160 | bytecode.OpOpPushFalse, 161 | )) 162 | case lexer.TypVector: 163 | c.pushFrame(c.writeFrame( 164 | c.writeOpPushVector(node.Cap), 165 | bytecode.OpOpPushVector, 166 | )) 167 | case lexer.TypOpAdd: 168 | c.pushFrame(c.writeFrame( 169 | c.writeOpAdd(), 170 | bytecode.OpOpAdd, 171 | )) 172 | case lexer.TypOpSub: 173 | c.pushFrame(c.writeFrame( 174 | c.writeOpSub(), 175 | bytecode.OpOpSub, 176 | )) 177 | case lexer.TypOpMul: 178 | c.pushFrame(c.writeFrame( 179 | c.writeOpMul(), 180 | bytecode.OpOpMul, 181 | )) 182 | case lexer.TypOpDiv: 183 | c.pushFrame(c.writeFrame( 184 | c.writeOpDiv(), 185 | bytecode.OpOpDiv, 186 | )) 187 | default: 188 | panic(fmt.Sprintf("unknown type <%d>, see lexer.Typ", node.Typ)) 189 | } 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /delegate/delegator.go: -------------------------------------------------------------------------------- 1 | package delegate 2 | 3 | import ( 4 | "github.com/regeda/expr/memory" 5 | ) 6 | 7 | type Delegator interface { 8 | Delegate(*memory.Memory, []memory.Addr) (memory.Addr, error) 9 | } 10 | 11 | type DelegatorFunc func(*memory.Memory, []memory.Addr) (memory.Addr, error) 12 | 13 | func (f DelegatorFunc) Delegate(mem *memory.Memory, argv []memory.Addr) (memory.Addr, error) { 14 | return f(mem, argv) 15 | } 16 | -------------------------------------------------------------------------------- /delegate/registry.go: -------------------------------------------------------------------------------- 1 | package delegate 2 | 3 | import "io" 4 | 5 | type Module map[string]Delegator 6 | 7 | type Registry struct { 8 | module Module 9 | tracing io.Writer 10 | } 11 | 12 | type RegistryOpt func(*Registry) 13 | 14 | func RegistryWithTracing(w io.Writer) RegistryOpt { 15 | return func(r *Registry) { 16 | r.tracing = w 17 | } 18 | } 19 | 20 | func NewRegistry(opts ...RegistryOpt) Registry { 21 | var r Registry 22 | 23 | for _, opt := range opts { 24 | opt(&r) 25 | } 26 | 27 | return r 28 | } 29 | 30 | func (r *Registry) Import(mods ...Module) { 31 | for _, mod := range mods { 32 | for k, d := range mod { 33 | r.Register(k, d) 34 | } 35 | } 36 | } 37 | 38 | func (r *Registry) Register(k string, f Delegator) { 39 | if r.module == nil { 40 | r.module = make(Module) 41 | } 42 | if r.tracing != nil { 43 | f = WithTracing(k, f, r.tracing) 44 | } 45 | r.module[k] = f 46 | } 47 | 48 | func (r *Registry) Get(k string) (Delegator, bool) { 49 | d, ok := r.module[k] 50 | return d, ok 51 | } 52 | 53 | func Import(mods ...Module) Registry { 54 | var r Registry 55 | r.Import(mods...) 56 | return r 57 | } 58 | -------------------------------------------------------------------------------- /delegate/tracing.go: -------------------------------------------------------------------------------- 1 | package delegate 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | 7 | "github.com/regeda/expr/memory" 8 | ) 9 | 10 | type Tracing struct { 11 | k string 12 | d Delegator 13 | w io.Writer 14 | } 15 | 16 | func WithTracing(key string, d Delegator, w io.Writer) Tracing { 17 | return Tracing{ 18 | k: key, 19 | d: d, 20 | w: w, 21 | } 22 | } 23 | 24 | func (t Tracing) write(f string, argv ...interface{}) { 25 | fmt.Fprintf(t.w, f, argv...) 26 | } 27 | 28 | func (t Tracing) Delegate(mem *memory.Memory, argv []memory.Addr) (memory.Addr, error) { 29 | t.write("%s(", t.k) 30 | for i, a := range argv { 31 | if i > 0 { 32 | t.write(", ") 33 | } 34 | a.Print(t.w) 35 | } 36 | addr, err := t.d.Delegate(mem, argv) 37 | if err != nil { 38 | t.write(") FATAL %v\n", err) 39 | return addr, err 40 | } 41 | t.write(") -> ") 42 | addr.Print(t.w) 43 | t.write("\n") 44 | return addr, nil 45 | } 46 | -------------------------------------------------------------------------------- /delegate/tracing_test.go: -------------------------------------------------------------------------------- 1 | package delegate_test 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "testing" 7 | 8 | "github.com/regeda/expr/delegate" 9 | "github.com/regeda/expr/memory" 10 | "github.com/stretchr/testify/assert" 11 | "github.com/stretchr/testify/require" 12 | ) 13 | 14 | func TestTracing(t *testing.T) { 15 | mem := memory.New() 16 | 17 | t.Run("result", func(t *testing.T) { 18 | buf := bytes.NewBuffer(nil) 19 | 20 | f := delegate.DelegatorFunc(func(mem *memory.Memory, argv []memory.Addr) (memory.Addr, error) { 21 | return mem.AllocInt64(argv[0].Int64() + argv[1].Int64()), nil 22 | }) 23 | 24 | d := delegate.WithTracing("sum", f, buf) 25 | 26 | _, err := d.Delegate(&mem, []memory.Addr{mem.AllocInt64(2), mem.AllocInt64(3)}) 27 | require.NoError(t, err) 28 | 29 | assert.Equal(t, "sum(int64=2, int64=3) -> int64=5\n", buf.String()) 30 | }) 31 | 32 | t.Run("error", func(t *testing.T) { 33 | buf := bytes.NewBuffer(nil) 34 | 35 | f := delegate.DelegatorFunc(func(*memory.Memory, []memory.Addr) (memory.Addr, error) { 36 | return memory.Nil, errors.New("die!") 37 | }) 38 | 39 | d := delegate.WithTracing("err", f, buf) 40 | 41 | _, err := d.Delegate(&mem, []memory.Addr{}) 42 | require.Error(t, err) 43 | 44 | assert.Equal(t, "err() FATAL die!\n", buf.String()) 45 | }) 46 | } 47 | -------------------------------------------------------------------------------- /example_test.go: -------------------------------------------------------------------------------- 1 | package expr_test 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/regeda/expr/compiler" 7 | "github.com/regeda/expr/delegate" 8 | "github.com/regeda/expr/exec" 9 | "github.com/regeda/expr/lexer" 10 | "github.com/regeda/expr/stdlib" 11 | ) 12 | 13 | func ExampleExpr() { 14 | code := `join(",", ["a", "b"])` 15 | 16 | tokens, err := lexer.Parse([]byte(code)) 17 | if err != nil { 18 | panic(err) 19 | } 20 | 21 | bytecode := compiler.Compile(tokens) 22 | 23 | ex := exec.New( 24 | exec.WithRegistry(delegate.Import(stdlib.Compare, stdlib.Strings)), 25 | ) 26 | addr, err := ex.Exec(bytecode) 27 | if err != nil { 28 | panic(err) 29 | } 30 | 31 | fmt.Println(addr.Type(), addr.Bytes()) 32 | } 33 | -------------------------------------------------------------------------------- /exec/errors.go: -------------------------------------------------------------------------------- 1 | package exec 2 | 3 | import "errors" 4 | 5 | var ( 6 | errNoVersion = errors.New("bytecode contains no version") 7 | errNoFrames = errors.New("no frames to execute") 8 | errEmptyDelegatorName = errors.New("empty delegator name") 9 | errUnexpectedEOF = errors.New("unexpected end of frames") 10 | errNoOperation = errors.New("no operation in frame") 11 | errDivByZero = errors.New("division by zero") 12 | ) 13 | -------------------------------------------------------------------------------- /exec/globals.go: -------------------------------------------------------------------------------- 1 | package exec 2 | 3 | import ( 4 | "github.com/regeda/expr/delegate" 5 | ) 6 | 7 | type Globals struct { 8 | delegators delegate.Registry 9 | } 10 | 11 | func (g *Globals) SetRegistry(r delegate.Registry) { 12 | g.delegators = r 13 | } 14 | -------------------------------------------------------------------------------- /exec/stack.go: -------------------------------------------------------------------------------- 1 | package exec 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/regeda/expr/memory" 7 | ) 8 | 9 | type stack []memory.Addr 10 | 11 | func (s *stack) reset() { 12 | *s = (*s)[:0] 13 | } 14 | 15 | func (s *stack) push(a memory.Addr) { 16 | *s = append(*s, a) 17 | } 18 | 19 | func (s *stack) pop(n uint32) ([]memory.Addr, error) { 20 | l := uint32(len(*s)) 21 | if n > l { 22 | return nil, fmt.Errorf("stack tail shorter than %d", n) 23 | } 24 | offset := l - n 25 | a := (*s)[offset:l] 26 | *s = (*s)[:offset] 27 | return a, nil 28 | } 29 | -------------------------------------------------------------------------------- /exec/vm.go: -------------------------------------------------------------------------------- 1 | package exec 2 | 3 | import ( 4 | "fmt" 5 | 6 | flatbuffers "github.com/google/flatbuffers/go" 7 | "github.com/pkg/errors" 8 | "github.com/regeda/expr/bytecode" 9 | "github.com/regeda/expr/compiler" 10 | "github.com/regeda/expr/delegate" 11 | "github.com/regeda/expr/memory" 12 | ) 13 | 14 | type VM struct { 15 | globals Globals 16 | memory memory.Memory 17 | stack stack 18 | prog bytecode.Program 19 | } 20 | 21 | type Opt func(*VM) 22 | 23 | func WithMemory(m memory.Memory) Opt { 24 | return func(vm *VM) { 25 | vm.memory = m 26 | } 27 | } 28 | 29 | func WithStackSize(n uint32) Opt { 30 | return func(vm *VM) { 31 | vm.stack = make(stack, 0, n) 32 | } 33 | } 34 | 35 | func WithRegistry(reg delegate.Registry) Opt { 36 | return func(vm *VM) { 37 | vm.globals.SetRegistry(reg) 38 | } 39 | } 40 | 41 | func New(opts ...Opt) *VM { 42 | vm := &VM{} 43 | 44 | for _, opt := range opts { 45 | opt(vm) 46 | } 47 | 48 | return vm 49 | } 50 | 51 | func (v *VM) reset() { 52 | v.memory.Reset() 53 | v.stack.reset() 54 | } 55 | 56 | func (v *VM) checkVersion() error { 57 | var ver bytecode.Version 58 | 59 | if v.prog.Ver(&ver) == nil { 60 | return errNoVersion 61 | } 62 | 63 | majorVer := ver.Major() 64 | 65 | if majorVer > compiler.MajorVersion { 66 | return fmt.Errorf("bytecode version %d is not supported, compiler version %d", majorVer, compiler.MajorVersion) 67 | } 68 | 69 | return nil 70 | } 71 | 72 | func (v *VM) terminate() (memory.Addr, error) { 73 | val, err := v.stack.pop(1) 74 | if err != nil { 75 | return memory.Nil, err 76 | } 77 | return val[0], nil 78 | } 79 | 80 | func (v *VM) Exec(bcode []byte) (memory.Addr, error) { 81 | v.reset() 82 | 83 | v.prog.Init(bcode, flatbuffers.GetUOffsetT(bcode)) 84 | 85 | if err := v.checkVersion(); err != nil { 86 | return memory.Nil, err 87 | } 88 | 89 | framesLen := v.prog.FramesLength() 90 | if framesLen == 0 { 91 | return memory.Nil, errNoFrames 92 | } 93 | 94 | var frame bytecode.Frame 95 | for i := 0; i < framesLen; i++ { 96 | if !v.prog.Frames(&frame, i) { 97 | return memory.Nil, errUnexpectedEOF 98 | } 99 | addr, err := v.execFrame(&frame) 100 | if err != nil { 101 | return memory.Nil, errors.Wrapf(err, "failed to exec frame at %d", i) 102 | } 103 | v.stack.push(addr) 104 | } 105 | 106 | return v.terminate() 107 | } 108 | 109 | func (v *VM) popType(n uint32, t memory.Type) ([]memory.Addr, error) { 110 | argv, err := v.stack.pop(n) 111 | if err != nil { 112 | return nil, err 113 | } 114 | for _, arg := range argv { 115 | if !arg.TypeOf(t) { 116 | return nil, fmt.Errorf("unexpected type %v instead of %v", arg.Type(), t) 117 | } 118 | } 119 | return argv, nil 120 | } 121 | 122 | func (v *VM) execFrame(frame *bytecode.Frame) (memory.Addr, error) { 123 | opType := frame.OpType() 124 | switch opType { 125 | case bytecode.OpOpPushTrue: 126 | return memory.True, nil 127 | case bytecode.OpOpPushFalse: 128 | return memory.False, nil 129 | case bytecode.OpOpAdd: 130 | argv, err := v.popType(2, memory.TypeInt64) 131 | if err != nil { 132 | return memory.Nil, err 133 | } 134 | return v.memory.AllocInt64(argv[0].Int64() + argv[1].Int64()), nil 135 | case bytecode.OpOpSub: 136 | argv, err := v.popType(2, memory.TypeInt64) 137 | if err != nil { 138 | return memory.Nil, err 139 | } 140 | return v.memory.AllocInt64(argv[0].Int64() - argv[1].Int64()), nil 141 | case bytecode.OpOpMul: 142 | argv, err := v.popType(2, memory.TypeInt64) 143 | if err != nil { 144 | return memory.Nil, err 145 | } 146 | return v.memory.AllocInt64(argv[0].Int64() * argv[1].Int64()), nil 147 | case bytecode.OpOpDiv: 148 | argv, err := v.popType(2, memory.TypeInt64) 149 | if err != nil { 150 | return memory.Nil, err 151 | } 152 | div := argv[1].Int64() 153 | if div == 0 { 154 | return memory.Nil, errDivByZero 155 | } 156 | return v.memory.AllocInt64(argv[0].Int64() / div), nil 157 | case bytecode.OpOpPushStr: 158 | var tab flatbuffers.Table 159 | if !frame.Op(&tab) { 160 | return memory.Nil, errNoOperation 161 | } 162 | var op bytecode.OpPushStr 163 | op.Init(tab.Bytes, tab.Pos) 164 | return v.memory.AllocBytesAddr(op.Val()), nil 165 | case bytecode.OpOpPushInt: 166 | var tab flatbuffers.Table 167 | if !frame.Op(&tab) { 168 | return memory.Nil, errNoOperation 169 | } 170 | var op bytecode.OpPushInt 171 | op.Init(tab.Bytes, tab.Pos) 172 | return v.memory.AllocInt64(op.Val()), nil 173 | case bytecode.OpOpPushVector: 174 | var tab flatbuffers.Table 175 | if !frame.Op(&tab) { 176 | return memory.Nil, errNoOperation 177 | } 178 | var op bytecode.OpPushVector 179 | op.Init(tab.Bytes, tab.Pos) 180 | elems, err := v.stack.pop(uint32(op.Elems())) 181 | if err != nil { 182 | return memory.Nil, err 183 | } 184 | return v.memory.CopyVector(elems...), nil 185 | case bytecode.OpOpInvoke: 186 | var tab flatbuffers.Table 187 | if !frame.Op(&tab) { 188 | return memory.Nil, errNoOperation 189 | } 190 | var op bytecode.OpInvoke 191 | op.Init(tab.Bytes, tab.Pos) 192 | fn := op.Name() 193 | if fn == nil { 194 | return memory.Nil, errEmptyDelegatorName 195 | } 196 | delegator, ok := v.globals.delegators.Get(string(fn)) 197 | if !ok { 198 | return memory.Nil, fmt.Errorf("delegator <%s> not exists", fn) 199 | } 200 | args := op.Args() 201 | argv, err := v.stack.pop(uint32(args)) 202 | if err != nil { 203 | return memory.Nil, err 204 | } 205 | return delegator.Delegate(&v.memory, argv) 206 | default: 207 | return memory.Nil, fmt.Errorf("unexpected frame type %s", opType) 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /exec/vm_test.go: -------------------------------------------------------------------------------- 1 | package exec_test 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | 7 | "github.com/regeda/expr/compiler" 8 | "github.com/regeda/expr/delegate" 9 | "github.com/regeda/expr/exec" 10 | "github.com/regeda/expr/lexer" 11 | "github.com/regeda/expr/memory" 12 | "github.com/regeda/expr/stdlib" 13 | "github.com/stretchr/testify/assert" 14 | "github.com/stretchr/testify/require" 15 | ) 16 | 17 | func TestVM_Exec(t *testing.T) { 18 | tracing := bytes.NewBuffer(nil) 19 | 20 | registry := delegate.NewRegistry(delegate.RegistryWithTracing(tracing)) 21 | registry.Import(stdlib.Compare, stdlib.Strings) 22 | 23 | var comp compiler.Compiler 24 | 25 | exec := exec.New(exec.WithRegistry(registry)) 26 | 27 | t.Run("const boolean", func(t *testing.T) { 28 | for _, bb := range [...]bool{true, false} { 29 | tracing.Reset() 30 | 31 | typ := lexer.TypFalse 32 | if bb { 33 | typ = lexer.TypTrue 34 | } 35 | 36 | bcode := comp.Compile([]lexer.Node{ 37 | {Typ: typ}, 38 | }) 39 | addr, err := exec.Exec(bcode) 40 | require.NoError(t, err) 41 | require.NotNil(t, addr) 42 | 43 | require.Equal(t, memory.TypeBool, addr.Type()) 44 | assert.Equal(t, bb, addr.Bool()) 45 | 46 | assert.Empty(t, tracing.String()) 47 | } 48 | }) 49 | 50 | t.Run("const int", func(t *testing.T) { 51 | tracing.Reset() 52 | 53 | bcode := comp.Compile([]lexer.Node{ 54 | {Typ: lexer.TypInt, DatN: 1}, 55 | }) 56 | addr, err := exec.Exec(bcode) 57 | require.NoError(t, err) 58 | require.NotNil(t, addr) 59 | 60 | require.Equal(t, memory.TypeInt64, addr.Type()) 61 | assert.Equal(t, int64(1), addr.Int64()) 62 | 63 | assert.Empty(t, tracing.String()) 64 | }) 65 | 66 | t.Run("const array", func(t *testing.T) { 67 | tracing.Reset() 68 | 69 | bcode := comp.Compile([]lexer.Node{ 70 | {Typ: lexer.TypInt, DatN: 1}, 71 | {Typ: lexer.TypInt, DatN: 2}, 72 | {Typ: lexer.TypInt, DatN: 3}, 73 | {Typ: lexer.TypVector, Cap: 3}, 74 | }) 75 | addr, err := exec.Exec(bcode) 76 | require.NoError(t, err) 77 | require.NotNil(t, addr) 78 | 79 | require.Equal(t, memory.TypeVector, addr.Type()) 80 | assert.Equal(t, 3, addr.VectorLen()) 81 | 82 | for i, n := range [...]int64{1, 2, 3} { 83 | addrAt := addr.VectorAt(i) 84 | require.NotNil(t, addrAt) 85 | 86 | require.Equal(t, memory.TypeInt64, addrAt.Type()) 87 | assert.Equal(t, n, addrAt.Int64()) 88 | } 89 | 90 | assert.Empty(t, tracing.String()) 91 | }) 92 | 93 | t.Run("array of array", func(t *testing.T) { 94 | tracing.Reset() 95 | 96 | bcode := comp.Compile([]lexer.Node{ 97 | {Typ: lexer.TypInt, DatN: 0xff}, 98 | {Typ: lexer.TypVector, Cap: 1}, 99 | {Typ: lexer.TypStr, DatS: "foo"}, 100 | {Typ: lexer.TypVector, Cap: 2}, 101 | }) 102 | addr, err := exec.Exec(bcode) 103 | require.NoError(t, err) 104 | require.NotNil(t, addr) 105 | 106 | require.Equal(t, memory.TypeVector, addr.Type()) 107 | assert.Equal(t, 2, addr.VectorLen()) 108 | 109 | subarrayAtPos0 := addr.VectorAt(0) 110 | require.NotNil(t, subarrayAtPos0) 111 | require.Equal(t, memory.TypeVector, subarrayAtPos0.Type()) 112 | assert.Equal(t, 1, subarrayAtPos0.VectorLen()) 113 | 114 | intAtSubarrayAtPos0 := subarrayAtPos0.VectorAt(0) 115 | require.NotNil(t, intAtSubarrayAtPos0) 116 | require.Equal(t, memory.TypeInt64, intAtSubarrayAtPos0.Type()) 117 | assert.Equal(t, int64(0xff), intAtSubarrayAtPos0.Int64()) 118 | 119 | strAtPos1 := addr.VectorAt(1) 120 | require.NotNil(t, strAtPos1) 121 | require.Equal(t, memory.TypeBytes, strAtPos1.Type()) 122 | assert.Equal(t, []byte("foo"), strAtPos1.Bytes()) 123 | 124 | assert.Empty(t, tracing.String()) 125 | }) 126 | 127 | t.Run("func join", func(t *testing.T) { 128 | tracing.Reset() 129 | 130 | bcode := comp.Compile([]lexer.Node{ 131 | {Typ: lexer.TypStr, DatS: "$"}, 132 | {Typ: lexer.TypStr, DatS: "a"}, 133 | {Typ: lexer.TypStr, DatS: "b"}, 134 | {Typ: lexer.TypStr, DatS: "c"}, 135 | {Typ: lexer.TypVector, Cap: 3}, 136 | {Typ: lexer.TypInvoke, DatS: "join", Cap: 2}, 137 | }) 138 | addr, err := exec.Exec(bcode) 139 | require.NoError(t, err) 140 | require.NotNil(t, addr) 141 | 142 | require.Equal(t, memory.TypeBytes, addr.Type()) 143 | assert.Equal(t, []byte("a$b$c"), addr.Bytes()) 144 | 145 | assert.Equal(t, "join(bytes=\"$\", vector=[bytes=\"a\", bytes=\"b\", bytes=\"c\"]) -> bytes=\"a$b$c\"\n", tracing.String()) 146 | }) 147 | 148 | t.Run("func concat", func(t *testing.T) { 149 | tracing.Reset() 150 | 151 | bcode := comp.Compile([]lexer.Node{ 152 | {Typ: lexer.TypStr, DatS: "foo"}, 153 | {Typ: lexer.TypStr, DatS: "bar"}, 154 | {Typ: lexer.TypStr, DatS: "baz"}, 155 | {Typ: lexer.TypInvoke, DatS: "concat", Cap: 3}, 156 | }) 157 | addr, err := exec.Exec(bcode) 158 | require.NoError(t, err) 159 | require.NotNil(t, addr) 160 | 161 | require.Equal(t, memory.TypeBytes, addr.Type()) 162 | assert.Equal(t, []byte("foobarbaz"), addr.Bytes()) 163 | 164 | assert.Equal(t, "concat(bytes=\"foo\", bytes=\"bar\", bytes=\"baz\") -> bytes=\"foobarbaz\"\n", tracing.String()) 165 | }) 166 | 167 | t.Run("func equals int", func(t *testing.T) { 168 | tracing.Reset() 169 | 170 | bcode := comp.Compile([]lexer.Node{ 171 | {Typ: lexer.TypInt, DatN: 1}, 172 | {Typ: lexer.TypInt, DatN: 1}, 173 | {Typ: lexer.TypInvoke, DatS: "equals", Cap: 2}, 174 | }) 175 | addr, err := exec.Exec(bcode) 176 | require.NoError(t, err) 177 | require.NotNil(t, addr) 178 | 179 | require.Equal(t, memory.TypeBool, addr.Type()) 180 | assert.True(t, addr.Bool()) 181 | 182 | assert.Equal(t, "equals(int64=1, int64=1) -> bool=1\n", tracing.String()) 183 | }) 184 | 185 | t.Run("func equals str", func(t *testing.T) { 186 | tracing.Reset() 187 | 188 | bcode := comp.Compile([]lexer.Node{ 189 | {Typ: lexer.TypStr, DatS: "foo"}, 190 | {Typ: lexer.TypStr, DatS: "foo"}, 191 | {Typ: lexer.TypInvoke, DatS: "equals", Cap: 2}, 192 | }) 193 | addr, err := exec.Exec(bcode) 194 | require.NoError(t, err) 195 | require.NotNil(t, addr) 196 | 197 | require.Equal(t, memory.TypeBool, addr.Type()) 198 | assert.True(t, addr.Bool()) 199 | 200 | assert.Equal(t, "equals(bytes=\"foo\", bytes=\"foo\") -> bool=1\n", tracing.String()) 201 | }) 202 | 203 | t.Run("func equals vector", func(t *testing.T) { 204 | tracing.Reset() 205 | 206 | bcode := comp.Compile([]lexer.Node{ 207 | {Typ: lexer.TypStr, DatS: "foo"}, 208 | {Typ: lexer.TypStr, DatS: "bar"}, 209 | {Typ: lexer.TypVector, Cap: 2}, 210 | {Typ: lexer.TypStr, DatS: "foo"}, 211 | {Typ: lexer.TypStr, DatS: "bar"}, 212 | {Typ: lexer.TypVector, Cap: 2}, 213 | {Typ: lexer.TypInvoke, DatS: "equals", Cap: 2}, 214 | }) 215 | addr, err := exec.Exec(bcode) 216 | require.NoError(t, err) 217 | require.NotNil(t, addr) 218 | 219 | require.Equal(t, memory.TypeBool, addr.Type()) 220 | assert.True(t, addr.Bool()) 221 | 222 | assert.Equal(t, "equals(vector=[bytes=\"foo\", bytes=\"bar\"], vector=[bytes=\"foo\", bytes=\"bar\"]) -> bool=1\n", tracing.String()) 223 | }) 224 | 225 | t.Run("func equals concat", func(t *testing.T) { 226 | tracing.Reset() 227 | 228 | bcode := comp.Compile([]lexer.Node{ 229 | {Typ: lexer.TypStr, DatS: "foobarbaz"}, 230 | {Typ: lexer.TypStr, DatS: "foo"}, 231 | {Typ: lexer.TypStr, DatS: "bar"}, 232 | {Typ: lexer.TypStr, DatS: "baz"}, 233 | {Typ: lexer.TypInvoke, DatS: "concat", Cap: 3}, 234 | {Typ: lexer.TypInvoke, DatS: "equals", Cap: 2}, 235 | }) 236 | addr, err := exec.Exec(bcode) 237 | require.NoError(t, err) 238 | require.NotNil(t, addr) 239 | 240 | require.Equal(t, memory.TypeBool, addr.Type()) 241 | assert.True(t, addr.Bool()) 242 | 243 | assert.Equal(t, "concat(bytes=\"foo\", bytes=\"bar\", bytes=\"baz\") -> bytes=\"foobarbaz\"\nequals(bytes=\"foobarbaz\", bytes=\"foobarbaz\") -> bool=1\n", tracing.String()) 244 | }) 245 | 246 | t.Run("func contains", func(t *testing.T) { 247 | tracing.Reset() 248 | 249 | bcode := comp.Compile([]lexer.Node{ 250 | {Typ: lexer.TypStr, DatS: "a"}, 251 | {Typ: lexer.TypStr, DatS: "b"}, 252 | {Typ: lexer.TypStr, DatS: "c"}, 253 | {Typ: lexer.TypVector, Cap: 3}, 254 | {Typ: lexer.TypStr, DatS: "a"}, 255 | {Typ: lexer.TypInvoke, DatS: "contains", Cap: 2}, 256 | }) 257 | addr, err := exec.Exec(bcode) 258 | require.NoError(t, err) 259 | require.NotNil(t, addr) 260 | 261 | require.Equal(t, memory.TypeBool, addr.Type()) 262 | assert.True(t, addr.Bool()) 263 | 264 | assert.Equal(t, "contains(vector=[bytes=\"a\", bytes=\"b\", bytes=\"c\"], bytes=\"a\") -> bool=1\n", tracing.String()) 265 | }) 266 | 267 | t.Run("func intersects", func(t *testing.T) { 268 | tracing.Reset() 269 | 270 | bcode := comp.Compile([]lexer.Node{ 271 | {Typ: lexer.TypInt, DatN: 1}, 272 | {Typ: lexer.TypInt, DatN: 2}, 273 | {Typ: lexer.TypVector, Cap: 2}, 274 | {Typ: lexer.TypInt, DatN: 2}, 275 | {Typ: lexer.TypVector, Cap: 1}, 276 | {Typ: lexer.TypInvoke, DatS: "intersects", Cap: 2}, 277 | }) 278 | addr, err := exec.Exec(bcode) 279 | require.NoError(t, err) 280 | require.NotNil(t, addr) 281 | 282 | require.Equal(t, memory.TypeBool, addr.Type()) 283 | assert.True(t, addr.Bool()) 284 | 285 | assert.Equal(t, "intersects(vector=[int64=1, int64=2], vector=[int64=2]) -> bool=1\n", tracing.String()) 286 | }) 287 | 288 | t.Run("delegator not exists", func(t *testing.T) { 289 | tracing.Reset() 290 | 291 | bcode := comp.Compile([]lexer.Node{ 292 | {Typ: lexer.TypInvoke, DatS: "NONAME"}, 293 | }) 294 | addr, err := exec.Exec(bcode) 295 | require.EqualError(t, err, "failed to exec frame at 0: delegator not exists") 296 | assert.Equal(t, memory.Nil, addr) 297 | }) 298 | 299 | t.Run("math expected int", func(t *testing.T) { 300 | bcode := comp.Compile([]lexer.Node{ 301 | {Typ: lexer.TypStr, DatS: "foo"}, 302 | {Typ: lexer.TypInt, DatN: 1}, 303 | {Typ: lexer.TypOpAdd}, 304 | }) 305 | addr, err := exec.Exec(bcode) 306 | require.Equal(t, memory.Nil, addr) 307 | assert.EqualError(t, err, "failed to exec frame at 2: unexpected type bytes instead of int64") 308 | }) 309 | 310 | t.Run("math no args", func(t *testing.T) { 311 | for _, typ := range [...]lexer.Typ{lexer.TypOpAdd, lexer.TypOpSub, lexer.TypOpMul, lexer.TypOpDiv} { 312 | t.Run(typ.String(), func(t *testing.T) { 313 | bcode := comp.Compile([]lexer.Node{ 314 | {Typ: typ}, 315 | }) 316 | addr, err := exec.Exec(bcode) 317 | require.Equal(t, memory.Nil, addr) 318 | assert.EqualError(t, err, "failed to exec frame at 0: stack tail shorter than 2") 319 | }) 320 | } 321 | }) 322 | 323 | t.Run("math", func(t *testing.T) { 324 | cases := []struct { 325 | name string 326 | nodes []lexer.Node 327 | expected int64 328 | }{ 329 | { 330 | "1+2", 331 | []lexer.Node{ 332 | {Typ: lexer.TypInt, DatN: 1}, 333 | {Typ: lexer.TypInt, DatN: 2}, 334 | {Typ: lexer.TypOpAdd}, 335 | }, 336 | 3, 337 | }, 338 | { 339 | "2-3", 340 | []lexer.Node{ 341 | {Typ: lexer.TypInt, DatN: 2}, 342 | {Typ: lexer.TypInt, DatN: 3}, 343 | {Typ: lexer.TypOpSub}, 344 | }, 345 | -1, 346 | }, 347 | { 348 | "2*3", 349 | []lexer.Node{ 350 | {Typ: lexer.TypInt, DatN: 2}, 351 | {Typ: lexer.TypInt, DatN: 3}, 352 | {Typ: lexer.TypOpMul}, 353 | }, 354 | 6, 355 | }, 356 | { 357 | "6/2", 358 | []lexer.Node{ 359 | {Typ: lexer.TypInt, DatN: 6}, 360 | {Typ: lexer.TypInt, DatN: 2}, 361 | {Typ: lexer.TypOpDiv}, 362 | }, 363 | 3, 364 | }, 365 | { 366 | "1+2*3", 367 | []lexer.Node{ 368 | {Typ: lexer.TypInt, DatN: 1}, 369 | {Typ: lexer.TypInt, DatN: 2}, 370 | {Typ: lexer.TypInt, DatN: 3}, 371 | {Typ: lexer.TypOpMul}, 372 | {Typ: lexer.TypOpAdd}, 373 | }, 374 | 7, 375 | }, 376 | { 377 | "1*2+3", 378 | []lexer.Node{ 379 | {Typ: lexer.TypInt, DatN: 1}, 380 | {Typ: lexer.TypInt, DatN: 2}, 381 | {Typ: lexer.TypOpMul}, 382 | {Typ: lexer.TypInt, DatN: 3}, 383 | {Typ: lexer.TypOpAdd}, 384 | }, 385 | 5, 386 | }, 387 | } 388 | for _, c := range cases { 389 | t.Run(c.name, func(t *testing.T) { 390 | bcode := comp.Compile(c.nodes) 391 | addr, err := exec.Exec(bcode) 392 | require.NoError(t, err) 393 | require.NotNil(t, addr) 394 | 395 | require.Equal(t, memory.TypeInt64, addr.Type()) 396 | assert.Equal(t, c.expected, addr.Int64()) 397 | }) 398 | } 399 | }) 400 | 401 | t.Run("math div by zero", func(t *testing.T) { 402 | bcode := comp.Compile([]lexer.Node{ 403 | {Typ: lexer.TypInt, DatN: 6}, 404 | {Typ: lexer.TypInt, DatN: 0}, 405 | {Typ: lexer.TypOpDiv}, 406 | }) 407 | addr, err := exec.Exec(bcode) 408 | require.Equal(t, memory.Nil, addr) 409 | require.EqualError(t, err, "failed to exec frame at 2: division by zero") 410 | }) 411 | } 412 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/regeda/expr 2 | 3 | go 1.15 4 | 5 | require ( 6 | github.com/google/flatbuffers v2.0.0+incompatible 7 | github.com/pkg/errors v0.9.1 8 | github.com/stretchr/testify v1.7.0 9 | ) 10 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/google/flatbuffers v2.0.0+incompatible h1:dicJ2oXwypfwUGnB2/TYWYEKiuk9eYQlQO/AnOHl5mI= 4 | github.com/google/flatbuffers v2.0.0+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= 5 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 6 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 7 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 8 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 9 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 10 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 11 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 12 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 13 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 14 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 15 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 16 | -------------------------------------------------------------------------------- /lexer/ast.go: -------------------------------------------------------------------------------- 1 | package lexer 2 | 3 | import "strings" 4 | 5 | type ast struct { 6 | rpn, ops, caps nvec 7 | } 8 | 9 | func (a *ast) reset() { 10 | a.rpn.reset() 11 | a.ops.reset() 12 | a.caps.reset() 13 | } 14 | 15 | func (a *ast) pushInt(n int64) { 16 | a.rpn.push(Node{Typ: TypInt, DatN: n}) 17 | } 18 | 19 | func (a *ast) pushStr(s string) { 20 | a.rpn.push(Node{Typ: TypStr, DatS: s}) 21 | } 22 | 23 | func (a *ast) pushIdent(s string) { 24 | a.rpn.push(Node{Typ: typIdent, DatS: strings.ToLower(s)}) 25 | } 26 | 27 | func (a *ast) pushTrue() { 28 | a.rpn.push(Node{Typ: TypTrue}) 29 | } 30 | 31 | func (a *ast) pushFalse() { 32 | a.rpn.push(Node{Typ: TypFalse}) 33 | } 34 | 35 | func (a *ast) pushMathOp(c byte) { 36 | switch c { 37 | case '+', '-': 38 | a.rotateType(TypOpAdd, TypOpSub, TypOpMul, TypOpDiv) 39 | case '*', '/': 40 | a.rotateType(TypOpMul, TypOpDiv) 41 | } 42 | a.ops.push(Node{Typ: typMathOp[c]}) 43 | } 44 | 45 | func (a *ast) pushInvoke() { 46 | n := a.rpn.pop().setTyp(TypInvoke) 47 | a.ops.push(n) 48 | a.caps.push(n) 49 | } 50 | 51 | func (a *ast) pushVector() { 52 | n := Node{Typ: TypVector} 53 | a.ops.push(n) 54 | a.caps.push(n) 55 | } 56 | 57 | func (a *ast) openPths() { 58 | a.ops.push(Node{Typ: typPths}) 59 | } 60 | 61 | func (a *ast) closePths() { 62 | a.rotateBreakOn(typPths) 63 | a.ops.pop() 64 | } 65 | 66 | func (a *ast) rotateComma() { 67 | a.rotateBreakOn(a.incCaps().Typ) 68 | } 69 | 70 | func (a *ast) incCaps() Node { 71 | n := a.caps.pop().incCap() 72 | a.caps.push(n) 73 | return n 74 | } 75 | 76 | func (a *ast) popCaps() { 77 | n := a.caps.pop() 78 | a.rotateBreakOn(n.Typ) 79 | a.ops.pop() 80 | a.rpn.push(n) 81 | } 82 | 83 | func (a *ast) rotateType(t ...Typ) { 84 | for !a.ops.empty() { 85 | if !a.ops.top().typeOf(t...) { 86 | break 87 | } 88 | a.rpn.push(a.ops.pop()) 89 | } 90 | } 91 | 92 | func (a *ast) rotateBreakOn(t ...Typ) { 93 | for !a.ops.empty() { 94 | if a.ops.top().typeOf(t...) { 95 | break 96 | } 97 | a.rpn.push(a.ops.pop()) 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /lexer/init.go: -------------------------------------------------------------------------------- 1 | package lexer 2 | 3 | var Default = Lexer{} 4 | 5 | func Parse(input []byte) ([]Node, error) { 6 | return Default.Parse(input) 7 | } 8 | -------------------------------------------------------------------------------- /lexer/lexer.go: -------------------------------------------------------------------------------- 1 | //line lexer/lexer.go.rl:1 2 | package lexer 3 | 4 | import ( 5 | "fmt" 6 | "strconv" 7 | 8 | "github.com/pkg/errors" 9 | ) 10 | 11 | //line lexer/lexer.go:11 12 | const lexer_start int = 1 13 | const lexer_first_final int = 95 14 | const lexer_error int = 0 15 | 16 | const lexer_en_pths_rest int = 23 17 | const lexer_en_vector_rest int = 37 18 | const lexer_en_invoke_rest int = 66 19 | const lexer_en_main int = 1 20 | 21 | //line lexer/lexer.go.rl:10 22 | 23 | type Lexer struct { 24 | p, pe, pb, eof int 25 | cs, top int 26 | data []byte 27 | stack [1024]int 28 | ast ast 29 | } 30 | 31 | func (l *Lexer) text() string { 32 | return string(l.data[l.pb:l.p]) 33 | } 34 | 35 | func (l *Lexer) Parse(input []byte) ([]Node, error) { 36 | l.ast.reset() 37 | 38 | l.data = input 39 | l.p = 0 40 | l.pb = 0 41 | l.pe = len(input) 42 | l.eof = len(input) 43 | 44 | var perr error 45 | var n64 int64 46 | var str string 47 | 48 | //line lexer/lexer.go:51 49 | { 50 | l.cs = lexer_start 51 | l.top = 0 52 | } 53 | 54 | //line lexer/lexer.go:57 55 | { 56 | if (l.p) == (l.pe) { 57 | goto _test_eof 58 | } 59 | goto _resume 60 | 61 | _again: 62 | switch l.cs { 63 | case 1: 64 | goto st1 65 | case 0: 66 | goto st0 67 | case 2: 68 | goto st2 69 | case 95: 70 | goto st95 71 | case 96: 72 | goto st96 73 | case 3: 74 | goto st3 75 | case 97: 76 | goto st97 77 | case 4: 78 | goto st4 79 | case 5: 80 | goto st5 81 | case 6: 82 | goto st6 83 | case 98: 84 | goto st98 85 | case 7: 86 | goto st7 87 | case 8: 88 | goto st8 89 | case 9: 90 | goto st9 91 | case 10: 92 | goto st10 93 | case 11: 94 | goto st11 95 | case 12: 96 | goto st12 97 | case 13: 98 | goto st13 99 | case 14: 100 | goto st14 101 | case 15: 102 | goto st15 103 | case 16: 104 | goto st16 105 | case 17: 106 | goto st17 107 | case 18: 108 | goto st18 109 | case 19: 110 | goto st19 111 | case 99: 112 | goto st99 113 | case 20: 114 | goto st20 115 | case 21: 116 | goto st21 117 | case 22: 118 | goto st22 119 | case 100: 120 | goto st100 121 | case 23: 122 | goto st23 123 | case 24: 124 | goto st24 125 | case 101: 126 | goto st101 127 | case 25: 128 | goto st25 129 | case 26: 130 | goto st26 131 | case 27: 132 | goto st27 133 | case 28: 134 | goto st28 135 | case 29: 136 | goto st29 137 | case 30: 138 | goto st30 139 | case 31: 140 | goto st31 141 | case 32: 142 | goto st32 143 | case 33: 144 | goto st33 145 | case 34: 146 | goto st34 147 | case 35: 148 | goto st35 149 | case 36: 150 | goto st36 151 | case 37: 152 | goto st37 153 | case 38: 154 | goto st38 155 | case 39: 156 | goto st39 157 | case 40: 158 | goto st40 159 | case 41: 160 | goto st41 161 | case 42: 162 | goto st42 163 | case 43: 164 | goto st43 165 | case 44: 166 | goto st44 167 | case 45: 168 | goto st45 169 | case 46: 170 | goto st46 171 | case 102: 172 | goto st102 173 | case 47: 174 | goto st47 175 | case 48: 176 | goto st48 177 | case 49: 178 | goto st49 179 | case 50: 180 | goto st50 181 | case 51: 182 | goto st51 183 | case 52: 184 | goto st52 185 | case 53: 186 | goto st53 187 | case 54: 188 | goto st54 189 | case 55: 190 | goto st55 191 | case 56: 192 | goto st56 193 | case 57: 194 | goto st57 195 | case 58: 196 | goto st58 197 | case 59: 198 | goto st59 199 | case 60: 200 | goto st60 201 | case 61: 202 | goto st61 203 | case 62: 204 | goto st62 205 | case 63: 206 | goto st63 207 | case 64: 208 | goto st64 209 | case 65: 210 | goto st65 211 | case 66: 212 | goto st66 213 | case 67: 214 | goto st67 215 | case 68: 216 | goto st68 217 | case 69: 218 | goto st69 219 | case 103: 220 | goto st103 221 | case 70: 222 | goto st70 223 | case 71: 224 | goto st71 225 | case 72: 226 | goto st72 227 | case 73: 228 | goto st73 229 | case 74: 230 | goto st74 231 | case 75: 232 | goto st75 233 | case 76: 234 | goto st76 235 | case 77: 236 | goto st77 237 | case 78: 238 | goto st78 239 | case 79: 240 | goto st79 241 | case 80: 242 | goto st80 243 | case 81: 244 | goto st81 245 | case 82: 246 | goto st82 247 | case 83: 248 | goto st83 249 | case 84: 250 | goto st84 251 | case 85: 252 | goto st85 253 | case 86: 254 | goto st86 255 | case 87: 256 | goto st87 257 | case 88: 258 | goto st88 259 | case 89: 260 | goto st89 261 | case 90: 262 | goto st90 263 | case 91: 264 | goto st91 265 | case 92: 266 | goto st92 267 | case 93: 268 | goto st93 269 | case 94: 270 | goto st94 271 | } 272 | 273 | if (l.p)++; (l.p) == (l.pe) { 274 | goto _test_eof 275 | } 276 | _resume: 277 | switch l.cs { 278 | case 1: 279 | goto st_case_1 280 | case 0: 281 | goto st_case_0 282 | case 2: 283 | goto st_case_2 284 | case 95: 285 | goto st_case_95 286 | case 96: 287 | goto st_case_96 288 | case 3: 289 | goto st_case_3 290 | case 97: 291 | goto st_case_97 292 | case 4: 293 | goto st_case_4 294 | case 5: 295 | goto st_case_5 296 | case 6: 297 | goto st_case_6 298 | case 98: 299 | goto st_case_98 300 | case 7: 301 | goto st_case_7 302 | case 8: 303 | goto st_case_8 304 | case 9: 305 | goto st_case_9 306 | case 10: 307 | goto st_case_10 308 | case 11: 309 | goto st_case_11 310 | case 12: 311 | goto st_case_12 312 | case 13: 313 | goto st_case_13 314 | case 14: 315 | goto st_case_14 316 | case 15: 317 | goto st_case_15 318 | case 16: 319 | goto st_case_16 320 | case 17: 321 | goto st_case_17 322 | case 18: 323 | goto st_case_18 324 | case 19: 325 | goto st_case_19 326 | case 99: 327 | goto st_case_99 328 | case 20: 329 | goto st_case_20 330 | case 21: 331 | goto st_case_21 332 | case 22: 333 | goto st_case_22 334 | case 100: 335 | goto st_case_100 336 | case 23: 337 | goto st_case_23 338 | case 24: 339 | goto st_case_24 340 | case 101: 341 | goto st_case_101 342 | case 25: 343 | goto st_case_25 344 | case 26: 345 | goto st_case_26 346 | case 27: 347 | goto st_case_27 348 | case 28: 349 | goto st_case_28 350 | case 29: 351 | goto st_case_29 352 | case 30: 353 | goto st_case_30 354 | case 31: 355 | goto st_case_31 356 | case 32: 357 | goto st_case_32 358 | case 33: 359 | goto st_case_33 360 | case 34: 361 | goto st_case_34 362 | case 35: 363 | goto st_case_35 364 | case 36: 365 | goto st_case_36 366 | case 37: 367 | goto st_case_37 368 | case 38: 369 | goto st_case_38 370 | case 39: 371 | goto st_case_39 372 | case 40: 373 | goto st_case_40 374 | case 41: 375 | goto st_case_41 376 | case 42: 377 | goto st_case_42 378 | case 43: 379 | goto st_case_43 380 | case 44: 381 | goto st_case_44 382 | case 45: 383 | goto st_case_45 384 | case 46: 385 | goto st_case_46 386 | case 102: 387 | goto st_case_102 388 | case 47: 389 | goto st_case_47 390 | case 48: 391 | goto st_case_48 392 | case 49: 393 | goto st_case_49 394 | case 50: 395 | goto st_case_50 396 | case 51: 397 | goto st_case_51 398 | case 52: 399 | goto st_case_52 400 | case 53: 401 | goto st_case_53 402 | case 54: 403 | goto st_case_54 404 | case 55: 405 | goto st_case_55 406 | case 56: 407 | goto st_case_56 408 | case 57: 409 | goto st_case_57 410 | case 58: 411 | goto st_case_58 412 | case 59: 413 | goto st_case_59 414 | case 60: 415 | goto st_case_60 416 | case 61: 417 | goto st_case_61 418 | case 62: 419 | goto st_case_62 420 | case 63: 421 | goto st_case_63 422 | case 64: 423 | goto st_case_64 424 | case 65: 425 | goto st_case_65 426 | case 66: 427 | goto st_case_66 428 | case 67: 429 | goto st_case_67 430 | case 68: 431 | goto st_case_68 432 | case 69: 433 | goto st_case_69 434 | case 103: 435 | goto st_case_103 436 | case 70: 437 | goto st_case_70 438 | case 71: 439 | goto st_case_71 440 | case 72: 441 | goto st_case_72 442 | case 73: 443 | goto st_case_73 444 | case 74: 445 | goto st_case_74 446 | case 75: 447 | goto st_case_75 448 | case 76: 449 | goto st_case_76 450 | case 77: 451 | goto st_case_77 452 | case 78: 453 | goto st_case_78 454 | case 79: 455 | goto st_case_79 456 | case 80: 457 | goto st_case_80 458 | case 81: 459 | goto st_case_81 460 | case 82: 461 | goto st_case_82 462 | case 83: 463 | goto st_case_83 464 | case 84: 465 | goto st_case_84 466 | case 85: 467 | goto st_case_85 468 | case 86: 469 | goto st_case_86 470 | case 87: 471 | goto st_case_87 472 | case 88: 473 | goto st_case_88 474 | case 89: 475 | goto st_case_89 476 | case 90: 477 | goto st_case_90 478 | case 91: 479 | goto st_case_91 480 | case 92: 481 | goto st_case_92 482 | case 93: 483 | goto st_case_93 484 | case 94: 485 | goto st_case_94 486 | } 487 | goto st_out 488 | st1: 489 | if (l.p)++; (l.p) == (l.pe) { 490 | goto _test_eof1 491 | } 492 | st_case_1: 493 | switch l.data[(l.p)] { 494 | case 32: 495 | goto st1 496 | case 34: 497 | goto tr2 498 | case 40: 499 | goto tr3 500 | case 43: 501 | goto tr4 502 | case 45: 503 | goto tr4 504 | case 91: 505 | goto tr7 506 | case 95: 507 | goto tr6 508 | case 102: 509 | goto tr8 510 | case 116: 511 | goto tr9 512 | } 513 | switch { 514 | case l.data[(l.p)] < 48: 515 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 516 | goto st1 517 | } 518 | case l.data[(l.p)] > 57: 519 | switch { 520 | case l.data[(l.p)] > 90: 521 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 522 | goto tr6 523 | } 524 | case l.data[(l.p)] >= 65: 525 | goto tr6 526 | } 527 | default: 528 | goto tr5 529 | } 530 | goto st0 531 | st_case_0: 532 | st0: 533 | l.cs = 0 534 | goto _out 535 | tr2: 536 | //line lexer/lexer.go.rl:45 537 | l.pb = l.p 538 | goto st2 539 | st2: 540 | if (l.p)++; (l.p) == (l.pe) { 541 | goto _test_eof2 542 | } 543 | st_case_2: 544 | //line lexer/lexer.go:547 545 | switch l.data[(l.p)] { 546 | case 34: 547 | goto st95 548 | case 92: 549 | goto st3 550 | } 551 | goto st2 552 | st95: 553 | if (l.p)++; (l.p) == (l.pe) { 554 | goto _test_eof95 555 | } 556 | st_case_95: 557 | if l.data[(l.p)] == 32 { 558 | goto tr206 559 | } 560 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 561 | goto tr206 562 | } 563 | goto st0 564 | tr7: 565 | //line lexer/lexer.go.rl:50 566 | l.ast.pushVector() 567 | //line lexer/lexer.go.rl:101 568 | { 569 | l.stack[l.top] = 96 570 | l.top++ 571 | goto st37 572 | } 573 | goto st96 574 | tr206: 575 | //line lexer/lexer.go.rl:54 576 | 577 | str, perr = strconv.Unquote(l.text()) 578 | if perr != nil { 579 | perr = errors.Wrapf(perr, "strconv.Unquote %s", l.text()) 580 | { 581 | (l.p)++ 582 | l.cs = 96 583 | goto _out 584 | } 585 | } 586 | l.ast.pushStr(str) 587 | 588 | goto st96 589 | tr212: 590 | //line lexer/lexer.go.rl:70 591 | l.ast.pushFalse() 592 | goto st96 593 | tr213: 594 | //line lexer/lexer.go.rl:69 595 | l.ast.pushTrue() 596 | goto st96 597 | st96: 598 | if (l.p)++; (l.p) == (l.pe) { 599 | goto _test_eof96 600 | } 601 | st_case_96: 602 | //line lexer/lexer.go:597 603 | if l.data[(l.p)] == 32 { 604 | goto st96 605 | } 606 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 607 | goto st96 608 | } 609 | goto st0 610 | st3: 611 | if (l.p)++; (l.p) == (l.pe) { 612 | goto _test_eof3 613 | } 614 | st_case_3: 615 | goto st2 616 | tr3: 617 | //line lexer/lexer.go.rl:51 618 | l.ast.openPths() 619 | //line lexer/lexer.go.rl:103 620 | { 621 | l.stack[l.top] = 97 622 | l.top++ 623 | goto st23 624 | } 625 | goto st97 626 | tr14: 627 | //line lexer/lexer.go.rl:71 628 | l.ast.pushMathOp(l.data[l.pb]) 629 | //line lexer/lexer.go.rl:51 630 | l.ast.openPths() 631 | //line lexer/lexer.go.rl:103 632 | { 633 | l.stack[l.top] = 97 634 | l.top++ 635 | goto st23 636 | } 637 | goto st97 638 | tr25: 639 | //line lexer/lexer.go.rl:53 640 | l.ast.pushIdent(l.text()) 641 | //line lexer/lexer.go.rl:49 642 | l.ast.pushInvoke() 643 | //line lexer/lexer.go.rl:102 644 | { 645 | l.stack[l.top] = 97 646 | l.top++ 647 | goto st66 648 | } 649 | goto st97 650 | tr28: 651 | //line lexer/lexer.go.rl:49 652 | l.ast.pushInvoke() 653 | //line lexer/lexer.go.rl:102 654 | { 655 | l.stack[l.top] = 97 656 | l.top++ 657 | goto st66 658 | } 659 | goto st97 660 | tr210: 661 | //line lexer/lexer.go.rl:62 662 | 663 | n64, perr = strconv.ParseInt(l.text(), 10, 64) 664 | if perr != nil { 665 | { 666 | (l.p)++ 667 | l.cs = 97 668 | goto _out 669 | } 670 | } 671 | l.ast.pushInt(n64) 672 | 673 | goto st97 674 | st97: 675 | if (l.p)++; (l.p) == (l.pe) { 676 | goto _test_eof97 677 | } 678 | st_case_97: 679 | //line lexer/lexer.go:654 680 | switch l.data[(l.p)] { 681 | case 32: 682 | goto st97 683 | case 45: 684 | goto tr209 685 | case 47: 686 | goto tr209 687 | } 688 | switch { 689 | case l.data[(l.p)] > 13: 690 | if 42 <= l.data[(l.p)] && l.data[(l.p)] <= 43 { 691 | goto tr209 692 | } 693 | case l.data[(l.p)] >= 9: 694 | goto st97 695 | } 696 | goto st0 697 | tr209: 698 | //line lexer/lexer.go.rl:45 699 | l.pb = l.p 700 | goto st4 701 | tr211: 702 | //line lexer/lexer.go.rl:62 703 | 704 | n64, perr = strconv.ParseInt(l.text(), 10, 64) 705 | if perr != nil { 706 | { 707 | (l.p)++ 708 | l.cs = 4 709 | goto _out 710 | } 711 | } 712 | l.ast.pushInt(n64) 713 | 714 | //line lexer/lexer.go.rl:45 715 | l.pb = l.p 716 | goto st4 717 | st4: 718 | if (l.p)++; (l.p) == (l.pe) { 719 | goto _test_eof4 720 | } 721 | st_case_4: 722 | //line lexer/lexer.go:693 723 | switch l.data[(l.p)] { 724 | case 32: 725 | goto tr13 726 | case 40: 727 | goto tr14 728 | case 43: 729 | goto tr15 730 | case 45: 731 | goto tr15 732 | case 95: 733 | goto tr17 734 | case 102: 735 | goto tr18 736 | case 116: 737 | goto tr19 738 | } 739 | switch { 740 | case l.data[(l.p)] < 48: 741 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 742 | goto tr13 743 | } 744 | case l.data[(l.p)] > 57: 745 | switch { 746 | case l.data[(l.p)] > 90: 747 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 748 | goto tr17 749 | } 750 | case l.data[(l.p)] >= 65: 751 | goto tr17 752 | } 753 | default: 754 | goto tr16 755 | } 756 | goto st0 757 | tr13: 758 | //line lexer/lexer.go.rl:71 759 | l.ast.pushMathOp(l.data[l.pb]) 760 | goto st5 761 | st5: 762 | if (l.p)++; (l.p) == (l.pe) { 763 | goto _test_eof5 764 | } 765 | st_case_5: 766 | //line lexer/lexer.go:737 767 | switch l.data[(l.p)] { 768 | case 32: 769 | goto st5 770 | case 40: 771 | goto tr3 772 | case 43: 773 | goto tr4 774 | case 45: 775 | goto tr4 776 | case 95: 777 | goto tr6 778 | case 102: 779 | goto tr21 780 | case 116: 781 | goto tr22 782 | } 783 | switch { 784 | case l.data[(l.p)] < 48: 785 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 786 | goto st5 787 | } 788 | case l.data[(l.p)] > 57: 789 | switch { 790 | case l.data[(l.p)] > 90: 791 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 792 | goto tr6 793 | } 794 | case l.data[(l.p)] >= 65: 795 | goto tr6 796 | } 797 | default: 798 | goto tr5 799 | } 800 | goto st0 801 | tr4: 802 | //line lexer/lexer.go.rl:45 803 | l.pb = l.p 804 | goto st6 805 | tr15: 806 | //line lexer/lexer.go.rl:71 807 | l.ast.pushMathOp(l.data[l.pb]) 808 | //line lexer/lexer.go.rl:45 809 | l.pb = l.p 810 | goto st6 811 | st6: 812 | if (l.p)++; (l.p) == (l.pe) { 813 | goto _test_eof6 814 | } 815 | st_case_6: 816 | //line lexer/lexer.go:787 817 | if 48 <= l.data[(l.p)] && l.data[(l.p)] <= 57 { 818 | goto st98 819 | } 820 | goto st0 821 | tr5: 822 | //line lexer/lexer.go.rl:45 823 | l.pb = l.p 824 | goto st98 825 | tr16: 826 | //line lexer/lexer.go.rl:71 827 | l.ast.pushMathOp(l.data[l.pb]) 828 | //line lexer/lexer.go.rl:45 829 | l.pb = l.p 830 | goto st98 831 | st98: 832 | if (l.p)++; (l.p) == (l.pe) { 833 | goto _test_eof98 834 | } 835 | st_case_98: 836 | //line lexer/lexer.go:807 837 | switch l.data[(l.p)] { 838 | case 32: 839 | goto tr210 840 | case 45: 841 | goto tr211 842 | case 47: 843 | goto tr211 844 | } 845 | switch { 846 | case l.data[(l.p)] < 42: 847 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 848 | goto tr210 849 | } 850 | case l.data[(l.p)] > 43: 851 | if 48 <= l.data[(l.p)] && l.data[(l.p)] <= 57 { 852 | goto st98 853 | } 854 | default: 855 | goto tr211 856 | } 857 | goto st0 858 | tr6: 859 | //line lexer/lexer.go.rl:45 860 | l.pb = l.p 861 | goto st7 862 | tr17: 863 | //line lexer/lexer.go.rl:71 864 | l.ast.pushMathOp(l.data[l.pb]) 865 | //line lexer/lexer.go.rl:45 866 | l.pb = l.p 867 | goto st7 868 | st7: 869 | if (l.p)++; (l.p) == (l.pe) { 870 | goto _test_eof7 871 | } 872 | st_case_7: 873 | //line lexer/lexer.go:844 874 | switch l.data[(l.p)] { 875 | case 32: 876 | goto tr24 877 | case 40: 878 | goto tr25 879 | case 95: 880 | goto st7 881 | } 882 | switch { 883 | case l.data[(l.p)] < 48: 884 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 885 | goto tr24 886 | } 887 | case l.data[(l.p)] > 57: 888 | switch { 889 | case l.data[(l.p)] > 90: 890 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 891 | goto st7 892 | } 893 | case l.data[(l.p)] >= 65: 894 | goto st7 895 | } 896 | default: 897 | goto st7 898 | } 899 | goto st0 900 | tr24: 901 | //line lexer/lexer.go.rl:53 902 | l.ast.pushIdent(l.text()) 903 | goto st8 904 | st8: 905 | if (l.p)++; (l.p) == (l.pe) { 906 | goto _test_eof8 907 | } 908 | st_case_8: 909 | //line lexer/lexer.go:880 910 | switch l.data[(l.p)] { 911 | case 32: 912 | goto st8 913 | case 40: 914 | goto tr28 915 | } 916 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 917 | goto st8 918 | } 919 | goto st0 920 | tr21: 921 | //line lexer/lexer.go.rl:45 922 | l.pb = l.p 923 | goto st9 924 | tr18: 925 | //line lexer/lexer.go.rl:71 926 | l.ast.pushMathOp(l.data[l.pb]) 927 | //line lexer/lexer.go.rl:45 928 | l.pb = l.p 929 | goto st9 930 | st9: 931 | if (l.p)++; (l.p) == (l.pe) { 932 | goto _test_eof9 933 | } 934 | st_case_9: 935 | //line lexer/lexer.go:906 936 | switch l.data[(l.p)] { 937 | case 32: 938 | goto tr24 939 | case 40: 940 | goto tr25 941 | case 95: 942 | goto st7 943 | case 97: 944 | goto st10 945 | } 946 | switch { 947 | case l.data[(l.p)] < 48: 948 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 949 | goto tr24 950 | } 951 | case l.data[(l.p)] > 57: 952 | switch { 953 | case l.data[(l.p)] > 90: 954 | if 98 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 955 | goto st7 956 | } 957 | case l.data[(l.p)] >= 65: 958 | goto st7 959 | } 960 | default: 961 | goto st7 962 | } 963 | goto st0 964 | st10: 965 | if (l.p)++; (l.p) == (l.pe) { 966 | goto _test_eof10 967 | } 968 | st_case_10: 969 | switch l.data[(l.p)] { 970 | case 32: 971 | goto tr24 972 | case 40: 973 | goto tr25 974 | case 95: 975 | goto st7 976 | case 108: 977 | goto st11 978 | } 979 | switch { 980 | case l.data[(l.p)] < 48: 981 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 982 | goto tr24 983 | } 984 | case l.data[(l.p)] > 57: 985 | switch { 986 | case l.data[(l.p)] > 90: 987 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 988 | goto st7 989 | } 990 | case l.data[(l.p)] >= 65: 991 | goto st7 992 | } 993 | default: 994 | goto st7 995 | } 996 | goto st0 997 | st11: 998 | if (l.p)++; (l.p) == (l.pe) { 999 | goto _test_eof11 1000 | } 1001 | st_case_11: 1002 | switch l.data[(l.p)] { 1003 | case 32: 1004 | goto tr24 1005 | case 40: 1006 | goto tr25 1007 | case 95: 1008 | goto st7 1009 | case 115: 1010 | goto st12 1011 | } 1012 | switch { 1013 | case l.data[(l.p)] < 48: 1014 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 1015 | goto tr24 1016 | } 1017 | case l.data[(l.p)] > 57: 1018 | switch { 1019 | case l.data[(l.p)] > 90: 1020 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 1021 | goto st7 1022 | } 1023 | case l.data[(l.p)] >= 65: 1024 | goto st7 1025 | } 1026 | default: 1027 | goto st7 1028 | } 1029 | goto st0 1030 | st12: 1031 | if (l.p)++; (l.p) == (l.pe) { 1032 | goto _test_eof12 1033 | } 1034 | st_case_12: 1035 | switch l.data[(l.p)] { 1036 | case 32: 1037 | goto tr24 1038 | case 40: 1039 | goto tr25 1040 | case 95: 1041 | goto st7 1042 | case 101: 1043 | goto st13 1044 | } 1045 | switch { 1046 | case l.data[(l.p)] < 48: 1047 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 1048 | goto tr24 1049 | } 1050 | case l.data[(l.p)] > 57: 1051 | switch { 1052 | case l.data[(l.p)] > 90: 1053 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 1054 | goto st7 1055 | } 1056 | case l.data[(l.p)] >= 65: 1057 | goto st7 1058 | } 1059 | default: 1060 | goto st7 1061 | } 1062 | goto st0 1063 | st13: 1064 | if (l.p)++; (l.p) == (l.pe) { 1065 | goto _test_eof13 1066 | } 1067 | st_case_13: 1068 | if l.data[(l.p)] == 95 { 1069 | goto st7 1070 | } 1071 | switch { 1072 | case l.data[(l.p)] < 65: 1073 | if 48 <= l.data[(l.p)] && l.data[(l.p)] <= 57 { 1074 | goto st7 1075 | } 1076 | case l.data[(l.p)] > 90: 1077 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 1078 | goto st7 1079 | } 1080 | default: 1081 | goto st7 1082 | } 1083 | goto st0 1084 | tr22: 1085 | //line lexer/lexer.go.rl:45 1086 | l.pb = l.p 1087 | goto st14 1088 | tr19: 1089 | //line lexer/lexer.go.rl:71 1090 | l.ast.pushMathOp(l.data[l.pb]) 1091 | //line lexer/lexer.go.rl:45 1092 | l.pb = l.p 1093 | goto st14 1094 | st14: 1095 | if (l.p)++; (l.p) == (l.pe) { 1096 | goto _test_eof14 1097 | } 1098 | st_case_14: 1099 | //line lexer/lexer.go:1070 1100 | switch l.data[(l.p)] { 1101 | case 32: 1102 | goto tr24 1103 | case 40: 1104 | goto tr25 1105 | case 95: 1106 | goto st7 1107 | case 114: 1108 | goto st15 1109 | } 1110 | switch { 1111 | case l.data[(l.p)] < 48: 1112 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 1113 | goto tr24 1114 | } 1115 | case l.data[(l.p)] > 57: 1116 | switch { 1117 | case l.data[(l.p)] > 90: 1118 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 1119 | goto st7 1120 | } 1121 | case l.data[(l.p)] >= 65: 1122 | goto st7 1123 | } 1124 | default: 1125 | goto st7 1126 | } 1127 | goto st0 1128 | st15: 1129 | if (l.p)++; (l.p) == (l.pe) { 1130 | goto _test_eof15 1131 | } 1132 | st_case_15: 1133 | switch l.data[(l.p)] { 1134 | case 32: 1135 | goto tr24 1136 | case 40: 1137 | goto tr25 1138 | case 95: 1139 | goto st7 1140 | case 117: 1141 | goto st12 1142 | } 1143 | switch { 1144 | case l.data[(l.p)] < 48: 1145 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 1146 | goto tr24 1147 | } 1148 | case l.data[(l.p)] > 57: 1149 | switch { 1150 | case l.data[(l.p)] > 90: 1151 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 1152 | goto st7 1153 | } 1154 | case l.data[(l.p)] >= 65: 1155 | goto st7 1156 | } 1157 | default: 1158 | goto st7 1159 | } 1160 | goto st0 1161 | tr8: 1162 | //line lexer/lexer.go.rl:45 1163 | l.pb = l.p 1164 | goto st16 1165 | st16: 1166 | if (l.p)++; (l.p) == (l.pe) { 1167 | goto _test_eof16 1168 | } 1169 | st_case_16: 1170 | //line lexer/lexer.go:1141 1171 | switch l.data[(l.p)] { 1172 | case 32: 1173 | goto tr24 1174 | case 40: 1175 | goto tr25 1176 | case 95: 1177 | goto st7 1178 | case 97: 1179 | goto st17 1180 | } 1181 | switch { 1182 | case l.data[(l.p)] < 48: 1183 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 1184 | goto tr24 1185 | } 1186 | case l.data[(l.p)] > 57: 1187 | switch { 1188 | case l.data[(l.p)] > 90: 1189 | if 98 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 1190 | goto st7 1191 | } 1192 | case l.data[(l.p)] >= 65: 1193 | goto st7 1194 | } 1195 | default: 1196 | goto st7 1197 | } 1198 | goto st0 1199 | st17: 1200 | if (l.p)++; (l.p) == (l.pe) { 1201 | goto _test_eof17 1202 | } 1203 | st_case_17: 1204 | switch l.data[(l.p)] { 1205 | case 32: 1206 | goto tr24 1207 | case 40: 1208 | goto tr25 1209 | case 95: 1210 | goto st7 1211 | case 108: 1212 | goto st18 1213 | } 1214 | switch { 1215 | case l.data[(l.p)] < 48: 1216 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 1217 | goto tr24 1218 | } 1219 | case l.data[(l.p)] > 57: 1220 | switch { 1221 | case l.data[(l.p)] > 90: 1222 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 1223 | goto st7 1224 | } 1225 | case l.data[(l.p)] >= 65: 1226 | goto st7 1227 | } 1228 | default: 1229 | goto st7 1230 | } 1231 | goto st0 1232 | st18: 1233 | if (l.p)++; (l.p) == (l.pe) { 1234 | goto _test_eof18 1235 | } 1236 | st_case_18: 1237 | switch l.data[(l.p)] { 1238 | case 32: 1239 | goto tr24 1240 | case 40: 1241 | goto tr25 1242 | case 95: 1243 | goto st7 1244 | case 115: 1245 | goto st19 1246 | } 1247 | switch { 1248 | case l.data[(l.p)] < 48: 1249 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 1250 | goto tr24 1251 | } 1252 | case l.data[(l.p)] > 57: 1253 | switch { 1254 | case l.data[(l.p)] > 90: 1255 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 1256 | goto st7 1257 | } 1258 | case l.data[(l.p)] >= 65: 1259 | goto st7 1260 | } 1261 | default: 1262 | goto st7 1263 | } 1264 | goto st0 1265 | st19: 1266 | if (l.p)++; (l.p) == (l.pe) { 1267 | goto _test_eof19 1268 | } 1269 | st_case_19: 1270 | switch l.data[(l.p)] { 1271 | case 32: 1272 | goto tr24 1273 | case 40: 1274 | goto tr25 1275 | case 95: 1276 | goto st7 1277 | case 101: 1278 | goto st99 1279 | } 1280 | switch { 1281 | case l.data[(l.p)] < 48: 1282 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 1283 | goto tr24 1284 | } 1285 | case l.data[(l.p)] > 57: 1286 | switch { 1287 | case l.data[(l.p)] > 90: 1288 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 1289 | goto st7 1290 | } 1291 | case l.data[(l.p)] >= 65: 1292 | goto st7 1293 | } 1294 | default: 1295 | goto st7 1296 | } 1297 | goto st0 1298 | st99: 1299 | if (l.p)++; (l.p) == (l.pe) { 1300 | goto _test_eof99 1301 | } 1302 | st_case_99: 1303 | switch l.data[(l.p)] { 1304 | case 32: 1305 | goto tr212 1306 | case 95: 1307 | goto st7 1308 | } 1309 | switch { 1310 | case l.data[(l.p)] < 48: 1311 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 1312 | goto tr212 1313 | } 1314 | case l.data[(l.p)] > 57: 1315 | switch { 1316 | case l.data[(l.p)] > 90: 1317 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 1318 | goto st7 1319 | } 1320 | case l.data[(l.p)] >= 65: 1321 | goto st7 1322 | } 1323 | default: 1324 | goto st7 1325 | } 1326 | goto st0 1327 | tr9: 1328 | //line lexer/lexer.go.rl:45 1329 | l.pb = l.p 1330 | goto st20 1331 | st20: 1332 | if (l.p)++; (l.p) == (l.pe) { 1333 | goto _test_eof20 1334 | } 1335 | st_case_20: 1336 | //line lexer/lexer.go:1307 1337 | switch l.data[(l.p)] { 1338 | case 32: 1339 | goto tr24 1340 | case 40: 1341 | goto tr25 1342 | case 95: 1343 | goto st7 1344 | case 114: 1345 | goto st21 1346 | } 1347 | switch { 1348 | case l.data[(l.p)] < 48: 1349 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 1350 | goto tr24 1351 | } 1352 | case l.data[(l.p)] > 57: 1353 | switch { 1354 | case l.data[(l.p)] > 90: 1355 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 1356 | goto st7 1357 | } 1358 | case l.data[(l.p)] >= 65: 1359 | goto st7 1360 | } 1361 | default: 1362 | goto st7 1363 | } 1364 | goto st0 1365 | st21: 1366 | if (l.p)++; (l.p) == (l.pe) { 1367 | goto _test_eof21 1368 | } 1369 | st_case_21: 1370 | switch l.data[(l.p)] { 1371 | case 32: 1372 | goto tr24 1373 | case 40: 1374 | goto tr25 1375 | case 95: 1376 | goto st7 1377 | case 117: 1378 | goto st22 1379 | } 1380 | switch { 1381 | case l.data[(l.p)] < 48: 1382 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 1383 | goto tr24 1384 | } 1385 | case l.data[(l.p)] > 57: 1386 | switch { 1387 | case l.data[(l.p)] > 90: 1388 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 1389 | goto st7 1390 | } 1391 | case l.data[(l.p)] >= 65: 1392 | goto st7 1393 | } 1394 | default: 1395 | goto st7 1396 | } 1397 | goto st0 1398 | st22: 1399 | if (l.p)++; (l.p) == (l.pe) { 1400 | goto _test_eof22 1401 | } 1402 | st_case_22: 1403 | switch l.data[(l.p)] { 1404 | case 32: 1405 | goto tr24 1406 | case 40: 1407 | goto tr25 1408 | case 95: 1409 | goto st7 1410 | case 101: 1411 | goto st100 1412 | } 1413 | switch { 1414 | case l.data[(l.p)] < 48: 1415 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 1416 | goto tr24 1417 | } 1418 | case l.data[(l.p)] > 57: 1419 | switch { 1420 | case l.data[(l.p)] > 90: 1421 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 1422 | goto st7 1423 | } 1424 | case l.data[(l.p)] >= 65: 1425 | goto st7 1426 | } 1427 | default: 1428 | goto st7 1429 | } 1430 | goto st0 1431 | st100: 1432 | if (l.p)++; (l.p) == (l.pe) { 1433 | goto _test_eof100 1434 | } 1435 | st_case_100: 1436 | switch l.data[(l.p)] { 1437 | case 32: 1438 | goto tr213 1439 | case 95: 1440 | goto st7 1441 | } 1442 | switch { 1443 | case l.data[(l.p)] < 48: 1444 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 1445 | goto tr213 1446 | } 1447 | case l.data[(l.p)] > 57: 1448 | switch { 1449 | case l.data[(l.p)] > 90: 1450 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 1451 | goto st7 1452 | } 1453 | case l.data[(l.p)] >= 65: 1454 | goto st7 1455 | } 1456 | default: 1457 | goto st7 1458 | } 1459 | goto st0 1460 | tr51: 1461 | //line lexer/lexer.go.rl:71 1462 | l.ast.pushMathOp(l.data[l.pb]) 1463 | goto st23 1464 | st23: 1465 | if (l.p)++; (l.p) == (l.pe) { 1466 | goto _test_eof23 1467 | } 1468 | st_case_23: 1469 | //line lexer/lexer.go:1440 1470 | switch l.data[(l.p)] { 1471 | case 32: 1472 | goto st23 1473 | case 40: 1474 | goto tr42 1475 | case 43: 1476 | goto tr43 1477 | case 45: 1478 | goto tr43 1479 | case 95: 1480 | goto tr45 1481 | case 102: 1482 | goto tr46 1483 | case 116: 1484 | goto tr47 1485 | } 1486 | switch { 1487 | case l.data[(l.p)] < 48: 1488 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 1489 | goto st23 1490 | } 1491 | case l.data[(l.p)] > 57: 1492 | switch { 1493 | case l.data[(l.p)] > 90: 1494 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 1495 | goto tr45 1496 | } 1497 | case l.data[(l.p)] >= 65: 1498 | goto tr45 1499 | } 1500 | default: 1501 | goto tr44 1502 | } 1503 | goto st0 1504 | tr42: 1505 | //line lexer/lexer.go.rl:51 1506 | l.ast.openPths() 1507 | //line lexer/lexer.go.rl:103 1508 | { 1509 | l.stack[l.top] = 24 1510 | l.top++ 1511 | goto st23 1512 | } 1513 | goto st24 1514 | tr52: 1515 | //line lexer/lexer.go.rl:71 1516 | l.ast.pushMathOp(l.data[l.pb]) 1517 | //line lexer/lexer.go.rl:51 1518 | l.ast.openPths() 1519 | //line lexer/lexer.go.rl:103 1520 | { 1521 | l.stack[l.top] = 24 1522 | l.top++ 1523 | goto st23 1524 | } 1525 | goto st24 1526 | tr63: 1527 | //line lexer/lexer.go.rl:53 1528 | l.ast.pushIdent(l.text()) 1529 | //line lexer/lexer.go.rl:49 1530 | l.ast.pushInvoke() 1531 | //line lexer/lexer.go.rl:102 1532 | { 1533 | l.stack[l.top] = 24 1534 | l.top++ 1535 | goto st66 1536 | } 1537 | goto st24 1538 | tr66: 1539 | //line lexer/lexer.go.rl:49 1540 | l.ast.pushInvoke() 1541 | //line lexer/lexer.go.rl:102 1542 | { 1543 | l.stack[l.top] = 24 1544 | l.top++ 1545 | goto st66 1546 | } 1547 | goto st24 1548 | tr59: 1549 | //line lexer/lexer.go.rl:62 1550 | 1551 | n64, perr = strconv.ParseInt(l.text(), 10, 64) 1552 | if perr != nil { 1553 | { 1554 | (l.p)++ 1555 | l.cs = 24 1556 | goto _out 1557 | } 1558 | } 1559 | l.ast.pushInt(n64) 1560 | 1561 | goto st24 1562 | st24: 1563 | if (l.p)++; (l.p) == (l.pe) { 1564 | goto _test_eof24 1565 | } 1566 | st_case_24: 1567 | //line lexer/lexer.go:1518 1568 | switch l.data[(l.p)] { 1569 | case 32: 1570 | goto st24 1571 | case 41: 1572 | goto tr49 1573 | case 45: 1574 | goto tr50 1575 | case 47: 1576 | goto tr50 1577 | } 1578 | switch { 1579 | case l.data[(l.p)] > 13: 1580 | if 42 <= l.data[(l.p)] && l.data[(l.p)] <= 43 { 1581 | goto tr50 1582 | } 1583 | case l.data[(l.p)] >= 9: 1584 | goto st24 1585 | } 1586 | goto st0 1587 | tr49: 1588 | //line lexer/lexer.go.rl:52 1589 | l.ast.closePths() 1590 | //line lexer/lexer.go.rl:44 1591 | { 1592 | l.top-- 1593 | l.cs = l.stack[l.top] 1594 | goto _again 1595 | } 1596 | goto st101 1597 | tr60: 1598 | //line lexer/lexer.go.rl:62 1599 | 1600 | n64, perr = strconv.ParseInt(l.text(), 10, 64) 1601 | if perr != nil { 1602 | { 1603 | (l.p)++ 1604 | l.cs = 101 1605 | goto _out 1606 | } 1607 | } 1608 | l.ast.pushInt(n64) 1609 | 1610 | //line lexer/lexer.go.rl:52 1611 | l.ast.closePths() 1612 | //line lexer/lexer.go.rl:44 1613 | { 1614 | l.top-- 1615 | l.cs = l.stack[l.top] 1616 | goto _again 1617 | } 1618 | goto st101 1619 | st101: 1620 | if (l.p)++; (l.p) == (l.pe) { 1621 | goto _test_eof101 1622 | } 1623 | st_case_101: 1624 | //line lexer/lexer.go:1563 1625 | goto st0 1626 | tr50: 1627 | //line lexer/lexer.go.rl:45 1628 | l.pb = l.p 1629 | goto st25 1630 | tr61: 1631 | //line lexer/lexer.go.rl:62 1632 | 1633 | n64, perr = strconv.ParseInt(l.text(), 10, 64) 1634 | if perr != nil { 1635 | { 1636 | (l.p)++ 1637 | l.cs = 25 1638 | goto _out 1639 | } 1640 | } 1641 | l.ast.pushInt(n64) 1642 | 1643 | //line lexer/lexer.go.rl:45 1644 | l.pb = l.p 1645 | goto st25 1646 | st25: 1647 | if (l.p)++; (l.p) == (l.pe) { 1648 | goto _test_eof25 1649 | } 1650 | st_case_25: 1651 | //line lexer/lexer.go:1586 1652 | switch l.data[(l.p)] { 1653 | case 32: 1654 | goto tr51 1655 | case 40: 1656 | goto tr52 1657 | case 43: 1658 | goto tr53 1659 | case 45: 1660 | goto tr53 1661 | case 95: 1662 | goto tr55 1663 | case 102: 1664 | goto tr56 1665 | case 116: 1666 | goto tr57 1667 | } 1668 | switch { 1669 | case l.data[(l.p)] < 48: 1670 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 1671 | goto tr51 1672 | } 1673 | case l.data[(l.p)] > 57: 1674 | switch { 1675 | case l.data[(l.p)] > 90: 1676 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 1677 | goto tr55 1678 | } 1679 | case l.data[(l.p)] >= 65: 1680 | goto tr55 1681 | } 1682 | default: 1683 | goto tr54 1684 | } 1685 | goto st0 1686 | tr43: 1687 | //line lexer/lexer.go.rl:45 1688 | l.pb = l.p 1689 | goto st26 1690 | tr53: 1691 | //line lexer/lexer.go.rl:71 1692 | l.ast.pushMathOp(l.data[l.pb]) 1693 | //line lexer/lexer.go.rl:45 1694 | l.pb = l.p 1695 | goto st26 1696 | st26: 1697 | if (l.p)++; (l.p) == (l.pe) { 1698 | goto _test_eof26 1699 | } 1700 | st_case_26: 1701 | //line lexer/lexer.go:1636 1702 | if 48 <= l.data[(l.p)] && l.data[(l.p)] <= 57 { 1703 | goto st27 1704 | } 1705 | goto st0 1706 | tr44: 1707 | //line lexer/lexer.go.rl:45 1708 | l.pb = l.p 1709 | goto st27 1710 | tr54: 1711 | //line lexer/lexer.go.rl:71 1712 | l.ast.pushMathOp(l.data[l.pb]) 1713 | //line lexer/lexer.go.rl:45 1714 | l.pb = l.p 1715 | goto st27 1716 | st27: 1717 | if (l.p)++; (l.p) == (l.pe) { 1718 | goto _test_eof27 1719 | } 1720 | st_case_27: 1721 | //line lexer/lexer.go:1656 1722 | switch l.data[(l.p)] { 1723 | case 32: 1724 | goto tr59 1725 | case 41: 1726 | goto tr60 1727 | case 45: 1728 | goto tr61 1729 | case 47: 1730 | goto tr61 1731 | } 1732 | switch { 1733 | case l.data[(l.p)] < 42: 1734 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 1735 | goto tr59 1736 | } 1737 | case l.data[(l.p)] > 43: 1738 | if 48 <= l.data[(l.p)] && l.data[(l.p)] <= 57 { 1739 | goto st27 1740 | } 1741 | default: 1742 | goto tr61 1743 | } 1744 | goto st0 1745 | tr45: 1746 | //line lexer/lexer.go.rl:45 1747 | l.pb = l.p 1748 | goto st28 1749 | tr55: 1750 | //line lexer/lexer.go.rl:71 1751 | l.ast.pushMathOp(l.data[l.pb]) 1752 | //line lexer/lexer.go.rl:45 1753 | l.pb = l.p 1754 | goto st28 1755 | st28: 1756 | if (l.p)++; (l.p) == (l.pe) { 1757 | goto _test_eof28 1758 | } 1759 | st_case_28: 1760 | //line lexer/lexer.go:1695 1761 | switch l.data[(l.p)] { 1762 | case 32: 1763 | goto tr62 1764 | case 40: 1765 | goto tr63 1766 | case 95: 1767 | goto st28 1768 | } 1769 | switch { 1770 | case l.data[(l.p)] < 48: 1771 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 1772 | goto tr62 1773 | } 1774 | case l.data[(l.p)] > 57: 1775 | switch { 1776 | case l.data[(l.p)] > 90: 1777 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 1778 | goto st28 1779 | } 1780 | case l.data[(l.p)] >= 65: 1781 | goto st28 1782 | } 1783 | default: 1784 | goto st28 1785 | } 1786 | goto st0 1787 | tr62: 1788 | //line lexer/lexer.go.rl:53 1789 | l.ast.pushIdent(l.text()) 1790 | goto st29 1791 | st29: 1792 | if (l.p)++; (l.p) == (l.pe) { 1793 | goto _test_eof29 1794 | } 1795 | st_case_29: 1796 | //line lexer/lexer.go:1731 1797 | switch l.data[(l.p)] { 1798 | case 32: 1799 | goto st29 1800 | case 40: 1801 | goto tr66 1802 | } 1803 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 1804 | goto st29 1805 | } 1806 | goto st0 1807 | tr46: 1808 | //line lexer/lexer.go.rl:45 1809 | l.pb = l.p 1810 | goto st30 1811 | tr56: 1812 | //line lexer/lexer.go.rl:71 1813 | l.ast.pushMathOp(l.data[l.pb]) 1814 | //line lexer/lexer.go.rl:45 1815 | l.pb = l.p 1816 | goto st30 1817 | st30: 1818 | if (l.p)++; (l.p) == (l.pe) { 1819 | goto _test_eof30 1820 | } 1821 | st_case_30: 1822 | //line lexer/lexer.go:1757 1823 | switch l.data[(l.p)] { 1824 | case 32: 1825 | goto tr62 1826 | case 40: 1827 | goto tr63 1828 | case 95: 1829 | goto st28 1830 | case 97: 1831 | goto st31 1832 | } 1833 | switch { 1834 | case l.data[(l.p)] < 48: 1835 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 1836 | goto tr62 1837 | } 1838 | case l.data[(l.p)] > 57: 1839 | switch { 1840 | case l.data[(l.p)] > 90: 1841 | if 98 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 1842 | goto st28 1843 | } 1844 | case l.data[(l.p)] >= 65: 1845 | goto st28 1846 | } 1847 | default: 1848 | goto st28 1849 | } 1850 | goto st0 1851 | st31: 1852 | if (l.p)++; (l.p) == (l.pe) { 1853 | goto _test_eof31 1854 | } 1855 | st_case_31: 1856 | switch l.data[(l.p)] { 1857 | case 32: 1858 | goto tr62 1859 | case 40: 1860 | goto tr63 1861 | case 95: 1862 | goto st28 1863 | case 108: 1864 | goto st32 1865 | } 1866 | switch { 1867 | case l.data[(l.p)] < 48: 1868 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 1869 | goto tr62 1870 | } 1871 | case l.data[(l.p)] > 57: 1872 | switch { 1873 | case l.data[(l.p)] > 90: 1874 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 1875 | goto st28 1876 | } 1877 | case l.data[(l.p)] >= 65: 1878 | goto st28 1879 | } 1880 | default: 1881 | goto st28 1882 | } 1883 | goto st0 1884 | st32: 1885 | if (l.p)++; (l.p) == (l.pe) { 1886 | goto _test_eof32 1887 | } 1888 | st_case_32: 1889 | switch l.data[(l.p)] { 1890 | case 32: 1891 | goto tr62 1892 | case 40: 1893 | goto tr63 1894 | case 95: 1895 | goto st28 1896 | case 115: 1897 | goto st33 1898 | } 1899 | switch { 1900 | case l.data[(l.p)] < 48: 1901 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 1902 | goto tr62 1903 | } 1904 | case l.data[(l.p)] > 57: 1905 | switch { 1906 | case l.data[(l.p)] > 90: 1907 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 1908 | goto st28 1909 | } 1910 | case l.data[(l.p)] >= 65: 1911 | goto st28 1912 | } 1913 | default: 1914 | goto st28 1915 | } 1916 | goto st0 1917 | st33: 1918 | if (l.p)++; (l.p) == (l.pe) { 1919 | goto _test_eof33 1920 | } 1921 | st_case_33: 1922 | switch l.data[(l.p)] { 1923 | case 32: 1924 | goto tr62 1925 | case 40: 1926 | goto tr63 1927 | case 95: 1928 | goto st28 1929 | case 101: 1930 | goto st34 1931 | } 1932 | switch { 1933 | case l.data[(l.p)] < 48: 1934 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 1935 | goto tr62 1936 | } 1937 | case l.data[(l.p)] > 57: 1938 | switch { 1939 | case l.data[(l.p)] > 90: 1940 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 1941 | goto st28 1942 | } 1943 | case l.data[(l.p)] >= 65: 1944 | goto st28 1945 | } 1946 | default: 1947 | goto st28 1948 | } 1949 | goto st0 1950 | st34: 1951 | if (l.p)++; (l.p) == (l.pe) { 1952 | goto _test_eof34 1953 | } 1954 | st_case_34: 1955 | if l.data[(l.p)] == 95 { 1956 | goto st28 1957 | } 1958 | switch { 1959 | case l.data[(l.p)] < 65: 1960 | if 48 <= l.data[(l.p)] && l.data[(l.p)] <= 57 { 1961 | goto st28 1962 | } 1963 | case l.data[(l.p)] > 90: 1964 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 1965 | goto st28 1966 | } 1967 | default: 1968 | goto st28 1969 | } 1970 | goto st0 1971 | tr47: 1972 | //line lexer/lexer.go.rl:45 1973 | l.pb = l.p 1974 | goto st35 1975 | tr57: 1976 | //line lexer/lexer.go.rl:71 1977 | l.ast.pushMathOp(l.data[l.pb]) 1978 | //line lexer/lexer.go.rl:45 1979 | l.pb = l.p 1980 | goto st35 1981 | st35: 1982 | if (l.p)++; (l.p) == (l.pe) { 1983 | goto _test_eof35 1984 | } 1985 | st_case_35: 1986 | //line lexer/lexer.go:1921 1987 | switch l.data[(l.p)] { 1988 | case 32: 1989 | goto tr62 1990 | case 40: 1991 | goto tr63 1992 | case 95: 1993 | goto st28 1994 | case 114: 1995 | goto st36 1996 | } 1997 | switch { 1998 | case l.data[(l.p)] < 48: 1999 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 2000 | goto tr62 2001 | } 2002 | case l.data[(l.p)] > 57: 2003 | switch { 2004 | case l.data[(l.p)] > 90: 2005 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 2006 | goto st28 2007 | } 2008 | case l.data[(l.p)] >= 65: 2009 | goto st28 2010 | } 2011 | default: 2012 | goto st28 2013 | } 2014 | goto st0 2015 | st36: 2016 | if (l.p)++; (l.p) == (l.pe) { 2017 | goto _test_eof36 2018 | } 2019 | st_case_36: 2020 | switch l.data[(l.p)] { 2021 | case 32: 2022 | goto tr62 2023 | case 40: 2024 | goto tr63 2025 | case 95: 2026 | goto st28 2027 | case 117: 2028 | goto st33 2029 | } 2030 | switch { 2031 | case l.data[(l.p)] < 48: 2032 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 2033 | goto tr62 2034 | } 2035 | case l.data[(l.p)] > 57: 2036 | switch { 2037 | case l.data[(l.p)] > 90: 2038 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 2039 | goto st28 2040 | } 2041 | case l.data[(l.p)] >= 65: 2042 | goto st28 2043 | } 2044 | default: 2045 | goto st28 2046 | } 2047 | goto st0 2048 | st37: 2049 | if (l.p)++; (l.p) == (l.pe) { 2050 | goto _test_eof37 2051 | } 2052 | st_case_37: 2053 | switch l.data[(l.p)] { 2054 | case 32: 2055 | goto st37 2056 | case 34: 2057 | goto tr73 2058 | case 40: 2059 | goto tr74 2060 | case 43: 2061 | goto tr75 2062 | case 45: 2063 | goto tr75 2064 | case 91: 2065 | goto tr78 2066 | case 93: 2067 | goto tr79 2068 | case 95: 2069 | goto tr77 2070 | case 102: 2071 | goto tr80 2072 | case 116: 2073 | goto tr81 2074 | } 2075 | switch { 2076 | case l.data[(l.p)] < 48: 2077 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 2078 | goto st37 2079 | } 2080 | case l.data[(l.p)] > 57: 2081 | switch { 2082 | case l.data[(l.p)] > 90: 2083 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 2084 | goto tr77 2085 | } 2086 | case l.data[(l.p)] >= 65: 2087 | goto tr77 2088 | } 2089 | default: 2090 | goto tr76 2091 | } 2092 | goto st0 2093 | tr91: 2094 | //line lexer/lexer.go.rl:45 2095 | l.pb = l.p 2096 | goto st38 2097 | tr73: 2098 | //line lexer/lexer.go.rl:46 2099 | l.ast.incCaps() 2100 | //line lexer/lexer.go.rl:45 2101 | l.pb = l.p 2102 | goto st38 2103 | st38: 2104 | if (l.p)++; (l.p) == (l.pe) { 2105 | goto _test_eof38 2106 | } 2107 | st_case_38: 2108 | //line lexer/lexer.go:2043 2109 | switch l.data[(l.p)] { 2110 | case 34: 2111 | goto st39 2112 | case 92: 2113 | goto st65 2114 | } 2115 | goto st38 2116 | st39: 2117 | if (l.p)++; (l.p) == (l.pe) { 2118 | goto _test_eof39 2119 | } 2120 | st_case_39: 2121 | switch l.data[(l.p)] { 2122 | case 32: 2123 | goto tr85 2124 | case 44: 2125 | goto tr86 2126 | case 93: 2127 | goto tr87 2128 | } 2129 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 2130 | goto tr85 2131 | } 2132 | goto st0 2133 | tr96: 2134 | //line lexer/lexer.go.rl:50 2135 | l.ast.pushVector() 2136 | //line lexer/lexer.go.rl:101 2137 | { 2138 | l.stack[l.top] = 40 2139 | l.top++ 2140 | goto st37 2141 | } 2142 | goto st40 2143 | tr78: 2144 | //line lexer/lexer.go.rl:46 2145 | l.ast.incCaps() 2146 | //line lexer/lexer.go.rl:50 2147 | l.ast.pushVector() 2148 | //line lexer/lexer.go.rl:101 2149 | { 2150 | l.stack[l.top] = 40 2151 | l.top++ 2152 | goto st37 2153 | } 2154 | goto st40 2155 | tr85: 2156 | //line lexer/lexer.go.rl:54 2157 | 2158 | str, perr = strconv.Unquote(l.text()) 2159 | if perr != nil { 2160 | perr = errors.Wrapf(perr, "strconv.Unquote %s", l.text()) 2161 | { 2162 | (l.p)++ 2163 | l.cs = 40 2164 | goto _out 2165 | } 2166 | } 2167 | l.ast.pushStr(str) 2168 | 2169 | goto st40 2170 | tr130: 2171 | //line lexer/lexer.go.rl:70 2172 | l.ast.pushFalse() 2173 | goto st40 2174 | tr136: 2175 | //line lexer/lexer.go.rl:69 2176 | l.ast.pushTrue() 2177 | goto st40 2178 | st40: 2179 | if (l.p)++; (l.p) == (l.pe) { 2180 | goto _test_eof40 2181 | } 2182 | st_case_40: 2183 | //line lexer/lexer.go:2106 2184 | switch l.data[(l.p)] { 2185 | case 32: 2186 | goto st40 2187 | case 44: 2188 | goto tr89 2189 | case 93: 2190 | goto tr79 2191 | } 2192 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 2193 | goto st40 2194 | } 2195 | goto st0 2196 | tr86: 2197 | //line lexer/lexer.go.rl:54 2198 | 2199 | str, perr = strconv.Unquote(l.text()) 2200 | if perr != nil { 2201 | perr = errors.Wrapf(perr, "strconv.Unquote %s", l.text()) 2202 | { 2203 | (l.p)++ 2204 | l.cs = 41 2205 | goto _out 2206 | } 2207 | } 2208 | l.ast.pushStr(str) 2209 | 2210 | //line lexer/lexer.go.rl:47 2211 | l.ast.rotateComma() 2212 | goto st41 2213 | tr89: 2214 | //line lexer/lexer.go.rl:47 2215 | l.ast.rotateComma() 2216 | goto st41 2217 | tr114: 2218 | //line lexer/lexer.go.rl:62 2219 | 2220 | n64, perr = strconv.ParseInt(l.text(), 10, 64) 2221 | if perr != nil { 2222 | { 2223 | (l.p)++ 2224 | l.cs = 41 2225 | goto _out 2226 | } 2227 | } 2228 | l.ast.pushInt(n64) 2229 | 2230 | //line lexer/lexer.go.rl:47 2231 | l.ast.rotateComma() 2232 | goto st41 2233 | tr131: 2234 | //line lexer/lexer.go.rl:70 2235 | l.ast.pushFalse() 2236 | //line lexer/lexer.go.rl:47 2237 | l.ast.rotateComma() 2238 | goto st41 2239 | tr137: 2240 | //line lexer/lexer.go.rl:69 2241 | l.ast.pushTrue() 2242 | //line lexer/lexer.go.rl:47 2243 | l.ast.rotateComma() 2244 | goto st41 2245 | st41: 2246 | if (l.p)++; (l.p) == (l.pe) { 2247 | goto _test_eof41 2248 | } 2249 | st_case_41: 2250 | //line lexer/lexer.go:2165 2251 | switch l.data[(l.p)] { 2252 | case 32: 2253 | goto st41 2254 | case 34: 2255 | goto tr91 2256 | case 40: 2257 | goto tr92 2258 | case 43: 2259 | goto tr93 2260 | case 45: 2261 | goto tr93 2262 | case 91: 2263 | goto tr96 2264 | case 95: 2265 | goto tr95 2266 | case 102: 2267 | goto tr97 2268 | case 116: 2269 | goto tr98 2270 | } 2271 | switch { 2272 | case l.data[(l.p)] < 48: 2273 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 2274 | goto st41 2275 | } 2276 | case l.data[(l.p)] > 57: 2277 | switch { 2278 | case l.data[(l.p)] > 90: 2279 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 2280 | goto tr95 2281 | } 2282 | case l.data[(l.p)] >= 65: 2283 | goto tr95 2284 | } 2285 | default: 2286 | goto tr94 2287 | } 2288 | goto st0 2289 | tr92: 2290 | //line lexer/lexer.go.rl:51 2291 | l.ast.openPths() 2292 | //line lexer/lexer.go.rl:103 2293 | { 2294 | l.stack[l.top] = 42 2295 | l.top++ 2296 | goto st23 2297 | } 2298 | goto st42 2299 | tr102: 2300 | //line lexer/lexer.go.rl:71 2301 | l.ast.pushMathOp(l.data[l.pb]) 2302 | //line lexer/lexer.go.rl:51 2303 | l.ast.openPths() 2304 | //line lexer/lexer.go.rl:103 2305 | { 2306 | l.stack[l.top] = 42 2307 | l.top++ 2308 | goto st23 2309 | } 2310 | goto st42 2311 | tr117: 2312 | //line lexer/lexer.go.rl:53 2313 | l.ast.pushIdent(l.text()) 2314 | //line lexer/lexer.go.rl:49 2315 | l.ast.pushInvoke() 2316 | //line lexer/lexer.go.rl:102 2317 | { 2318 | l.stack[l.top] = 42 2319 | l.top++ 2320 | goto st66 2321 | } 2322 | goto st42 2323 | tr120: 2324 | //line lexer/lexer.go.rl:49 2325 | l.ast.pushInvoke() 2326 | //line lexer/lexer.go.rl:102 2327 | { 2328 | l.stack[l.top] = 42 2329 | l.top++ 2330 | goto st66 2331 | } 2332 | goto st42 2333 | tr112: 2334 | //line lexer/lexer.go.rl:62 2335 | 2336 | n64, perr = strconv.ParseInt(l.text(), 10, 64) 2337 | if perr != nil { 2338 | { 2339 | (l.p)++ 2340 | l.cs = 42 2341 | goto _out 2342 | } 2343 | } 2344 | l.ast.pushInt(n64) 2345 | 2346 | goto st42 2347 | tr74: 2348 | //line lexer/lexer.go.rl:46 2349 | l.ast.incCaps() 2350 | //line lexer/lexer.go.rl:51 2351 | l.ast.openPths() 2352 | //line lexer/lexer.go.rl:103 2353 | { 2354 | l.stack[l.top] = 42 2355 | l.top++ 2356 | goto st23 2357 | } 2358 | goto st42 2359 | st42: 2360 | if (l.p)++; (l.p) == (l.pe) { 2361 | goto _test_eof42 2362 | } 2363 | st_case_42: 2364 | //line lexer/lexer.go:2255 2365 | switch l.data[(l.p)] { 2366 | case 32: 2367 | goto st42 2368 | case 44: 2369 | goto tr89 2370 | case 47: 2371 | goto tr100 2372 | case 93: 2373 | goto tr79 2374 | } 2375 | switch { 2376 | case l.data[(l.p)] > 13: 2377 | if 42 <= l.data[(l.p)] && l.data[(l.p)] <= 45 { 2378 | goto tr100 2379 | } 2380 | case l.data[(l.p)] >= 9: 2381 | goto st42 2382 | } 2383 | goto st0 2384 | tr100: 2385 | //line lexer/lexer.go.rl:45 2386 | l.pb = l.p 2387 | goto st43 2388 | tr113: 2389 | //line lexer/lexer.go.rl:62 2390 | 2391 | n64, perr = strconv.ParseInt(l.text(), 10, 64) 2392 | if perr != nil { 2393 | { 2394 | (l.p)++ 2395 | l.cs = 43 2396 | goto _out 2397 | } 2398 | } 2399 | l.ast.pushInt(n64) 2400 | 2401 | //line lexer/lexer.go.rl:45 2402 | l.pb = l.p 2403 | goto st43 2404 | st43: 2405 | if (l.p)++; (l.p) == (l.pe) { 2406 | goto _test_eof43 2407 | } 2408 | st_case_43: 2409 | //line lexer/lexer.go:2296 2410 | switch l.data[(l.p)] { 2411 | case 32: 2412 | goto tr101 2413 | case 40: 2414 | goto tr102 2415 | case 43: 2416 | goto tr103 2417 | case 45: 2418 | goto tr103 2419 | case 95: 2420 | goto tr105 2421 | case 102: 2422 | goto tr106 2423 | case 116: 2424 | goto tr107 2425 | } 2426 | switch { 2427 | case l.data[(l.p)] < 48: 2428 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 2429 | goto tr101 2430 | } 2431 | case l.data[(l.p)] > 57: 2432 | switch { 2433 | case l.data[(l.p)] > 90: 2434 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 2435 | goto tr105 2436 | } 2437 | case l.data[(l.p)] >= 65: 2438 | goto tr105 2439 | } 2440 | default: 2441 | goto tr104 2442 | } 2443 | goto st0 2444 | tr101: 2445 | //line lexer/lexer.go.rl:71 2446 | l.ast.pushMathOp(l.data[l.pb]) 2447 | goto st44 2448 | st44: 2449 | if (l.p)++; (l.p) == (l.pe) { 2450 | goto _test_eof44 2451 | } 2452 | st_case_44: 2453 | //line lexer/lexer.go:2340 2454 | switch l.data[(l.p)] { 2455 | case 32: 2456 | goto st44 2457 | case 40: 2458 | goto tr92 2459 | case 43: 2460 | goto tr93 2461 | case 45: 2462 | goto tr93 2463 | case 95: 2464 | goto tr95 2465 | case 102: 2466 | goto tr109 2467 | case 116: 2468 | goto tr110 2469 | } 2470 | switch { 2471 | case l.data[(l.p)] < 48: 2472 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 2473 | goto st44 2474 | } 2475 | case l.data[(l.p)] > 57: 2476 | switch { 2477 | case l.data[(l.p)] > 90: 2478 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 2479 | goto tr95 2480 | } 2481 | case l.data[(l.p)] >= 65: 2482 | goto tr95 2483 | } 2484 | default: 2485 | goto tr94 2486 | } 2487 | goto st0 2488 | tr93: 2489 | //line lexer/lexer.go.rl:45 2490 | l.pb = l.p 2491 | goto st45 2492 | tr103: 2493 | //line lexer/lexer.go.rl:71 2494 | l.ast.pushMathOp(l.data[l.pb]) 2495 | //line lexer/lexer.go.rl:45 2496 | l.pb = l.p 2497 | goto st45 2498 | tr75: 2499 | //line lexer/lexer.go.rl:46 2500 | l.ast.incCaps() 2501 | //line lexer/lexer.go.rl:45 2502 | l.pb = l.p 2503 | goto st45 2504 | st45: 2505 | if (l.p)++; (l.p) == (l.pe) { 2506 | goto _test_eof45 2507 | } 2508 | st_case_45: 2509 | //line lexer/lexer.go:2396 2510 | if 48 <= l.data[(l.p)] && l.data[(l.p)] <= 57 { 2511 | goto st46 2512 | } 2513 | goto st0 2514 | tr94: 2515 | //line lexer/lexer.go.rl:45 2516 | l.pb = l.p 2517 | goto st46 2518 | tr104: 2519 | //line lexer/lexer.go.rl:71 2520 | l.ast.pushMathOp(l.data[l.pb]) 2521 | //line lexer/lexer.go.rl:45 2522 | l.pb = l.p 2523 | goto st46 2524 | tr76: 2525 | //line lexer/lexer.go.rl:46 2526 | l.ast.incCaps() 2527 | //line lexer/lexer.go.rl:45 2528 | l.pb = l.p 2529 | goto st46 2530 | st46: 2531 | if (l.p)++; (l.p) == (l.pe) { 2532 | goto _test_eof46 2533 | } 2534 | st_case_46: 2535 | //line lexer/lexer.go:2422 2536 | switch l.data[(l.p)] { 2537 | case 32: 2538 | goto tr112 2539 | case 44: 2540 | goto tr114 2541 | case 47: 2542 | goto tr113 2543 | case 93: 2544 | goto tr115 2545 | } 2546 | switch { 2547 | case l.data[(l.p)] < 42: 2548 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 2549 | goto tr112 2550 | } 2551 | case l.data[(l.p)] > 45: 2552 | if 48 <= l.data[(l.p)] && l.data[(l.p)] <= 57 { 2553 | goto st46 2554 | } 2555 | default: 2556 | goto tr113 2557 | } 2558 | goto st0 2559 | tr79: 2560 | //line lexer/lexer.go.rl:48 2561 | l.ast.popCaps() 2562 | //line lexer/lexer.go.rl:44 2563 | { 2564 | l.top-- 2565 | l.cs = l.stack[l.top] 2566 | goto _again 2567 | } 2568 | goto st102 2569 | tr87: 2570 | //line lexer/lexer.go.rl:54 2571 | 2572 | str, perr = strconv.Unquote(l.text()) 2573 | if perr != nil { 2574 | perr = errors.Wrapf(perr, "strconv.Unquote %s", l.text()) 2575 | { 2576 | (l.p)++ 2577 | l.cs = 102 2578 | goto _out 2579 | } 2580 | } 2581 | l.ast.pushStr(str) 2582 | 2583 | //line lexer/lexer.go.rl:48 2584 | l.ast.popCaps() 2585 | //line lexer/lexer.go.rl:44 2586 | { 2587 | l.top-- 2588 | l.cs = l.stack[l.top] 2589 | goto _again 2590 | } 2591 | goto st102 2592 | tr115: 2593 | //line lexer/lexer.go.rl:62 2594 | 2595 | n64, perr = strconv.ParseInt(l.text(), 10, 64) 2596 | if perr != nil { 2597 | { 2598 | (l.p)++ 2599 | l.cs = 102 2600 | goto _out 2601 | } 2602 | } 2603 | l.ast.pushInt(n64) 2604 | 2605 | //line lexer/lexer.go.rl:48 2606 | l.ast.popCaps() 2607 | //line lexer/lexer.go.rl:44 2608 | { 2609 | l.top-- 2610 | l.cs = l.stack[l.top] 2611 | goto _again 2612 | } 2613 | goto st102 2614 | tr132: 2615 | //line lexer/lexer.go.rl:70 2616 | l.ast.pushFalse() 2617 | //line lexer/lexer.go.rl:48 2618 | l.ast.popCaps() 2619 | //line lexer/lexer.go.rl:44 2620 | { 2621 | l.top-- 2622 | l.cs = l.stack[l.top] 2623 | goto _again 2624 | } 2625 | goto st102 2626 | tr138: 2627 | //line lexer/lexer.go.rl:69 2628 | l.ast.pushTrue() 2629 | //line lexer/lexer.go.rl:48 2630 | l.ast.popCaps() 2631 | //line lexer/lexer.go.rl:44 2632 | { 2633 | l.top-- 2634 | l.cs = l.stack[l.top] 2635 | goto _again 2636 | } 2637 | goto st102 2638 | st102: 2639 | if (l.p)++; (l.p) == (l.pe) { 2640 | goto _test_eof102 2641 | } 2642 | st_case_102: 2643 | //line lexer/lexer.go:2502 2644 | goto st0 2645 | tr95: 2646 | //line lexer/lexer.go.rl:45 2647 | l.pb = l.p 2648 | goto st47 2649 | tr105: 2650 | //line lexer/lexer.go.rl:71 2651 | l.ast.pushMathOp(l.data[l.pb]) 2652 | //line lexer/lexer.go.rl:45 2653 | l.pb = l.p 2654 | goto st47 2655 | tr77: 2656 | //line lexer/lexer.go.rl:46 2657 | l.ast.incCaps() 2658 | //line lexer/lexer.go.rl:45 2659 | l.pb = l.p 2660 | goto st47 2661 | st47: 2662 | if (l.p)++; (l.p) == (l.pe) { 2663 | goto _test_eof47 2664 | } 2665 | st_case_47: 2666 | //line lexer/lexer.go:2525 2667 | switch l.data[(l.p)] { 2668 | case 32: 2669 | goto tr116 2670 | case 40: 2671 | goto tr117 2672 | case 95: 2673 | goto st47 2674 | } 2675 | switch { 2676 | case l.data[(l.p)] < 48: 2677 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 2678 | goto tr116 2679 | } 2680 | case l.data[(l.p)] > 57: 2681 | switch { 2682 | case l.data[(l.p)] > 90: 2683 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 2684 | goto st47 2685 | } 2686 | case l.data[(l.p)] >= 65: 2687 | goto st47 2688 | } 2689 | default: 2690 | goto st47 2691 | } 2692 | goto st0 2693 | tr116: 2694 | //line lexer/lexer.go.rl:53 2695 | l.ast.pushIdent(l.text()) 2696 | goto st48 2697 | st48: 2698 | if (l.p)++; (l.p) == (l.pe) { 2699 | goto _test_eof48 2700 | } 2701 | st_case_48: 2702 | //line lexer/lexer.go:2561 2703 | switch l.data[(l.p)] { 2704 | case 32: 2705 | goto st48 2706 | case 40: 2707 | goto tr120 2708 | } 2709 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 2710 | goto st48 2711 | } 2712 | goto st0 2713 | tr109: 2714 | //line lexer/lexer.go.rl:45 2715 | l.pb = l.p 2716 | goto st49 2717 | tr106: 2718 | //line lexer/lexer.go.rl:71 2719 | l.ast.pushMathOp(l.data[l.pb]) 2720 | //line lexer/lexer.go.rl:45 2721 | l.pb = l.p 2722 | goto st49 2723 | st49: 2724 | if (l.p)++; (l.p) == (l.pe) { 2725 | goto _test_eof49 2726 | } 2727 | st_case_49: 2728 | //line lexer/lexer.go:2587 2729 | switch l.data[(l.p)] { 2730 | case 32: 2731 | goto tr116 2732 | case 40: 2733 | goto tr117 2734 | case 95: 2735 | goto st47 2736 | case 97: 2737 | goto st50 2738 | } 2739 | switch { 2740 | case l.data[(l.p)] < 48: 2741 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 2742 | goto tr116 2743 | } 2744 | case l.data[(l.p)] > 57: 2745 | switch { 2746 | case l.data[(l.p)] > 90: 2747 | if 98 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 2748 | goto st47 2749 | } 2750 | case l.data[(l.p)] >= 65: 2751 | goto st47 2752 | } 2753 | default: 2754 | goto st47 2755 | } 2756 | goto st0 2757 | st50: 2758 | if (l.p)++; (l.p) == (l.pe) { 2759 | goto _test_eof50 2760 | } 2761 | st_case_50: 2762 | switch l.data[(l.p)] { 2763 | case 32: 2764 | goto tr116 2765 | case 40: 2766 | goto tr117 2767 | case 95: 2768 | goto st47 2769 | case 108: 2770 | goto st51 2771 | } 2772 | switch { 2773 | case l.data[(l.p)] < 48: 2774 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 2775 | goto tr116 2776 | } 2777 | case l.data[(l.p)] > 57: 2778 | switch { 2779 | case l.data[(l.p)] > 90: 2780 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 2781 | goto st47 2782 | } 2783 | case l.data[(l.p)] >= 65: 2784 | goto st47 2785 | } 2786 | default: 2787 | goto st47 2788 | } 2789 | goto st0 2790 | st51: 2791 | if (l.p)++; (l.p) == (l.pe) { 2792 | goto _test_eof51 2793 | } 2794 | st_case_51: 2795 | switch l.data[(l.p)] { 2796 | case 32: 2797 | goto tr116 2798 | case 40: 2799 | goto tr117 2800 | case 95: 2801 | goto st47 2802 | case 115: 2803 | goto st52 2804 | } 2805 | switch { 2806 | case l.data[(l.p)] < 48: 2807 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 2808 | goto tr116 2809 | } 2810 | case l.data[(l.p)] > 57: 2811 | switch { 2812 | case l.data[(l.p)] > 90: 2813 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 2814 | goto st47 2815 | } 2816 | case l.data[(l.p)] >= 65: 2817 | goto st47 2818 | } 2819 | default: 2820 | goto st47 2821 | } 2822 | goto st0 2823 | st52: 2824 | if (l.p)++; (l.p) == (l.pe) { 2825 | goto _test_eof52 2826 | } 2827 | st_case_52: 2828 | switch l.data[(l.p)] { 2829 | case 32: 2830 | goto tr116 2831 | case 40: 2832 | goto tr117 2833 | case 95: 2834 | goto st47 2835 | case 101: 2836 | goto st53 2837 | } 2838 | switch { 2839 | case l.data[(l.p)] < 48: 2840 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 2841 | goto tr116 2842 | } 2843 | case l.data[(l.p)] > 57: 2844 | switch { 2845 | case l.data[(l.p)] > 90: 2846 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 2847 | goto st47 2848 | } 2849 | case l.data[(l.p)] >= 65: 2850 | goto st47 2851 | } 2852 | default: 2853 | goto st47 2854 | } 2855 | goto st0 2856 | st53: 2857 | if (l.p)++; (l.p) == (l.pe) { 2858 | goto _test_eof53 2859 | } 2860 | st_case_53: 2861 | if l.data[(l.p)] == 95 { 2862 | goto st47 2863 | } 2864 | switch { 2865 | case l.data[(l.p)] < 65: 2866 | if 48 <= l.data[(l.p)] && l.data[(l.p)] <= 57 { 2867 | goto st47 2868 | } 2869 | case l.data[(l.p)] > 90: 2870 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 2871 | goto st47 2872 | } 2873 | default: 2874 | goto st47 2875 | } 2876 | goto st0 2877 | tr110: 2878 | //line lexer/lexer.go.rl:45 2879 | l.pb = l.p 2880 | goto st54 2881 | tr107: 2882 | //line lexer/lexer.go.rl:71 2883 | l.ast.pushMathOp(l.data[l.pb]) 2884 | //line lexer/lexer.go.rl:45 2885 | l.pb = l.p 2886 | goto st54 2887 | st54: 2888 | if (l.p)++; (l.p) == (l.pe) { 2889 | goto _test_eof54 2890 | } 2891 | st_case_54: 2892 | //line lexer/lexer.go:2751 2893 | switch l.data[(l.p)] { 2894 | case 32: 2895 | goto tr116 2896 | case 40: 2897 | goto tr117 2898 | case 95: 2899 | goto st47 2900 | case 114: 2901 | goto st55 2902 | } 2903 | switch { 2904 | case l.data[(l.p)] < 48: 2905 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 2906 | goto tr116 2907 | } 2908 | case l.data[(l.p)] > 57: 2909 | switch { 2910 | case l.data[(l.p)] > 90: 2911 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 2912 | goto st47 2913 | } 2914 | case l.data[(l.p)] >= 65: 2915 | goto st47 2916 | } 2917 | default: 2918 | goto st47 2919 | } 2920 | goto st0 2921 | st55: 2922 | if (l.p)++; (l.p) == (l.pe) { 2923 | goto _test_eof55 2924 | } 2925 | st_case_55: 2926 | switch l.data[(l.p)] { 2927 | case 32: 2928 | goto tr116 2929 | case 40: 2930 | goto tr117 2931 | case 95: 2932 | goto st47 2933 | case 117: 2934 | goto st52 2935 | } 2936 | switch { 2937 | case l.data[(l.p)] < 48: 2938 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 2939 | goto tr116 2940 | } 2941 | case l.data[(l.p)] > 57: 2942 | switch { 2943 | case l.data[(l.p)] > 90: 2944 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 2945 | goto st47 2946 | } 2947 | case l.data[(l.p)] >= 65: 2948 | goto st47 2949 | } 2950 | default: 2951 | goto st47 2952 | } 2953 | goto st0 2954 | tr97: 2955 | //line lexer/lexer.go.rl:45 2956 | l.pb = l.p 2957 | goto st56 2958 | tr80: 2959 | //line lexer/lexer.go.rl:46 2960 | l.ast.incCaps() 2961 | //line lexer/lexer.go.rl:45 2962 | l.pb = l.p 2963 | goto st56 2964 | st56: 2965 | if (l.p)++; (l.p) == (l.pe) { 2966 | goto _test_eof56 2967 | } 2968 | st_case_56: 2969 | //line lexer/lexer.go:2828 2970 | switch l.data[(l.p)] { 2971 | case 32: 2972 | goto tr116 2973 | case 40: 2974 | goto tr117 2975 | case 95: 2976 | goto st47 2977 | case 97: 2978 | goto st57 2979 | } 2980 | switch { 2981 | case l.data[(l.p)] < 48: 2982 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 2983 | goto tr116 2984 | } 2985 | case l.data[(l.p)] > 57: 2986 | switch { 2987 | case l.data[(l.p)] > 90: 2988 | if 98 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 2989 | goto st47 2990 | } 2991 | case l.data[(l.p)] >= 65: 2992 | goto st47 2993 | } 2994 | default: 2995 | goto st47 2996 | } 2997 | goto st0 2998 | st57: 2999 | if (l.p)++; (l.p) == (l.pe) { 3000 | goto _test_eof57 3001 | } 3002 | st_case_57: 3003 | switch l.data[(l.p)] { 3004 | case 32: 3005 | goto tr116 3006 | case 40: 3007 | goto tr117 3008 | case 95: 3009 | goto st47 3010 | case 108: 3011 | goto st58 3012 | } 3013 | switch { 3014 | case l.data[(l.p)] < 48: 3015 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 3016 | goto tr116 3017 | } 3018 | case l.data[(l.p)] > 57: 3019 | switch { 3020 | case l.data[(l.p)] > 90: 3021 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 3022 | goto st47 3023 | } 3024 | case l.data[(l.p)] >= 65: 3025 | goto st47 3026 | } 3027 | default: 3028 | goto st47 3029 | } 3030 | goto st0 3031 | st58: 3032 | if (l.p)++; (l.p) == (l.pe) { 3033 | goto _test_eof58 3034 | } 3035 | st_case_58: 3036 | switch l.data[(l.p)] { 3037 | case 32: 3038 | goto tr116 3039 | case 40: 3040 | goto tr117 3041 | case 95: 3042 | goto st47 3043 | case 115: 3044 | goto st59 3045 | } 3046 | switch { 3047 | case l.data[(l.p)] < 48: 3048 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 3049 | goto tr116 3050 | } 3051 | case l.data[(l.p)] > 57: 3052 | switch { 3053 | case l.data[(l.p)] > 90: 3054 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 3055 | goto st47 3056 | } 3057 | case l.data[(l.p)] >= 65: 3058 | goto st47 3059 | } 3060 | default: 3061 | goto st47 3062 | } 3063 | goto st0 3064 | st59: 3065 | if (l.p)++; (l.p) == (l.pe) { 3066 | goto _test_eof59 3067 | } 3068 | st_case_59: 3069 | switch l.data[(l.p)] { 3070 | case 32: 3071 | goto tr116 3072 | case 40: 3073 | goto tr117 3074 | case 95: 3075 | goto st47 3076 | case 101: 3077 | goto st60 3078 | } 3079 | switch { 3080 | case l.data[(l.p)] < 48: 3081 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 3082 | goto tr116 3083 | } 3084 | case l.data[(l.p)] > 57: 3085 | switch { 3086 | case l.data[(l.p)] > 90: 3087 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 3088 | goto st47 3089 | } 3090 | case l.data[(l.p)] >= 65: 3091 | goto st47 3092 | } 3093 | default: 3094 | goto st47 3095 | } 3096 | goto st0 3097 | st60: 3098 | if (l.p)++; (l.p) == (l.pe) { 3099 | goto _test_eof60 3100 | } 3101 | st_case_60: 3102 | switch l.data[(l.p)] { 3103 | case 32: 3104 | goto tr130 3105 | case 44: 3106 | goto tr131 3107 | case 93: 3108 | goto tr132 3109 | case 95: 3110 | goto st47 3111 | } 3112 | switch { 3113 | case l.data[(l.p)] < 48: 3114 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 3115 | goto tr130 3116 | } 3117 | case l.data[(l.p)] > 57: 3118 | switch { 3119 | case l.data[(l.p)] > 90: 3120 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 3121 | goto st47 3122 | } 3123 | case l.data[(l.p)] >= 65: 3124 | goto st47 3125 | } 3126 | default: 3127 | goto st47 3128 | } 3129 | goto st0 3130 | tr98: 3131 | //line lexer/lexer.go.rl:45 3132 | l.pb = l.p 3133 | goto st61 3134 | tr81: 3135 | //line lexer/lexer.go.rl:46 3136 | l.ast.incCaps() 3137 | //line lexer/lexer.go.rl:45 3138 | l.pb = l.p 3139 | goto st61 3140 | st61: 3141 | if (l.p)++; (l.p) == (l.pe) { 3142 | goto _test_eof61 3143 | } 3144 | st_case_61: 3145 | //line lexer/lexer.go:3004 3146 | switch l.data[(l.p)] { 3147 | case 32: 3148 | goto tr116 3149 | case 40: 3150 | goto tr117 3151 | case 95: 3152 | goto st47 3153 | case 114: 3154 | goto st62 3155 | } 3156 | switch { 3157 | case l.data[(l.p)] < 48: 3158 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 3159 | goto tr116 3160 | } 3161 | case l.data[(l.p)] > 57: 3162 | switch { 3163 | case l.data[(l.p)] > 90: 3164 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 3165 | goto st47 3166 | } 3167 | case l.data[(l.p)] >= 65: 3168 | goto st47 3169 | } 3170 | default: 3171 | goto st47 3172 | } 3173 | goto st0 3174 | st62: 3175 | if (l.p)++; (l.p) == (l.pe) { 3176 | goto _test_eof62 3177 | } 3178 | st_case_62: 3179 | switch l.data[(l.p)] { 3180 | case 32: 3181 | goto tr116 3182 | case 40: 3183 | goto tr117 3184 | case 95: 3185 | goto st47 3186 | case 117: 3187 | goto st63 3188 | } 3189 | switch { 3190 | case l.data[(l.p)] < 48: 3191 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 3192 | goto tr116 3193 | } 3194 | case l.data[(l.p)] > 57: 3195 | switch { 3196 | case l.data[(l.p)] > 90: 3197 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 3198 | goto st47 3199 | } 3200 | case l.data[(l.p)] >= 65: 3201 | goto st47 3202 | } 3203 | default: 3204 | goto st47 3205 | } 3206 | goto st0 3207 | st63: 3208 | if (l.p)++; (l.p) == (l.pe) { 3209 | goto _test_eof63 3210 | } 3211 | st_case_63: 3212 | switch l.data[(l.p)] { 3213 | case 32: 3214 | goto tr116 3215 | case 40: 3216 | goto tr117 3217 | case 95: 3218 | goto st47 3219 | case 101: 3220 | goto st64 3221 | } 3222 | switch { 3223 | case l.data[(l.p)] < 48: 3224 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 3225 | goto tr116 3226 | } 3227 | case l.data[(l.p)] > 57: 3228 | switch { 3229 | case l.data[(l.p)] > 90: 3230 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 3231 | goto st47 3232 | } 3233 | case l.data[(l.p)] >= 65: 3234 | goto st47 3235 | } 3236 | default: 3237 | goto st47 3238 | } 3239 | goto st0 3240 | st64: 3241 | if (l.p)++; (l.p) == (l.pe) { 3242 | goto _test_eof64 3243 | } 3244 | st_case_64: 3245 | switch l.data[(l.p)] { 3246 | case 32: 3247 | goto tr136 3248 | case 44: 3249 | goto tr137 3250 | case 93: 3251 | goto tr138 3252 | case 95: 3253 | goto st47 3254 | } 3255 | switch { 3256 | case l.data[(l.p)] < 48: 3257 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 3258 | goto tr136 3259 | } 3260 | case l.data[(l.p)] > 57: 3261 | switch { 3262 | case l.data[(l.p)] > 90: 3263 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 3264 | goto st47 3265 | } 3266 | case l.data[(l.p)] >= 65: 3267 | goto st47 3268 | } 3269 | default: 3270 | goto st47 3271 | } 3272 | goto st0 3273 | st65: 3274 | if (l.p)++; (l.p) == (l.pe) { 3275 | goto _test_eof65 3276 | } 3277 | st_case_65: 3278 | goto st38 3279 | st66: 3280 | if (l.p)++; (l.p) == (l.pe) { 3281 | goto _test_eof66 3282 | } 3283 | st_case_66: 3284 | switch l.data[(l.p)] { 3285 | case 32: 3286 | goto st66 3287 | case 34: 3288 | goto tr140 3289 | case 40: 3290 | goto tr141 3291 | case 41: 3292 | goto tr142 3293 | case 43: 3294 | goto tr143 3295 | case 45: 3296 | goto tr143 3297 | case 91: 3298 | goto tr146 3299 | case 95: 3300 | goto tr145 3301 | case 102: 3302 | goto tr147 3303 | case 116: 3304 | goto tr148 3305 | } 3306 | switch { 3307 | case l.data[(l.p)] < 48: 3308 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 3309 | goto st66 3310 | } 3311 | case l.data[(l.p)] > 57: 3312 | switch { 3313 | case l.data[(l.p)] > 90: 3314 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 3315 | goto tr145 3316 | } 3317 | case l.data[(l.p)] >= 65: 3318 | goto tr145 3319 | } 3320 | default: 3321 | goto tr144 3322 | } 3323 | goto st0 3324 | tr158: 3325 | //line lexer/lexer.go.rl:45 3326 | l.pb = l.p 3327 | goto st67 3328 | tr140: 3329 | //line lexer/lexer.go.rl:46 3330 | l.ast.incCaps() 3331 | //line lexer/lexer.go.rl:45 3332 | l.pb = l.p 3333 | goto st67 3334 | st67: 3335 | if (l.p)++; (l.p) == (l.pe) { 3336 | goto _test_eof67 3337 | } 3338 | st_case_67: 3339 | //line lexer/lexer.go:3198 3340 | switch l.data[(l.p)] { 3341 | case 34: 3342 | goto st68 3343 | case 92: 3344 | goto st94 3345 | } 3346 | goto st67 3347 | st68: 3348 | if (l.p)++; (l.p) == (l.pe) { 3349 | goto _test_eof68 3350 | } 3351 | st_case_68: 3352 | switch l.data[(l.p)] { 3353 | case 32: 3354 | goto tr152 3355 | case 41: 3356 | goto tr153 3357 | case 44: 3358 | goto tr154 3359 | } 3360 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 3361 | goto tr152 3362 | } 3363 | goto st0 3364 | tr163: 3365 | //line lexer/lexer.go.rl:50 3366 | l.ast.pushVector() 3367 | //line lexer/lexer.go.rl:101 3368 | { 3369 | l.stack[l.top] = 69 3370 | l.top++ 3371 | goto st37 3372 | } 3373 | goto st69 3374 | tr146: 3375 | //line lexer/lexer.go.rl:46 3376 | l.ast.incCaps() 3377 | //line lexer/lexer.go.rl:50 3378 | l.ast.pushVector() 3379 | //line lexer/lexer.go.rl:101 3380 | { 3381 | l.stack[l.top] = 69 3382 | l.top++ 3383 | goto st37 3384 | } 3385 | goto st69 3386 | tr152: 3387 | //line lexer/lexer.go.rl:54 3388 | 3389 | str, perr = strconv.Unquote(l.text()) 3390 | if perr != nil { 3391 | perr = errors.Wrapf(perr, "strconv.Unquote %s", l.text()) 3392 | { 3393 | (l.p)++ 3394 | l.cs = 69 3395 | goto _out 3396 | } 3397 | } 3398 | l.ast.pushStr(str) 3399 | 3400 | goto st69 3401 | tr197: 3402 | //line lexer/lexer.go.rl:70 3403 | l.ast.pushFalse() 3404 | goto st69 3405 | tr203: 3406 | //line lexer/lexer.go.rl:69 3407 | l.ast.pushTrue() 3408 | goto st69 3409 | st69: 3410 | if (l.p)++; (l.p) == (l.pe) { 3411 | goto _test_eof69 3412 | } 3413 | st_case_69: 3414 | //line lexer/lexer.go:3261 3415 | switch l.data[(l.p)] { 3416 | case 32: 3417 | goto st69 3418 | case 41: 3419 | goto tr142 3420 | case 44: 3421 | goto tr156 3422 | } 3423 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 3424 | goto st69 3425 | } 3426 | goto st0 3427 | tr142: 3428 | //line lexer/lexer.go.rl:48 3429 | l.ast.popCaps() 3430 | //line lexer/lexer.go.rl:44 3431 | { 3432 | l.top-- 3433 | l.cs = l.stack[l.top] 3434 | goto _again 3435 | } 3436 | goto st103 3437 | tr153: 3438 | //line lexer/lexer.go.rl:54 3439 | 3440 | str, perr = strconv.Unquote(l.text()) 3441 | if perr != nil { 3442 | perr = errors.Wrapf(perr, "strconv.Unquote %s", l.text()) 3443 | { 3444 | (l.p)++ 3445 | l.cs = 103 3446 | goto _out 3447 | } 3448 | } 3449 | l.ast.pushStr(str) 3450 | 3451 | //line lexer/lexer.go.rl:48 3452 | l.ast.popCaps() 3453 | //line lexer/lexer.go.rl:44 3454 | { 3455 | l.top-- 3456 | l.cs = l.stack[l.top] 3457 | goto _again 3458 | } 3459 | goto st103 3460 | tr180: 3461 | //line lexer/lexer.go.rl:62 3462 | 3463 | n64, perr = strconv.ParseInt(l.text(), 10, 64) 3464 | if perr != nil { 3465 | { 3466 | (l.p)++ 3467 | l.cs = 103 3468 | goto _out 3469 | } 3470 | } 3471 | l.ast.pushInt(n64) 3472 | 3473 | //line lexer/lexer.go.rl:48 3474 | l.ast.popCaps() 3475 | //line lexer/lexer.go.rl:44 3476 | { 3477 | l.top-- 3478 | l.cs = l.stack[l.top] 3479 | goto _again 3480 | } 3481 | goto st103 3482 | tr198: 3483 | //line lexer/lexer.go.rl:70 3484 | l.ast.pushFalse() 3485 | //line lexer/lexer.go.rl:48 3486 | l.ast.popCaps() 3487 | //line lexer/lexer.go.rl:44 3488 | { 3489 | l.top-- 3490 | l.cs = l.stack[l.top] 3491 | goto _again 3492 | } 3493 | goto st103 3494 | tr204: 3495 | //line lexer/lexer.go.rl:69 3496 | l.ast.pushTrue() 3497 | //line lexer/lexer.go.rl:48 3498 | l.ast.popCaps() 3499 | //line lexer/lexer.go.rl:44 3500 | { 3501 | l.top-- 3502 | l.cs = l.stack[l.top] 3503 | goto _again 3504 | } 3505 | goto st103 3506 | st103: 3507 | if (l.p)++; (l.p) == (l.pe) { 3508 | goto _test_eof103 3509 | } 3510 | st_case_103: 3511 | //line lexer/lexer.go:3330 3512 | goto st0 3513 | tr154: 3514 | //line lexer/lexer.go.rl:54 3515 | 3516 | str, perr = strconv.Unquote(l.text()) 3517 | if perr != nil { 3518 | perr = errors.Wrapf(perr, "strconv.Unquote %s", l.text()) 3519 | { 3520 | (l.p)++ 3521 | l.cs = 70 3522 | goto _out 3523 | } 3524 | } 3525 | l.ast.pushStr(str) 3526 | 3527 | //line lexer/lexer.go.rl:47 3528 | l.ast.rotateComma() 3529 | goto st70 3530 | tr156: 3531 | //line lexer/lexer.go.rl:47 3532 | l.ast.rotateComma() 3533 | goto st70 3534 | tr182: 3535 | //line lexer/lexer.go.rl:62 3536 | 3537 | n64, perr = strconv.ParseInt(l.text(), 10, 64) 3538 | if perr != nil { 3539 | { 3540 | (l.p)++ 3541 | l.cs = 70 3542 | goto _out 3543 | } 3544 | } 3545 | l.ast.pushInt(n64) 3546 | 3547 | //line lexer/lexer.go.rl:47 3548 | l.ast.rotateComma() 3549 | goto st70 3550 | tr199: 3551 | //line lexer/lexer.go.rl:70 3552 | l.ast.pushFalse() 3553 | //line lexer/lexer.go.rl:47 3554 | l.ast.rotateComma() 3555 | goto st70 3556 | tr205: 3557 | //line lexer/lexer.go.rl:69 3558 | l.ast.pushTrue() 3559 | //line lexer/lexer.go.rl:47 3560 | l.ast.rotateComma() 3561 | goto st70 3562 | st70: 3563 | if (l.p)++; (l.p) == (l.pe) { 3564 | goto _test_eof70 3565 | } 3566 | st_case_70: 3567 | //line lexer/lexer.go:3378 3568 | switch l.data[(l.p)] { 3569 | case 32: 3570 | goto st70 3571 | case 34: 3572 | goto tr158 3573 | case 40: 3574 | goto tr159 3575 | case 43: 3576 | goto tr160 3577 | case 45: 3578 | goto tr160 3579 | case 91: 3580 | goto tr163 3581 | case 95: 3582 | goto tr162 3583 | case 102: 3584 | goto tr164 3585 | case 116: 3586 | goto tr165 3587 | } 3588 | switch { 3589 | case l.data[(l.p)] < 48: 3590 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 3591 | goto st70 3592 | } 3593 | case l.data[(l.p)] > 57: 3594 | switch { 3595 | case l.data[(l.p)] > 90: 3596 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 3597 | goto tr162 3598 | } 3599 | case l.data[(l.p)] >= 65: 3600 | goto tr162 3601 | } 3602 | default: 3603 | goto tr161 3604 | } 3605 | goto st0 3606 | tr159: 3607 | //line lexer/lexer.go.rl:51 3608 | l.ast.openPths() 3609 | //line lexer/lexer.go.rl:103 3610 | { 3611 | l.stack[l.top] = 71 3612 | l.top++ 3613 | goto st23 3614 | } 3615 | goto st71 3616 | tr169: 3617 | //line lexer/lexer.go.rl:71 3618 | l.ast.pushMathOp(l.data[l.pb]) 3619 | //line lexer/lexer.go.rl:51 3620 | l.ast.openPths() 3621 | //line lexer/lexer.go.rl:103 3622 | { 3623 | l.stack[l.top] = 71 3624 | l.top++ 3625 | goto st23 3626 | } 3627 | goto st71 3628 | tr184: 3629 | //line lexer/lexer.go.rl:53 3630 | l.ast.pushIdent(l.text()) 3631 | //line lexer/lexer.go.rl:49 3632 | l.ast.pushInvoke() 3633 | //line lexer/lexer.go.rl:102 3634 | { 3635 | l.stack[l.top] = 71 3636 | l.top++ 3637 | goto st66 3638 | } 3639 | goto st71 3640 | tr187: 3641 | //line lexer/lexer.go.rl:49 3642 | l.ast.pushInvoke() 3643 | //line lexer/lexer.go.rl:102 3644 | { 3645 | l.stack[l.top] = 71 3646 | l.top++ 3647 | goto st66 3648 | } 3649 | goto st71 3650 | tr179: 3651 | //line lexer/lexer.go.rl:62 3652 | 3653 | n64, perr = strconv.ParseInt(l.text(), 10, 64) 3654 | if perr != nil { 3655 | { 3656 | (l.p)++ 3657 | l.cs = 71 3658 | goto _out 3659 | } 3660 | } 3661 | l.ast.pushInt(n64) 3662 | 3663 | goto st71 3664 | tr141: 3665 | //line lexer/lexer.go.rl:46 3666 | l.ast.incCaps() 3667 | //line lexer/lexer.go.rl:51 3668 | l.ast.openPths() 3669 | //line lexer/lexer.go.rl:103 3670 | { 3671 | l.stack[l.top] = 71 3672 | l.top++ 3673 | goto st23 3674 | } 3675 | goto st71 3676 | st71: 3677 | if (l.p)++; (l.p) == (l.pe) { 3678 | goto _test_eof71 3679 | } 3680 | st_case_71: 3681 | //line lexer/lexer.go:3468 3682 | switch l.data[(l.p)] { 3683 | case 32: 3684 | goto st71 3685 | case 41: 3686 | goto tr142 3687 | case 44: 3688 | goto tr156 3689 | case 47: 3690 | goto tr167 3691 | } 3692 | switch { 3693 | case l.data[(l.p)] > 13: 3694 | if 42 <= l.data[(l.p)] && l.data[(l.p)] <= 45 { 3695 | goto tr167 3696 | } 3697 | case l.data[(l.p)] >= 9: 3698 | goto st71 3699 | } 3700 | goto st0 3701 | tr167: 3702 | //line lexer/lexer.go.rl:45 3703 | l.pb = l.p 3704 | goto st72 3705 | tr181: 3706 | //line lexer/lexer.go.rl:62 3707 | 3708 | n64, perr = strconv.ParseInt(l.text(), 10, 64) 3709 | if perr != nil { 3710 | { 3711 | (l.p)++ 3712 | l.cs = 72 3713 | goto _out 3714 | } 3715 | } 3716 | l.ast.pushInt(n64) 3717 | 3718 | //line lexer/lexer.go.rl:45 3719 | l.pb = l.p 3720 | goto st72 3721 | st72: 3722 | if (l.p)++; (l.p) == (l.pe) { 3723 | goto _test_eof72 3724 | } 3725 | st_case_72: 3726 | //line lexer/lexer.go:3509 3727 | switch l.data[(l.p)] { 3728 | case 32: 3729 | goto tr168 3730 | case 40: 3731 | goto tr169 3732 | case 43: 3733 | goto tr170 3734 | case 45: 3735 | goto tr170 3736 | case 95: 3737 | goto tr172 3738 | case 102: 3739 | goto tr173 3740 | case 116: 3741 | goto tr174 3742 | } 3743 | switch { 3744 | case l.data[(l.p)] < 48: 3745 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 3746 | goto tr168 3747 | } 3748 | case l.data[(l.p)] > 57: 3749 | switch { 3750 | case l.data[(l.p)] > 90: 3751 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 3752 | goto tr172 3753 | } 3754 | case l.data[(l.p)] >= 65: 3755 | goto tr172 3756 | } 3757 | default: 3758 | goto tr171 3759 | } 3760 | goto st0 3761 | tr168: 3762 | //line lexer/lexer.go.rl:71 3763 | l.ast.pushMathOp(l.data[l.pb]) 3764 | goto st73 3765 | st73: 3766 | if (l.p)++; (l.p) == (l.pe) { 3767 | goto _test_eof73 3768 | } 3769 | st_case_73: 3770 | //line lexer/lexer.go:3553 3771 | switch l.data[(l.p)] { 3772 | case 32: 3773 | goto st73 3774 | case 40: 3775 | goto tr159 3776 | case 43: 3777 | goto tr160 3778 | case 45: 3779 | goto tr160 3780 | case 95: 3781 | goto tr162 3782 | case 102: 3783 | goto tr176 3784 | case 116: 3785 | goto tr177 3786 | } 3787 | switch { 3788 | case l.data[(l.p)] < 48: 3789 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 3790 | goto st73 3791 | } 3792 | case l.data[(l.p)] > 57: 3793 | switch { 3794 | case l.data[(l.p)] > 90: 3795 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 3796 | goto tr162 3797 | } 3798 | case l.data[(l.p)] >= 65: 3799 | goto tr162 3800 | } 3801 | default: 3802 | goto tr161 3803 | } 3804 | goto st0 3805 | tr160: 3806 | //line lexer/lexer.go.rl:45 3807 | l.pb = l.p 3808 | goto st74 3809 | tr170: 3810 | //line lexer/lexer.go.rl:71 3811 | l.ast.pushMathOp(l.data[l.pb]) 3812 | //line lexer/lexer.go.rl:45 3813 | l.pb = l.p 3814 | goto st74 3815 | tr143: 3816 | //line lexer/lexer.go.rl:46 3817 | l.ast.incCaps() 3818 | //line lexer/lexer.go.rl:45 3819 | l.pb = l.p 3820 | goto st74 3821 | st74: 3822 | if (l.p)++; (l.p) == (l.pe) { 3823 | goto _test_eof74 3824 | } 3825 | st_case_74: 3826 | //line lexer/lexer.go:3609 3827 | if 48 <= l.data[(l.p)] && l.data[(l.p)] <= 57 { 3828 | goto st75 3829 | } 3830 | goto st0 3831 | tr161: 3832 | //line lexer/lexer.go.rl:45 3833 | l.pb = l.p 3834 | goto st75 3835 | tr171: 3836 | //line lexer/lexer.go.rl:71 3837 | l.ast.pushMathOp(l.data[l.pb]) 3838 | //line lexer/lexer.go.rl:45 3839 | l.pb = l.p 3840 | goto st75 3841 | tr144: 3842 | //line lexer/lexer.go.rl:46 3843 | l.ast.incCaps() 3844 | //line lexer/lexer.go.rl:45 3845 | l.pb = l.p 3846 | goto st75 3847 | st75: 3848 | if (l.p)++; (l.p) == (l.pe) { 3849 | goto _test_eof75 3850 | } 3851 | st_case_75: 3852 | //line lexer/lexer.go:3635 3853 | switch l.data[(l.p)] { 3854 | case 32: 3855 | goto tr179 3856 | case 41: 3857 | goto tr180 3858 | case 44: 3859 | goto tr182 3860 | case 47: 3861 | goto tr181 3862 | } 3863 | switch { 3864 | case l.data[(l.p)] < 42: 3865 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 3866 | goto tr179 3867 | } 3868 | case l.data[(l.p)] > 45: 3869 | if 48 <= l.data[(l.p)] && l.data[(l.p)] <= 57 { 3870 | goto st75 3871 | } 3872 | default: 3873 | goto tr181 3874 | } 3875 | goto st0 3876 | tr162: 3877 | //line lexer/lexer.go.rl:45 3878 | l.pb = l.p 3879 | goto st76 3880 | tr172: 3881 | //line lexer/lexer.go.rl:71 3882 | l.ast.pushMathOp(l.data[l.pb]) 3883 | //line lexer/lexer.go.rl:45 3884 | l.pb = l.p 3885 | goto st76 3886 | tr145: 3887 | //line lexer/lexer.go.rl:46 3888 | l.ast.incCaps() 3889 | //line lexer/lexer.go.rl:45 3890 | l.pb = l.p 3891 | goto st76 3892 | st76: 3893 | if (l.p)++; (l.p) == (l.pe) { 3894 | goto _test_eof76 3895 | } 3896 | st_case_76: 3897 | //line lexer/lexer.go:3680 3898 | switch l.data[(l.p)] { 3899 | case 32: 3900 | goto tr183 3901 | case 40: 3902 | goto tr184 3903 | case 95: 3904 | goto st76 3905 | } 3906 | switch { 3907 | case l.data[(l.p)] < 48: 3908 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 3909 | goto tr183 3910 | } 3911 | case l.data[(l.p)] > 57: 3912 | switch { 3913 | case l.data[(l.p)] > 90: 3914 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 3915 | goto st76 3916 | } 3917 | case l.data[(l.p)] >= 65: 3918 | goto st76 3919 | } 3920 | default: 3921 | goto st76 3922 | } 3923 | goto st0 3924 | tr183: 3925 | //line lexer/lexer.go.rl:53 3926 | l.ast.pushIdent(l.text()) 3927 | goto st77 3928 | st77: 3929 | if (l.p)++; (l.p) == (l.pe) { 3930 | goto _test_eof77 3931 | } 3932 | st_case_77: 3933 | //line lexer/lexer.go:3716 3934 | switch l.data[(l.p)] { 3935 | case 32: 3936 | goto st77 3937 | case 40: 3938 | goto tr187 3939 | } 3940 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 3941 | goto st77 3942 | } 3943 | goto st0 3944 | tr176: 3945 | //line lexer/lexer.go.rl:45 3946 | l.pb = l.p 3947 | goto st78 3948 | tr173: 3949 | //line lexer/lexer.go.rl:71 3950 | l.ast.pushMathOp(l.data[l.pb]) 3951 | //line lexer/lexer.go.rl:45 3952 | l.pb = l.p 3953 | goto st78 3954 | st78: 3955 | if (l.p)++; (l.p) == (l.pe) { 3956 | goto _test_eof78 3957 | } 3958 | st_case_78: 3959 | //line lexer/lexer.go:3742 3960 | switch l.data[(l.p)] { 3961 | case 32: 3962 | goto tr183 3963 | case 40: 3964 | goto tr184 3965 | case 95: 3966 | goto st76 3967 | case 97: 3968 | goto st79 3969 | } 3970 | switch { 3971 | case l.data[(l.p)] < 48: 3972 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 3973 | goto tr183 3974 | } 3975 | case l.data[(l.p)] > 57: 3976 | switch { 3977 | case l.data[(l.p)] > 90: 3978 | if 98 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 3979 | goto st76 3980 | } 3981 | case l.data[(l.p)] >= 65: 3982 | goto st76 3983 | } 3984 | default: 3985 | goto st76 3986 | } 3987 | goto st0 3988 | st79: 3989 | if (l.p)++; (l.p) == (l.pe) { 3990 | goto _test_eof79 3991 | } 3992 | st_case_79: 3993 | switch l.data[(l.p)] { 3994 | case 32: 3995 | goto tr183 3996 | case 40: 3997 | goto tr184 3998 | case 95: 3999 | goto st76 4000 | case 108: 4001 | goto st80 4002 | } 4003 | switch { 4004 | case l.data[(l.p)] < 48: 4005 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 4006 | goto tr183 4007 | } 4008 | case l.data[(l.p)] > 57: 4009 | switch { 4010 | case l.data[(l.p)] > 90: 4011 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 4012 | goto st76 4013 | } 4014 | case l.data[(l.p)] >= 65: 4015 | goto st76 4016 | } 4017 | default: 4018 | goto st76 4019 | } 4020 | goto st0 4021 | st80: 4022 | if (l.p)++; (l.p) == (l.pe) { 4023 | goto _test_eof80 4024 | } 4025 | st_case_80: 4026 | switch l.data[(l.p)] { 4027 | case 32: 4028 | goto tr183 4029 | case 40: 4030 | goto tr184 4031 | case 95: 4032 | goto st76 4033 | case 115: 4034 | goto st81 4035 | } 4036 | switch { 4037 | case l.data[(l.p)] < 48: 4038 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 4039 | goto tr183 4040 | } 4041 | case l.data[(l.p)] > 57: 4042 | switch { 4043 | case l.data[(l.p)] > 90: 4044 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 4045 | goto st76 4046 | } 4047 | case l.data[(l.p)] >= 65: 4048 | goto st76 4049 | } 4050 | default: 4051 | goto st76 4052 | } 4053 | goto st0 4054 | st81: 4055 | if (l.p)++; (l.p) == (l.pe) { 4056 | goto _test_eof81 4057 | } 4058 | st_case_81: 4059 | switch l.data[(l.p)] { 4060 | case 32: 4061 | goto tr183 4062 | case 40: 4063 | goto tr184 4064 | case 95: 4065 | goto st76 4066 | case 101: 4067 | goto st82 4068 | } 4069 | switch { 4070 | case l.data[(l.p)] < 48: 4071 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 4072 | goto tr183 4073 | } 4074 | case l.data[(l.p)] > 57: 4075 | switch { 4076 | case l.data[(l.p)] > 90: 4077 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 4078 | goto st76 4079 | } 4080 | case l.data[(l.p)] >= 65: 4081 | goto st76 4082 | } 4083 | default: 4084 | goto st76 4085 | } 4086 | goto st0 4087 | st82: 4088 | if (l.p)++; (l.p) == (l.pe) { 4089 | goto _test_eof82 4090 | } 4091 | st_case_82: 4092 | if l.data[(l.p)] == 95 { 4093 | goto st76 4094 | } 4095 | switch { 4096 | case l.data[(l.p)] < 65: 4097 | if 48 <= l.data[(l.p)] && l.data[(l.p)] <= 57 { 4098 | goto st76 4099 | } 4100 | case l.data[(l.p)] > 90: 4101 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 4102 | goto st76 4103 | } 4104 | default: 4105 | goto st76 4106 | } 4107 | goto st0 4108 | tr177: 4109 | //line lexer/lexer.go.rl:45 4110 | l.pb = l.p 4111 | goto st83 4112 | tr174: 4113 | //line lexer/lexer.go.rl:71 4114 | l.ast.pushMathOp(l.data[l.pb]) 4115 | //line lexer/lexer.go.rl:45 4116 | l.pb = l.p 4117 | goto st83 4118 | st83: 4119 | if (l.p)++; (l.p) == (l.pe) { 4120 | goto _test_eof83 4121 | } 4122 | st_case_83: 4123 | //line lexer/lexer.go:3906 4124 | switch l.data[(l.p)] { 4125 | case 32: 4126 | goto tr183 4127 | case 40: 4128 | goto tr184 4129 | case 95: 4130 | goto st76 4131 | case 114: 4132 | goto st84 4133 | } 4134 | switch { 4135 | case l.data[(l.p)] < 48: 4136 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 4137 | goto tr183 4138 | } 4139 | case l.data[(l.p)] > 57: 4140 | switch { 4141 | case l.data[(l.p)] > 90: 4142 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 4143 | goto st76 4144 | } 4145 | case l.data[(l.p)] >= 65: 4146 | goto st76 4147 | } 4148 | default: 4149 | goto st76 4150 | } 4151 | goto st0 4152 | st84: 4153 | if (l.p)++; (l.p) == (l.pe) { 4154 | goto _test_eof84 4155 | } 4156 | st_case_84: 4157 | switch l.data[(l.p)] { 4158 | case 32: 4159 | goto tr183 4160 | case 40: 4161 | goto tr184 4162 | case 95: 4163 | goto st76 4164 | case 117: 4165 | goto st81 4166 | } 4167 | switch { 4168 | case l.data[(l.p)] < 48: 4169 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 4170 | goto tr183 4171 | } 4172 | case l.data[(l.p)] > 57: 4173 | switch { 4174 | case l.data[(l.p)] > 90: 4175 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 4176 | goto st76 4177 | } 4178 | case l.data[(l.p)] >= 65: 4179 | goto st76 4180 | } 4181 | default: 4182 | goto st76 4183 | } 4184 | goto st0 4185 | tr164: 4186 | //line lexer/lexer.go.rl:45 4187 | l.pb = l.p 4188 | goto st85 4189 | tr147: 4190 | //line lexer/lexer.go.rl:46 4191 | l.ast.incCaps() 4192 | //line lexer/lexer.go.rl:45 4193 | l.pb = l.p 4194 | goto st85 4195 | st85: 4196 | if (l.p)++; (l.p) == (l.pe) { 4197 | goto _test_eof85 4198 | } 4199 | st_case_85: 4200 | //line lexer/lexer.go:3983 4201 | switch l.data[(l.p)] { 4202 | case 32: 4203 | goto tr183 4204 | case 40: 4205 | goto tr184 4206 | case 95: 4207 | goto st76 4208 | case 97: 4209 | goto st86 4210 | } 4211 | switch { 4212 | case l.data[(l.p)] < 48: 4213 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 4214 | goto tr183 4215 | } 4216 | case l.data[(l.p)] > 57: 4217 | switch { 4218 | case l.data[(l.p)] > 90: 4219 | if 98 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 4220 | goto st76 4221 | } 4222 | case l.data[(l.p)] >= 65: 4223 | goto st76 4224 | } 4225 | default: 4226 | goto st76 4227 | } 4228 | goto st0 4229 | st86: 4230 | if (l.p)++; (l.p) == (l.pe) { 4231 | goto _test_eof86 4232 | } 4233 | st_case_86: 4234 | switch l.data[(l.p)] { 4235 | case 32: 4236 | goto tr183 4237 | case 40: 4238 | goto tr184 4239 | case 95: 4240 | goto st76 4241 | case 108: 4242 | goto st87 4243 | } 4244 | switch { 4245 | case l.data[(l.p)] < 48: 4246 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 4247 | goto tr183 4248 | } 4249 | case l.data[(l.p)] > 57: 4250 | switch { 4251 | case l.data[(l.p)] > 90: 4252 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 4253 | goto st76 4254 | } 4255 | case l.data[(l.p)] >= 65: 4256 | goto st76 4257 | } 4258 | default: 4259 | goto st76 4260 | } 4261 | goto st0 4262 | st87: 4263 | if (l.p)++; (l.p) == (l.pe) { 4264 | goto _test_eof87 4265 | } 4266 | st_case_87: 4267 | switch l.data[(l.p)] { 4268 | case 32: 4269 | goto tr183 4270 | case 40: 4271 | goto tr184 4272 | case 95: 4273 | goto st76 4274 | case 115: 4275 | goto st88 4276 | } 4277 | switch { 4278 | case l.data[(l.p)] < 48: 4279 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 4280 | goto tr183 4281 | } 4282 | case l.data[(l.p)] > 57: 4283 | switch { 4284 | case l.data[(l.p)] > 90: 4285 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 4286 | goto st76 4287 | } 4288 | case l.data[(l.p)] >= 65: 4289 | goto st76 4290 | } 4291 | default: 4292 | goto st76 4293 | } 4294 | goto st0 4295 | st88: 4296 | if (l.p)++; (l.p) == (l.pe) { 4297 | goto _test_eof88 4298 | } 4299 | st_case_88: 4300 | switch l.data[(l.p)] { 4301 | case 32: 4302 | goto tr183 4303 | case 40: 4304 | goto tr184 4305 | case 95: 4306 | goto st76 4307 | case 101: 4308 | goto st89 4309 | } 4310 | switch { 4311 | case l.data[(l.p)] < 48: 4312 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 4313 | goto tr183 4314 | } 4315 | case l.data[(l.p)] > 57: 4316 | switch { 4317 | case l.data[(l.p)] > 90: 4318 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 4319 | goto st76 4320 | } 4321 | case l.data[(l.p)] >= 65: 4322 | goto st76 4323 | } 4324 | default: 4325 | goto st76 4326 | } 4327 | goto st0 4328 | st89: 4329 | if (l.p)++; (l.p) == (l.pe) { 4330 | goto _test_eof89 4331 | } 4332 | st_case_89: 4333 | switch l.data[(l.p)] { 4334 | case 32: 4335 | goto tr197 4336 | case 41: 4337 | goto tr198 4338 | case 44: 4339 | goto tr199 4340 | case 95: 4341 | goto st76 4342 | } 4343 | switch { 4344 | case l.data[(l.p)] < 48: 4345 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 4346 | goto tr197 4347 | } 4348 | case l.data[(l.p)] > 57: 4349 | switch { 4350 | case l.data[(l.p)] > 90: 4351 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 4352 | goto st76 4353 | } 4354 | case l.data[(l.p)] >= 65: 4355 | goto st76 4356 | } 4357 | default: 4358 | goto st76 4359 | } 4360 | goto st0 4361 | tr165: 4362 | //line lexer/lexer.go.rl:45 4363 | l.pb = l.p 4364 | goto st90 4365 | tr148: 4366 | //line lexer/lexer.go.rl:46 4367 | l.ast.incCaps() 4368 | //line lexer/lexer.go.rl:45 4369 | l.pb = l.p 4370 | goto st90 4371 | st90: 4372 | if (l.p)++; (l.p) == (l.pe) { 4373 | goto _test_eof90 4374 | } 4375 | st_case_90: 4376 | //line lexer/lexer.go:4159 4377 | switch l.data[(l.p)] { 4378 | case 32: 4379 | goto tr183 4380 | case 40: 4381 | goto tr184 4382 | case 95: 4383 | goto st76 4384 | case 114: 4385 | goto st91 4386 | } 4387 | switch { 4388 | case l.data[(l.p)] < 48: 4389 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 4390 | goto tr183 4391 | } 4392 | case l.data[(l.p)] > 57: 4393 | switch { 4394 | case l.data[(l.p)] > 90: 4395 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 4396 | goto st76 4397 | } 4398 | case l.data[(l.p)] >= 65: 4399 | goto st76 4400 | } 4401 | default: 4402 | goto st76 4403 | } 4404 | goto st0 4405 | st91: 4406 | if (l.p)++; (l.p) == (l.pe) { 4407 | goto _test_eof91 4408 | } 4409 | st_case_91: 4410 | switch l.data[(l.p)] { 4411 | case 32: 4412 | goto tr183 4413 | case 40: 4414 | goto tr184 4415 | case 95: 4416 | goto st76 4417 | case 117: 4418 | goto st92 4419 | } 4420 | switch { 4421 | case l.data[(l.p)] < 48: 4422 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 4423 | goto tr183 4424 | } 4425 | case l.data[(l.p)] > 57: 4426 | switch { 4427 | case l.data[(l.p)] > 90: 4428 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 4429 | goto st76 4430 | } 4431 | case l.data[(l.p)] >= 65: 4432 | goto st76 4433 | } 4434 | default: 4435 | goto st76 4436 | } 4437 | goto st0 4438 | st92: 4439 | if (l.p)++; (l.p) == (l.pe) { 4440 | goto _test_eof92 4441 | } 4442 | st_case_92: 4443 | switch l.data[(l.p)] { 4444 | case 32: 4445 | goto tr183 4446 | case 40: 4447 | goto tr184 4448 | case 95: 4449 | goto st76 4450 | case 101: 4451 | goto st93 4452 | } 4453 | switch { 4454 | case l.data[(l.p)] < 48: 4455 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 4456 | goto tr183 4457 | } 4458 | case l.data[(l.p)] > 57: 4459 | switch { 4460 | case l.data[(l.p)] > 90: 4461 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 4462 | goto st76 4463 | } 4464 | case l.data[(l.p)] >= 65: 4465 | goto st76 4466 | } 4467 | default: 4468 | goto st76 4469 | } 4470 | goto st0 4471 | st93: 4472 | if (l.p)++; (l.p) == (l.pe) { 4473 | goto _test_eof93 4474 | } 4475 | st_case_93: 4476 | switch l.data[(l.p)] { 4477 | case 32: 4478 | goto tr203 4479 | case 41: 4480 | goto tr204 4481 | case 44: 4482 | goto tr205 4483 | case 95: 4484 | goto st76 4485 | } 4486 | switch { 4487 | case l.data[(l.p)] < 48: 4488 | if 9 <= l.data[(l.p)] && l.data[(l.p)] <= 13 { 4489 | goto tr203 4490 | } 4491 | case l.data[(l.p)] > 57: 4492 | switch { 4493 | case l.data[(l.p)] > 90: 4494 | if 97 <= l.data[(l.p)] && l.data[(l.p)] <= 122 { 4495 | goto st76 4496 | } 4497 | case l.data[(l.p)] >= 65: 4498 | goto st76 4499 | } 4500 | default: 4501 | goto st76 4502 | } 4503 | goto st0 4504 | st94: 4505 | if (l.p)++; (l.p) == (l.pe) { 4506 | goto _test_eof94 4507 | } 4508 | st_case_94: 4509 | goto st67 4510 | st_out: 4511 | _test_eof1: 4512 | l.cs = 1 4513 | goto _test_eof 4514 | _test_eof2: 4515 | l.cs = 2 4516 | goto _test_eof 4517 | _test_eof95: 4518 | l.cs = 95 4519 | goto _test_eof 4520 | _test_eof96: 4521 | l.cs = 96 4522 | goto _test_eof 4523 | _test_eof3: 4524 | l.cs = 3 4525 | goto _test_eof 4526 | _test_eof97: 4527 | l.cs = 97 4528 | goto _test_eof 4529 | _test_eof4: 4530 | l.cs = 4 4531 | goto _test_eof 4532 | _test_eof5: 4533 | l.cs = 5 4534 | goto _test_eof 4535 | _test_eof6: 4536 | l.cs = 6 4537 | goto _test_eof 4538 | _test_eof98: 4539 | l.cs = 98 4540 | goto _test_eof 4541 | _test_eof7: 4542 | l.cs = 7 4543 | goto _test_eof 4544 | _test_eof8: 4545 | l.cs = 8 4546 | goto _test_eof 4547 | _test_eof9: 4548 | l.cs = 9 4549 | goto _test_eof 4550 | _test_eof10: 4551 | l.cs = 10 4552 | goto _test_eof 4553 | _test_eof11: 4554 | l.cs = 11 4555 | goto _test_eof 4556 | _test_eof12: 4557 | l.cs = 12 4558 | goto _test_eof 4559 | _test_eof13: 4560 | l.cs = 13 4561 | goto _test_eof 4562 | _test_eof14: 4563 | l.cs = 14 4564 | goto _test_eof 4565 | _test_eof15: 4566 | l.cs = 15 4567 | goto _test_eof 4568 | _test_eof16: 4569 | l.cs = 16 4570 | goto _test_eof 4571 | _test_eof17: 4572 | l.cs = 17 4573 | goto _test_eof 4574 | _test_eof18: 4575 | l.cs = 18 4576 | goto _test_eof 4577 | _test_eof19: 4578 | l.cs = 19 4579 | goto _test_eof 4580 | _test_eof99: 4581 | l.cs = 99 4582 | goto _test_eof 4583 | _test_eof20: 4584 | l.cs = 20 4585 | goto _test_eof 4586 | _test_eof21: 4587 | l.cs = 21 4588 | goto _test_eof 4589 | _test_eof22: 4590 | l.cs = 22 4591 | goto _test_eof 4592 | _test_eof100: 4593 | l.cs = 100 4594 | goto _test_eof 4595 | _test_eof23: 4596 | l.cs = 23 4597 | goto _test_eof 4598 | _test_eof24: 4599 | l.cs = 24 4600 | goto _test_eof 4601 | _test_eof101: 4602 | l.cs = 101 4603 | goto _test_eof 4604 | _test_eof25: 4605 | l.cs = 25 4606 | goto _test_eof 4607 | _test_eof26: 4608 | l.cs = 26 4609 | goto _test_eof 4610 | _test_eof27: 4611 | l.cs = 27 4612 | goto _test_eof 4613 | _test_eof28: 4614 | l.cs = 28 4615 | goto _test_eof 4616 | _test_eof29: 4617 | l.cs = 29 4618 | goto _test_eof 4619 | _test_eof30: 4620 | l.cs = 30 4621 | goto _test_eof 4622 | _test_eof31: 4623 | l.cs = 31 4624 | goto _test_eof 4625 | _test_eof32: 4626 | l.cs = 32 4627 | goto _test_eof 4628 | _test_eof33: 4629 | l.cs = 33 4630 | goto _test_eof 4631 | _test_eof34: 4632 | l.cs = 34 4633 | goto _test_eof 4634 | _test_eof35: 4635 | l.cs = 35 4636 | goto _test_eof 4637 | _test_eof36: 4638 | l.cs = 36 4639 | goto _test_eof 4640 | _test_eof37: 4641 | l.cs = 37 4642 | goto _test_eof 4643 | _test_eof38: 4644 | l.cs = 38 4645 | goto _test_eof 4646 | _test_eof39: 4647 | l.cs = 39 4648 | goto _test_eof 4649 | _test_eof40: 4650 | l.cs = 40 4651 | goto _test_eof 4652 | _test_eof41: 4653 | l.cs = 41 4654 | goto _test_eof 4655 | _test_eof42: 4656 | l.cs = 42 4657 | goto _test_eof 4658 | _test_eof43: 4659 | l.cs = 43 4660 | goto _test_eof 4661 | _test_eof44: 4662 | l.cs = 44 4663 | goto _test_eof 4664 | _test_eof45: 4665 | l.cs = 45 4666 | goto _test_eof 4667 | _test_eof46: 4668 | l.cs = 46 4669 | goto _test_eof 4670 | _test_eof102: 4671 | l.cs = 102 4672 | goto _test_eof 4673 | _test_eof47: 4674 | l.cs = 47 4675 | goto _test_eof 4676 | _test_eof48: 4677 | l.cs = 48 4678 | goto _test_eof 4679 | _test_eof49: 4680 | l.cs = 49 4681 | goto _test_eof 4682 | _test_eof50: 4683 | l.cs = 50 4684 | goto _test_eof 4685 | _test_eof51: 4686 | l.cs = 51 4687 | goto _test_eof 4688 | _test_eof52: 4689 | l.cs = 52 4690 | goto _test_eof 4691 | _test_eof53: 4692 | l.cs = 53 4693 | goto _test_eof 4694 | _test_eof54: 4695 | l.cs = 54 4696 | goto _test_eof 4697 | _test_eof55: 4698 | l.cs = 55 4699 | goto _test_eof 4700 | _test_eof56: 4701 | l.cs = 56 4702 | goto _test_eof 4703 | _test_eof57: 4704 | l.cs = 57 4705 | goto _test_eof 4706 | _test_eof58: 4707 | l.cs = 58 4708 | goto _test_eof 4709 | _test_eof59: 4710 | l.cs = 59 4711 | goto _test_eof 4712 | _test_eof60: 4713 | l.cs = 60 4714 | goto _test_eof 4715 | _test_eof61: 4716 | l.cs = 61 4717 | goto _test_eof 4718 | _test_eof62: 4719 | l.cs = 62 4720 | goto _test_eof 4721 | _test_eof63: 4722 | l.cs = 63 4723 | goto _test_eof 4724 | _test_eof64: 4725 | l.cs = 64 4726 | goto _test_eof 4727 | _test_eof65: 4728 | l.cs = 65 4729 | goto _test_eof 4730 | _test_eof66: 4731 | l.cs = 66 4732 | goto _test_eof 4733 | _test_eof67: 4734 | l.cs = 67 4735 | goto _test_eof 4736 | _test_eof68: 4737 | l.cs = 68 4738 | goto _test_eof 4739 | _test_eof69: 4740 | l.cs = 69 4741 | goto _test_eof 4742 | _test_eof103: 4743 | l.cs = 103 4744 | goto _test_eof 4745 | _test_eof70: 4746 | l.cs = 70 4747 | goto _test_eof 4748 | _test_eof71: 4749 | l.cs = 71 4750 | goto _test_eof 4751 | _test_eof72: 4752 | l.cs = 72 4753 | goto _test_eof 4754 | _test_eof73: 4755 | l.cs = 73 4756 | goto _test_eof 4757 | _test_eof74: 4758 | l.cs = 74 4759 | goto _test_eof 4760 | _test_eof75: 4761 | l.cs = 75 4762 | goto _test_eof 4763 | _test_eof76: 4764 | l.cs = 76 4765 | goto _test_eof 4766 | _test_eof77: 4767 | l.cs = 77 4768 | goto _test_eof 4769 | _test_eof78: 4770 | l.cs = 78 4771 | goto _test_eof 4772 | _test_eof79: 4773 | l.cs = 79 4774 | goto _test_eof 4775 | _test_eof80: 4776 | l.cs = 80 4777 | goto _test_eof 4778 | _test_eof81: 4779 | l.cs = 81 4780 | goto _test_eof 4781 | _test_eof82: 4782 | l.cs = 82 4783 | goto _test_eof 4784 | _test_eof83: 4785 | l.cs = 83 4786 | goto _test_eof 4787 | _test_eof84: 4788 | l.cs = 84 4789 | goto _test_eof 4790 | _test_eof85: 4791 | l.cs = 85 4792 | goto _test_eof 4793 | _test_eof86: 4794 | l.cs = 86 4795 | goto _test_eof 4796 | _test_eof87: 4797 | l.cs = 87 4798 | goto _test_eof 4799 | _test_eof88: 4800 | l.cs = 88 4801 | goto _test_eof 4802 | _test_eof89: 4803 | l.cs = 89 4804 | goto _test_eof 4805 | _test_eof90: 4806 | l.cs = 90 4807 | goto _test_eof 4808 | _test_eof91: 4809 | l.cs = 91 4810 | goto _test_eof 4811 | _test_eof92: 4812 | l.cs = 92 4813 | goto _test_eof 4814 | _test_eof93: 4815 | l.cs = 93 4816 | goto _test_eof 4817 | _test_eof94: 4818 | l.cs = 94 4819 | goto _test_eof 4820 | 4821 | _test_eof: 4822 | { 4823 | } 4824 | if (l.p) == (l.eof) { 4825 | switch l.cs { 4826 | case 95: 4827 | //line lexer/lexer.go.rl:54 4828 | 4829 | str, perr = strconv.Unquote(l.text()) 4830 | if perr != nil { 4831 | perr = errors.Wrapf(perr, "strconv.Unquote %s", l.text()) 4832 | { 4833 | (l.p)++ 4834 | l.cs = 0 4835 | goto _out 4836 | } 4837 | } 4838 | l.ast.pushStr(str) 4839 | 4840 | case 98: 4841 | //line lexer/lexer.go.rl:62 4842 | 4843 | n64, perr = strconv.ParseInt(l.text(), 10, 64) 4844 | if perr != nil { 4845 | { 4846 | (l.p)++ 4847 | l.cs = 0 4848 | goto _out 4849 | } 4850 | } 4851 | l.ast.pushInt(n64) 4852 | 4853 | case 100: 4854 | //line lexer/lexer.go.rl:69 4855 | l.ast.pushTrue() 4856 | case 99: 4857 | //line lexer/lexer.go.rl:70 4858 | l.ast.pushFalse() 4859 | //line lexer/lexer.go:4426 4860 | } 4861 | } 4862 | 4863 | _out: 4864 | { 4865 | } 4866 | } 4867 | 4868 | //line lexer/lexer.go.rl:121 4869 | 4870 | if l.top > 0 { 4871 | return nil, fmt.Errorf("stack parsing error at %d", l.pb) 4872 | } 4873 | 4874 | if l.cs < 95 { 4875 | if perr != nil { 4876 | return nil, fmt.Errorf("parsing error at %d: %w", l.pb, perr) 4877 | } 4878 | return nil, fmt.Errorf("token parsing error at %d", l.pb) 4879 | } 4880 | 4881 | l.ast.rotateBreakOn() 4882 | 4883 | return l.ast.rpn, nil 4884 | } 4885 | -------------------------------------------------------------------------------- /lexer/lexer.go.rl: -------------------------------------------------------------------------------- 1 | package lexer 2 | 3 | import ( 4 | "github.com/pkg/errors" 5 | ) 6 | 7 | %%{ 8 | machine lexer; 9 | write data; 10 | }%% 11 | 12 | type Lexer struct { 13 | p, pe, pb, eof int 14 | cs, top int 15 | data []byte 16 | stack [1024]int 17 | ast ast 18 | } 19 | 20 | func (l *Lexer) text() string { 21 | return string(l.data[l.pb:l.p]) 22 | } 23 | 24 | func (l *Lexer) Parse(input []byte) ([]Node, error) { 25 | l.ast.reset() 26 | 27 | l.data = input 28 | l.p = 0 29 | l.pb = 0 30 | l.pe = len(input) 31 | l.eof = len(input) 32 | 33 | var perr error 34 | var n64 int64 35 | var str string 36 | 37 | %%{ 38 | access l.; 39 | 40 | variable p l.p; 41 | variable pe l.pe; 42 | variable eof l.eof; 43 | 44 | action return { fret; } 45 | action mark { l.pb = l.p } 46 | action opts_first_param { l.ast.incCaps() } 47 | action rotate_comma { l.ast.rotateComma() } 48 | action pop_caps { l.ast.popCaps() } 49 | action push_invoke { l.ast.pushInvoke() } 50 | action push_vector { l.ast.pushVector() } 51 | action open_pths { l.ast.openPths() } 52 | action close_pths { l.ast.closePths() } 53 | action push_ident { l.ast.pushIdent(l.text()) } 54 | action push_str { 55 | str, perr = strconv.Unquote(l.text()) 56 | if perr != nil { 57 | perr = errors.Wrapf(perr, "strconv.Unquote %s", l.text()) 58 | fbreak; 59 | } 60 | l.ast.pushStr(str) 61 | } 62 | action push_int { 63 | n64, perr = strconv.ParseInt(l.text(), 10, 64) 64 | if perr != nil { 65 | fbreak; 66 | } 67 | l.ast.pushInt(n64) 68 | } 69 | action push_true { l.ast.pushTrue() } 70 | action push_false { l.ast.pushFalse() } 71 | action push_math_op { l.ast.pushMathOp(l.data[l.pb]) } 72 | 73 | not_dquote = [^"\\]; 74 | esc_smth = /\\./; 75 | 76 | str_body = not_dquote | esc_smth; 77 | 78 | alpha_u = alpha | '_'; 79 | alnum_u = alnum | '_'; 80 | 81 | int = ([\+\-]? digit+) >mark %push_int; 82 | str = ('"' str_body* '"') >mark %push_str; 83 | true = 'true' %push_true; 84 | false = 'false' %push_false; 85 | bool = true | false; 86 | keywords = bool; 87 | ident = (alpha_u alnum_u* & !keywords) >mark %push_ident; 88 | 89 | ws = space*; 90 | 91 | comma = ','; 92 | 93 | # round brackets 94 | orbr = '('; 95 | crbr = ')'; 96 | 97 | # square brackets 98 | osbr = '['; 99 | csbr = ']'; 100 | 101 | vector = osbr @push_vector @{ fcall vector_rest; }; 102 | invoke = ident ws orbr @push_invoke @{ fcall invoke_rest; }; 103 | pths = orbr @open_pths @{ fcall pths_rest; }; 104 | 105 | math_op = [\+\-\*\/] >mark %push_math_op; 106 | math_pred = int | invoke | pths; 107 | math = math_pred (ws math_op ws math_pred)*; 108 | 109 | opts = math | vector | str | bool; 110 | 111 | opts_delim = opts >opts_first_param (ws comma @rotate_comma ws opts)*; 112 | 113 | pths_rest := ws math ws crbr @close_pths @return; 114 | vector_rest := ws opts_delim? ws csbr @pop_caps @return; 115 | invoke_rest := ws opts_delim? ws crbr @pop_caps @return; 116 | 117 | main := ws opts ws; 118 | 119 | write init; 120 | write exec; 121 | }%% 122 | if l.top > 0 { 123 | return nil, fmt.Errorf("stack parsing error at %d", l.pb) 124 | } 125 | 126 | if l.cs < %%{ write first_final; }%% { 127 | if perr != nil { 128 | return nil, fmt.Errorf("parsing error at %d: %w", l.pb, perr) 129 | } 130 | return nil, fmt.Errorf("token parsing error at %d", l.pb) 131 | } 132 | 133 | l.ast.rotateBreakOn() 134 | 135 | return l.ast.rpn, nil 136 | } 137 | -------------------------------------------------------------------------------- /lexer/lexer_test.go: -------------------------------------------------------------------------------- 1 | package lexer 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestLexer_Parse(t *testing.T) { 11 | cases := []struct { 12 | input string 13 | expected []Node 14 | }{ 15 | { 16 | "true", 17 | []Node{ 18 | {Typ: TypTrue}, 19 | }, 20 | }, 21 | { 22 | "false", 23 | []Node{ 24 | {Typ: TypFalse}, 25 | }, 26 | }, 27 | { 28 | `"str"`, 29 | []Node{ 30 | {Typ: TypStr, DatS: "str"}, 31 | }, 32 | }, 33 | { 34 | `"foo\"bar"`, 35 | []Node{ 36 | {Typ: TypStr, DatS: `foo"bar`}, 37 | }, 38 | }, 39 | { 40 | "000123", 41 | []Node{ 42 | {Typ: TypInt, DatN: 123}, 43 | }, 44 | }, 45 | { 46 | "-123", 47 | []Node{ 48 | {Typ: TypInt, DatN: -123}, 49 | }, 50 | }, 51 | { 52 | "+123", 53 | []Node{ 54 | {Typ: TypInt, DatN: 123}, 55 | }, 56 | }, 57 | { 58 | "[]", 59 | []Node{ 60 | {Typ: TypVector}, 61 | }, 62 | }, 63 | { 64 | "[ ]", 65 | []Node{ 66 | {Typ: TypVector}, 67 | }, 68 | }, 69 | { 70 | " [ ]", 71 | []Node{ 72 | {Typ: TypVector}, 73 | }, 74 | }, 75 | { 76 | " [ ] ", 77 | []Node{ 78 | {Typ: TypVector}, 79 | }, 80 | }, 81 | { 82 | "[ foo () ]", 83 | []Node{ 84 | {Typ: TypInvoke, DatS: "foo"}, 85 | {Typ: TypVector, Cap: 1}, 86 | }, 87 | }, 88 | { 89 | "[[]]", 90 | []Node{ 91 | {Typ: TypVector}, 92 | {Typ: TypVector, Cap: 1}, 93 | }, 94 | }, 95 | { 96 | `[255]`, 97 | []Node{ 98 | {Typ: TypInt, DatN: 255}, 99 | {Typ: TypVector, Cap: 1}, 100 | }, 101 | }, 102 | { 103 | "[1,2]", 104 | []Node{ 105 | {Typ: TypInt, DatN: 1}, 106 | {Typ: TypInt, DatN: 2}, 107 | {Typ: TypVector, Cap: 2}, 108 | }, 109 | }, 110 | { 111 | "[1 * 2]", 112 | []Node{ 113 | {Typ: TypInt, DatN: 1}, 114 | {Typ: TypInt, DatN: 2}, 115 | {Typ: TypOpMul}, 116 | {Typ: TypVector, Cap: 1}, 117 | }, 118 | }, 119 | { 120 | "[1 + 2, 3 * 4]", 121 | []Node{ 122 | {Typ: TypInt, DatN: 1}, 123 | {Typ: TypInt, DatN: 2}, 124 | {Typ: TypOpAdd}, 125 | {Typ: TypInt, DatN: 3}, 126 | {Typ: TypInt, DatN: 4}, 127 | {Typ: TypOpMul}, 128 | {Typ: TypVector, Cap: 2}, 129 | }, 130 | }, 131 | { 132 | "foo()", 133 | []Node{ 134 | {Typ: TypInvoke, DatS: "foo"}, 135 | }, 136 | }, 137 | { 138 | "foo ()", 139 | []Node{ 140 | {Typ: TypInvoke, DatS: "foo"}, 141 | }, 142 | }, 143 | { 144 | "foo ( )", 145 | []Node{ 146 | {Typ: TypInvoke, DatS: "foo"}, 147 | }, 148 | }, 149 | { 150 | "foo(bar())", 151 | []Node{ 152 | {Typ: TypInvoke, DatS: "bar"}, 153 | {Typ: TypInvoke, DatS: "foo", Cap: 1}, 154 | }, 155 | }, 156 | { 157 | "foo(123)", 158 | []Node{ 159 | {Typ: TypInt, DatN: 123}, 160 | {Typ: TypInvoke, DatS: "foo", Cap: 1}, 161 | }, 162 | }, 163 | { 164 | "foo([1])", 165 | []Node{ 166 | {Typ: TypInt, DatN: 1}, 167 | {Typ: TypVector, Cap: 1}, 168 | {Typ: TypInvoke, DatS: "foo", Cap: 1}, 169 | }, 170 | }, 171 | { 172 | "foo(1, 2)", 173 | []Node{ 174 | {Typ: TypInt, DatN: 1}, 175 | {Typ: TypInt, DatN: 2}, 176 | {Typ: TypInvoke, DatS: "foo", Cap: 2}, 177 | }, 178 | }, 179 | { 180 | "1+1", 181 | []Node{ 182 | {Typ: TypInt, DatN: 1}, 183 | {Typ: TypInt, DatN: 1}, 184 | {Typ: TypOpAdd}, 185 | }, 186 | }, 187 | { 188 | "1+-1", 189 | []Node{ 190 | {Typ: TypInt, DatN: 1}, 191 | {Typ: TypInt, DatN: -1}, 192 | {Typ: TypOpAdd}, 193 | }, 194 | }, 195 | { 196 | "1-1", 197 | []Node{ 198 | {Typ: TypInt, DatN: 1}, 199 | {Typ: TypInt, DatN: 1}, 200 | {Typ: TypOpSub}, 201 | }, 202 | }, 203 | { 204 | "1-+1", 205 | []Node{ 206 | {Typ: TypInt, DatN: 1}, 207 | {Typ: TypInt, DatN: 1}, 208 | {Typ: TypOpSub}, 209 | }, 210 | }, 211 | { 212 | "1*1", 213 | []Node{ 214 | {Typ: TypInt, DatN: 1}, 215 | {Typ: TypInt, DatN: 1}, 216 | {Typ: TypOpMul}, 217 | }, 218 | }, 219 | { 220 | "1/1", 221 | []Node{ 222 | {Typ: TypInt, DatN: 1}, 223 | {Typ: TypInt, DatN: 1}, 224 | {Typ: TypOpDiv}, 225 | }, 226 | }, 227 | { 228 | "1 + 2 * 3", 229 | []Node{ 230 | {Typ: TypInt, DatN: 1}, 231 | {Typ: TypInt, DatN: 2}, 232 | {Typ: TypInt, DatN: 3}, 233 | {Typ: TypOpMul}, 234 | {Typ: TypOpAdd}, 235 | }, 236 | }, 237 | { 238 | "(1 + 2) * 3", 239 | []Node{ 240 | {Typ: TypInt, DatN: 1}, 241 | {Typ: TypInt, DatN: 2}, 242 | {Typ: TypOpAdd}, 243 | {Typ: TypInt, DatN: 3}, 244 | {Typ: TypOpMul}, 245 | }, 246 | }, 247 | { 248 | " ( 1 ) ", 249 | []Node{ 250 | {Typ: TypInt, DatN: 1}, 251 | }, 252 | }, 253 | { 254 | " ( ( 1 + 2 ) * 3 ) ", 255 | []Node{ 256 | {Typ: TypInt, DatN: 1}, 257 | {Typ: TypInt, DatN: 2}, 258 | {Typ: TypOpAdd}, 259 | {Typ: TypInt, DatN: 3}, 260 | {Typ: TypOpMul}, 261 | }, 262 | }, 263 | { 264 | "1 * 2 + 3", 265 | []Node{ 266 | {Typ: TypInt, DatN: 1}, 267 | {Typ: TypInt, DatN: 2}, 268 | {Typ: TypOpMul}, 269 | {Typ: TypInt, DatN: 3}, 270 | {Typ: TypOpAdd}, 271 | }, 272 | }, 273 | { 274 | "1 * (2 + (-3))", 275 | []Node{ 276 | {Typ: TypInt, DatN: 1}, 277 | {Typ: TypInt, DatN: 2}, 278 | {Typ: TypInt, DatN: -3}, 279 | {Typ: TypOpAdd}, 280 | {Typ: TypOpMul}, 281 | }, 282 | }, 283 | { 284 | "(100)+(200)", 285 | []Node{ 286 | {Typ: TypInt, DatN: 100}, 287 | {Typ: TypInt, DatN: 200}, 288 | {Typ: TypOpAdd}, 289 | }, 290 | }, 291 | { 292 | "foo((1))", 293 | []Node{ 294 | {Typ: TypInt, DatN: 1}, 295 | {Typ: TypInvoke, DatS: "foo", Cap: 1}, 296 | }, 297 | }, 298 | { 299 | "foo(1 + 2)", 300 | []Node{ 301 | {Typ: TypInt, DatN: 1}, 302 | {Typ: TypInt, DatN: 2}, 303 | {Typ: TypOpAdd}, 304 | {Typ: TypInvoke, DatS: "foo", Cap: 1}, 305 | }, 306 | }, 307 | { 308 | "foo(1 + 2 * 3, [true])", 309 | []Node{ 310 | {Typ: TypInt, DatN: 1}, 311 | {Typ: TypInt, DatN: 2}, 312 | {Typ: TypInt, DatN: 3}, 313 | {Typ: TypOpMul}, 314 | {Typ: TypOpAdd}, 315 | {Typ: TypTrue}, 316 | {Typ: TypVector, Cap: 1}, 317 | {Typ: TypInvoke, DatS: "foo", Cap: 2}, 318 | }, 319 | }, 320 | { 321 | "1 + foo(true) * 3", 322 | []Node{ 323 | {Typ: TypInt, DatN: 1}, 324 | {Typ: TypTrue}, 325 | {Typ: TypInvoke, DatS: "foo", Cap: 1}, 326 | {Typ: TypInt, DatN: 3}, 327 | {Typ: TypOpMul}, 328 | {Typ: TypOpAdd}, 329 | }, 330 | }, 331 | } 332 | 333 | var lex Lexer 334 | 335 | for _, c := range cases { 336 | t.Run(c.input, func(t *testing.T) { 337 | tokens, err := lex.Parse([]byte(c.input)) 338 | 339 | require.NoError(t, err) 340 | assert.Equal(t, c.expected, tokens) 341 | }) 342 | } 343 | } 344 | 345 | func TestLexer_ParseFailed(t *testing.T) { 346 | cases := []struct { 347 | input, errmsg string 348 | }{ 349 | { 350 | "", 351 | "token parsing error at 0", 352 | }, 353 | { 354 | "9223372036854775808", 355 | "parsing error at 0: strconv.ParseInt: parsing \"9223372036854775808\": value out of range", 356 | }, 357 | { 358 | `"hello`, 359 | "token parsing error at 0", 360 | }, 361 | { 362 | `"hello \ world"`, 363 | `parsing error at 0: strconv.Unquote "hello \ world": invalid syntax`, 364 | }, 365 | { 366 | "1 2", 367 | "token parsing error at 0", 368 | }, 369 | { 370 | "tru", 371 | "token parsing error at 0", 372 | }, 373 | { 374 | "(", 375 | "stack parsing error at 0", 376 | }, 377 | { 378 | "()", 379 | "stack parsing error at 0", 380 | }, 381 | { 382 | "func([)", 383 | "stack parsing error at 0", 384 | }, 385 | { 386 | "[func(]", 387 | "stack parsing error at 1", 388 | }, 389 | { 390 | "*1", 391 | "token parsing error at 0", 392 | }, 393 | { 394 | "/1", 395 | "token parsing error at 0", 396 | }, 397 | { 398 | "1*", 399 | "token parsing error at 1", 400 | }, 401 | { 402 | "1/", 403 | "token parsing error at 1", 404 | }, 405 | { 406 | "1+", 407 | "token parsing error at 1", 408 | }, 409 | { 410 | "1-", 411 | "token parsing error at 1", 412 | }, 413 | { 414 | "(1-", 415 | "stack parsing error at 2", 416 | }, 417 | { 418 | "1()", 419 | "token parsing error at 0", 420 | }, 421 | { 422 | "true()", 423 | "token parsing error at 0", 424 | }, 425 | { 426 | "false()", 427 | "token parsing error at 0", 428 | }, 429 | { 430 | "1+++1", 431 | "token parsing error at 2", 432 | }, 433 | { 434 | "1 + + 1", 435 | "token parsing error at 4", 436 | }, 437 | { 438 | "1+ - 1", 439 | "token parsing error at 3", 440 | }, 441 | { 442 | "1)", 443 | "token parsing error at 0", 444 | }, 445 | { 446 | `1 + ""`, 447 | "token parsing error at 2", 448 | }, 449 | { 450 | "true + false", 451 | "token parsing error at 0", 452 | }, 453 | { 454 | "func(1 2)", 455 | "stack parsing error at 5", 456 | }, 457 | { 458 | "func(1, 2,)", 459 | "stack parsing error at 8", 460 | }, 461 | { 462 | "[1 2]", 463 | "stack parsing error at 1", 464 | }, 465 | { 466 | "[1, 2,]", 467 | "stack parsing error at 4", 468 | }, 469 | } 470 | 471 | var lex Lexer 472 | 473 | for _, c := range cases { 474 | t.Run(c.input, func(t *testing.T) { 475 | tokens, err := lex.Parse([]byte(c.input)) 476 | 477 | require.Nil(t, tokens) 478 | assert.EqualError(t, err, c.errmsg) 479 | }) 480 | } 481 | } 482 | -------------------------------------------------------------------------------- /lexer/node.go: -------------------------------------------------------------------------------- 1 | package lexer 2 | 3 | import "fmt" 4 | 5 | type Typ uint8 6 | 7 | const ( 8 | typIllegal Typ = iota 9 | typPths 10 | typIdent 11 | // exported types 12 | TypInt 13 | TypStr 14 | TypTrue 15 | TypFalse 16 | TypInvoke 17 | TypVector 18 | TypOpAdd 19 | TypOpSub 20 | TypOpMul 21 | TypOpDiv 22 | ) 23 | 24 | var typ2str = [...]string{ 25 | "illegal", "pths", "ident", 26 | "int", "str", "true", "false", "invoke", "vector", 27 | "op_add", "op_sub", "op_mul", "op_div", 28 | } 29 | 30 | var typMathOp = map[byte]Typ{ 31 | '+': TypOpAdd, 32 | '-': TypOpSub, 33 | '*': TypOpMul, 34 | '/': TypOpDiv, 35 | } 36 | 37 | func (t Typ) String() string { 38 | i := int(t) 39 | if i < len(typ2str) { 40 | return typ2str[i] 41 | } 42 | return fmt.Sprintf("_unknown_%d", i) 43 | } 44 | 45 | type Node struct { 46 | Typ 47 | Cap uint 48 | DatN int64 49 | DatS string 50 | } 51 | 52 | func (n Node) setTyp(t Typ) Node { 53 | n.Typ = t 54 | return n 55 | } 56 | 57 | func (n Node) incCap() Node { 58 | n.Cap++ 59 | return n 60 | } 61 | 62 | func (n Node) typeOf(tt ...Typ) bool { 63 | for _, t := range tt { 64 | if n.Typ == t { 65 | return true 66 | } 67 | } 68 | return false 69 | } 70 | -------------------------------------------------------------------------------- /lexer/nvec.go: -------------------------------------------------------------------------------- 1 | package lexer 2 | 3 | type nvec []Node 4 | 5 | func (s *nvec) reset() { 6 | *s = (*s)[:0] 7 | } 8 | 9 | func (s *nvec) empty() bool { 10 | return s.size() == 0 11 | } 12 | 13 | func (s *nvec) size() int { 14 | return len(*s) 15 | } 16 | 17 | func (s nvec) top() Node { 18 | return s[len(s)-1] 19 | } 20 | 21 | func (s *nvec) push(t Node) { 22 | *s = append(*s, t) 23 | } 24 | 25 | func (s *nvec) popN(n int) []Node { 26 | l := len(*s) - n 27 | tail := (*s)[l:] 28 | *s = (*s)[:l] 29 | return tail 30 | } 31 | 32 | func (s *nvec) pop() Node { 33 | return s.popN(1)[0] 34 | } 35 | -------------------------------------------------------------------------------- /memory/addr.go: -------------------------------------------------------------------------------- 1 | package memory 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "fmt" 7 | "io" 8 | "strconv" 9 | ) 10 | 11 | var ( 12 | True = NewAddr(TypeBool, 1) 13 | False = NewAddr(TypeBool, 0) 14 | NoBytes = NewAddr(TypeBytes) 15 | Nil = NewAddr(TypeNil) 16 | ) 17 | 18 | type Addr struct { 19 | typ Type 20 | dat []byte 21 | vec []Addr 22 | } 23 | 24 | func NewAddr(t Type, dat ...byte) Addr { 25 | return Addr{ 26 | typ: t, 27 | dat: dat, 28 | } 29 | } 30 | 31 | func (a Addr) Size() uint32 { return uint32(len(a.dat)) } 32 | 33 | func (a Addr) Vector() []Addr { 34 | return a.vec 35 | } 36 | 37 | func (a Addr) CopyBytes(src ...Addr) { 38 | var offset uint32 39 | for _, s := range src { 40 | copy(a.dat[offset:], s.dat) 41 | offset += s.Size() 42 | } 43 | } 44 | 45 | func (a Addr) CopyVector(v []Addr) { 46 | copy(a.vec, v) 47 | } 48 | 49 | func (a Addr) VectorAt(i int) Addr { 50 | return a.vec[i] 51 | } 52 | 53 | func (a Addr) SetVectorAt(i int, v Addr) { 54 | a.vec[i] = v 55 | } 56 | 57 | func (a Addr) VectorLen() int { 58 | return len(a.vec) 59 | } 60 | 61 | func (a Addr) Bytes() []byte { 62 | return a.dat 63 | } 64 | 65 | func (a Addr) Int64() int64 { 66 | return int64(binary.BigEndian.Uint64(a.dat)) 67 | } 68 | 69 | func (a Addr) SetInt64(n int64) { 70 | binary.BigEndian.PutUint64(a.dat, uint64(n)) 71 | } 72 | 73 | func (a Addr) Bool() bool { 74 | return a.dat[0] == 1 75 | } 76 | 77 | func (a Addr) Type() Type { 78 | return a.typ 79 | } 80 | 81 | func (a Addr) TypeOf(t Type) bool { 82 | return a.typ == t 83 | } 84 | 85 | func (a Addr) EqualType(b Addr) bool { 86 | return a.typ == b.typ 87 | } 88 | 89 | func (a Addr) EqualBytes(b Addr) bool { 90 | return bytes.Equal(a.dat, b.dat) 91 | } 92 | 93 | func (a Addr) Equal(b Addr) bool { 94 | if !a.EqualType(b) { 95 | return false 96 | } 97 | if a.TypeOf(TypeVector) { 98 | if a.VectorLen() != b.VectorLen() { 99 | return false 100 | } 101 | for i, ax := range a.Vector() { 102 | if !ax.Equal(b.VectorAt(i)) { 103 | return false 104 | } 105 | } 106 | return true 107 | } 108 | return a.EqualBytes(b) 109 | } 110 | 111 | func (a Addr) Print(w io.Writer) { 112 | fmt.Fprint(w, a.typ) 113 | switch a.typ { 114 | case TypeBytes: 115 | fmt.Fprintf(w, "=%s", strconv.Quote(string(a.dat))) 116 | case TypeBool: 117 | fmt.Fprintf(w, "=%d", a.dat[0]) 118 | case TypeInt64: 119 | fmt.Fprintf(w, "=%d", a.Int64()) 120 | case TypeVector: 121 | fmt.Fprint(w, "=[") 122 | for i, v := range a.vec { 123 | if i > 0 { 124 | fmt.Fprint(w, ", ") 125 | } 126 | v.Print(w) 127 | } 128 | fmt.Fprint(w, "]") 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /memory/addr_test.go: -------------------------------------------------------------------------------- 1 | package memory_test 2 | 3 | import ( 4 | "bytes" 5 | "testing" 6 | 7 | "github.com/regeda/expr/memory" 8 | "github.com/stretchr/testify/assert" 9 | "github.com/stretchr/testify/require" 10 | ) 11 | 12 | func TestAddr_Size(t *testing.T) { 13 | addr := memory.NewAddr(memory.TypeBytes, 1, 2, 3) 14 | assert.Equal(t, uint32(3), addr.Size()) 15 | } 16 | 17 | func TestAddr_Bool(t *testing.T) { 18 | addrTrue := memory.NewAddr(memory.TypeBool, 1) 19 | assert.True(t, addrTrue.Bool()) 20 | 21 | addrFalse := memory.NewAddr(memory.TypeBool, 0) 22 | assert.False(t, addrFalse.Bool()) 23 | } 24 | 25 | func TestAddr_NilVector(t *testing.T) { 26 | addr := memory.NewAddr(memory.TypeVector) 27 | 28 | require.Nil(t, addr.Vector()) 29 | } 30 | 31 | func TestAddr_CopyBytes(t *testing.T) { 32 | addr1 := memory.NewAddr(memory.TypeBytes, 1, 2, 3) 33 | addr2 := memory.NewAddr(memory.TypeBytes, 4, 5, 6) 34 | 35 | addrX := memory.NewAddr(memory.TypeBytes, make([]byte, 6)...) 36 | addrX.CopyBytes(addr1, addr2) 37 | 38 | assert.Equal(t, []byte{1, 2, 3, 4, 5, 6}, addrX.Bytes()) 39 | } 40 | 41 | func TestAddr_TypeOf(t *testing.T) { 42 | assert.True(t, memory.True.TypeOf(memory.TypeBool)) 43 | assert.False(t, memory.True.TypeOf(memory.TypeNil)) 44 | } 45 | 46 | func TestAddr_EqualType(t *testing.T) { 47 | assert.True(t, memory.True.EqualType(memory.False)) 48 | } 49 | 50 | func TestAddr_EqualBytes(t *testing.T) { 51 | assert.True(t, memory.True.EqualBytes(memory.True)) 52 | assert.False(t, memory.True.EqualBytes(memory.False)) 53 | } 54 | 55 | func TestAddr_Equal(t *testing.T) { 56 | mem := memory.New() 57 | 58 | cases := []struct { 59 | name string 60 | a, b memory.Addr 61 | res bool 62 | }{ 63 | { 64 | "false: array of array", 65 | mem.CopyVector( 66 | mem.CopyVector( 67 | mem.AllocInt64(1), 68 | ), 69 | ), 70 | mem.CopyVector( 71 | mem.CopyVector( 72 | mem.AllocInt64(2), 73 | ), 74 | ), 75 | false, 76 | }, 77 | { 78 | "false: array diff len", 79 | mem.CopyVector( 80 | mem.CopyVector(), 81 | ), 82 | mem.CopyVector( 83 | mem.CopyVector( 84 | mem.AllocInt64(1), 85 | ), 86 | ), 87 | false, 88 | }, 89 | { 90 | "false: array of diff types", 91 | mem.CopyVector( 92 | mem.CopyVector( 93 | mem.AllocBytesAddr([]byte("foo")), 94 | ), 95 | ), 96 | mem.CopyVector( 97 | mem.CopyVector( 98 | mem.AllocInt64(1), 99 | ), 100 | ), 101 | false, 102 | }, 103 | { 104 | "true: array of array", 105 | mem.CopyVector( 106 | mem.CopyVector( 107 | mem.AllocInt64(1), 108 | ), 109 | ), 110 | mem.CopyVector( 111 | mem.CopyVector( 112 | mem.AllocInt64(1), 113 | ), 114 | ), 115 | true, 116 | }, 117 | } 118 | for _, c := range cases { 119 | t.Run(c.name, func(t *testing.T) { 120 | require.Equal(t, c.res, c.a.Equal(c.b)) 121 | }) 122 | } 123 | 124 | } 125 | 126 | func TestAddr_Print(t *testing.T) { 127 | mem := memory.New() 128 | 129 | cases := []struct { 130 | name string 131 | v interface{} 132 | expected string 133 | }{ 134 | {"string", "hello world", `bytes="hello world"`}, 135 | {"quoted string", `hi "dude"`, `bytes="hi \"dude\""`}, 136 | {"bool true", true, "bool=1"}, 137 | {"bool false", false, "bool=0"}, 138 | {"int", 123, "int64=123"}, 139 | {"vector", []interface{}{1, true, "foo"}, `vector=[int64=1, bool=1, bytes="foo"]`}, 140 | {"vector of vector", []interface{}{[]interface{}{true}, 1}, `vector=[vector=[bool=1], int64=1]`}, 141 | } 142 | 143 | for _, c := range cases { 144 | t.Run(c.name, func(t *testing.T) { 145 | buf := bytes.NewBuffer(nil) 146 | addr, err := mem.Alloc(c.v) 147 | require.NoError(t, err) 148 | 149 | addr.Print(buf) 150 | 151 | assert.Equal(t, c.expected, buf.String()) 152 | }) 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /memory/grid.go: -------------------------------------------------------------------------------- 1 | package memory 2 | 3 | type grid struct { 4 | off uint32 5 | buf []Addr 6 | } 7 | 8 | func (g *grid) grow(n uint32) { 9 | l := uint32(len(g.buf)) 10 | if g.off+n < l { 11 | return 12 | } 13 | buf := make([]Addr, 2*l+n) 14 | copy(buf, g.buf) 15 | g.buf = buf 16 | } 17 | 18 | func (g *grid) alloc(n uint32) []Addr { 19 | g.grow(n) 20 | off := g.off 21 | g.off += n 22 | return g.buf[off:g.off] 23 | } 24 | 25 | func (g *grid) reset() { 26 | g.off = 0 27 | } 28 | -------------------------------------------------------------------------------- /memory/heap.go: -------------------------------------------------------------------------------- 1 | package memory 2 | 3 | type heap struct { 4 | off uint32 5 | buf []byte 6 | } 7 | 8 | func (h *heap) grow(n uint32) { 9 | l := uint32(len(h.buf)) 10 | if h.off+n < l { 11 | return 12 | } 13 | buf := make([]byte, 2*l+n) 14 | copy(buf, h.buf) 15 | h.buf = buf 16 | } 17 | 18 | func (h *heap) reset() { 19 | h.off = 0 20 | } 21 | 22 | func (h *heap) alloc(n uint32) []byte { 23 | h.grow(n) 24 | off := h.off 25 | h.off += n 26 | return h.buf[off:h.off] 27 | } 28 | -------------------------------------------------------------------------------- /memory/memory.go: -------------------------------------------------------------------------------- 1 | package memory 2 | 3 | import "fmt" 4 | 5 | const ( 6 | sizeInt8 = 1 7 | sizeInt16 = sizeInt8 << 1 8 | sizeInt32 = sizeInt16 << 1 9 | sizeInt64 = sizeInt32 << 1 10 | ) 11 | 12 | type Memory struct { 13 | g grid 14 | h heap 15 | } 16 | 17 | type Opt func(*Memory) 18 | 19 | func PreallocGrid(size uint32) Opt { 20 | return func(m *Memory) { 21 | m.g.grow(size) 22 | } 23 | } 24 | 25 | func PreallocHeap(size uint32) Opt { 26 | return func(m *Memory) { 27 | m.h.grow(size) 28 | } 29 | } 30 | 31 | func New(opts ...Opt) Memory { 32 | m := Memory{} 33 | 34 | for _, opt := range opts { 35 | opt(&m) 36 | } 37 | 38 | return m 39 | } 40 | 41 | func (b *Memory) Reset() { 42 | b.g.reset() 43 | b.h.reset() 44 | } 45 | 46 | func (b *Memory) alloc(t Type, size uint32) Addr { 47 | buf := b.h.alloc(size) 48 | return NewAddr(t, buf...) 49 | } 50 | 51 | func (b *Memory) Alloc(in interface{}) (Addr, error) { 52 | switch v := in.(type) { 53 | case []byte: 54 | return b.AllocBytesAddr(v), nil 55 | case string: 56 | return b.AllocBytesAddr([]byte(v)), nil 57 | case int: 58 | return b.AllocInt64(int64(v)), nil 59 | case int64: 60 | return b.AllocInt64(v), nil 61 | case bool: 62 | if v { 63 | return True, nil 64 | } 65 | return False, nil 66 | case []interface{}: 67 | vec := b.AllocVector(uint32(len(v))) 68 | for i, e := range v { 69 | addr, err := b.Alloc(e) 70 | if err != nil { 71 | return Nil, err 72 | } 73 | vec.SetVectorAt(i, addr) 74 | } 75 | return vec, nil 76 | default: 77 | return Nil, fmt.Errorf("memory: unsupported type %T", v) 78 | } 79 | } 80 | 81 | func (b *Memory) AllocBytesAddr(dat []byte) Addr { 82 | return NewAddr(TypeBytes, dat...) 83 | } 84 | 85 | func (b *Memory) AllocBytes(size uint32) Addr { 86 | if size == 0 { 87 | return NoBytes 88 | } 89 | return b.alloc(TypeBytes, size) 90 | } 91 | 92 | func (b *Memory) AllocInt64(v int64) Addr { 93 | addr := b.alloc(TypeInt64, sizeInt64) 94 | addr.SetInt64(v) 95 | return addr 96 | } 97 | 98 | func (b *Memory) AllocVector(size uint32) Addr { 99 | addr := NewAddr(TypeVector) 100 | addr.vec = b.g.alloc(size) 101 | return addr 102 | } 103 | 104 | func (b *Memory) CopyVector(elems ...Addr) Addr { 105 | addr := b.AllocVector(uint32(len(elems))) 106 | addr.CopyVector(elems) 107 | return addr 108 | } 109 | -------------------------------------------------------------------------------- /memory/memory_test.go: -------------------------------------------------------------------------------- 1 | package memory_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/regeda/expr/memory" 7 | "github.com/stretchr/testify/assert" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | var mem memory.Memory 12 | 13 | func TestMemory_AllocBytes(t *testing.T) { 14 | t.Run("alloc zero", func(t *testing.T) { 15 | addr := mem.AllocBytes(0) 16 | assert.Equal(t, uint32(0), addr.Size()) 17 | }) 18 | } 19 | 20 | func TestMemory_AllocInt64(t *testing.T) { 21 | t.Run("alloc int64", func(t *testing.T) { 22 | addr := mem.AllocInt64(0xffffff) 23 | 24 | assert.Equal(t, memory.TypeInt64, addr.Type()) 25 | assert.Equal(t, int64(0xffffff), addr.Int64()) 26 | }) 27 | } 28 | 29 | func TestMemory_AllocBytesAddr(t *testing.T) { 30 | addr := mem.AllocBytesAddr([]byte{1}) 31 | require.NotNil(t, addr) 32 | 33 | assert.Equal(t, memory.TypeBytes, addr.Type()) 34 | assert.Equal(t, []byte{1}, addr.Bytes()) 35 | } 36 | 37 | func TestMemory_AllocVector(t *testing.T) { 38 | t.Run("alloc vector", func(t *testing.T) { 39 | addr := mem.AllocVector(3) 40 | 41 | assert.Equal(t, memory.TypeVector, addr.Type()) 42 | assert.Equal(t, 3, addr.VectorLen()) 43 | }) 44 | 45 | t.Run("copy vector", func(t *testing.T) { 46 | elem := mem.AllocBytes(1) 47 | 48 | addr := mem.CopyVector(elem, elem, elem) 49 | require.NotNil(t, addr) 50 | 51 | assert.Equal(t, memory.TypeVector, addr.Type()) 52 | assert.Equal(t, 3, addr.VectorLen()) 53 | 54 | for i := 0; i < 3; i++ { 55 | assert.Equal(t, elem, addr.VectorAt(i)) 56 | } 57 | }) 58 | } 59 | 60 | func TestMemory_Alloc(t *testing.T) { 61 | t.Run("bytes", func(t *testing.T) { 62 | addr, err := mem.Alloc([]byte{1, 2, 3}) 63 | require.NoError(t, err) 64 | require.NotNil(t, addr) 65 | 66 | assert.Equal(t, memory.TypeBytes, addr.Type()) 67 | assert.Equal(t, []byte{1, 2, 3}, addr.Bytes()) 68 | }) 69 | 70 | t.Run("string", func(t *testing.T) { 71 | addr, err := mem.Alloc("foobar") 72 | require.NoError(t, err) 73 | require.NotNil(t, addr) 74 | 75 | assert.Equal(t, memory.TypeBytes, addr.Type()) 76 | assert.Equal(t, []byte("foobar"), addr.Bytes()) 77 | }) 78 | 79 | t.Run("bool", func(t *testing.T) { 80 | addrT, err := mem.Alloc(true) 81 | require.NoError(t, err) 82 | assert.Equal(t, memory.True, addrT) 83 | 84 | addrF, err := mem.Alloc(false) 85 | require.NoError(t, err) 86 | assert.Equal(t, memory.False, addrF) 87 | }) 88 | 89 | t.Run("int", func(t *testing.T) { 90 | addr, err := mem.Alloc(1) 91 | require.NoError(t, err) 92 | require.NotNil(t, addr) 93 | 94 | assert.Equal(t, memory.TypeInt64, addr.Type()) 95 | assert.Equal(t, int64(1), addr.Int64()) 96 | }) 97 | 98 | t.Run("int64", func(t *testing.T) { 99 | addr, err := mem.Alloc(int64(1)) 100 | require.NoError(t, err) 101 | require.NotNil(t, addr) 102 | 103 | assert.Equal(t, memory.TypeInt64, addr.Type()) 104 | assert.Equal(t, int64(1), addr.Int64()) 105 | }) 106 | 107 | t.Run("untyped vector", func(t *testing.T) { 108 | addr, err := mem.Alloc([]interface{}{"foo", "bar"}) 109 | require.NoError(t, err) 110 | require.NotNil(t, addr) 111 | 112 | require.Equal(t, memory.TypeVector, addr.Type()) 113 | require.Equal(t, 2, addr.VectorLen()) 114 | 115 | require.Equal(t, memory.TypeBytes, addr.VectorAt(0).Type()) 116 | assert.Equal(t, []byte("foo"), addr.VectorAt(0).Bytes()) 117 | 118 | require.Equal(t, memory.TypeBytes, addr.VectorAt(1).Type()) 119 | assert.Equal(t, []byte("bar"), addr.VectorAt(1).Bytes()) 120 | }) 121 | 122 | t.Run("unsupported type", func(t *testing.T) { 123 | addr, err := mem.Alloc(struct{}{}) 124 | require.EqualError(t, err, "memory: unsupported type struct {}") 125 | assert.Equal(t, memory.Nil, addr) 126 | }) 127 | } 128 | -------------------------------------------------------------------------------- /memory/type.go: -------------------------------------------------------------------------------- 1 | package memory 2 | 3 | // Memory types supported by the virtual machine. 4 | const ( 5 | TypeNil Type = iota 6 | TypeBytes 7 | TypeInt64 8 | TypeBool 9 | TypeVector 10 | ) 11 | 12 | var typeNames = [...]string{ 13 | "nil", 14 | "bytes", 15 | "int64", 16 | "bool", 17 | "vector", 18 | } 19 | 20 | // Type represents a data type. 21 | type Type uint8 22 | 23 | // String returns a name of the type. 24 | func (t Type) String() string { 25 | if int(t) < len(typeNames) { 26 | return typeNames[t] 27 | } 28 | return "unknown" 29 | } 30 | -------------------------------------------------------------------------------- /memory/type_test.go: -------------------------------------------------------------------------------- 1 | package memory_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/regeda/expr/memory" 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func Test_Type_String(t *testing.T) { 11 | unknown := -1 12 | 13 | cases := []struct { 14 | typ memory.Type 15 | expected string 16 | }{ 17 | {memory.TypeNil, "nil"}, 18 | {memory.TypeBytes, "bytes"}, 19 | {memory.TypeInt64, "int64"}, 20 | {memory.TypeBool, "bool"}, 21 | {memory.TypeVector, "vector"}, 22 | {memory.Type(unknown), "unknown"}, 23 | } 24 | 25 | for _, c := range cases { 26 | t.Run(c.expected, func(t *testing.T) { 27 | assert.Equal(t, c.expected, c.typ.String()) 28 | }) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /stdlib/compare.go: -------------------------------------------------------------------------------- 1 | package stdlib 2 | 3 | import ( 4 | "errors" 5 | 6 | "github.com/regeda/expr/delegate" 7 | "github.com/regeda/expr/memory" 8 | ) 9 | 10 | var Compare = delegate.Module{ 11 | "equals": delegate.DelegatorFunc(equals), 12 | "contains": delegate.DelegatorFunc(contains), 13 | "intersects": delegate.DelegatorFunc(intersects), 14 | } 15 | 16 | var ( 17 | errEqualsExpectedTwoArgs = errors.New("equals: expected 2 args") 18 | ) 19 | 20 | func equals(mem *memory.Memory, argv []memory.Addr) (memory.Addr, error) { 21 | if len(argv) != 2 { 22 | return memory.Nil, errEqualsExpectedTwoArgs 23 | } 24 | if argv[0].Equal(argv[1]) { 25 | return memory.True, nil 26 | } 27 | return memory.False, nil 28 | } 29 | 30 | var ( 31 | errContainsExpectedTwoArgs = errors.New("contains: expected 2 args") 32 | errContainsExpectedArrayAt0 = errors.New("contains: expected array at 0") 33 | errContainsExpectedScalarAt1 = errors.New("contains: expected scalar at 1") 34 | ) 35 | 36 | func contains(mem *memory.Memory, argv []memory.Addr) (memory.Addr, error) { 37 | if len(argv) != 2 { 38 | return memory.Nil, errContainsExpectedTwoArgs 39 | } 40 | if !argv[0].TypeOf(memory.TypeVector) { 41 | return memory.Nil, errContainsExpectedArrayAt0 42 | } 43 | if argv[1].TypeOf(memory.TypeVector) { 44 | return memory.Nil, errContainsExpectedScalarAt1 45 | } 46 | for _, p := range argv[0].Vector() { 47 | if p.Equal(argv[1]) { 48 | return memory.True, nil 49 | } 50 | } 51 | return memory.False, nil 52 | } 53 | 54 | var ( 55 | errIntersectsExpectedTwoArgs = errors.New("intersects: expected 2 args") 56 | errIntersectsExpectedArrays = errors.New("intersects: expected arrays") 57 | ) 58 | 59 | func intersects(mem *memory.Memory, argv []memory.Addr) (memory.Addr, error) { 60 | if len(argv) != 2 { 61 | return memory.Nil, errIntersectsExpectedTwoArgs 62 | } 63 | if !argv[0].EqualType(argv[1]) || !argv[0].TypeOf(memory.TypeVector) { 64 | return memory.Nil, errIntersectsExpectedArrays 65 | } 66 | for _, a := range argv[0].Vector() { 67 | for _, b := range argv[1].Vector() { 68 | if a.Equal(b) { 69 | return memory.True, nil 70 | } 71 | } 72 | } 73 | return memory.False, nil 74 | } 75 | -------------------------------------------------------------------------------- /stdlib/compare_test.go: -------------------------------------------------------------------------------- 1 | package stdlib_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/regeda/expr/memory" 7 | "github.com/regeda/expr/stdlib" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func TestCompare_Error(t *testing.T) { 12 | mem := memory.New() 13 | 14 | cases := map[string][]struct { 15 | name string 16 | argv []memory.Addr 17 | errMsg string 18 | }{ 19 | "equals": { 20 | { 21 | "wrong args num", 22 | []memory.Addr{}, 23 | "equals: expected 2 args", 24 | }, 25 | }, 26 | "contains": { 27 | { 28 | "wrong args num", 29 | []memory.Addr{}, 30 | "contains: expected 2 args", 31 | }, 32 | { 33 | "first arg should be array", 34 | []memory.Addr{memory.Nil, memory.Nil}, 35 | "contains: expected array at 0", 36 | }, 37 | { 38 | "second arg is scalar", 39 | []memory.Addr{mem.AllocVector(1), mem.AllocVector(1)}, 40 | "contains: expected scalar at 1", 41 | }, 42 | }, 43 | "intersects": { 44 | { 45 | "wrong args num", 46 | []memory.Addr{}, 47 | "intersects: expected 2 args", 48 | }, 49 | { 50 | "expected arrays only", 51 | []memory.Addr{memory.Nil, memory.Nil}, 52 | "intersects: expected arrays", 53 | }, 54 | }, 55 | } 56 | 57 | for dname, unit := range cases { 58 | for _, c := range unit { 59 | t.Run(dname+"_"+c.name, func(t *testing.T) { 60 | addr, err := stdlib.Compare[dname].Delegate(&mem, c.argv) 61 | 62 | require.Equal(t, memory.Nil, addr) 63 | require.EqualError(t, err, c.errMsg) 64 | }) 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /stdlib/strings.go: -------------------------------------------------------------------------------- 1 | package stdlib 2 | 3 | import ( 4 | "errors" 5 | 6 | "github.com/regeda/expr/delegate" 7 | "github.com/regeda/expr/memory" 8 | ) 9 | 10 | var Strings = delegate.Module{ 11 | "concat": delegate.DelegatorFunc(concat), 12 | "join": delegate.DelegatorFunc(join), 13 | } 14 | 15 | var ( 16 | errConcatExpectedBytes = errors.New("concat: expected bytes") 17 | ) 18 | 19 | func concat(mem *memory.Memory, argv []memory.Addr) (memory.Addr, error) { 20 | var size uint32 21 | for _, a := range argv { 22 | if !a.TypeOf(memory.TypeBytes) { 23 | return memory.Nil, errConcatExpectedBytes 24 | } 25 | size += a.Size() 26 | } 27 | addr := mem.AllocBytes(size) 28 | addr.CopyBytes(argv...) 29 | return addr, nil 30 | } 31 | 32 | var ( 33 | errJoinExpectedTwoArgs = errors.New("join: expected 2 args") 34 | errJoinExpectedBytesAt0 = errors.New("join: expected bytes at 0") 35 | errJoinExpectedArrayOfBytesAt1 = errors.New("join: expected array of bytes at 1") 36 | ) 37 | 38 | func join(mem *memory.Memory, argv []memory.Addr) (memory.Addr, error) { 39 | if len(argv) != 2 { 40 | return memory.Nil, errJoinExpectedTwoArgs 41 | } 42 | if !argv[0].TypeOf(memory.TypeBytes) { 43 | return memory.Nil, errJoinExpectedBytesAt0 44 | } 45 | if !argv[1].TypeOf(memory.TypeVector) { 46 | return memory.Nil, errJoinExpectedArrayOfBytesAt1 47 | } 48 | sep, srcs := argv[0], argv[1].Vector() 49 | if len(srcs) == 0 { 50 | return memory.NoBytes, nil 51 | } 52 | size := sep.Size() * uint32(len(srcs)-1) 53 | for _, src := range srcs { 54 | if !src.TypeOf(memory.TypeBytes) { 55 | return memory.Nil, errJoinExpectedArrayOfBytesAt1 56 | } 57 | size += src.Size() 58 | } 59 | addr := mem.AllocBytes(size) 60 | buf := addr.Bytes() 61 | var offset uint32 62 | for i, src := range srcs { 63 | if i > 0 { 64 | copy(buf[offset:], sep.Bytes()) 65 | offset += sep.Size() 66 | } 67 | copy(buf[offset:], src.Bytes()) 68 | offset += src.Size() 69 | } 70 | return addr, nil 71 | } 72 | -------------------------------------------------------------------------------- /stdlib/strings_test.go: -------------------------------------------------------------------------------- 1 | package stdlib_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/regeda/expr/memory" 7 | "github.com/regeda/expr/stdlib" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func TestStrings_Error(t *testing.T) { 12 | mem := memory.New() 13 | 14 | cases := map[string][]struct { 15 | name string 16 | argv []memory.Addr 17 | errMsg string 18 | }{ 19 | "concat": { 20 | { 21 | "expected bytes", 22 | []memory.Addr{memory.Nil}, 23 | "concat: expected bytes", 24 | }, 25 | }, 26 | "join": { 27 | { 28 | "wrong args num", 29 | []memory.Addr{}, 30 | "join: expected 2 args", 31 | }, 32 | { 33 | "expected bytes at 0", 34 | []memory.Addr{memory.Nil, memory.Nil}, 35 | "join: expected bytes at 0", 36 | }, 37 | { 38 | "expected array at 0", 39 | []memory.Addr{memory.NoBytes, memory.Nil}, 40 | "join: expected array of bytes at 1", 41 | }, 42 | { 43 | "expected array of bytes at 0", 44 | []memory.Addr{memory.NoBytes, mem.CopyVector(memory.Nil)}, 45 | "join: expected array of bytes at 1", 46 | }, 47 | }, 48 | } 49 | 50 | for dname, unit := range cases { 51 | for _, c := range unit { 52 | t.Run(dname+"_"+c.name, func(t *testing.T) { 53 | addr, err := stdlib.Strings[dname].Delegate(&mem, c.argv) 54 | 55 | require.Equal(t, memory.Nil, addr) 56 | require.EqualError(t, err, c.errMsg) 57 | }) 58 | } 59 | } 60 | } 61 | --------------------------------------------------------------------------------