├── LICENSE ├── README.md ├── core └── core.go ├── example.gsp ├── examples ├── even_fib_terms.gsp ├── factorial.gsp ├── highly_divisible_triangular_number.gsp ├── longest_collatz_sequence.gsp ├── multiples_of_3_5.gsp └── power_digit_sum.gsp ├── generator ├── eval.go ├── funcs.go ├── generator.go ├── helpers │ └── helpers.go ├── idents.go ├── imports.go ├── literals.go ├── makers.go ├── operators.go └── statements.go ├── gisp.go ├── lexer └── lexer.go ├── parser └── parser.go └── play ├── ast_print.go ├── call_ellipse_func.go ├── call_interface_function.go ├── calling_const_func.go ├── func_call_benchmark_test.go ├── gisp.go └── output.go /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Joseph Adams 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | gisp 2 | ==== 3 | 4 | Simple (non standard) compiler of Lisp/Scheme to Go. 5 | 6 | ## Includes 7 | - Lexer based on Rob Pike's [Lexical Scanning in Go](http://cuddle.googlecode.com/hg/talk/lex.html#title-slide) 8 | - Simple recursive parser, supporting ints, floats, strings, bools 9 | - TCO via loop/recur 10 | - AST generating REPL included 11 | 12 | 13 | ## Build and Run 14 | ``` 15 | > go build && ./gisp 16 | >> 17 | ``` 18 | From here you can type in forms and you'll get the Go AST back. 19 | To compile a file: 20 | ``` 21 | > ./gisp filename.gsp 22 | ```` 23 | 24 | # Functions 25 | ``` 26 | +, -, *, mod, let, if, ns, def, fn, all pre-existing Go functions 27 | ``` 28 | See [examples](examples) for some Project Euler solutions 29 | 30 | # License 31 | 32 | MIT 33 | -------------------------------------------------------------------------------- /core/core.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import "fmt" 4 | 5 | type Any interface{} 6 | 7 | func MOD(a, b Any) int { 8 | var n, m int 9 | 10 | if isInt(a) { 11 | n = a.(int) 12 | } else if isFloat(a) { 13 | n = int(a.(float64)) 14 | } else { 15 | panic("need int/float argument to mod!") 16 | } 17 | 18 | if isInt(b) { 19 | m = b.(int) 20 | } else if isFloat(a) { 21 | m = int(b.(float64)) 22 | } else { 23 | panic("need int/float argument to mod!") 24 | } 25 | 26 | return n % m 27 | } 28 | 29 | func ADD(args ...Any) float64 { 30 | var sum float64 = 0 31 | 32 | for i := 0; i < len(args); i++ { 33 | switch n := args[i]; { 34 | case isInt(n): 35 | sum += float64(n.(int)) 36 | case isFloat(n): 37 | sum += n.(float64) 38 | } 39 | } 40 | 41 | return sum 42 | } 43 | 44 | func SUB(args ...Any) float64 { 45 | var result float64 46 | if isInt(args[0]) { 47 | result = float64(args[0].(int)) 48 | } else if isFloat(args[0]) { 49 | result = args[0].(float64) 50 | } else { 51 | panic("need int/float for SUB") 52 | } 53 | 54 | for i := 1; i < len(args); i++ { 55 | switch n := args[i]; { 56 | case isInt(n): 57 | result -= float64(n.(int)) 58 | case isFloat(n): 59 | result -= n.(float64) 60 | } 61 | } 62 | 63 | return result 64 | } 65 | 66 | func MUL(args ...Any) float64 { 67 | var prod float64 = 1 68 | 69 | for i := 0; i < len(args); i++ { 70 | switch n := args[i]; { 71 | case isInt(n): 72 | prod *= float64(n.(int)) 73 | case isFloat(n): 74 | prod *= n.(float64) 75 | } 76 | } 77 | 78 | return prod 79 | } 80 | func DIV() {} 81 | 82 | // TODO: can only compare ints and slice lens for now. 83 | func LT(args ...Any) bool { 84 | if len(args) < 2 { 85 | panic("can't compare less than 2 values!") 86 | } 87 | 88 | for i := 0; i < len(args)-1; i++ { 89 | var n float64 90 | if isInt(args[i]) { 91 | n = float64(args[i].(int)) 92 | } else if isFloat(args[i]) { 93 | n = args[i].(float64) 94 | } else { 95 | panic("you can't compare that!") 96 | } 97 | 98 | var m float64 99 | if isInt(args[i+1]) { 100 | m = float64(args[i+1].(int)) 101 | } else if isFloat(args[i+1]) { 102 | m = args[i+1].(float64) 103 | } else { 104 | panic("you can't compare that!") 105 | } 106 | 107 | if n >= m { 108 | return false 109 | } 110 | } 111 | 112 | return true 113 | } 114 | 115 | // TODO: can only compare ints and slice lens for now. 116 | func GT(args ...Any) bool { 117 | if len(args) < 2 { 118 | panic("can't compare less than 2 values!") 119 | } 120 | 121 | for i := 0; i < len(args)-1; i++ { 122 | var n float64 123 | if isInt(args[i]) { 124 | n = float64(args[i].(int)) 125 | } else if isFloat(args[i]) { 126 | n = args[i].(float64) 127 | } else { 128 | panic("you can't compare that!") 129 | } 130 | 131 | var m float64 132 | if isInt(args[i+1]) { 133 | m = float64(args[i+1].(int)) 134 | } else if isFloat(args[i+1]) { 135 | m = args[i+1].(float64) 136 | } else { 137 | panic("you can't compare that!") 138 | } 139 | 140 | if n <= m { 141 | return false 142 | } 143 | } 144 | 145 | return true 146 | } 147 | 148 | func EQ(args ...Any) bool { 149 | if len(args) < 2 { 150 | panic("can't compare less than 2 values!") 151 | } 152 | 153 | for i := 0; i < len(args)-1; i++ { 154 | var n float64 155 | if isInt(args[i]) { 156 | n = float64(args[i].(int)) 157 | } else if isFloat(args[i]) { 158 | n = args[i].(float64) 159 | } else { 160 | panic("you can't compare that!") 161 | } 162 | 163 | var m float64 164 | if isInt(args[i+1]) { 165 | m = float64(args[i+1].(int)) 166 | } else if isFloat(args[i+1]) { 167 | m = args[i+1].(float64) 168 | } else { 169 | panic("you can't compare that!") 170 | } 171 | 172 | if n != m { 173 | return false 174 | } 175 | } 176 | 177 | return true 178 | } 179 | 180 | // greater than or equal 181 | func GTEQ(args ...Any) bool { 182 | if GT(args...) || EQ(args...) { 183 | return true 184 | } 185 | 186 | return false 187 | } 188 | 189 | // less than or equal 190 | func LTEQ(args ...Any) bool { 191 | if LT(args...) || EQ(args...) { 192 | return true 193 | } 194 | 195 | return false 196 | } 197 | 198 | func isFloat(n Any) bool { 199 | _, ok := n.(float64) 200 | return ok 201 | } 202 | 203 | func isInt(n Any) bool { 204 | _, ok := n.(int) 205 | return ok 206 | } 207 | 208 | func Get(args ...Any) Any { 209 | if len(args) != 2 && len(args) != 3 { 210 | panic(fmt.Sprintf("get needs 2 or 3 arguments %d given.", len(args))) 211 | } 212 | 213 | if len(args) == 2 { 214 | if a, ok := args[1].([]Any); ok { 215 | return a[args[0].(int)] 216 | } else if a, ok := args[1].(string); ok { 217 | return a[args[0].(int)] 218 | } else { 219 | panic("arguments to get must include slice/vector/string") 220 | } 221 | } else { 222 | if a, ok := args[2].([]Any); ok { 223 | if args[1].(int) == -1 { 224 | return a[args[0].(int):] 225 | } 226 | 227 | return a[args[0].(int):args[1].(int)] 228 | } else if a, ok := args[2].(string); ok { 229 | if args[1].(int) == -1 { 230 | return a[args[0].(int):] 231 | } 232 | 233 | return a[args[0].(int):args[1].(int)] 234 | } else { 235 | panic("arguments to get must include slice/vector/string") 236 | } 237 | } 238 | } -------------------------------------------------------------------------------- /example.gsp: -------------------------------------------------------------------------------- 1 | (ns main 2 | "fmt" 3 | "../core") 4 | 5 | (def main (fn [] 6 | (loop [[x 0] [y 10]] 7 | (if (< x 10) (recur (+ x 1) (+ -1 y)) x)))) -------------------------------------------------------------------------------- /examples/even_fib_terms.gsp: -------------------------------------------------------------------------------- 1 | (ns main 2 | "fmt" 3 | "github.com/jcla1/gisp/core") 4 | 5 | (def main (fn [] 6 | (let [[n 4000000]] 7 | (fmt/printf "Sum of all even fibonacci terms below %d: %0.0f\n" n (sum-even-fib n)) 8 | ()))) 9 | 10 | (def sum-even-fib (fn [not-exceeding] 11 | (loop [[a 0.0] 12 | [b 1.0] 13 | [sum 0.0]] 14 | (let [[next (+ a b)]] 15 | (if (>= next not-exceeding) 16 | sum 17 | (if (= 0 (mod next 2)) 18 | (recur b next (+ sum next)) 19 | (recur b next sum))))))) -------------------------------------------------------------------------------- /examples/factorial.gsp: -------------------------------------------------------------------------------- 1 | (ns main 2 | "fmt" 3 | "github.com/jcla1/gisp/core") 4 | 5 | (def main (fn [] 6 | (fmt/printf "10! = %d\n" (int (assert float64 (factorial 10)))))) 7 | 8 | (def factorial (fn [n] 9 | (if (< n 2) 1 (* n (factorial (+ n -1)))))) -------------------------------------------------------------------------------- /examples/highly_divisible_triangular_number.gsp: -------------------------------------------------------------------------------- 1 | (ns main 2 | "github.com/jcla1/gisp/core" 3 | ; "math" 4 | "fmt") 5 | 6 | (def main (fn [] 7 | (fmt/println "starting...") 8 | ; (fmt/println (divisors 76576500)) 9 | (let [[target 500]] 10 | (loop [[n 2] 11 | [num 1]] 12 | (if (> (divisors num) target) 13 | ; We need this extra let, because we can't have multiple 14 | ; return values which all fmt/PrintXYZ functions have 15 | (let [] (fmt/printf "The %dth triangular (%d) was the first with more than %d divisors!\n" n num target) ()) 16 | (recur (int (+ n 1)) (int (+ num n -1)))))))) 17 | 18 | ; Actually not needed, generating the 19 | ; triangular numbers in the main loop 20 | (def nth-triangular (fn [n] 21 | (loop [[acc 1.0] 22 | [next n]] 23 | (if (>= 1 next) 24 | (int acc) 25 | (recur (+ acc next) (- next 1)))))) 26 | 27 | (def divisors (fn [n] 28 | (loop [[start (float64 (assert int n))] 29 | [acc 1.0]] 30 | (if (<= start 1) 31 | (int acc) 32 | (if (= 0 (mod (assert int n) (int start))) 33 | (recur (- start 1) (+ 1 acc)) 34 | (recur (- start 1) acc)))))) -------------------------------------------------------------------------------- /examples/longest_collatz_sequence.gsp: -------------------------------------------------------------------------------- 1 | (ns main 2 | "fmt" 3 | "github.com/jcla1/gisp/core") 4 | 5 | (def main (fn [] 6 | (let [[n (collatz-longest 1000000)]] 7 | (fmt/println "Longest sequence produced by:" n) 8 | (fmt/printf "It was %d elements long!\n" (collatz-length n)) 9 | ()))) 10 | 11 | (def collatz-longest (fn [below-val] 12 | (loop [[below below-val] 13 | [n 1.0] 14 | [max 0]] 15 | (if (= below 1) (+ 1 n) 16 | (let [[l (collatz-length below)] 17 | [m (+ -1 below)]] 18 | (if (> l max) 19 | (recur m (assert float64 below) (assert int l)) 20 | (recur m n max))))))) 21 | 22 | (def collatz-length (fn [n] 23 | (loop [[next n] 24 | [acc 1]] 25 | (if (= next 1) 26 | acc 27 | (recur (collatz-next next) (int (+ acc 1))))))) 28 | 29 | (def collatz-next (fn [n] 30 | (if (= 0 (mod n 2)) 31 | (* 0.5 n) 32 | (+ 1 (* 3 n))))) -------------------------------------------------------------------------------- /examples/multiples_of_3_5.gsp: -------------------------------------------------------------------------------- 1 | (ns main 2 | "fmt" 3 | "github.com/jcla1/gisp/core") 4 | 5 | (def main (fn [] 6 | (fmt/println (sum-of-multiples 1000)))) 7 | 8 | (def sum-of-multiples (fn [below] 9 | (loop [[below (+ -1 below)] 10 | [sum 0.0]] 11 | (if (= below 0) 12 | sum 13 | (let [[n (+ -1 below)]] 14 | (if (or (= 0 (mod below 3)) (= 0 (mod below 5))) 15 | (recur n (+ sum below 1))) 16 | (recur n sum)))))) -------------------------------------------------------------------------------- /examples/power_digit_sum.gsp: -------------------------------------------------------------------------------- 1 | (ns main 2 | "fmt" 3 | "strconv" 4 | "math/big" 5 | "github.com/jcla1/gisp/core") 6 | 7 | (def main (fn [] 8 | (fmt/println "The sum of the digits of 2^1000 is:" 9 | (let [[two (big/new-int 2)] 10 | [thousand (big/new-int 1000)] 11 | [n (big/new-int 0)]] 12 | (n/exp two thousand nil) 13 | (loop [[acc 0.0] 14 | [s (n/string)]] 15 | (if (>= 0 (len s)) 16 | (int acc) 17 | (let [[d _ (strconv/parse-int (assert string (get 0 1 s)) 10 0)]] 18 | (recur (+ acc (int d)) (assert string (get 1 -1 s)))))))))) -------------------------------------------------------------------------------- /generator/eval.go: -------------------------------------------------------------------------------- 1 | package generator 2 | 3 | import ( 4 | "github.com/jcla1/gisp/parser" 5 | "go/ast" 6 | "go/token" 7 | ) 8 | 9 | func EvalExprs(nodes []parser.Node) []ast.Expr { 10 | out := make([]ast.Expr, len(nodes)) 11 | 12 | for i, node := range nodes { 13 | out[i] = EvalExpr(node) 14 | } 15 | 16 | return out 17 | } 18 | 19 | func EvalExpr(node parser.Node) ast.Expr { 20 | switch t := node.Type(); t { 21 | case parser.NodeCall: 22 | node := node.(*parser.CallNode) 23 | return evalFuncCall(node) 24 | 25 | case parser.NodeVector: 26 | node := node.(*parser.VectorNode) 27 | return makeVector(anyType, EvalExprs(node.Nodes)) 28 | 29 | case parser.NodeNumber: 30 | node := node.(*parser.NumberNode) 31 | return makeBasicLit(node.NumberType, node.Value) 32 | 33 | case parser.NodeString: 34 | node := node.(*parser.StringNode) 35 | return makeBasicLit(token.STRING, node.Value) 36 | 37 | case parser.NodeIdent: 38 | node := node.(*parser.IdentNode) 39 | return makeIdomaticSelector(node.Ident) 40 | 41 | default: 42 | println(t) 43 | panic("not implemented yet!") 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /generator/funcs.go: -------------------------------------------------------------------------------- 1 | package generator 2 | 3 | import ( 4 | "github.com/jcla1/gisp/parser" 5 | h "github.com/jcla1/gisp/generator/helpers" 6 | "go/ast" 7 | "go/token" 8 | ) 9 | 10 | func evalFuncCall(node *parser.CallNode) ast.Expr { 11 | switch { 12 | case isUnaryOperator(node): 13 | return makeUnaryExpr(unaryOperatorMap[node.Callee.(*parser.IdentNode).Ident], EvalExpr(node.Args[0])) 14 | 15 | case isCallableOperator(node): 16 | return makeNAryCallableExpr(node) 17 | 18 | case isLogicOperator(node): 19 | return makeNAryLogicExpr(node) 20 | 21 | case isLoop(node): 22 | return makeLoop(node) 23 | 24 | case isRecur(node): 25 | return makeRecur(node) 26 | 27 | case isAssert(node): 28 | return makeAssert(node) 29 | 30 | case isCoreFunc(node): 31 | return makeCoreCall(node) 32 | 33 | case checkLetArgs(node): 34 | return makeLetFun(node) 35 | 36 | case checkIfArgs(node): 37 | return makeIfStmtFunc(node) 38 | 39 | case checkFuncArgs(node): 40 | // TODO: In case of type annotations change the following 41 | returnField := []*ast.Field{makeField(nil, anyType)} 42 | results := makeFieldList(returnField) 43 | 44 | argIdents, ellipsis := getArgIdentsFromVector(node.Args[0].(*parser.VectorNode)) 45 | params := make([]*ast.Field, 0, len(argIdents)) 46 | 47 | if len(argIdents) != 0 { 48 | params = append(params, makeField(argIdents, anyType)) 49 | } 50 | 51 | if ellipsis != nil { 52 | params = append(params, makeField(h.I(ellipsis), makeEllipsis(anyType))) 53 | } 54 | 55 | fnType := makeFuncType(results, makeFieldList(params)) 56 | body := makeFuncBody(EvalExprs(node.Args[1:])) 57 | 58 | return makeFuncLit(fnType, body) 59 | 60 | case checkDefArgs(node): 61 | panic("you can't have a def within an expression!") 62 | 63 | case checkNSArgs(node): 64 | panic("you can't define a namespace in an expression!") 65 | } 66 | 67 | callee := EvalExpr(node.Callee) 68 | if c, ok := callee.(*ast.Ident); ok { 69 | callee = makeIdomaticIdent(c.Name) 70 | } 71 | 72 | args := EvalExprs(node.Args) 73 | 74 | return makeFuncCall(callee, args) 75 | } 76 | 77 | func getArgIdentsFromVector(vect *parser.VectorNode) ([]*ast.Ident, *ast.Ident) { 78 | args := vect.Nodes 79 | argIdents := make([]*ast.Ident, 0, len(vect.Nodes)) 80 | 81 | var ident string 82 | var ellipsis *ast.Ident 83 | 84 | for i := 0; i < len(args); i++ { 85 | ident = args[i].(*parser.IdentNode).Ident 86 | 87 | if ident == "&" { 88 | ellipsis = makeIdomaticIdent(args[i+1].(*parser.IdentNode).Ident) 89 | break 90 | } 91 | 92 | argIdents = append(argIdents, makeIdomaticIdent(ident)) 93 | } 94 | 95 | return argIdents, ellipsis 96 | } 97 | 98 | func makeFuncBody(exprs []ast.Expr) *ast.BlockStmt { 99 | wrapped := wrapExprsWithStmt(exprs) 100 | wrapped[len(wrapped)-1] = makeReturnStmt(h.E(wrapped[len(wrapped)-1].(*ast.ExprStmt).X)) 101 | return makeBlockStmt(wrapped) 102 | } 103 | 104 | func makeFuncLit(typ *ast.FuncType, body *ast.BlockStmt) *ast.FuncLit { 105 | return &ast.FuncLit{ 106 | Type: typ, 107 | Body: body, 108 | } 109 | } 110 | 111 | func makeFuncType(results, params *ast.FieldList) *ast.FuncType { 112 | return &ast.FuncType{ 113 | Results: results, 114 | Params: params, 115 | } 116 | } 117 | 118 | func makeFieldList(list []*ast.Field) *ast.FieldList { 119 | return &ast.FieldList{ 120 | List: list, 121 | } 122 | } 123 | 124 | func makeField(names []*ast.Ident, typ ast.Expr) *ast.Field { 125 | return &ast.Field{ 126 | Names: names, 127 | Type: typ, 128 | } 129 | } 130 | 131 | func makeReturnStmt(exprs []ast.Expr) ast.Stmt { 132 | return &ast.ReturnStmt{ 133 | Results: exprs, 134 | } 135 | } 136 | 137 | func makeFuncCall(callee ast.Expr, args []ast.Expr) *ast.CallExpr { 138 | return &ast.CallExpr{ 139 | Fun: callee, 140 | Args: args, 141 | } 142 | } 143 | 144 | // Fn type checks (let, fn, def, ns, etc.) 145 | 146 | func checkIfArgs(node *parser.CallNode) bool { 147 | if node.Callee.Type() != parser.NodeIdent { 148 | return false 149 | } 150 | 151 | if callee := node.Callee.(*parser.IdentNode); callee.Ident != "if" { 152 | return false 153 | } 154 | 155 | if len(node.Args) < 2 { 156 | return false 157 | } 158 | 159 | return true 160 | } 161 | 162 | // Only need this to check if "def" is in 163 | // an expression, which is illegal 164 | func checkDefArgs(node *parser.CallNode) bool { 165 | if node.Callee.Type() != parser.NodeIdent { 166 | return false 167 | } 168 | 169 | if callee := node.Callee.(*parser.IdentNode); callee.Ident != "def" { 170 | return false 171 | } 172 | 173 | return true 174 | } 175 | 176 | func checkFuncArgs(node *parser.CallNode) bool { 177 | // Need an identifier for it to be "fn" 178 | if node.Callee.Type() != parser.NodeIdent { 179 | return false 180 | } 181 | 182 | if callee := node.Callee.(*parser.IdentNode); callee.Ident != "fn" { 183 | return false 184 | } 185 | 186 | // Need argument list and at least one expression 187 | if len(node.Args) < 2 { 188 | return false 189 | } 190 | 191 | // Parameters should be a vector 192 | params := node.Args[0] 193 | if params.Type() != parser.NodeVector { 194 | return false 195 | } 196 | 197 | p := params.(*parser.VectorNode) 198 | for _, param := range p.Nodes { 199 | // TODO: change this in case of variable unpacking 200 | if param.Type() != parser.NodeIdent { 201 | return false 202 | } 203 | } 204 | 205 | return true 206 | } 207 | 208 | func checkLetArgs(node *parser.CallNode) bool { 209 | // Need an identifier for it to be "let" 210 | if node.Callee.Type() != parser.NodeIdent { 211 | return false 212 | } 213 | 214 | // Not a "let" 215 | if callee := node.Callee.(*parser.IdentNode); callee.Ident != "let" { 216 | return false 217 | } 218 | 219 | // Need _at least_ the bindings & one expression 220 | if len(node.Args) < 2 { 221 | return false 222 | } 223 | 224 | // Bindings should be a vector 225 | bindings := node.Args[0] 226 | if bindings.Type() != parser.NodeVector { 227 | return false 228 | } 229 | 230 | // The bindings should be also vectors 231 | b := bindings.(*parser.VectorNode) 232 | for _, bind := range b.Nodes { 233 | if _, ok := bind.(*parser.VectorNode); !ok { 234 | return false 235 | } 236 | } 237 | 238 | // The bound identifiers, should be identifiers 239 | for _, bind := range b.Nodes { 240 | bindingVect := bind.(*parser.VectorNode) 241 | if bindingVect.Nodes[0].Type() != parser.NodeIdent { 242 | return false 243 | } 244 | } 245 | 246 | return true 247 | } 248 | 249 | func isLoop(node *parser.CallNode) bool { 250 | // Need an identifier for it to be "loop" 251 | if node.Callee.Type() != parser.NodeIdent { 252 | return false 253 | } 254 | 255 | // Not a "loop" 256 | if callee := node.Callee.(*parser.IdentNode); callee.Ident != "loop" { 257 | return false 258 | } 259 | 260 | // Bindings should be a vector 261 | bindings := node.Args[0] 262 | if bindings.Type() != parser.NodeVector { 263 | return false 264 | } 265 | 266 | // The bindings should be also vectors 267 | b := bindings.(*parser.VectorNode) 268 | for _, bind := range b.Nodes { 269 | if _, ok := bind.(*parser.VectorNode); !ok { 270 | return false 271 | } 272 | } 273 | 274 | // The bound identifiers, should be identifiers 275 | for _, bind := range b.Nodes { 276 | bindingVect := bind.(*parser.VectorNode) 277 | if bindingVect.Nodes[0].Type() != parser.NodeIdent { 278 | return false 279 | } 280 | } 281 | 282 | if !searchForRecur(node.Args[1:]) { 283 | panic("no recur found in loop!") 284 | } 285 | 286 | return true 287 | } 288 | 289 | func isRecur(node *parser.CallNode) bool { 290 | // Need an identifier for it to be "loop" 291 | if node.Callee.Type() != parser.NodeIdent { 292 | return false 293 | } 294 | 295 | // Not a "loop" 296 | if callee := node.Callee.(*parser.IdentNode); callee.Ident != "recur" { 297 | return false 298 | } 299 | 300 | // Bindings should be a vector 301 | bindings := node.Args[0] 302 | if bindings.Type() != parser.NodeVector { 303 | return false 304 | } 305 | 306 | // The bindings should be also vectors 307 | b := bindings.(*parser.VectorNode) 308 | for _, bind := range b.Nodes { 309 | if _, ok := bind.(*parser.VectorNode); !ok { 310 | return false 311 | } 312 | } 313 | 314 | // The bound identifiers, should be identifiers 315 | for _, bind := range b.Nodes { 316 | bindingVect := bind.(*parser.VectorNode) 317 | if bindingVect.Nodes[0].Type() != parser.NodeIdent { 318 | return false 319 | } 320 | } 321 | 322 | return true 323 | } 324 | 325 | func searchForRecur(nodes []parser.Node) bool { 326 | for _, node := range nodes { 327 | if node.Type() == parser.NodeCall { 328 | n := node.(*parser.CallNode) 329 | if ident, ok := n.Callee.(*parser.IdentNode); ok && ident.Ident == "recur" { 330 | return true 331 | } else if searchForRecur(n.Args) { 332 | return true 333 | } 334 | } 335 | } 336 | 337 | return false 338 | } 339 | 340 | func addNewValuesToBindings(bindingsVector *parser.VectorNode, vals []parser.Node) *parser.VectorNode { 341 | for i, _ := range bindingsVector.Nodes { 342 | bind := bindingsVector.Nodes[i].(*parser.VectorNode).Nodes 343 | bind[len(bind)-1] = vals[i] 344 | } 345 | 346 | return bindingsVector 347 | } 348 | 349 | func addRecurLabelAndBindings(label *parser.IdentNode, bindingsVector *parser.VectorNode, nodes []parser.Node) { 350 | for _, node := range nodes { 351 | if node.Type() == parser.NodeCall { 352 | n := node.(*parser.CallNode) 353 | if ident, ok := n.Callee.(*parser.IdentNode); ok && ident.Ident == "recur" { 354 | newValues := make([]parser.Node, len(n.Args)) 355 | copy(newValues, n.Args) 356 | 357 | n.Args = make([]parser.Node, 2) 358 | n.Args[0] = addNewValuesToBindings(bindingsVector.Copy().(*parser.VectorNode), newValues) 359 | n.Args[1] = label 360 | } else { 361 | addRecurLabelAndBindings(label, bindingsVector, n.Args) 362 | } 363 | } 364 | } 365 | } 366 | 367 | func makeLoop(node *parser.CallNode) *ast.CallExpr { 368 | returnIdent := generateIdent() 369 | loopIdent := generateIdent() 370 | 371 | fnBody := h.EmptyS() 372 | 373 | bindingsVector := node.Args[0].(*parser.VectorNode) 374 | 375 | addRecurLabelAndBindings(parser.NewIdentNode(loopIdent.String()), bindingsVector.Copy().(*parser.VectorNode), node.Args[1:]) 376 | 377 | bindings := makeBindings(bindingsVector, token.DEFINE) 378 | returnIdentValueSpec := makeValueSpec(h.I(returnIdent), nil, anyType) 379 | returnIdentDecl := makeDeclStmt(makeGeneralDecl(token.VAR, []ast.Spec{returnIdentValueSpec})) 380 | 381 | fnBody = append(fnBody, bindings...) 382 | fnBody = append(fnBody, returnIdentDecl) 383 | 384 | init := makeAssignStmt(h.E(loopIdent), h.E(ast.NewIdent("true")), token.DEFINE) 385 | forBody := h.EmptyS() 386 | 387 | forBody = append(forBody, makeAssignStmt(h.E(loopIdent), h.E(ast.NewIdent("false")), token.ASSIGN)) 388 | forBody = append(forBody, wrapExprsWithStmt(EvalExprs(node.Args[1:len(node.Args)-1]))...) 389 | forBody = append(forBody, makeAssignStmt(h.E(returnIdent), h.E(EvalExpr(node.Args[len(node.Args)-1])), token.ASSIGN)) 390 | 391 | forStmt := makeForStmt(init, nil, loopIdent, makeBlockStmt(forBody)) 392 | 393 | fnBody = append(fnBody, forStmt) 394 | fnBody = append(fnBody, makeReturnStmt(h.E(returnIdent))) 395 | 396 | results := makeFieldList([]*ast.Field{makeField(nil, anyType)}) 397 | fnType := makeFuncType(results, nil) 398 | fn := makeFuncLit(fnType, makeBlockStmt(fnBody)) 399 | 400 | return makeFuncCall(fn, h.EmptyE()) 401 | } 402 | 403 | func makeRecur(node *parser.CallNode) *ast.CallExpr { 404 | bindings := makeBindings(node.Args[0].(*parser.VectorNode), token.ASSIGN) 405 | loopUpdate := makeAssignStmt(h.E(EvalExpr(node.Args[1])), h.E(ast.NewIdent("true")), token.ASSIGN) 406 | 407 | body := append(h.EmptyS(), bindings...) 408 | body = append(body, loopUpdate, makeReturnStmt(h.E(ast.NewIdent("nil")))) 409 | 410 | resultType := makeFieldList([]*ast.Field{makeField(nil, anyType)}) 411 | fnType := makeFuncType(resultType, nil) 412 | fn := makeFuncLit(fnType, makeBlockStmt(body)) 413 | return makeFuncCall(fn, h.EmptyE()) 414 | } 415 | 416 | func isAssert(node *parser.CallNode) bool { 417 | // Need an identifier for it to be "assert" 418 | if node.Callee.Type() != parser.NodeIdent { 419 | return false 420 | } 421 | 422 | // Not a "loop" 423 | if callee := node.Callee.(*parser.IdentNode); callee.Ident != "assert" { 424 | return false 425 | } 426 | 427 | if len(node.Args) != 2 { 428 | panic("assert needs 2 arguments") 429 | } 430 | 431 | if _, ok := node.Args[0].(*parser.IdentNode); !ok { 432 | panic("assert's first argument needs to be a type") 433 | } 434 | 435 | return true 436 | } 437 | 438 | func makeAssert(node *parser.CallNode) *ast.TypeAssertExpr { 439 | return makeTypeAssertion(EvalExpr(node.Args[1]), ast.NewIdent(node.Args[0].(*parser.IdentNode).Ident)) 440 | } 441 | 442 | var coreFuncs = []string{"get"} 443 | 444 | func isCoreFunc(node *parser.CallNode) bool { 445 | // Need an identifier for it to be a func 446 | if node.Callee.Type() != parser.NodeIdent { 447 | return false 448 | } 449 | 450 | ident := node.Callee.(*parser.IdentNode).Ident 451 | 452 | for _, v := range coreFuncs { 453 | if v == ident { 454 | return true 455 | } 456 | } 457 | 458 | return false 459 | } 460 | 461 | // TODO: just a quick and dirty implementation 462 | func makeCoreCall(node *parser.CallNode) ast.Expr { 463 | ident := node.Callee.(*parser.IdentNode).Ident 464 | node.Callee.(*parser.IdentNode).Ident = "core/" + ident 465 | return evalFuncCall(node) 466 | } -------------------------------------------------------------------------------- /generator/generator.go: -------------------------------------------------------------------------------- 1 | package generator 2 | 3 | import ( 4 | "github.com/jcla1/gisp/parser" 5 | "fmt" 6 | "go/ast" 7 | "go/token" 8 | ) 9 | 10 | var anyType = makeSelectorExpr(ast.NewIdent("core"), ast.NewIdent("Any")) 11 | 12 | func GenerateAST(tree []parser.Node) *ast.File { 13 | f := &ast.File{Name: ast.NewIdent("main")} 14 | decls := make([]ast.Decl, 0, len(tree)) 15 | 16 | if len(tree) < 1 { 17 | return f 18 | } 19 | 20 | // you can only have (ns ...) as the first form 21 | if isNSDecl(tree[0]) { 22 | name, imports := getNamespace(tree[0].(*parser.CallNode)) 23 | 24 | f.Name = name 25 | if imports != nil { 26 | decls = append(decls, imports) 27 | } 28 | 29 | tree = tree[1:] 30 | } 31 | 32 | decls = append(decls, generateDecls(tree)...) 33 | 34 | f.Decls = decls 35 | return f 36 | } 37 | 38 | func generateDecls(tree []parser.Node) []ast.Decl { 39 | decls := make([]ast.Decl, len(tree)) 40 | 41 | for i, node := range tree { 42 | if node.Type() != parser.NodeCall { 43 | panic("expected call node in root scope!") 44 | } 45 | 46 | decls[i] = evalDeclNode(node.(*parser.CallNode)) 47 | } 48 | 49 | return decls 50 | } 51 | 52 | func evalDeclNode(node *parser.CallNode) ast.Decl { 53 | // Let's just assume that all top-level functions called will be "def" 54 | if node.Callee.Type() != parser.NodeIdent { 55 | panic("expecting call to identifier (i.e. def, defconst, etc.)") 56 | } 57 | 58 | callee := node.Callee.(*parser.IdentNode) 59 | switch callee.Ident { 60 | case "def": 61 | return evalDef(node) 62 | } 63 | 64 | return nil 65 | } 66 | 67 | func evalDef(node *parser.CallNode) ast.Decl { 68 | if len(node.Args) < 2 { 69 | panic(fmt.Sprintf("expecting expression to be assigned to variable: %q", node.Args[0])) 70 | } 71 | 72 | val := EvalExpr(node.Args[1]) 73 | fn, ok := val.(*ast.FuncLit) 74 | 75 | ident := makeIdomaticIdent(node.Args[0].(*parser.IdentNode).Ident) 76 | 77 | if ok { 78 | if ident.Name == "main" { 79 | mainable(fn) 80 | } 81 | 82 | return makeFunDeclFromFuncLit(ident, fn) 83 | } else { 84 | return makeGeneralDecl(token.VAR, []ast.Spec{makeValueSpec([]*ast.Ident{ident}, []ast.Expr{val}, nil)}) 85 | } 86 | } 87 | 88 | func isNSDecl(node parser.Node) bool { 89 | if node.Type() != parser.NodeCall { 90 | return false 91 | } 92 | 93 | call := node.(*parser.CallNode) 94 | if call.Callee.(*parser.IdentNode).Ident != "ns" { 95 | return false 96 | } 97 | 98 | if len(call.Args) < 1 { 99 | return false 100 | } 101 | 102 | return true 103 | } 104 | 105 | func getNamespace(node *parser.CallNode) (*ast.Ident, ast.Decl) { 106 | return getPackageName(node), getImports(node) 107 | } 108 | 109 | func getPackageName(node *parser.CallNode) *ast.Ident { 110 | if node.Args[0].Type() != parser.NodeIdent { 111 | panic("ns package name is not an identifier!") 112 | } 113 | 114 | return ast.NewIdent(node.Args[0].(*parser.IdentNode).Ident) 115 | } 116 | 117 | func checkNSArgs(node *parser.CallNode) bool { 118 | if node.Callee.Type() != parser.NodeIdent { 119 | return false 120 | } 121 | 122 | if callee := node.Callee.(*parser.IdentNode); callee.Ident != "ns" { 123 | return false 124 | } 125 | 126 | return true 127 | } 128 | -------------------------------------------------------------------------------- /generator/helpers/helpers.go: -------------------------------------------------------------------------------- 1 | package helpers 2 | 3 | import ( 4 | "go/ast" 5 | ) 6 | 7 | func EmptyS() []ast.Stmt { 8 | return []ast.Stmt{} 9 | } 10 | 11 | func S(stmts ...ast.Stmt) []ast.Stmt { 12 | return stmts 13 | } 14 | 15 | func EmptyE() []ast.Expr { 16 | return []ast.Expr{} 17 | } 18 | 19 | func E(exprs ...ast.Expr) []ast.Expr { 20 | return exprs 21 | } 22 | 23 | func EmptyI() []*ast.Ident { 24 | return []*ast.Ident{} 25 | } 26 | 27 | func I(ident *ast.Ident) []*ast.Ident { 28 | return []*ast.Ident{ident} 29 | } 30 | -------------------------------------------------------------------------------- /generator/idents.go: -------------------------------------------------------------------------------- 1 | package generator 2 | 3 | import ( 4 | "github.com/jcla1/gisp/parser" 5 | "bytes" 6 | "go/ast" 7 | "regexp" 8 | "strconv" 9 | "strings" 10 | ) 11 | 12 | func makeIdentSlice(nodes []*parser.IdentNode) []*ast.Ident { 13 | out := make([]*ast.Ident, len(nodes)) 14 | for i, node := range nodes { 15 | out[i] = ast.NewIdent(node.Ident) 16 | } 17 | return out 18 | } 19 | 20 | func makeSelectorExpr(x ast.Expr, sel *ast.Ident) *ast.SelectorExpr { 21 | return &ast.SelectorExpr{ 22 | X: x, 23 | Sel: sel, 24 | } 25 | } 26 | 27 | func makeIdomaticSelector(src string) ast.Expr { 28 | strs := strings.Split(src, "/") 29 | var expr ast.Expr = makeIdomaticIdent(strs[0]) 30 | 31 | for i := 1; i < len(strs); i++ { 32 | ido := CamelCase(strs[i], true) 33 | expr = makeSelectorExpr(expr, ast.NewIdent(ido)) 34 | } 35 | 36 | return expr 37 | } 38 | 39 | func makeIdomaticIdent(src string) *ast.Ident { 40 | if src == "_" { return ast.NewIdent(src) } 41 | return ast.NewIdent(CamelCase(src, false)) 42 | } 43 | 44 | var camelingRegex = regexp.MustCompile("[0-9A-Za-z]+") 45 | 46 | func CamelCase(src string, capit bool) string { 47 | byteSrc := []byte(src) 48 | chunks := camelingRegex.FindAll(byteSrc, -1) 49 | for idx, val := range chunks { 50 | if idx > 0 || capit { 51 | chunks[idx] = bytes.Title(val) 52 | } 53 | } 54 | return string(bytes.Join(chunks, nil)) 55 | } 56 | 57 | var gensyms = func() <-chan string { 58 | syms := make(chan string) 59 | go func() { 60 | i := 0 61 | for { 62 | syms <- "GEN" + strconv.Itoa(i) 63 | i++ 64 | } 65 | }() 66 | return syms 67 | }() 68 | 69 | func generateIdent() *ast.Ident { 70 | return ast.NewIdent(<-gensyms) 71 | } 72 | -------------------------------------------------------------------------------- /generator/imports.go: -------------------------------------------------------------------------------- 1 | package generator 2 | 3 | import ( 4 | "github.com/jcla1/gisp/parser" 5 | "go/ast" 6 | "go/token" 7 | ) 8 | 9 | func getImports(node *parser.CallNode) ast.Decl { 10 | if len(node.Args) < 2 { 11 | return nil 12 | } 13 | 14 | imports := node.Args[1:] 15 | specs := make([]ast.Spec, len(imports)) 16 | 17 | for i, imp := range imports { 18 | if t := imp.Type(); t == parser.NodeVector { 19 | specs[i] = makeImportSpecFromVector(imp.(*parser.VectorNode)) 20 | } else if t == parser.NodeString { 21 | path := makeBasicLit(token.STRING, imp.(*parser.StringNode).Value) 22 | specs[i] = makeImportSpec(path, nil) 23 | } else { 24 | panic("invalid import!") 25 | } 26 | } 27 | 28 | decl := makeGeneralDecl(token.IMPORT, specs) 29 | decl.Lparen = token.Pos(1) // Need this so we can have multiple imports 30 | return decl 31 | } 32 | 33 | func makeImportSpecFromVector(vect *parser.VectorNode) *ast.ImportSpec { 34 | if len(vect.Nodes) < 3 { 35 | panic("invalid use of import!") 36 | } 37 | 38 | if vect.Nodes[0].Type() != parser.NodeString { 39 | panic("invalid use of import!") 40 | } 41 | 42 | pathString := vect.Nodes[0].(*parser.StringNode).Value 43 | path := makeBasicLit(token.STRING, pathString) 44 | 45 | if vect.Nodes[1].Type() != parser.NodeIdent || vect.Nodes[1].(*parser.IdentNode).Ident != ":as" { 46 | panic("invalid use of import! expecting: \":as\"!!!") 47 | } 48 | name := ast.NewIdent(vect.Nodes[2].(*parser.IdentNode).Ident) 49 | 50 | return makeImportSpec(path, name) 51 | } 52 | 53 | func makeImportSpec(path *ast.BasicLit, name *ast.Ident) *ast.ImportSpec { 54 | return &ast.ImportSpec{ 55 | Path: path, 56 | Name: name, 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /generator/literals.go: -------------------------------------------------------------------------------- 1 | package generator 2 | 3 | import ( 4 | "go/ast" 5 | "go/token" 6 | ) 7 | 8 | func makeBasicLit(kind token.Token, value string) *ast.BasicLit { 9 | return &ast.BasicLit{Kind: kind, Value: value} 10 | } 11 | 12 | func makeVector(typ ast.Expr, elements []ast.Expr) *ast.CompositeLit { 13 | return makeCompositeLit(&ast.ArrayType{Elt: typ}, elements) 14 | } 15 | 16 | func makeCompositeLit(typ ast.Expr, elements []ast.Expr) *ast.CompositeLit { 17 | return &ast.CompositeLit{ 18 | Type: typ, 19 | Elts: elements, 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /generator/makers.go: -------------------------------------------------------------------------------- 1 | package generator 2 | 3 | import ( 4 | "github.com/jcla1/gisp/parser" 5 | h "github.com/jcla1/gisp/generator/helpers" 6 | "go/ast" 7 | "go/token" 8 | ) 9 | 10 | func makeIfStmtFunc(node *parser.CallNode) ast.Expr { 11 | var elseBody ast.Stmt 12 | if len(node.Args) > 2 { 13 | elseBody = makeBlockStmt(h.S(makeReturnStmt(h.E(EvalExpr(node.Args[2]))))) 14 | } else { 15 | elseBody = makeBlockStmt(h.S(makeReturnStmt(h.E(ast.NewIdent("nil"))))) 16 | } 17 | 18 | cond := EvalExpr(node.Args[0]) 19 | ifBody := makeBlockStmt(h.S(makeReturnStmt(h.E(EvalExpr(node.Args[1]))))) 20 | 21 | ifStmt := makeIfStmt(cond, ifBody, elseBody) 22 | fnBody := makeBlockStmt(h.S(ifStmt)) 23 | 24 | returnList := makeFieldList([]*ast.Field{makeField(nil, anyType)}) 25 | fnType := makeFuncType(returnList, nil) 26 | 27 | fn := makeFuncLit(fnType, fnBody) 28 | 29 | return makeFuncCall(fn, h.EmptyE()) 30 | } 31 | 32 | func makeLetFun(node *parser.CallNode) ast.Expr { 33 | bindings := makeBindings(node.Args[0].(*parser.VectorNode), token.DEFINE) 34 | 35 | body := append(bindings, wrapExprsWithStmt(EvalExprs(node.Args[1:]))...) 36 | body[len(body)-1] = makeReturnStmt(h.E(body[len(body)-1].(*ast.ExprStmt).X)) 37 | 38 | fieldList := makeFieldList([]*ast.Field{makeField(nil, anyType)}) 39 | typ := makeFuncType(fieldList, nil) 40 | fn := makeFuncLit(typ, makeBlockStmt(body)) 41 | 42 | return makeFuncCall(fn, h.EmptyE()) 43 | } 44 | 45 | func makeBindings(bindings *parser.VectorNode, assignmentType token.Token) []ast.Stmt { 46 | assignments := make([]ast.Stmt, len(bindings.Nodes)) 47 | 48 | for i, bind := range bindings.Nodes { 49 | b := bind.(*parser.VectorNode) 50 | idents := b.Nodes[:len(b.Nodes)-1] 51 | 52 | vars := make([]ast.Expr, len(idents)) 53 | 54 | for j, ident := range idents { 55 | vars[j] = makeIdomaticSelector(ident.(*parser.IdentNode).Ident) 56 | } 57 | 58 | assignments[i] = makeAssignStmt(vars, h.E(EvalExpr(b.Nodes[len(b.Nodes)-1])), assignmentType) 59 | } 60 | 61 | return assignments 62 | } 63 | 64 | func mainable(fn *ast.FuncLit) { 65 | fn.Type.Results = nil 66 | 67 | returnStmt := fn.Body.List[len(fn.Body.List)-1].(*ast.ReturnStmt) 68 | fn.Body.List[len(fn.Body.List)-1] = makeExprStmt(returnStmt.Results[0]) 69 | 70 | // return fn 71 | } 72 | 73 | // func makeTypeAssertFromArgList(expr ast.Expr, args []parser.Node) *ast.TypeAssertExpr { 74 | 75 | // argList 76 | 77 | // // currently we only support HOF that were written in Gisp 78 | // returnList := makeFieldList([]*ast.Field{makeField(nil, anyType)}) 79 | // fnType := makeFuncType(returnList, argList) 80 | 81 | // return makeTypeAssertion(expr, fnType) 82 | // } 83 | 84 | ////////////////////////////////// 85 | // Checked makers from here on! // 86 | ////////////////////////////////// 87 | 88 | func makeValueSpec(names []*ast.Ident, values []ast.Expr, typ ast.Expr) *ast.ValueSpec { 89 | return &ast.ValueSpec{ 90 | Names: names, 91 | Values: values, 92 | Type: typ, 93 | } 94 | } 95 | 96 | func makeFunDeclFromFuncLit(name *ast.Ident, f *ast.FuncLit) *ast.FuncDecl { 97 | return &ast.FuncDecl{ 98 | Name: name, 99 | Type: f.Type, 100 | Body: f.Body, 101 | } 102 | } 103 | 104 | func makeGeneralDecl(typ token.Token, specs []ast.Spec) *ast.GenDecl { 105 | return &ast.GenDecl{ 106 | Tok: typ, 107 | Specs: specs, 108 | } 109 | } 110 | 111 | func makeDeclStmt(decl ast.Decl) *ast.DeclStmt { 112 | return &ast.DeclStmt{ 113 | Decl: decl, 114 | } 115 | } 116 | 117 | func makeTypeAssertion(expr, typ ast.Expr) *ast.TypeAssertExpr { 118 | return &ast.TypeAssertExpr{ 119 | X: expr, 120 | Type: typ, 121 | } 122 | } 123 | 124 | func makeEllipsis(typ ast.Expr) *ast.Ellipsis { 125 | return &ast.Ellipsis{ 126 | Elt: typ, 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /generator/operators.go: -------------------------------------------------------------------------------- 1 | package generator 2 | 3 | import ( 4 | "github.com/jcla1/gisp/parser" 5 | "go/ast" 6 | "go/token" 7 | ) 8 | 9 | var ( 10 | callableOperators = []string{">", ">=", "<", "<=", "=", "+", "-", "*", "/", "mod"} 11 | logicOperatorMap = map[string]token.Token{ 12 | "and": token.LAND, 13 | "or": token.LOR, 14 | } 15 | 16 | unaryOperatorMap = map[string]token.Token{ 17 | "!": token.NOT, 18 | } 19 | ) 20 | 21 | func isCallableOperator(node *parser.CallNode) bool { 22 | if node.Callee.Type() != parser.NodeIdent { 23 | return false 24 | } 25 | 26 | ident := node.Callee.(*parser.IdentNode).Ident 27 | 28 | return isInSlice(ident, callableOperators) 29 | } 30 | 31 | // We handle comparisons as a call to some go code, since you can only 32 | // compare ints, floats, cmplx, and such, you know... 33 | // We handle arithmetic operations as function calls, since all args are evaluated 34 | func makeNAryCallableExpr(node *parser.CallNode) *ast.CallExpr { 35 | op := node.Callee.(*parser.IdentNode).Ident 36 | args := EvalExprs(node.Args) 37 | var selector string 38 | 39 | // TODO: abstract this away into a map!!! 40 | switch op { 41 | case ">": 42 | selector = "GT" 43 | case ">=": 44 | selector = "GTEQ" 45 | case "<": 46 | selector = "LT" 47 | case "<=": 48 | selector = "LTEQ" 49 | case "=": 50 | selector = "EQ" 51 | case "+": 52 | selector = "ADD" 53 | case "-": 54 | selector = "SUB" 55 | case "*": 56 | selector = "MUL" 57 | case "/": 58 | selector = "DIV" 59 | case "mod": 60 | if len(node.Args) > 2 { 61 | panic("can't calculate modulo with more than 2 arguments!") 62 | } 63 | selector = "MOD" 64 | } 65 | 66 | return makeFuncCall(makeSelectorExpr(ast.NewIdent("core"), ast.NewIdent(selector)), args) 67 | } 68 | 69 | func isLogicOperator(node *parser.CallNode) bool { 70 | if node.Callee.Type() != parser.NodeIdent { 71 | return false 72 | } 73 | 74 | _, ok := logicOperatorMap[node.Callee.(*parser.IdentNode).Ident] 75 | 76 | if len(node.Args) < 2 && ok { 77 | panic("can't use binary operator with only one argument!") 78 | } 79 | 80 | return ok 81 | } 82 | 83 | // But logical comparisons are done properly, since those can short-circuit 84 | func makeNAryLogicExpr(node *parser.CallNode) *ast.BinaryExpr { 85 | op := logicOperatorMap[node.Callee.(*parser.IdentNode).Ident] 86 | outer := makeBinaryExpr(op, EvalExpr(node.Args[0]), EvalExpr(node.Args[1])) 87 | 88 | for i := 2; i < len(node.Args); i++ { 89 | outer = makeBinaryExpr(op, outer, EvalExpr(node.Args[i])) 90 | } 91 | 92 | return outer 93 | } 94 | 95 | func makeBinaryExpr(op token.Token, x, y ast.Expr) *ast.BinaryExpr { 96 | return &ast.BinaryExpr{ 97 | X: x, 98 | Y: y, 99 | Op: op, 100 | } 101 | } 102 | 103 | func isUnaryOperator(node *parser.CallNode) bool { 104 | if node.Callee.Type() != parser.NodeIdent { 105 | return false 106 | } 107 | 108 | _, ok := unaryOperatorMap[node.Callee.(*parser.IdentNode).Ident] 109 | 110 | if len(node.Args) != 1 && ok { 111 | panic("unary expression takes, exactly, one argument!") 112 | } 113 | 114 | return ok 115 | } 116 | 117 | func makeUnaryExpr(op token.Token, x ast.Expr) *ast.UnaryExpr { 118 | return &ast.UnaryExpr{ 119 | X: x, 120 | Op: op, 121 | } 122 | } 123 | 124 | func isInSlice(elem string, slice []string) bool { 125 | for _, el := range slice { 126 | if elem == el { 127 | return true 128 | } 129 | } 130 | 131 | return false 132 | } 133 | -------------------------------------------------------------------------------- /generator/statements.go: -------------------------------------------------------------------------------- 1 | package generator 2 | 3 | import ( 4 | "go/ast" 5 | "go/token" 6 | ) 7 | 8 | func wrapExprsWithStmt(exps []ast.Expr) []ast.Stmt { 9 | out := make([]ast.Stmt, len(exps)) 10 | for i, v := range exps { 11 | out[i] = makeExprStmt(v) 12 | } 13 | return out 14 | } 15 | 16 | func makeBlockStmt(statements []ast.Stmt) *ast.BlockStmt { 17 | return &ast.BlockStmt{List: statements} 18 | } 19 | 20 | func makeExprStmt(exp ast.Expr) ast.Stmt { 21 | return &ast.ExprStmt{X: exp} 22 | } 23 | 24 | func makeIfStmt(cond ast.Expr, body *ast.BlockStmt, otherwise ast.Stmt) *ast.IfStmt { 25 | return &ast.IfStmt{ 26 | Cond: cond, 27 | Body: body, 28 | Else: otherwise, 29 | } 30 | } 31 | 32 | func makeAssignStmt(names, vals []ast.Expr, assignType token.Token) *ast.AssignStmt { 33 | return &ast.AssignStmt{ 34 | Lhs: names, 35 | Rhs: vals, 36 | Tok: assignType, 37 | } 38 | } 39 | 40 | func makeBranchStmt(tok token.Token, labelName *ast.Ident) *ast.BranchStmt { 41 | return &ast.BranchStmt{ 42 | Tok: tok, 43 | Label: labelName, 44 | } 45 | } 46 | 47 | func makeLabeledStmt(labelName *ast.Ident, stmt ast.Stmt) *ast.LabeledStmt { 48 | return &ast.LabeledStmt{ 49 | Label: labelName, 50 | Stmt: stmt, 51 | } 52 | } 53 | 54 | func makeForStmt(init, post ast.Stmt, cond ast.Expr, body *ast.BlockStmt) *ast.ForStmt { 55 | return &ast.ForStmt{ 56 | Init: init, 57 | Post: post, 58 | Cond: cond, 59 | Body: body, 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /gisp.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/jcla1/gisp/generator" 5 | "github.com/jcla1/gisp/parser" 6 | "bufio" 7 | "bytes" 8 | "fmt" 9 | "go/ast" 10 | "go/printer" 11 | "go/token" 12 | "io/ioutil" 13 | "os" 14 | ) 15 | 16 | func args(filename string) { 17 | b, err := ioutil.ReadFile(filename) 18 | if err != nil { 19 | panic(err) 20 | } 21 | 22 | p := parser.ParseFromString(filename, string(b)+"\n") 23 | 24 | a := generator.GenerateAST(p) 25 | 26 | fset := token.NewFileSet() 27 | 28 | var buf bytes.Buffer 29 | printer.Fprint(&buf, fset, a) 30 | fmt.Printf("%s\n", buf.String()) 31 | } 32 | 33 | func main() { 34 | if len(os.Args) > 1 { 35 | args(os.Args[1]) 36 | return 37 | } 38 | 39 | r := bufio.NewReader(os.Stdin) 40 | 41 | for { 42 | fmt.Print(">> ") 43 | line, _, _ := r.ReadLine() 44 | p := parser.ParseFromString("", string(line)+"\n") 45 | fmt.Println(p) 46 | 47 | // a := generator.GenerateAST(p) 48 | a := generator.EvalExprs(p) 49 | fset := token.NewFileSet() 50 | ast.Print(fset, a) 51 | 52 | var buf bytes.Buffer 53 | printer.Fprint(&buf, fset, a) 54 | fmt.Printf("%s\n", buf.String()) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /lexer/lexer.go: -------------------------------------------------------------------------------- 1 | package lexer 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | "unicode" 7 | "unicode/utf8" 8 | ) 9 | 10 | type Pos int 11 | 12 | type Item struct { 13 | Type ItemType 14 | Pos Pos 15 | Value string 16 | } 17 | 18 | type ItemType int 19 | 20 | const ( 21 | ItemError ItemType = iota 22 | ItemEOF 23 | 24 | ItemLeftParen 25 | ItemRightParen 26 | ItemLeftVect 27 | ItemRightVect 28 | 29 | ItemIdent 30 | ItemString 31 | ItemChar 32 | ItemFloat 33 | ItemInt 34 | ItemComplex 35 | 36 | ItemQuote 37 | ItemQuasiQuote 38 | ItemUnquote 39 | ItemUnquoteSplice 40 | ) 41 | 42 | const EOF = -1 43 | 44 | type stateFn func(*Lexer) stateFn 45 | 46 | type Lexer struct { 47 | name string 48 | input string 49 | state stateFn 50 | pos Pos 51 | start Pos 52 | width Pos 53 | lastPos Pos 54 | items chan Item 55 | 56 | parenDepth int 57 | vectDepth int 58 | } 59 | 60 | // next returns the next rune in the input. 61 | func (l *Lexer) next() rune { 62 | if int(l.pos) >= len(l.input) { 63 | l.width = 0 64 | return EOF 65 | } 66 | r, w := utf8.DecodeRuneInString(l.input[l.pos:]) 67 | l.width = Pos(w) 68 | l.pos += l.width 69 | return r 70 | } 71 | 72 | // peek returns but does not consume the next rune in the input. 73 | func (l *Lexer) peek() rune { 74 | r := l.next() 75 | l.backup() 76 | return r 77 | } 78 | 79 | // backup steps back one rune. Can only be called once per call of next. 80 | func (l *Lexer) backup() { 81 | l.pos -= l.width 82 | } 83 | 84 | // emit passes an Item back to the client. 85 | func (l *Lexer) emit(t ItemType) { 86 | l.items <- Item{t, l.start, l.input[l.start:l.pos]} 87 | l.start = l.pos 88 | } 89 | 90 | func (l *Lexer) ignore() { 91 | l.start = l.pos 92 | } 93 | 94 | // accept consumes the next rune if it's from the valid set. 95 | func (l *Lexer) accept(valid string) bool { 96 | if strings.IndexRune(valid, l.next()) >= 0 { 97 | return true 98 | } 99 | l.backup() 100 | return false 101 | } 102 | 103 | // acceptRun consumes a run of runes from the valid set. 104 | func (l *Lexer) acceptRun(valid string) { 105 | for strings.IndexRune(valid, l.next()) >= 0 { 106 | } 107 | l.backup() 108 | } 109 | 110 | func (l *Lexer) errorf(format string, args ...interface{}) stateFn { 111 | l.items <- Item{ItemError, l.start, fmt.Sprintf(format, args...)} 112 | return nil 113 | } 114 | 115 | func (l *Lexer) NextItem() Item { 116 | item := <-l.items 117 | l.lastPos = item.Pos 118 | return item 119 | } 120 | 121 | func Lex(name, input string) *Lexer { 122 | l := &Lexer{ 123 | name: name, 124 | input: input, 125 | items: make(chan Item), 126 | } 127 | go l.run() 128 | return l 129 | } 130 | 131 | func (l *Lexer) run() { 132 | for l.state = lexWhitespace; l.state != nil; { 133 | l.state = l.state(l) 134 | } 135 | close(l.items) 136 | } 137 | 138 | func lexLeftVect(l *Lexer) stateFn { 139 | l.emit(ItemLeftVect) 140 | 141 | return lexWhitespace 142 | } 143 | 144 | func lexRightVect(l *Lexer) stateFn { 145 | l.emit(ItemRightVect) 146 | 147 | return lexWhitespace 148 | } 149 | 150 | // lexes an open parenthesis 151 | func lexLeftParen(l *Lexer) stateFn { 152 | l.emit(ItemLeftParen) 153 | 154 | return lexWhitespace 155 | } 156 | 157 | func lexWhitespace(l *Lexer) stateFn { 158 | for r := l.next(); isSpace(r) || r == '\n'; l.next() { 159 | r = l.peek() 160 | } 161 | l.backup() 162 | l.ignore() 163 | 164 | switch r := l.next(); { 165 | case r == EOF: 166 | l.emit(ItemEOF) 167 | return nil 168 | case r == '(': 169 | return lexLeftParen 170 | case r == ')': 171 | return lexRightParen 172 | case r == '[': 173 | return lexLeftVect 174 | case r == ']': 175 | return lexRightVect 176 | case r == '"': 177 | return lexString 178 | case r == '+' || r == '-' || ('0' <= r && r <= '9'): 179 | return lexNumber 180 | case r == ';': 181 | return lexComment 182 | case isAlphaNumeric(r): 183 | return lexIdentifier 184 | default: 185 | panic(fmt.Sprintf("don't know what to do with: %q", r)) 186 | } 187 | } 188 | 189 | func lexString(l *Lexer) stateFn { 190 | for r := l.next(); r != '"'; r = l.next() { 191 | if r == '\\' { 192 | r = l.next() 193 | } 194 | if r == EOF { 195 | return l.errorf("unterminated quoted string") 196 | } 197 | } 198 | l.emit(ItemString) 199 | return lexWhitespace 200 | } 201 | 202 | func lexIdentifier(l *Lexer) stateFn { 203 | for r := l.next(); isAlphaNumeric(r); r = l.next() { 204 | } 205 | l.backup() 206 | 207 | l.emit(ItemIdent) 208 | return lexWhitespace 209 | } 210 | 211 | // lex a close parenthesis 212 | func lexRightParen(l *Lexer) stateFn { 213 | l.emit(ItemRightParen) 214 | 215 | return lexWhitespace 216 | } 217 | 218 | // lex a comment, comment delimiter is known to be already read 219 | func lexComment(l *Lexer) stateFn { 220 | i := strings.Index(l.input[l.pos:], "\n") 221 | l.pos += Pos(i) 222 | l.ignore() 223 | return lexWhitespace 224 | } 225 | 226 | func lexNumber(l *Lexer) stateFn { 227 | if !l.scanNumber() { 228 | return l.errorf("bad number syntax: %q", l.input[l.start:l.pos]) 229 | } 230 | 231 | if l.start+1 == l.pos { 232 | return lexIdentifier 233 | } 234 | 235 | if sign := l.peek(); sign == '+' || sign == '-' { 236 | // Complex: 1+2i. No spaces, must end in 'i'. 237 | if !l.scanNumber() || l.input[l.pos-1] != 'i' { 238 | return l.errorf("bad number syntax: %q", l.input[l.start:l.pos]) 239 | } 240 | l.emit(ItemComplex) 241 | } else if strings.ContainsRune(l.input[l.start:l.pos], '.') { 242 | l.emit(ItemFloat) 243 | } else { 244 | l.emit(ItemInt) 245 | } 246 | 247 | return lexWhitespace 248 | } 249 | 250 | func (l *Lexer) scanNumber() bool { 251 | // Optional leading sign. 252 | l.accept("+-") 253 | // Is it hex? 254 | digits := "0123456789" 255 | if l.accept("0") && l.accept("xX") { 256 | digits = "0123456789abcdefABCDEF" 257 | } 258 | l.acceptRun(digits) 259 | if l.accept(".") { 260 | l.acceptRun(digits) 261 | } 262 | if l.accept("eE") { 263 | l.accept("+-") 264 | l.acceptRun("0123456789") 265 | } 266 | // Is it imaginary? 267 | l.accept("i") 268 | // Next thing mustn't be alphanumeric. 269 | if r := l.peek(); isAlphaNumeric(r) { 270 | l.next() 271 | return false 272 | } 273 | return true 274 | } 275 | 276 | // isSpace reports whether r is a space character. 277 | func isSpace(r rune) bool { 278 | return r == ' ' || r == '\t' 279 | } 280 | 281 | // isEndOfLine reports whether r is an end-of-line character. 282 | func isEndOfLine(r rune) bool { 283 | return r == '\r' || r == '\n' 284 | } 285 | 286 | // isAlphaNumeric reports whether r is a valid rune for an identifier. 287 | func isAlphaNumeric(r rune) bool { 288 | return r == '>' || r == '<' || r == '=' || r == '-' || r == '+' || r == '*' || r == '&' || r == '_' || r == '/' || unicode.IsLetter(r) || unicode.IsDigit(r) 289 | } 290 | 291 | func debug(msg string) { 292 | fmt.Println(msg) 293 | } 294 | -------------------------------------------------------------------------------- /parser/parser.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "github.com/jcla1/gisp/lexer" 5 | "fmt" 6 | "go/token" 7 | ) 8 | 9 | type Node interface { 10 | Type() NodeType 11 | // Position() Pos 12 | String() string 13 | Copy() Node 14 | } 15 | 16 | type Pos int 17 | 18 | func (p Pos) Position() Pos { 19 | return p 20 | } 21 | 22 | type NodeType int 23 | 24 | func (t NodeType) Type() NodeType { 25 | return t 26 | } 27 | 28 | const ( 29 | NodeIdent NodeType = iota 30 | NodeString 31 | NodeNumber 32 | NodeCall 33 | NodeVector 34 | ) 35 | 36 | type IdentNode struct { 37 | // Pos 38 | NodeType 39 | Ident string 40 | } 41 | 42 | func (node *IdentNode) Copy() Node { 43 | return NewIdentNode(node.Ident) 44 | } 45 | 46 | func (node *IdentNode) String() string { 47 | if node.Ident == "nil" { 48 | return "()" 49 | } 50 | 51 | return node.Ident 52 | } 53 | 54 | type StringNode struct { 55 | // Pos 56 | NodeType 57 | Value string 58 | } 59 | 60 | func (node *StringNode) Copy() Node { 61 | return newStringNode(node.Value) 62 | } 63 | 64 | func (node *StringNode) String() string { 65 | return node.Value 66 | } 67 | 68 | type NumberNode struct { 69 | // Pos 70 | NodeType 71 | Value string 72 | NumberType token.Token 73 | } 74 | 75 | func (node *NumberNode) Copy() Node { 76 | return &NumberNode{NodeType: node.Type(), Value: node.Value, NumberType: node.NumberType} 77 | } 78 | 79 | func (node *NumberNode) String() string { 80 | return node.Value 81 | } 82 | 83 | type VectorNode struct { 84 | // Pos 85 | NodeType 86 | Nodes []Node 87 | } 88 | 89 | func (node *VectorNode) Copy() Node { 90 | vect := &VectorNode{NodeType: node.Type(), Nodes: make([]Node, len(node.Nodes))} 91 | for i, v := range node.Nodes { 92 | vect.Nodes[i] = v.Copy() 93 | } 94 | return vect 95 | } 96 | 97 | func (node *VectorNode) String() string { 98 | return fmt.Sprint(node.Nodes) 99 | } 100 | 101 | type CallNode struct { 102 | // Pos 103 | NodeType 104 | Callee Node 105 | Args []Node 106 | } 107 | 108 | func (node *CallNode) Copy() Node { 109 | call := &CallNode{NodeType: node.Type(), Callee: node.Callee.Copy(), Args: make([]Node, len(node.Args))} 110 | for i, v := range node.Args { 111 | call.Args[i] = v.Copy() 112 | } 113 | return call 114 | } 115 | 116 | func (node *CallNode) String() string { 117 | args := fmt.Sprint(node.Args) 118 | return fmt.Sprintf("(%s %s)", node.Callee, args[1:len(args)-1]) 119 | } 120 | 121 | var nilNode = NewIdentNode("nil") 122 | 123 | func ParseFromString(name, program string) []Node { 124 | return Parse(lexer.Lex(name, program)) 125 | } 126 | 127 | func Parse(l *lexer.Lexer) []Node { 128 | return parser(l, make([]Node, 0), ' ') 129 | } 130 | 131 | func parser(l *lexer.Lexer, tree []Node, lookingFor rune) []Node { 132 | for item := l.NextItem(); item.Type != lexer.ItemEOF; { 133 | switch t := item.Type; t { 134 | case lexer.ItemIdent: 135 | tree = append(tree, NewIdentNode(item.Value)) 136 | case lexer.ItemString: 137 | tree = append(tree, newStringNode(item.Value)) 138 | case lexer.ItemInt: 139 | tree = append(tree, newIntNode(item.Value)) 140 | case lexer.ItemFloat: 141 | tree = append(tree, newFloatNode(item.Value)) 142 | case lexer.ItemComplex: 143 | tree = append(tree, newComplexNode(item.Value)) 144 | case lexer.ItemLeftParen: 145 | tree = append(tree, newCallNode(parser(l, make([]Node, 0), ')'))) 146 | case lexer.ItemLeftVect: 147 | tree = append(tree, newVectNode(parser(l, make([]Node, 0), ']'))) 148 | case lexer.ItemRightParen: 149 | if lookingFor != ')' { 150 | panic(fmt.Sprintf("unexpected \")\" [%d]", item.Pos)) 151 | } 152 | return tree 153 | case lexer.ItemRightVect: 154 | if lookingFor != ']' { 155 | panic(fmt.Sprintf("unexpected \"]\" [%d]", item.Pos)) 156 | } 157 | return tree 158 | case lexer.ItemError: 159 | println(item.Value) 160 | default: 161 | panic("Bad Item type") 162 | } 163 | item = l.NextItem() 164 | } 165 | 166 | return tree 167 | } 168 | 169 | func NewIdentNode(name string) *IdentNode { 170 | return &IdentNode{NodeType: NodeIdent, Ident: name} 171 | } 172 | 173 | func newStringNode(val string) *StringNode { 174 | return &StringNode{NodeType: NodeString, Value: val} 175 | } 176 | 177 | func newIntNode(val string) *NumberNode { 178 | return &NumberNode{NodeType: NodeNumber, Value: val, NumberType: token.INT} 179 | } 180 | 181 | func newFloatNode(val string) *NumberNode { 182 | return &NumberNode{NodeType: NodeNumber, Value: val, NumberType: token.FLOAT} 183 | } 184 | 185 | func newComplexNode(val string) *NumberNode { 186 | return &NumberNode{NodeType: NodeNumber, Value: val, NumberType: token.IMAG} 187 | } 188 | 189 | // We return Node here, because it could be that it's nil 190 | func newCallNode(args []Node) Node { 191 | if len(args) > 0 { 192 | return &CallNode{NodeType: NodeCall, Callee: args[0], Args: args[1:]} 193 | } else { 194 | return nilNode 195 | } 196 | } 197 | 198 | func newVectNode(content []Node) *VectorNode { 199 | return &VectorNode{NodeType: NodeVector, Nodes: content} 200 | } 201 | -------------------------------------------------------------------------------- /play/ast_print.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "go/ast" 7 | "go/parser" 8 | "go/printer" 9 | "go/token" 10 | ) 11 | 12 | func main() { 13 | // src is the input for which we want to print the AST. 14 | src := ` 15 | package main 16 | 17 | func hello(a, b Any, rest ...Any) Any { 18 | return a 19 | } 20 | 21 | func main() { 22 | f := 10 23 | f.(func(int)Any) 24 | } 25 | ` 26 | 27 | // Create the AST by parsing src. 28 | fset := token.NewFileSet() // positions are relative to fset 29 | f, err := parser.ParseFile(fset, "", src, 0) 30 | if err != nil { 31 | panic(err) 32 | } 33 | 34 | // (f.Decls[0].(*ast.GenDecl)).Specs[0].Name.Obj = nil 35 | // ((f.Decls[0].(*ast.GenDecl)).Specs[0].(*ast.TypeSpec).Name.Obj) = nil 36 | // f.Imports = nil 37 | ast.Print(fset, f) 38 | 39 | // Print the AST. 40 | var buf bytes.Buffer 41 | printer.Fprint(&buf, fset, f) 42 | fmt.Println(buf.String()) 43 | 44 | } 45 | -------------------------------------------------------------------------------- /play/call_ellipse_func.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type Any interface{} 4 | 5 | func main() { 6 | myFunc(func(x, y int, rest ...int) { 7 | println(x) 8 | println(y) 9 | println(rest) 10 | }) 11 | } 12 | 13 | func myFunc(fn interface{}) { 14 | fn.(func(Any, Any, ...Any))(1, 2, 3, 4, 5) 15 | } 16 | -------------------------------------------------------------------------------- /play/call_interface_function.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Any interface{} 6 | 7 | var MyToplevelFunc = func() { 8 | fmt.Println("In: MyToplevelFunc") 9 | } 10 | 11 | var MyMap = func(sequence, f Any) { 12 | for _, v := range sequence.([]Any) { 13 | fmt.Println(f.(func(Any) Any)(v)) 14 | } 15 | } 16 | 17 | func main() { 18 | MyToplevelFunc() 19 | MyMap([]Any{1, 2, 3, 4}, func(val Any) Any { 20 | return 10 * val.(int) 21 | }) 22 | } 23 | -------------------------------------------------------------------------------- /play/calling_const_func.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // Won't work. Funcs are not constant, but why? 6 | const MyConstFunc = func() string { 7 | return "This is from your ConstFunc!" 8 | } 9 | 10 | func main() { 11 | fmt.Println(MyConstFunc()) 12 | } 13 | -------------------------------------------------------------------------------- /play/func_call_benchmark_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "testing" 4 | 5 | func BenchmarkFuncCallSpeedWithInner(b *testing.B) { 6 | for i := 0; i < b.N; i++ { 7 | withInner() 8 | } 9 | } 10 | 11 | func BenchmarkFuncCallSpeedWithoutInner(b *testing.B) { 12 | for i := 0; i < b.N; i++ { 13 | withInner() 14 | } 15 | } 16 | 17 | func withInner() int { 18 | return func() int { 19 | return 10 20 | }() 21 | } 22 | 23 | func withoutInner() int { 24 | return 10 25 | } 26 | -------------------------------------------------------------------------------- /play/gisp.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "fmt" 7 | "os" 8 | "regexp" 9 | "strconv" 10 | "strings" 11 | "unicode" 12 | "unicode/utf8" 13 | ) 14 | 15 | type Any interface{} 16 | type Symbol string 17 | type tokenType int 18 | 19 | const ( 20 | _INVALID tokenType = iota 21 | _EOF 22 | _INT 23 | _SYMBOL 24 | _LPAREN 25 | _RPAREN 26 | _STRING 27 | _FLOAT 28 | _BOOL 29 | _QUOTE 30 | _QUASIQUOTE 31 | _UNQUOTE 32 | _UNQUOTESPLICE 33 | ) 34 | 35 | func (t tokenType) String() string { 36 | switch t { 37 | case _INVALID: 38 | return "INVALID TOKEN" 39 | case _EOF: 40 | return "EOF" 41 | case _INT: 42 | return "INT" 43 | case _SYMBOL: 44 | return "SYMBOL" 45 | case _LPAREN: 46 | return "LEFT_PAREN" 47 | case _RPAREN: 48 | return "RIGHT_PAREN" 49 | case _STRING: 50 | return "STRING" 51 | case _FLOAT: 52 | return "FLOAT" 53 | case _BOOL: 54 | return "BOOL" 55 | case _QUOTE: 56 | return "'" 57 | case _QUASIQUOTE: 58 | return "`" 59 | case _UNQUOTE: 60 | return "," 61 | case _UNQUOTESPLICE: 62 | return ",@" 63 | default: 64 | return "WTF!?" 65 | } 66 | } 67 | 68 | type token struct { 69 | typ tokenType // The type of this item. 70 | pos Pos // The starting position, in bytes, of this item in the input string. 71 | val string // The value of this item. 72 | } 73 | 74 | func (t token) String() string { 75 | return fmt.Sprintf("%s", t.val) 76 | } 77 | 78 | const eof = -1 79 | 80 | type stateFn func(*lexer) stateFn 81 | type Pos int 82 | 83 | type lexer struct { 84 | name string 85 | input string 86 | state stateFn 87 | pos Pos 88 | start Pos 89 | width Pos 90 | lastPos Pos 91 | tokens chan token 92 | parenDepth int 93 | } 94 | 95 | func (l *lexer) run() { 96 | for l.state = lexWhitespace; l.state != nil; { 97 | l.state = l.state(l) 98 | } 99 | } 100 | 101 | func (l *lexer) next() rune { 102 | if int(l.pos) >= len(l.input) { 103 | l.width = 0 104 | return eof 105 | } 106 | r, w := utf8.DecodeRuneInString(l.input[l.pos:]) 107 | l.width = Pos(w) 108 | l.pos += l.width 109 | return r 110 | } 111 | 112 | // peek returns but does not consume the next rune in the input. 113 | func (l *lexer) peek() rune { 114 | r := l.next() 115 | l.backup() 116 | return r 117 | } 118 | 119 | // backup steps back one rune. Can only be called once per call of next. 120 | func (l *lexer) backup() { 121 | l.pos -= l.width 122 | } 123 | 124 | func (l *lexer) emit(t tokenType) { 125 | l.tokens <- token{t, l.start, l.input[l.start:l.pos]} 126 | l.start = l.pos 127 | } 128 | 129 | func (l *lexer) ignore() { 130 | l.start = l.pos 131 | } 132 | 133 | // accept consumes the next rune if it's from the valid set. 134 | func (l *lexer) accept(valid string) bool { 135 | if strings.IndexRune(valid, l.next()) >= 0 { 136 | return true 137 | } 138 | l.backup() 139 | return false 140 | } 141 | 142 | // acceptRun consumes a run of runes from the valid set. 143 | func (l *lexer) acceptRun(valid string) { 144 | for strings.IndexRune(valid, l.next()) >= 0 { 145 | } 146 | l.backup() 147 | } 148 | 149 | func (l *lexer) lineNumber() int { 150 | return 1 + strings.Count(l.input[:l.lastPos], "\n") 151 | } 152 | 153 | func (l *lexer) errorf(format string, args ...interface{}) stateFn { 154 | l.tokens <- token{_INVALID, l.start, fmt.Sprintf(format, args...)} 155 | return nil 156 | } 157 | 158 | func (l *lexer) nextToken() token { 159 | token := <-l.tokens 160 | l.lastPos = token.pos 161 | return token 162 | } 163 | 164 | // lexes an open parenthesis 165 | func lexOpenParen(l *lexer) stateFn { 166 | 167 | l.emit(_LPAREN) 168 | l.parenDepth++ 169 | 170 | r := l.next() 171 | 172 | switch r { 173 | case ' ', '\t', '\n', '\r': 174 | return lexWhitespace 175 | case '\'': 176 | return lexQuote 177 | case '`': 178 | return lexQuasiquote 179 | case ',': 180 | return lexUnquote 181 | case '(': 182 | return lexOpenParen 183 | case ')': 184 | return lexCloseParen 185 | case ';': 186 | return lexComment 187 | case '#': 188 | return lexBool 189 | } 190 | 191 | if unicode.IsDigit(r) { 192 | return lexInt 193 | } 194 | 195 | return lexSymbol 196 | } 197 | 198 | func lexBool(l *lexer) stateFn { 199 | l.accept("tf") 200 | l.emit(_BOOL) 201 | 202 | r := l.next() 203 | 204 | switch r { 205 | case ' ', '\t', '\n': 206 | return lexWhitespace 207 | case ')': 208 | return lexCloseParen 209 | case ';': 210 | return lexComment 211 | } 212 | 213 | return l.errorf("unexpected tokens") 214 | } 215 | 216 | func lexQuote(l *lexer) stateFn { 217 | l.acceptRun(" ") 218 | l.ignore() 219 | l.emit(_QUOTE) 220 | 221 | r := l.next() 222 | 223 | switch r { 224 | case '"': 225 | return lexString 226 | case '(': 227 | return lexOpenParen 228 | case ')': 229 | return lexCloseParen 230 | case '#': 231 | return lexBool 232 | case '\'': 233 | return lexQuote 234 | case '`': 235 | return lexQuasiquote 236 | case ',': 237 | return lexUnquote 238 | } 239 | 240 | if unicode.IsDigit(r) { 241 | return lexInt 242 | } 243 | 244 | return lexSymbol 245 | } 246 | 247 | func lexQuasiquote(l *lexer) stateFn { 248 | l.acceptRun(" ") 249 | l.ignore() 250 | l.emit(_QUASIQUOTE) 251 | 252 | r := l.next() 253 | 254 | switch r { 255 | case '"': 256 | return lexString 257 | case '(': 258 | return lexOpenParen 259 | case ')': 260 | return lexCloseParen 261 | case '#': 262 | return lexBool 263 | case '\'': 264 | return lexQuote 265 | case '`': 266 | return lexQuasiquote 267 | case ',': 268 | return lexUnquote 269 | } 270 | 271 | if unicode.IsDigit(r) { 272 | return lexInt 273 | } 274 | 275 | return lexSymbol 276 | } 277 | 278 | func lexUnquote(l *lexer) stateFn { 279 | 280 | if l.peek() == '@' { 281 | return lexUnquoteSplice 282 | } 283 | 284 | l.acceptRun(" ") 285 | l.ignore() 286 | l.emit(_UNQUOTE) 287 | 288 | r := l.next() 289 | 290 | switch r { 291 | case '"': 292 | return lexString 293 | case '(': 294 | return lexOpenParen 295 | case ')': 296 | return lexCloseParen 297 | case '#': 298 | return lexBool 299 | case '\'': 300 | return lexQuote 301 | case '`': 302 | return lexQuasiquote 303 | case ',': 304 | return lexUnquote 305 | } 306 | 307 | if unicode.IsDigit(r) { 308 | return lexInt 309 | } 310 | 311 | return lexSymbol 312 | } 313 | 314 | func lexUnquoteSplice(l *lexer) stateFn { 315 | r := l.next() 316 | l.acceptRun(" ") 317 | l.ignore() 318 | l.emit(_UNQUOTESPLICE) 319 | 320 | r = l.next() 321 | 322 | switch r { 323 | case '"': 324 | return lexString 325 | case '(': 326 | return lexOpenParen 327 | case ')': 328 | return lexCloseParen 329 | case '#': 330 | return lexBool 331 | case '\'': 332 | return lexQuote 333 | case '`': 334 | return lexQuasiquote 335 | case ',': 336 | return lexUnquote 337 | } 338 | 339 | if unicode.IsDigit(r) { 340 | return lexInt 341 | } 342 | 343 | return lexSymbol 344 | } 345 | 346 | func lexWhitespace(l *lexer) stateFn { 347 | l.ignore() 348 | r := l.next() 349 | 350 | switch r { 351 | case ' ', '\t', '\n': 352 | return lexWhitespace 353 | case '\'': 354 | return lexQuote 355 | case '`': 356 | return lexQuasiquote 357 | case ',': 358 | return lexUnquote 359 | case '"': 360 | return lexString 361 | case '(': 362 | return lexOpenParen 363 | case ')': 364 | return lexCloseParen 365 | case ';': 366 | return lexComment 367 | case '#': 368 | return lexBool 369 | case eof: 370 | if l.parenDepth > 0 { 371 | return l.errorf("unclosed paren") 372 | } 373 | l.emit(_EOF) 374 | return nil 375 | } 376 | 377 | if unicode.IsDigit(r) { 378 | return lexInt 379 | } 380 | 381 | return lexSymbol 382 | } 383 | 384 | func lexString(l *lexer) stateFn { 385 | r := l.next() 386 | 387 | switch r { 388 | case '"': 389 | l.emit(_STRING) 390 | return lexWhitespace 391 | case '\\': 392 | // l.backup() 393 | // l.input = append(l.input[:l.pos], l.input[l.pos+1:]) 394 | l.next() 395 | return lexString 396 | } 397 | 398 | return lexString 399 | } 400 | 401 | // lex an integer. Once we're on an integer, the only valid characters are 402 | // whitespace, close paren, a period to indicate we want a float, or more 403 | // digits. Everything else is crap. 404 | func lexInt(l *lexer) stateFn { 405 | digits := "0123456789" 406 | l.acceptRun(digits) 407 | 408 | r := l.peek() 409 | 410 | switch r { 411 | case ' ', '\t', '\n': 412 | l.emit(_INT) 413 | l.next() 414 | return lexWhitespace 415 | case '.': 416 | l.next() 417 | return lexFloat 418 | case ')': 419 | l.emit(_INT) 420 | l.next() 421 | return lexCloseParen 422 | case ';': 423 | l.emit(_INT) 424 | l.next() 425 | return lexComment 426 | } 427 | 428 | return l.errorf("unexpected rune in lexInt: %c", r) 429 | } 430 | 431 | // once we're in a float, the only valid values are digits, whitespace or close 432 | // paren. 433 | func lexFloat(l *lexer) stateFn { 434 | 435 | digits := "0123456789" 436 | l.acceptRun(digits) 437 | 438 | l.emit(_FLOAT) 439 | 440 | r := l.next() 441 | 442 | switch r { 443 | case ' ', '\t', '\n': 444 | return lexWhitespace 445 | case ')': 446 | return lexCloseParen 447 | case ';': 448 | return lexComment 449 | } 450 | 451 | return l.errorf("unexpected run in lexFloat: %c", r) 452 | } 453 | 454 | func lexSymbol(l *lexer) stateFn { 455 | 456 | r := l.peek() 457 | 458 | switch r { 459 | case ' ', '\t', '\n': 460 | l.emit(_SYMBOL) 461 | l.next() 462 | return lexWhitespace 463 | case ')': 464 | l.emit(_SYMBOL) 465 | l.next() 466 | return lexCloseParen 467 | case ';': 468 | l.emit(_SYMBOL) 469 | l.next() 470 | return lexComment 471 | default: 472 | l.next() 473 | return lexSymbol 474 | } 475 | } 476 | 477 | // lex a close parenthesis 478 | func lexCloseParen(l *lexer) stateFn { 479 | l.emit(_RPAREN) 480 | l.parenDepth-- 481 | if l.parenDepth < 0 { 482 | return l.errorf("unexpected close paren") 483 | } 484 | 485 | r := l.next() 486 | switch r { 487 | case ' ', '\t', '\n': 488 | return lexWhitespace 489 | case '(': 490 | return lexOpenParen 491 | case ')': 492 | return lexCloseParen 493 | case ';': 494 | return lexComment 495 | } 496 | return l.errorf("unimplemented") 497 | } 498 | 499 | // lexes a comment 500 | func lexComment(l *lexer) stateFn { 501 | 502 | r := l.next() 503 | 504 | switch r { 505 | case '\n', '\r': 506 | return lexWhitespace 507 | } 508 | return lexComment 509 | } 510 | 511 | func lex(input string) *lexer { 512 | l := &lexer{ 513 | // name: name, 514 | input: input, 515 | tokens: make(chan token), 516 | } 517 | go l.run() 518 | return l 519 | } 520 | 521 | func parse(l *lexer, p []Any) []Any { 522 | 523 | for { 524 | t := l.nextToken() 525 | if t.typ == _EOF { 526 | break 527 | } else if t.typ == _INVALID { 528 | panic("syntax error") 529 | } 530 | 531 | if t.typ == _LPAREN { 532 | p = append(p, parse(l, []Any{})) 533 | return parse(l, p) 534 | } else if t.typ == _RPAREN { 535 | return p 536 | } else { 537 | var v Any 538 | switch t.typ { 539 | case _UNQUOTESPLICE: 540 | nextExp := parse(l, []Any{}) 541 | return append(append(p, []Any{Symbol("unquote-splice"), nextExp[0]}), nextExp[1:]...) 542 | case _UNQUOTE: 543 | nextExp := parse(l, []Any{}) 544 | return append(append(p, []Any{Symbol("unquote"), nextExp[0]}), nextExp[1:]...) 545 | case _QUASIQUOTE: 546 | nextExp := parse(l, []Any{}) 547 | return append(append(p, []Any{Symbol("quasiquote"), nextExp[0]}), nextExp[1:]...) 548 | case _QUOTE: 549 | nextExp := parse(l, []Any{}) 550 | return append(append(p, []Any{Symbol("quote"), nextExp[0]}), nextExp[1:]...) 551 | case _INT: 552 | v, _ = strconv.ParseInt(t.val, 10, 0) 553 | case _FLOAT: 554 | v, _ = strconv.ParseFloat(t.val, 64) 555 | case _STRING: 556 | v = t.val[1 : len(t.val)-1] 557 | case _BOOL: 558 | if t.val == "#t" { 559 | v = true 560 | } else { 561 | v = false 562 | } 563 | case _SYMBOL: 564 | v = Symbol(t.val) 565 | } 566 | return parse(l, append(p, v)) 567 | } 568 | } 569 | 570 | return p 571 | } 572 | 573 | func CamelCase(src string) string { 574 | var camelingRegex = regexp.MustCompile("[0-9A-Za-z]+") 575 | byteSrc := []byte(src) 576 | chunks := camelingRegex.FindAll(byteSrc, -1) 577 | for idx, val := range chunks { 578 | //if idx > 0 { chunks[idx] = bytes.Title(val) } 579 | chunks[idx] = bytes.Title(val) 580 | } 581 | 582 | return string(bytes.Join(chunks, nil)) 583 | } 584 | 585 | func main() { 586 | fmt.Println(CamelCase("this-is-a-clojure-name")) 587 | r := bufio.NewReader(os.Stdin) 588 | 589 | for { 590 | fmt.Print(">> ") 591 | line, _, _ := r.ReadLine() 592 | 593 | l := lex(string(line) + "\n") 594 | p := parse(l, []Any{}) 595 | fmt.Printf("%#v\n", p) 596 | } 597 | } 598 | -------------------------------------------------------------------------------- /play/output.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | var square = func(x Any) Any { 4 | println("Hello, World!") 5 | times(x, x) 6 | return func(y Any) Any { 7 | return id(y) 8 | }(x) 9 | } 10 | 11 | // Output ends here! 12 | 13 | type Any interface{} 14 | 15 | func times(x, y Any) int { 16 | return x.(int) * y.(int) 17 | } 18 | 19 | func id(y Any) Any { 20 | return y 21 | } 22 | 23 | func main() { 24 | square(10) 25 | } 26 | --------------------------------------------------------------------------------