├── .gitignore ├── LICENSE ├── README.md ├── ast ├── ast.go ├── ast_test.go ├── modify.go └── modify_test.go ├── eval ├── builtin.go ├── eval.go ├── eval_test.go ├── macro.go ├── macro_test.go ├── quote.go └── quote_test.go ├── lexer ├── lexer.go └── lexer_test.go ├── main.go ├── object ├── environment.go ├── object.go └── object_test.go ├── parser ├── parser.go └── parser_test.go ├── repl └── repl.go ├── token └── token.go └── wercker.yml /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Soshi Katsuta 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Monkey interpreter 2 | 3 | [![wercker status](https://app.wercker.com/status/20b05c4eb17fc957ff322da01bb157fc/s/master "wercker status")](https://app.wercker.com/project/byKey/20b05c4eb17fc957ff322da01bb157fc) 4 | [![Go Report Card](https://goreportcard.com/badge/github.com/skatsuta/monkey-interpreter)](https://goreportcard.com/report/github.com/skatsuta/monkey-interpreter) 5 | [![GoDoc](https://godoc.org/github.com/skatsuta/monkey-interpreter?status.svg)](https://godoc.org/github.com/skatsuta/monkey-interpreter) 6 | 7 | 8 | Monkey programming language interpreter designed in [_Writing An Interpreter In Go_](https://interpreterbook.com/). 9 | 10 | 11 | ## Usage 12 | 13 | Install the Monkey interpreter using `go get`: 14 | 15 | ```sh 16 | $ go get -v -u github.com/skatsuta/monkey-interpreter/... 17 | ``` 18 | 19 | Then run REPL: 20 | 21 | ```sh 22 | $ $GOPATH/bin/monkey-interpreter 23 | This is the Monkey programming language! 24 | Feel free to type in commands 25 | >> 26 | ``` 27 | 28 | Or run a Monkey script file (for example `script.monkey` file): 29 | 30 | ```sh 31 | $ $GOPATH/bin/monkey-interpreter script.monkey 32 | ``` 33 | 34 | ## Getting started with Monkey 35 | 36 | ### Variable bindings and number types 37 | 38 | You can define variables using `let` keyword. Supported number types are integers and floating-point numbers. 39 | 40 | ```sh 41 | >> let a = 1; 42 | >> a 43 | 1 44 | >> let b = 0.5; 45 | >> b 46 | 0.5 47 | ``` 48 | 49 | ### Arithmetic expressions 50 | 51 | You can do usual arithmetic operations against numbers, such as `+`, `-`, `*` and `/`. 52 | 53 | ```sh 54 | >> let a = 10; 55 | >> let b = a * 2; 56 | >> (a + b) / 2 - 3; 57 | 12 58 | >> let c = 2.5; 59 | >> b + c 60 | 22.5 61 | ``` 62 | 63 | ### If expressions 64 | 65 | You can use `if` and `else` keywords for conditional expressions. The last value in an executed block are returned from the expression. 66 | 67 | ```sh 68 | >> let a = 10; 69 | >> let b = a * 2; 70 | >> let c = if (b > a) { 99 } else { 100 }; 71 | >> c 72 | 99 73 | ``` 74 | 75 | ### Functions and closures 76 | 77 | You can define functions using `fn` keyword. All functions are closures in Monkey and you must use `let` along with `fn` to bind a closure to a variable. Closures enclose an environment where they are defined, and are evaluated in *the* environment when called. The last value in an executed function body are returned as a return value. 78 | 79 | ```sh 80 | >> let multiply = fn(x, y) { x * y }; 81 | >> multiply(50 / 2, 1 * 2) 82 | 50 83 | >> fn(x) { x + 10 }(10) 84 | 20 85 | >> let newAdder = fn(x) { fn(y) { x + y }; }; 86 | >> let addTwo = newAdder(2); 87 | >> addTwo(3); 88 | 5 89 | >> let sub = fn(a, b) { a - b }; 90 | >> let applyFunc = fn(a, b, func) { func(a, b) }; 91 | >> applyFunc(10, 2, sub); 92 | 8 93 | ``` 94 | 95 | ### Strings 96 | 97 | You can build strings using a pair of double quotes `""`. Strings are immutable values just like numbers. You can concatenate strings with `+` operator. 98 | 99 | ```sh 100 | >> let makeGreeter = fn(greeting) { fn(name) { greeting + " " + name + "!" } }; 101 | >> let hello = makeGreeter("Hello"); 102 | >> hello("John"); 103 | Hello John! 104 | ``` 105 | 106 | ### Arrays 107 | 108 | You can build arrays using square brackets `[]`. Arrays can contain any type of values, such as integers, strings, even arrays and functions (closures). To get an element at an index from an array, use `array[index]` syntax. 109 | 110 | ```sh 111 | >> let myArray = ["Thorsten", "Ball", 28, fn(x) { x * x }]; 112 | >> myArray[0] 113 | Thorsten 114 | >> myArray[4 - 2] 115 | 28 116 | >> myArray[3](2); 117 | 4 118 | ``` 119 | 120 | ### Hash tables 121 | 122 | You can build hash tables using curly brackets `{}`. Hash literals are `{key1: value1, key2: value2, ...}`. You can use numbers, strings and booleans as keys, and any type of objects as values. To get a value of a key from a hash table, use `hash[key]` syntax. 123 | 124 | ```sh 125 | >> let myHash = {"name": "Jimmy", "age": 72, true: "yes, a boolean", 99: "correct, an integer"}; 126 | >> myHash["name"] 127 | Jimmy 128 | >> myHash["age"] 129 | 72 130 | >> myHash[true] 131 | yes, a boolean 132 | >> myHash[99] 133 | correct, an integer 134 | ``` 135 | 136 | ### Built-in functions 137 | 138 | There are many built-in functions in Monkey, for example `len()`, `first()` and `last()`. Special function, `quote`, returns an unevaluated code block (think it as an AST). Opposite function to `quote`, `unquote`, evaluates code inside `quote`. 139 | 140 | ```sh 141 | >> len("hello"); 142 | 5 143 | >> len("∑"); 144 | 3 145 | >> let myArray = ["one", "two", "three"]; 146 | >> len(myArray) 147 | 3 148 | >> first(myArray) 149 | one 150 | >> rest(myArray) 151 | [two, three] 152 | >> last(myArray) 153 | three 154 | >> push(myArray, "four") 155 | [one, two, three, four] 156 | >> puts("Hello World") 157 | Hello World 158 | nil 159 | >> quote(2 + 2) 160 | Quote((2 + 2)) # Unevaluated code 161 | >> quote(unquote(1 + 2)) 162 | Quote(3) 163 | ``` 164 | 165 | ### Macros 166 | 167 | You can define macros using `macro` keyword. Note that macro definitions must return `Quote` objects generated from `quote` function. 168 | 169 | ```sh 170 | # Define `unless` macro which does the opposite to `if` 171 | >> let unless = macro(condition, consequence, alternative) { 172 | quote( 173 | if (!(unquote(condition))) { 174 | unquote(consequence); 175 | } else { 176 | unquote(alternative); 177 | } 178 | ); 179 | }; 180 | >> unless(10 > 5, puts("not greater"), puts("greater")); 181 | greater 182 | nil 183 | ``` 184 | -------------------------------------------------------------------------------- /ast/ast.go: -------------------------------------------------------------------------------- 1 | package ast 2 | 3 | import ( 4 | "bytes" 5 | "strings" 6 | 7 | "github.com/skatsuta/monkey-interpreter/token" 8 | ) 9 | 10 | // Node represents an AST node. 11 | type Node interface { 12 | TokenLiteral() string 13 | String() string 14 | } 15 | 16 | // Statement represents a statement. 17 | type Statement interface { 18 | Node 19 | statementNode() 20 | } 21 | 22 | // Expression represents an expression. 23 | type Expression interface { 24 | Node 25 | expressionNode() 26 | } 27 | 28 | // Program is a top-level AST node of a program. 29 | type Program struct { 30 | Statements []Statement 31 | } 32 | 33 | // TokenLiteral returns the first token literal of a program. 34 | func (p *Program) TokenLiteral() string { 35 | if len(p.Statements) == 0 { 36 | return "" 37 | } 38 | return p.Statements[0].TokenLiteral() 39 | } 40 | 41 | func (p *Program) String() string { 42 | var out bytes.Buffer 43 | 44 | for _, s := range p.Statements { 45 | out.WriteString(s.String()) 46 | } 47 | 48 | return out.String() 49 | } 50 | 51 | // LetStatement represents a let statement. 52 | type LetStatement struct { 53 | Token token.Token // the token.LET token 54 | Name *Ident 55 | Value Expression 56 | } 57 | 58 | func (ls *LetStatement) statementNode() {} 59 | 60 | // TokenLiteral returns a token literal of let statement. 61 | func (ls *LetStatement) TokenLiteral() string { 62 | return ls.Token.Literal 63 | } 64 | 65 | func (ls *LetStatement) String() string { 66 | var out bytes.Buffer 67 | 68 | out.WriteString(ls.TokenLiteral() + " ") 69 | out.WriteString(ls.Name.String()) 70 | out.WriteString(" = ") 71 | 72 | if ls.Value != nil { 73 | out.WriteString(ls.Value.String()) 74 | } 75 | 76 | out.WriteString(";") 77 | 78 | return out.String() 79 | } 80 | 81 | // Ident represents an identifier. 82 | type Ident struct { 83 | Token token.Token // the token.IDENT token 84 | Value string 85 | } 86 | 87 | func (i *Ident) expressionNode() {} 88 | 89 | // TokenLiteral returns a token literal of an identifier. 90 | func (i *Ident) TokenLiteral() string { 91 | return i.Token.Literal 92 | } 93 | 94 | func (i *Ident) String() string { 95 | return i.Value 96 | } 97 | 98 | // ReturnStatement represents a return statement. 99 | type ReturnStatement struct { 100 | Token token.Token // the token.RETURN token 101 | ReturnValue Expression 102 | } 103 | 104 | func (rs *ReturnStatement) statementNode() {} 105 | 106 | // TokenLiteral returns a token literal of return statement. 107 | func (rs *ReturnStatement) TokenLiteral() string { 108 | return rs.Token.Literal 109 | } 110 | 111 | func (rs *ReturnStatement) String() string { 112 | var out bytes.Buffer 113 | 114 | out.WriteString(rs.TokenLiteral() + " ") 115 | 116 | if rs.ReturnValue != nil { 117 | out.WriteString(rs.ReturnValue.String()) 118 | } 119 | 120 | out.WriteString(";") 121 | 122 | return out.String() 123 | } 124 | 125 | // ExpressionStatement represents an expression statement. 126 | type ExpressionStatement struct { 127 | Token token.Token // the first token of the expression 128 | Expression Expression 129 | } 130 | 131 | func (es *ExpressionStatement) statementNode() {} 132 | 133 | // TokenLiteral returns a token literal of expression statement. 134 | func (es *ExpressionStatement) TokenLiteral() string { 135 | return es.Token.Literal 136 | } 137 | 138 | func (es *ExpressionStatement) String() string { 139 | if es.Expression != nil { 140 | return es.Expression.String() 141 | } 142 | 143 | return "" 144 | } 145 | 146 | // IntegerLiteral represents an integer literal. 147 | type IntegerLiteral struct { 148 | Token token.Token 149 | Value int64 150 | } 151 | 152 | func (il *IntegerLiteral) expressionNode() {} 153 | 154 | // TokenLiteral returns a token literal of integer. 155 | func (il *IntegerLiteral) TokenLiteral() string { 156 | return il.Token.Literal 157 | } 158 | 159 | func (il *IntegerLiteral) String() string { 160 | return il.Token.Literal 161 | } 162 | 163 | // FloatLiteral represents a floating point number literal. 164 | type FloatLiteral struct { 165 | Token token.Token 166 | Value float64 167 | } 168 | 169 | func (fl *FloatLiteral) expressionNode() {} 170 | 171 | // TokenLiteral returns a token literal of floating point number. 172 | func (fl *FloatLiteral) TokenLiteral() string { 173 | return fl.Token.Literal 174 | } 175 | 176 | func (fl *FloatLiteral) String() string { 177 | return fl.Token.Literal 178 | } 179 | 180 | // PrefixExpression represents a prefix expression. 181 | type PrefixExpression struct { 182 | Token token.Token // The prefix token, e.g. ! 183 | Operator string 184 | Right Expression 185 | } 186 | 187 | func (pe *PrefixExpression) expressionNode() {} 188 | 189 | // TokenLiteral returns a token literal. 190 | func (pe *PrefixExpression) TokenLiteral() string { 191 | return pe.Token.Literal 192 | } 193 | 194 | func (pe *PrefixExpression) String() string { 195 | var out bytes.Buffer 196 | 197 | out.WriteString("(") 198 | out.WriteString(pe.Operator) 199 | out.WriteString(pe.Right.String()) 200 | out.WriteString(")") 201 | 202 | return out.String() 203 | } 204 | 205 | // InfixExpression represents an infix expression. 206 | type InfixExpression struct { 207 | Token token.Token // The operator token, e.g. + 208 | Left Expression 209 | Operator string 210 | Right Expression 211 | } 212 | 213 | func (ie *InfixExpression) expressionNode() {} 214 | 215 | // TokenLiteral returns a token literal. 216 | func (ie *InfixExpression) TokenLiteral() string { 217 | return ie.Token.Literal 218 | } 219 | 220 | func (ie *InfixExpression) String() string { 221 | var out bytes.Buffer 222 | 223 | out.WriteString("(") 224 | out.WriteString(ie.Left.String()) 225 | out.WriteString(" " + ie.Operator + " ") 226 | out.WriteString(ie.Right.String()) 227 | out.WriteString(")") 228 | 229 | return out.String() 230 | } 231 | 232 | // Boolean represents a boolean value. 233 | type Boolean struct { 234 | Token token.Token 235 | Value bool 236 | } 237 | 238 | func (b *Boolean) expressionNode() {} 239 | 240 | // TokenLiteral returns a token literal of boolean value. 241 | func (b *Boolean) TokenLiteral() string { 242 | return b.Token.Literal 243 | } 244 | 245 | func (b *Boolean) String() string { 246 | return b.Token.Literal 247 | } 248 | 249 | // IfExpression represents an if expression. 250 | type IfExpression struct { 251 | Token token.Token // The 'if' token 252 | Condition Expression 253 | Consequence *BlockStatement 254 | Alternative *BlockStatement 255 | } 256 | 257 | func (ie *IfExpression) expressionNode() {} 258 | 259 | // TokenLiteral returns a token literal of if expression. 260 | func (ie *IfExpression) TokenLiteral() string { 261 | return ie.Token.Literal 262 | } 263 | 264 | func (ie *IfExpression) String() string { 265 | var out bytes.Buffer 266 | 267 | out.WriteString("if") 268 | out.WriteString(ie.Condition.String()) 269 | out.WriteString(" ") 270 | out.WriteString(ie.Consequence.String()) 271 | 272 | if ie.Alternative != nil { 273 | out.WriteString("else ") 274 | out.WriteString(ie.Alternative.String()) 275 | } 276 | 277 | return out.String() 278 | } 279 | 280 | // BlockStatement represents a block statement. 281 | type BlockStatement struct { 282 | Token token.Token // the '{' token 283 | Statements []Statement 284 | } 285 | 286 | func (bs *BlockStatement) expressionNode() {} 287 | 288 | // TokenLiteral returns a token literal of block statement. 289 | func (bs *BlockStatement) TokenLiteral() string { 290 | return bs.Token.Literal 291 | } 292 | 293 | func (bs *BlockStatement) String() string { 294 | var out bytes.Buffer 295 | 296 | for _, s := range bs.Statements { 297 | out.WriteString(s.String()) 298 | } 299 | 300 | return out.String() 301 | } 302 | 303 | // FunctionLiteral represents a fuction literal. 304 | type FunctionLiteral struct { 305 | Token token.Token 306 | Parameters []*Ident 307 | Body *BlockStatement 308 | } 309 | 310 | func (fl *FunctionLiteral) expressionNode() {} 311 | 312 | // TokenLiteral returns a token literal of function. 313 | func (fl *FunctionLiteral) TokenLiteral() string { 314 | return fl.Token.Literal 315 | } 316 | 317 | func (fl *FunctionLiteral) String() string { 318 | var out bytes.Buffer 319 | 320 | params := make([]string, 0, len(fl.Parameters)) 321 | for _, p := range fl.Parameters { 322 | params = append(params, p.String()) 323 | } 324 | 325 | out.WriteString(fl.TokenLiteral()) 326 | out.WriteString("(") 327 | out.WriteString(strings.Join(params, ", ")) 328 | out.WriteString(") ") 329 | out.WriteString(fl.Body.String()) 330 | 331 | return out.String() 332 | } 333 | 334 | // CallExpression represents a function call expression. 335 | type CallExpression struct { 336 | Token token.Token // the '(' token 337 | Function Expression // Ident or FunctionLiteral 338 | Arguments []Expression 339 | } 340 | 341 | func (ce *CallExpression) expressionNode() {} 342 | 343 | // TokenLiteral returns a token literal of function call expression. 344 | func (ce *CallExpression) TokenLiteral() string { 345 | return ce.Token.Literal 346 | } 347 | 348 | func (ce *CallExpression) String() string { 349 | var out bytes.Buffer 350 | 351 | args := make([]string, 0, len(ce.Arguments)) 352 | for _, arg := range ce.Arguments { 353 | args = append(args, arg.String()) 354 | } 355 | 356 | out.WriteString(ce.Function.String()) 357 | out.WriteString("(") 358 | out.WriteString(strings.Join(args, ", ")) 359 | out.WriteString(")") 360 | 361 | return out.String() 362 | } 363 | 364 | // StringLiteral represents a string literal. 365 | type StringLiteral struct { 366 | Token token.Token 367 | Value string 368 | } 369 | 370 | func (sl *StringLiteral) expressionNode() {} 371 | 372 | // TokenLiteral returns a token literal of string. 373 | func (sl *StringLiteral) TokenLiteral() string { 374 | if sl == nil { 375 | return "" 376 | } 377 | return sl.Token.Literal 378 | } 379 | 380 | func (sl *StringLiteral) String() string { 381 | return sl.TokenLiteral() 382 | } 383 | 384 | // ArrayLiteral represents an array literal. 385 | type ArrayLiteral struct { 386 | Token token.Token // the '[' token 387 | Elements []Expression 388 | } 389 | 390 | func (*ArrayLiteral) expressionNode() {} 391 | 392 | // TokenLiteral returns a token literal of array. 393 | func (al *ArrayLiteral) TokenLiteral() string { 394 | if al == nil { 395 | return "" 396 | } 397 | return al.Token.Literal 398 | } 399 | 400 | func (al *ArrayLiteral) String() string { 401 | if al == nil { 402 | return "" 403 | } 404 | 405 | elements := make([]string, 0, len(al.Elements)) 406 | for _, el := range al.Elements { 407 | elements = append(elements, el.String()) 408 | } 409 | 410 | var out bytes.Buffer 411 | 412 | out.WriteString("[") 413 | out.WriteString(strings.Join(elements, ", ")) 414 | out.WriteString("]") 415 | 416 | return out.String() 417 | } 418 | 419 | // IndexExpression represents an expression in array index operator. 420 | type IndexExpression struct { 421 | Token token.Token // the '[' token 422 | Left Expression 423 | Index Expression 424 | } 425 | 426 | func (*IndexExpression) expressionNode() {} 427 | 428 | // TokenLiteral returns a token literal of array. 429 | func (ie *IndexExpression) TokenLiteral() string { 430 | if ie == nil { 431 | return "" 432 | } 433 | return ie.Token.Literal 434 | } 435 | 436 | func (ie *IndexExpression) String() string { 437 | if ie == nil { 438 | return "" 439 | } 440 | 441 | var out bytes.Buffer 442 | 443 | out.WriteString("(") 444 | out.WriteString(ie.Left.String()) 445 | out.WriteString("[") 446 | out.WriteString(ie.Index.String()) 447 | out.WriteString("])") 448 | 449 | return out.String() 450 | } 451 | 452 | // HashLiteral represents a hash literal. 453 | type HashLiteral struct { 454 | Token token.Token // the '{' token 455 | Pairs map[Expression]Expression 456 | } 457 | 458 | func (*HashLiteral) expressionNode() {} 459 | 460 | // TokenLiteral returns a token literal of hash. 461 | func (hl *HashLiteral) TokenLiteral() string { 462 | if hl == nil { 463 | return "" 464 | } 465 | return hl.Token.Literal 466 | } 467 | 468 | func (hl *HashLiteral) String() string { 469 | if hl == nil { 470 | return "" 471 | } 472 | 473 | pairs := make([]string, len(hl.Pairs)) 474 | for key, value := range hl.Pairs { 475 | pairs = append(pairs, key.String()+": "+value.String()) 476 | } 477 | 478 | var out bytes.Buffer 479 | out.WriteString("{") 480 | out.WriteString(strings.Join(pairs, ", ")) 481 | out.WriteString("}") 482 | return out.String() 483 | } 484 | 485 | // MacroLiteral represents a macro literal. 486 | type MacroLiteral struct { 487 | Token token.Token 488 | Parameters []*Ident 489 | Body *BlockStatement 490 | } 491 | 492 | func (ml *MacroLiteral) expressionNode() {} 493 | 494 | // TokenLiteral returns a token literal of function. 495 | func (ml *MacroLiteral) TokenLiteral() string { 496 | return ml.Token.Literal 497 | } 498 | 499 | func (ml *MacroLiteral) String() string { 500 | var out bytes.Buffer 501 | 502 | params := make([]string, 0, len(ml.Parameters)) 503 | for _, p := range ml.Parameters { 504 | params = append(params, p.String()) 505 | } 506 | 507 | out.WriteString(ml.TokenLiteral()) 508 | out.WriteString("(") 509 | out.WriteString(strings.Join(params, ", ")) 510 | out.WriteString(") ") 511 | out.WriteString(ml.Body.String()) 512 | 513 | return out.String() 514 | } 515 | -------------------------------------------------------------------------------- /ast/ast_test.go: -------------------------------------------------------------------------------- 1 | package ast 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/skatsuta/monkey-interpreter/token" 7 | ) 8 | 9 | func TestString(t *testing.T) { 10 | program := &Program{ 11 | Statements: []Statement{ 12 | &LetStatement{ 13 | Token: token.Token{Type: token.LET, Literal: "let"}, 14 | Name: &Ident{ 15 | Token: token.Token{Type: token.IDENT, Literal: "myVar"}, 16 | Value: "myVar", 17 | }, 18 | Value: &Ident{ 19 | Token: token.Token{Type: token.IDENT, Literal: "anotherVar"}, 20 | Value: "anotherVar", 21 | }, 22 | }, 23 | }, 24 | } 25 | 26 | if program.String() != "let myVar = anotherVar;" { 27 | t.Errorf("program.String() wrong. got=%T", program.String()) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ast/modify.go: -------------------------------------------------------------------------------- 1 | package ast 2 | 3 | // ModifierFunc represents a function which modifies a node. 4 | type ModifierFunc func(Node) Node 5 | 6 | // Modify modifies a `node` using `modifier` function. 7 | func Modify(node Node, modifier ModifierFunc) Node { 8 | switch node := node.(type) { 9 | case *Program: 10 | for i, stmt := range node.Statements { 11 | node.Statements[i] = Modify(stmt, modifier).(Statement) 12 | } 13 | case *ExpressionStatement: 14 | node.Expression = Modify(node.Expression, modifier).(Expression) 15 | case *InfixExpression: 16 | node.Left = Modify(node.Left, modifier).(Expression) 17 | node.Right = Modify(node.Right, modifier).(Expression) 18 | case *PrefixExpression: 19 | node.Right = Modify(node.Right, modifier).(Expression) 20 | case *IndexExpression: 21 | node.Left = Modify(node.Left, modifier).(Expression) 22 | node.Index = Modify(node.Index, modifier).(Expression) 23 | case *IfExpression: 24 | node.Condition = Modify(node.Condition, modifier).(Expression) 25 | node.Consequence = Modify(node.Consequence, modifier).(*BlockStatement) 26 | if node.Alternative != nil { 27 | node.Alternative = Modify(node.Alternative, modifier).(*BlockStatement) 28 | } 29 | case *BlockStatement: 30 | for i, stmt := range node.Statements { 31 | node.Statements[i] = Modify(stmt, modifier).(Statement) 32 | } 33 | case *ReturnStatement: 34 | node.ReturnValue = Modify(node.ReturnValue, modifier).(Expression) 35 | case *LetStatement: 36 | node.Value = Modify(node.Value, modifier).(Expression) 37 | case *FunctionLiteral: 38 | for i, param := range node.Parameters { 39 | node.Parameters[i] = Modify(param, modifier).(*Ident) 40 | } 41 | node.Body = Modify(node.Body, modifier).(*BlockStatement) 42 | case *ArrayLiteral: 43 | for i, elem := range node.Elements { 44 | node.Elements[i] = Modify(elem, modifier).(Expression) 45 | } 46 | case *HashLiteral: 47 | newPairs := make(map[Expression]Expression, len(node.Pairs)) 48 | for key, val := range node.Pairs { 49 | newKey := Modify(key, modifier).(Expression) 50 | newVal := Modify(val, modifier).(Expression) 51 | newPairs[newKey] = newVal 52 | } 53 | node.Pairs = newPairs 54 | } 55 | 56 | return modifier(node) 57 | } 58 | -------------------------------------------------------------------------------- /ast/modify_test.go: -------------------------------------------------------------------------------- 1 | package ast 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | func createIntLitFunc(i int64) func() Expression { 9 | return func() Expression { return &IntegerLiteral{Value: i} } 10 | } 11 | 12 | func TestModify(t *testing.T) { 13 | one := createIntLitFunc(1) 14 | two := createIntLitFunc(2) 15 | 16 | turnOneIntoTwo := func(node Node) Node { 17 | i, ok := node.(*IntegerLiteral) 18 | if !ok { 19 | return node 20 | } 21 | 22 | if i.Value != 1 { 23 | return node 24 | } 25 | 26 | i.Value = 2 27 | return i 28 | } 29 | 30 | tests := []struct { 31 | input Node 32 | want Node 33 | }{ 34 | { 35 | input: one(), 36 | want: two(), 37 | }, 38 | { 39 | input: &Program{Statements: []Statement{&ExpressionStatement{Expression: one()}}}, 40 | want: &Program{Statements: []Statement{&ExpressionStatement{Expression: two()}}}, 41 | }, 42 | { 43 | input: &InfixExpression{Left: one(), Operator: "+", Right: two()}, 44 | want: &InfixExpression{Left: two(), Operator: "+", Right: two()}, 45 | }, 46 | { 47 | input: &InfixExpression{Left: two(), Operator: "+", Right: one()}, 48 | want: &InfixExpression{Left: two(), Operator: "+", Right: two()}, 49 | }, 50 | { 51 | input: &PrefixExpression{Operator: "-", Right: one()}, 52 | want: &PrefixExpression{Operator: "-", Right: two()}, 53 | }, 54 | { 55 | input: &IndexExpression{Left: one(), Index: one()}, 56 | want: &IndexExpression{Left: two(), Index: two()}, 57 | }, 58 | { 59 | input: &IfExpression{ 60 | Condition: one(), 61 | Consequence: &BlockStatement{ 62 | Statements: []Statement{&ExpressionStatement{Expression: one()}}, 63 | }, 64 | Alternative: &BlockStatement{ 65 | Statements: []Statement{&ExpressionStatement{Expression: one()}}, 66 | }, 67 | }, 68 | want: &IfExpression{ 69 | Condition: two(), 70 | Consequence: &BlockStatement{ 71 | Statements: []Statement{&ExpressionStatement{Expression: two()}}, 72 | }, 73 | Alternative: &BlockStatement{ 74 | Statements: []Statement{&ExpressionStatement{Expression: two()}}, 75 | }, 76 | }, 77 | }, 78 | { 79 | input: &ReturnStatement{ReturnValue: one()}, 80 | want: &ReturnStatement{ReturnValue: two()}, 81 | }, 82 | { 83 | input: &LetStatement{Value: one()}, 84 | want: &LetStatement{Value: two()}, 85 | }, 86 | { 87 | input: &FunctionLiteral{ 88 | Parameters: []*Ident{}, 89 | Body: &BlockStatement{ 90 | Statements: []Statement{&ExpressionStatement{Expression: one()}}, 91 | }, 92 | }, 93 | want: &FunctionLiteral{ 94 | Parameters: []*Ident{}, 95 | Body: &BlockStatement{ 96 | Statements: []Statement{&ExpressionStatement{Expression: two()}}, 97 | }, 98 | }, 99 | }, 100 | { 101 | input: &ArrayLiteral{Elements: []Expression{one(), one()}}, 102 | want: &ArrayLiteral{Elements: []Expression{two(), two()}}, 103 | }, 104 | } 105 | 106 | for _, tt := range tests { 107 | got := Modify(tt.input, turnOneIntoTwo) 108 | 109 | if !reflect.DeepEqual(got, tt.want) { 110 | t.Errorf("expected %#v, but got %#v", tt.want, got) 111 | } 112 | } 113 | 114 | // Test for hash literals 115 | 116 | hashLit := &HashLiteral{ 117 | Pairs: map[Expression]Expression{ 118 | one(): one(), 119 | one(): one(), 120 | }, 121 | } 122 | 123 | Modify(hashLit, turnOneIntoTwo) 124 | 125 | for key, val := range hashLit.Pairs { 126 | key := key.(*IntegerLiteral) 127 | if key.Value != 2 { 128 | t.Errorf("key is not %d and got %d", 2, key.Value) 129 | } 130 | val := val.(*IntegerLiteral) 131 | if val.Value != 2 { 132 | t.Errorf("value is not %d and got %d", 2, key.Value) 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /eval/builtin.go: -------------------------------------------------------------------------------- 1 | package eval 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/skatsuta/monkey-interpreter/object" 7 | ) 8 | 9 | var builtins = map[string]*object.Builtin{ 10 | "len": { 11 | Fn: func(args ...object.Object) object.Object { 12 | if l := len(args); l != 1 { 13 | return newError("wrong number of arguments. want=1, got=%d", l) 14 | } 15 | 16 | switch arg := args[0].(type) { 17 | case *object.String: 18 | return &object.Integer{Value: int64(len(arg.Value))} 19 | case *object.Array: 20 | return &object.Integer{Value: int64(len(arg.Elements))} 21 | default: 22 | return newError("argument to `len` not supported, got %s", arg.Type()) 23 | } 24 | }, 25 | }, 26 | 27 | "first": { 28 | Fn: func(args ...object.Object) object.Object { 29 | if l := len(args); l != 1 { 30 | return newError("wrong number of arguments. want=1, got=%d", l) 31 | } 32 | 33 | if typ := args[0].Type(); typ != object.ArrayType { 34 | return newError("argument to `first` must be Array, got %s", typ) 35 | } 36 | 37 | arr := args[0].(*object.Array) 38 | if len(arr.Elements) == 0 { 39 | return NilValue 40 | } 41 | return arr.Elements[0] 42 | }, 43 | }, 44 | 45 | "last": { 46 | Fn: func(args ...object.Object) object.Object { 47 | if l := len(args); l != 1 { 48 | return newError("wrong number of arguments. want=1, got=%d", l) 49 | } 50 | 51 | if typ := args[0].Type(); typ != object.ArrayType { 52 | return newError("argument to `last` must be Array, got %s", typ) 53 | } 54 | 55 | arr := args[0].(*object.Array) 56 | l := len(arr.Elements) 57 | if l == 0 { 58 | return NilValue 59 | } 60 | return arr.Elements[l-1] 61 | }, 62 | }, 63 | 64 | "rest": { 65 | Fn: func(args ...object.Object) object.Object { 66 | if l := len(args); l != 1 { 67 | return newError("wrong number of arguments. want=1, got=%d", l) 68 | } 69 | 70 | if typ := args[0].Type(); typ != object.ArrayType { 71 | return newError("argument to `last` must be Array, got %s", typ) 72 | } 73 | 74 | arr := args[0].(*object.Array) 75 | l := len(arr.Elements) 76 | if l == 0 { 77 | return NilValue 78 | } 79 | 80 | newElems := make([]object.Object, l-1) 81 | copy(newElems, arr.Elements[1:l]) 82 | return &object.Array{Elements: newElems} 83 | }, 84 | }, 85 | 86 | "push": { 87 | Fn: func(args ...object.Object) object.Object { 88 | if l := len(args); l != 2 { 89 | return newError("wrong number of arguments. want=%d, got=%d", 2, l) 90 | } 91 | 92 | if typ := args[0].Type(); typ != object.ArrayType { 93 | return newError("first argument to `push` must be Array, got %s", typ) 94 | } 95 | 96 | arr := args[0].(*object.Array) 97 | l := len(arr.Elements) 98 | 99 | newElems := make([]object.Object, l+1) 100 | copy(newElems, arr.Elements) 101 | newElems[l] = args[1] 102 | return &object.Array{Elements: newElems} 103 | }, 104 | }, 105 | 106 | "puts": { 107 | Fn: func(args ...object.Object) object.Object { 108 | for _, arg := range args { 109 | fmt.Println(arg.Inspect()) 110 | } 111 | return NilValue 112 | }, 113 | }, 114 | } 115 | -------------------------------------------------------------------------------- /eval/eval.go: -------------------------------------------------------------------------------- 1 | package eval 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/skatsuta/monkey-interpreter/ast" 7 | "github.com/skatsuta/monkey-interpreter/object" 8 | ) 9 | 10 | var ( 11 | // NilValue represents a value of nil reference. 12 | NilValue = &object.Nil{} 13 | // TrueValue represents a value of true literals. 14 | TrueValue = &object.Boolean{Value: true} 15 | // FalseValue represents a value of false literals. 16 | FalseValue = &object.Boolean{Value: false} 17 | ) 18 | 19 | // Eval evaluates the given node and returns an evaluated object. 20 | func Eval(node ast.Node, env object.Environment) object.Object { 21 | switch node := node.(type) { 22 | // Statements 23 | 24 | case *ast.Program: 25 | return evalProgram(node, env) 26 | 27 | case *ast.ExpressionStatement: 28 | return Eval(node.Expression, env) 29 | 30 | case *ast.ReturnStatement: 31 | value := Eval(node.ReturnValue, env) 32 | if isError(value) { 33 | return value 34 | } 35 | return &object.ReturnValue{Value: value} 36 | 37 | case *ast.BlockStatement: 38 | return evalBlockStatement(node, env) 39 | 40 | case *ast.LetStatement: 41 | value := Eval(node.Value, env) 42 | if isError(value) { 43 | return value 44 | } 45 | env.Set(node.Name.Value, value) 46 | 47 | // Expressions 48 | 49 | case *ast.IntegerLiteral: 50 | return &object.Integer{Value: node.Value} 51 | 52 | case *ast.FloatLiteral: 53 | return &object.Float{Value: node.Value} 54 | 55 | case *ast.Boolean: 56 | return nativeBoolToBooleanObject(node.Value) 57 | 58 | case *ast.PrefixExpression: 59 | right := Eval(node.Right, env) 60 | if isError(right) { 61 | return right 62 | } 63 | return evalPrefixExpression(node.Operator, right) 64 | 65 | case *ast.InfixExpression: 66 | left := Eval(node.Left, env) 67 | if isError(left) { 68 | return left 69 | } 70 | right := Eval(node.Right, env) 71 | if isError(right) { 72 | return right 73 | } 74 | return evalInfixExpression(node.Operator, left, right) 75 | 76 | case *ast.IfExpression: 77 | return evalIfExpression(node, env) 78 | 79 | case *ast.Ident: 80 | return evalIdent(node, env) 81 | 82 | case *ast.FunctionLiteral: 83 | return &object.Function{ 84 | Parameters: node.Parameters, 85 | Body: node.Body, 86 | Env: env, 87 | } 88 | 89 | case *ast.CallExpression: 90 | if node.Function.TokenLiteral() == FuncNameQuote { 91 | return quote(node.Arguments[0], env) 92 | } 93 | 94 | function := Eval(node.Function, env) 95 | if isError(function) { 96 | return function 97 | } 98 | 99 | args := evalExpressions(node.Arguments, env) 100 | if len(args) == 1 && isError(args[0]) { 101 | return args[0] 102 | } 103 | 104 | return applyFunction(function, args) 105 | 106 | case *ast.StringLiteral: 107 | return &object.String{Value: node.Value} 108 | 109 | case *ast.ArrayLiteral: 110 | elems := evalExpressions(node.Elements, env) 111 | if len(elems) == 1 && isError(elems[0]) { 112 | return elems[0] 113 | } 114 | return &object.Array{Elements: elems} 115 | 116 | case *ast.IndexExpression: 117 | left := Eval(node.Left, env) 118 | if isError(left) { 119 | return left 120 | } 121 | index := Eval(node.Index, env) 122 | if isError(index) { 123 | return index 124 | } 125 | return evalIndexExpression(left, index) 126 | 127 | case *ast.HashLiteral: 128 | return evalHashLiteral(node, env) 129 | } 130 | 131 | return nil 132 | } 133 | 134 | func evalProgram(program *ast.Program, env object.Environment) object.Object { 135 | var result object.Object 136 | 137 | for _, stmt := range program.Statements { 138 | result = Eval(stmt, env) 139 | 140 | switch result := result.(type) { 141 | case *object.ReturnValue: 142 | return result.Value 143 | case *object.Error: 144 | return result 145 | } 146 | } 147 | 148 | return result 149 | } 150 | 151 | func nativeBoolToBooleanObject(input bool) *object.Boolean { 152 | if input { 153 | return TrueValue 154 | } 155 | return FalseValue 156 | } 157 | 158 | func evalPrefixExpression(operator string, right object.Object) object.Object { 159 | switch operator { 160 | case "!": 161 | return evalBangOperatorExpression(right) 162 | case "-": 163 | return evalMinusPrefixOperatorExpression(right) 164 | default: 165 | return newError("unknown operator: %s%s", operator, right.Type()) 166 | } 167 | } 168 | 169 | func evalBangOperatorExpression(right object.Object) object.Object { 170 | if right == NilValue || right == FalseValue { 171 | return TrueValue 172 | } 173 | return FalseValue 174 | } 175 | 176 | func evalMinusPrefixOperatorExpression(right object.Object) object.Object { 177 | switch right := right.(type) { 178 | case *object.Integer: 179 | return &object.Integer{Value: -right.Value} 180 | case *object.Float: 181 | return &object.Float{Value: -right.Value} 182 | default: 183 | return newError("unknown operator: -%s", right.Type()) 184 | } 185 | } 186 | 187 | func evalInfixExpression(operator string, left, right object.Object) object.Object { 188 | switch { 189 | case left.Type() == object.IntegerType && right.Type() == object.IntegerType: 190 | return evalIntegerInfixExpression(operator, left, right) 191 | case left.Type() == object.FloatType || right.Type() == object.FloatType: 192 | return evalFloatInfixExpression(operator, left, right) 193 | case left.Type() == object.StringType && right.Type() == object.StringType: 194 | return evalStringInfixExpression(operator, left, right) 195 | case operator == "==": 196 | return nativeBoolToBooleanObject(left == right) 197 | case operator == "!=": 198 | return nativeBoolToBooleanObject(left != right) 199 | case left.Type() != right.Type(): 200 | return newError("type mismatch: %s %s %s", left.Type(), operator, right.Type()) 201 | default: 202 | return newError("unknown operator: %s %s %s", left.Type(), operator, right.Type()) 203 | } 204 | } 205 | 206 | func evalIntegerInfixExpression(operator string, left, right object.Object) object.Object { 207 | leftVal := left.(*object.Integer).Value 208 | rightVal := right.(*object.Integer).Value 209 | 210 | switch operator { 211 | case "+": 212 | return &object.Integer{Value: leftVal + rightVal} 213 | case "-": 214 | return &object.Integer{Value: leftVal - rightVal} 215 | case "*": 216 | return &object.Integer{Value: leftVal * rightVal} 217 | case "/": 218 | return &object.Integer{Value: leftVal / rightVal} 219 | case "<": 220 | return nativeBoolToBooleanObject(leftVal < rightVal) 221 | case ">": 222 | return nativeBoolToBooleanObject(leftVal > rightVal) 223 | case "<=": 224 | return nativeBoolToBooleanObject(leftVal <= rightVal) 225 | case ">=": 226 | return nativeBoolToBooleanObject(leftVal >= rightVal) 227 | case "==": 228 | return nativeBoolToBooleanObject(leftVal == rightVal) 229 | case "!=": 230 | return nativeBoolToBooleanObject(leftVal != rightVal) 231 | default: 232 | return newError("unknown operator: %s %s %s", left.Type(), operator, right.Type()) 233 | } 234 | } 235 | 236 | func evalFloatInfixExpression(operator string, left, right object.Object) object.Object { 237 | var leftVal, rightVal float64 238 | 239 | switch left := left.(type) { 240 | case *object.Integer: 241 | leftVal = float64(left.Value) 242 | case *object.Float: 243 | leftVal = left.Value 244 | default: 245 | return newError("unknown operator: %s %s %s", left.Type(), operator, right.Type()) 246 | } 247 | 248 | switch right := right.(type) { 249 | case *object.Integer: 250 | rightVal = float64(right.Value) 251 | case *object.Float: 252 | rightVal = right.Value 253 | default: 254 | return newError("unknown operator: %s %s %s", left.Type(), operator, right.Type()) 255 | } 256 | 257 | switch operator { 258 | case "+": 259 | return &object.Float{Value: leftVal + rightVal} 260 | case "-": 261 | return &object.Float{Value: leftVal - rightVal} 262 | case "*": 263 | return &object.Float{Value: leftVal * rightVal} 264 | case "/": 265 | return &object.Float{Value: leftVal / rightVal} 266 | case "<": 267 | return nativeBoolToBooleanObject(leftVal < rightVal) 268 | case ">": 269 | return nativeBoolToBooleanObject(leftVal > rightVal) 270 | case "<=": 271 | return nativeBoolToBooleanObject(leftVal <= rightVal) 272 | case ">=": 273 | return nativeBoolToBooleanObject(leftVal >= rightVal) 274 | case "==": 275 | return nativeBoolToBooleanObject(leftVal == rightVal) 276 | case "!=": 277 | return nativeBoolToBooleanObject(leftVal != rightVal) 278 | default: 279 | return newError("unknown operator: %s %s %s", left.Type(), operator, right.Type()) 280 | } 281 | } 282 | 283 | func evalStringInfixExpression(operator string, left, right object.Object) object.Object { 284 | leftVal := left.(*object.String).Value 285 | rightVal := right.(*object.String).Value 286 | 287 | switch operator { 288 | case "+": 289 | return &object.String{Value: leftVal + rightVal} 290 | case "==": 291 | return nativeBoolToBooleanObject(leftVal == rightVal) 292 | case "!=": 293 | return nativeBoolToBooleanObject(leftVal != rightVal) 294 | default: 295 | return newError("unknown operator: %s %s %s", left.Type(), operator, right.Type()) 296 | } 297 | } 298 | 299 | func evalBlockStatement(block *ast.BlockStatement, env object.Environment) object.Object { 300 | var result object.Object 301 | 302 | for _, stmt := range block.Statements { 303 | result = Eval(stmt, env) 304 | if result == nil { 305 | continue 306 | } 307 | 308 | if rt := result.Type(); rt == object.ReturnValueType || rt == object.ErrorType { 309 | return result 310 | } 311 | } 312 | 313 | return result 314 | } 315 | 316 | func evalIfExpression(ie *ast.IfExpression, env object.Environment) object.Object { 317 | condition := Eval(ie.Condition, env) 318 | if isError(condition) { 319 | return condition 320 | } 321 | 322 | if isTruthy(condition) { 323 | return Eval(ie.Consequence, env) 324 | } else if ie.Alternative != nil { 325 | return Eval(ie.Alternative, env) 326 | } 327 | return NilValue 328 | } 329 | 330 | func isTruthy(obj object.Object) bool { 331 | return obj != NilValue && obj != FalseValue 332 | } 333 | 334 | func newError(format string, a ...interface{}) *object.Error { 335 | return &object.Error{Message: fmt.Sprintf(format, a...)} 336 | } 337 | 338 | func isError(obj object.Object) bool { 339 | return obj != nil && obj.Type() == object.ErrorType 340 | } 341 | 342 | func evalIdent(node *ast.Ident, env object.Environment) object.Object { 343 | if val, ok := env.Get(node.Value); ok { 344 | return val 345 | } 346 | 347 | if builtin, ok := builtins[node.Value]; ok { 348 | return builtin 349 | } 350 | 351 | return newError("identifier not found: %s", node.Value) 352 | } 353 | 354 | func evalExpressions(exprs []ast.Expression, env object.Environment) []object.Object { 355 | result := make([]object.Object, 0, len(exprs)) 356 | 357 | for _, expr := range exprs { 358 | evaluated := Eval(expr, env) 359 | if isError(evaluated) { 360 | return []object.Object{evaluated} 361 | } 362 | result = append(result, evaluated) 363 | } 364 | 365 | return result 366 | } 367 | 368 | func extendFunctionEnv(fn *object.Function, args []object.Object) object.Environment { 369 | env := object.NewEnclosedEnvironment(fn.Env) 370 | 371 | for i, param := range fn.Parameters { 372 | env.Set(param.Value, args[i]) 373 | } 374 | 375 | return env 376 | } 377 | 378 | func applyFunction(fn object.Object, args []object.Object) object.Object { 379 | switch fn := fn.(type) { 380 | case *object.Function: 381 | extendedEnv := extendFunctionEnv(fn, args) 382 | evaluated := Eval(fn.Body, extendedEnv) 383 | return unwrapReturnValue(evaluated) 384 | case *object.Builtin: 385 | return fn.Fn(args...) 386 | default: 387 | return newError("not a function: %s", fn.Type()) 388 | } 389 | } 390 | 391 | func unwrapReturnValue(obj object.Object) object.Object { 392 | if returnValue, ok := obj.(*object.ReturnValue); ok { 393 | return returnValue.Value 394 | } 395 | return obj 396 | } 397 | 398 | func evalIndexExpression(left, index object.Object) object.Object { 399 | switch { 400 | case left.Type() == object.ArrayType && index.Type() == object.IntegerType: 401 | return evalArrayIndexExpression(left, index) 402 | case left.Type() == object.HashType: 403 | return evalHashIndexExpression(left, index) 404 | default: 405 | return newError("index operator not supported: %s", left.Type()) 406 | } 407 | } 408 | 409 | func evalArrayIndexExpression(array, index object.Object) object.Object { 410 | arrObj := array.(*object.Array) 411 | idx := index.(*object.Integer).Value 412 | max := int64(len(arrObj.Elements) - 1) 413 | 414 | if idx < 0 || idx > max { 415 | return NilValue 416 | } 417 | 418 | return arrObj.Elements[idx] 419 | } 420 | 421 | func evalHashLiteral(node *ast.HashLiteral, env object.Environment) object.Object { 422 | pairs := make(map[object.HashKey]object.HashPair, len(node.Pairs)) 423 | 424 | for keyNode, valueNode := range node.Pairs { 425 | key := Eval(keyNode, env) 426 | if isError(key) { 427 | return key 428 | } 429 | 430 | hashKey, ok := key.(object.Hashable) 431 | if !ok { 432 | return newError("unusable as hash key: %s", key.Type()) 433 | } 434 | 435 | value := Eval(valueNode, env) 436 | if isError(value) { 437 | return value 438 | } 439 | 440 | hashed := hashKey.HashKey() 441 | pairs[hashed] = object.HashPair{ 442 | Key: key, 443 | Value: value, 444 | } 445 | } 446 | 447 | return &object.Hash{Pairs: pairs} 448 | } 449 | 450 | func evalHashIndexExpression(left, index object.Object) object.Object { 451 | key, ok := index.(object.Hashable) 452 | if !ok { 453 | return newError("unusable as hash key: %s", index.Type()) 454 | } 455 | 456 | hashObj := left.(*object.Hash) 457 | if pair, exists := hashObj.Pairs[key.HashKey()]; exists { 458 | return pair.Value 459 | } 460 | return NilValue 461 | } 462 | -------------------------------------------------------------------------------- /eval/eval_test.go: -------------------------------------------------------------------------------- 1 | package eval 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | 7 | "github.com/skatsuta/monkey-interpreter/lexer" 8 | "github.com/skatsuta/monkey-interpreter/object" 9 | "github.com/skatsuta/monkey-interpreter/parser" 10 | ) 11 | 12 | func testEval(t *testing.T, input string) object.Object { 13 | l := lexer.New(input) 14 | p := parser.New(l) 15 | program := p.ParseProgram() 16 | 17 | if len(p.Errors()) > 0 { 18 | t.Fatalf("input %q has errors: \n%v", input, strings.Join(p.Errors(), "\n")) 19 | } 20 | 21 | env := object.NewEnvironment() 22 | return Eval(program, env) 23 | } 24 | 25 | func testIntegerObject(t *testing.T, obj object.Object, expected int64) { 26 | result, ok := obj.(*object.Integer) 27 | if !ok { 28 | t.Fatalf("object is not *object.Integer. got=%#v", obj) 29 | } 30 | 31 | if result.Value != expected { 32 | t.Errorf("object has wrong value. want=%d, got=%d", expected, result.Value) 33 | } 34 | } 35 | 36 | func TestEvalIntegerExpression(t *testing.T) { 37 | tests := []struct { 38 | input string 39 | expected int64 40 | }{ 41 | {"5", 5}, 42 | {"10", 10}, 43 | {"-5", -5}, 44 | {"-10", -10}, 45 | {"5 + 5 + 5 + 5 - 10", 10}, 46 | {"2 * 2 * 2 * 2 * 2", 32}, 47 | {"-50 + 100 + -50", 0}, 48 | {"5 * 2 + 10", 20}, 49 | {"5 + 2 * 10", 25}, 50 | {"20 + 2 * -10", 0}, 51 | {"50 / 2 * 2 + 10", 60}, 52 | {"3 * 3 * 3 + 10", 37}, 53 | {"3 * (3 * 3) + 10", 37}, 54 | {"(5 + 10 * 2 + 15 / 3) * 2 + -10", 50}, 55 | } 56 | 57 | for _, tt := range tests { 58 | evaluated := testEval(t, tt.input) 59 | testIntegerObject(t, evaluated, tt.expected) 60 | } 61 | } 62 | 63 | func testFloatObject(t *testing.T, obj object.Object, expected float64) { 64 | f, ok := obj.(*object.Float) 65 | if !ok { 66 | t.Errorf("object is not *object.Float. got=%#v", obj) 67 | return 68 | } 69 | 70 | if f.Value != expected { 71 | t.Errorf("object has wrong value. want=%f, got=%f", expected, f.Value) 72 | } 73 | } 74 | 75 | func TestEvalFloatExpression(t *testing.T) { 76 | tests := []struct { 77 | input string 78 | expected float64 79 | }{ 80 | {"12.34", 12.34}, 81 | {"0.56", 0.56}, 82 | {"78.00", 78.00}, 83 | {"-12.34", -12.34}, 84 | {"-0.56", -0.56}, 85 | {"-78.00", -78.00}, 86 | {"(5 + 10.0 * 2.5 + 15.0 / 3) * 2.1 + -10.1", 63.4}, 87 | } 88 | 89 | for _, tt := range tests { 90 | evaluated := testEval(t, tt.input) 91 | testFloatObject(t, evaluated, tt.expected) 92 | } 93 | } 94 | 95 | func testBooleanObject(t *testing.T, obj object.Object, expected bool) { 96 | result, ok := obj.(*object.Boolean) 97 | if !ok { 98 | t.Fatalf("object is not *object.Boolean. got=%#v", obj) 99 | } 100 | 101 | if result.Value != expected { 102 | t.Errorf("object has wrong value. want=%t, got=%t", expected, result.Value) 103 | } 104 | } 105 | 106 | func TestEvalBooleanExpression(t *testing.T) { 107 | tests := []struct { 108 | input string 109 | expected bool 110 | }{ 111 | {"true", true}, 112 | {"false", false}, 113 | {"1 < 2", true}, 114 | {"1 > 2", false}, 115 | {"1 < 1", false}, 116 | {"1 > 1", false}, 117 | {"1 == 1", true}, 118 | {"1 != 1", false}, 119 | {"1 == 2", false}, 120 | {"1 != 2", true}, 121 | {"true == true", true}, 122 | {"false == false", true}, 123 | {"true == false", false}, 124 | {"true != false", true}, 125 | {"false != true", true}, 126 | {"(1 < 2) == true", true}, 127 | {"(1 < 2) == false", false}, 128 | {"(1 > 2) == true", false}, 129 | {"(1 > 2) == false", true}, 130 | {`"hello" == "hello"`, true}, 131 | {`"hello" == "world"`, false}, 132 | {`"foo" != "bar"`, true}, 133 | {`"foo" != "foo"`, false}, 134 | } 135 | 136 | for _, tt := range tests { 137 | evaluated := testEval(t, tt.input) 138 | testBooleanObject(t, evaluated, tt.expected) 139 | } 140 | } 141 | 142 | func TestBangOperator(t *testing.T) { 143 | tests := []struct { 144 | input string 145 | expected bool 146 | }{ 147 | {"!true", false}, 148 | {"!false", true}, 149 | {"!5", false}, 150 | {"!!true", true}, 151 | {"!!false", false}, 152 | {"!!5", true}, 153 | } 154 | 155 | for _, tt := range tests { 156 | evaluated := testEval(t, tt.input) 157 | testBooleanObject(t, evaluated, tt.expected) 158 | } 159 | } 160 | 161 | func TestIfExpression(t *testing.T) { 162 | tests := []struct { 163 | input string 164 | expected interface{} 165 | }{ 166 | {"if (true) { 10 }", 10}, 167 | {"if (false) { 10 }", nil}, 168 | {"if (1) { 10 }", 10}, 169 | {"if (1 < 2) { 10 }", 10}, 170 | {"if (1 > 2) { 10 }", nil}, 171 | {"if (1 < 2) { 10 } else { 20 }", 10}, 172 | {"if (1 > 2) { 10 } else { 20 }", 20}, 173 | } 174 | 175 | for _, tt := range tests { 176 | evaluated := testEval(t, tt.input) 177 | if i, ok := tt.expected.(int); ok { 178 | testIntegerObject(t, evaluated, int64(i)) 179 | } else { 180 | testNilObject(t, evaluated) 181 | } 182 | } 183 | } 184 | 185 | func testNilObject(t *testing.T, obj object.Object) { 186 | if obj != NilValue { 187 | t.Errorf("object is not NilValue. got=%#v", obj) 188 | } 189 | } 190 | 191 | func TestReturnStatements(t *testing.T) { 192 | tests := []struct { 193 | input string 194 | expected int64 195 | }{ 196 | {"return 10;", 10}, 197 | {"return 10; 9;", 10}, 198 | {"return 2 * 5; 9;", 10}, 199 | {"9; return 2 * 5; 11;", 10}, 200 | {` 201 | if (10 > 1) { 202 | if (10 > 1) { 203 | return 10; 204 | } 205 | 206 | return 1; 207 | } 208 | `, 10}, 209 | } 210 | 211 | for _, tt := range tests { 212 | evaluated := testEval(t, tt.input) 213 | testIntegerObject(t, evaluated, tt.expected) 214 | } 215 | } 216 | 217 | func TestErrorHandling(t *testing.T) { 218 | tests := []struct { 219 | input string 220 | expectedMessage string 221 | }{ 222 | {"5 + true;", "type mismatch: Integer + Boolean"}, 223 | {"5 + true; 5;", "type mismatch: Integer + Boolean"}, 224 | {"-true", "unknown operator: -Boolean"}, 225 | {"true + false", "unknown operator: Boolean + Boolean"}, 226 | {"5; true + false; 5", "unknown operator: Boolean + Boolean"}, 227 | {"if (10 > 1) { true + false; }", "unknown operator: Boolean + Boolean"}, 228 | {` 229 | if (10 > 1) { 230 | if (10 > 1) { 231 | return true + false; 232 | } 233 | 234 | return 1; 235 | } 236 | `, "unknown operator: Boolean + Boolean"}, 237 | {"foobar", "identifier not found: foobar"}, 238 | {`"Hello" - "World"`, "unknown operator: String - String"}, 239 | {`1.5 + "World"`, "unknown operator: Float + String"}, 240 | {`{[1, 2]: "Monkey"}`, "unusable as hash key: Array"}, 241 | {`{"name": "Monkey"}[fn(x) { x }]`, "unusable as hash key: Function"}, 242 | } 243 | 244 | for _, tt := range tests { 245 | evaluated := testEval(t, tt.input) 246 | 247 | errObj, ok := evaluated.(*object.Error) 248 | if !ok { 249 | t.Errorf("no error object returned. got=%#v", evaluated) 250 | continue 251 | } 252 | 253 | if errObj.Message != tt.expectedMessage { 254 | t.Errorf("wrong error message. expected=%q, got=%q", tt.expectedMessage, errObj.Message) 255 | } 256 | } 257 | } 258 | 259 | func TestLetStatements(t *testing.T) { 260 | tests := []struct { 261 | input string 262 | expected int64 263 | }{ 264 | {"let a = 5; a;", 5}, 265 | {"let a = 5 * 5; a;", 25}, 266 | {"let a = 5; let b = a; b;", 5}, 267 | {"let a = 5; let b = a; let c = a + b + 5; c;", 15}, 268 | } 269 | 270 | for _, tt := range tests { 271 | evaluated := testEval(t, tt.input) 272 | testIntegerObject(t, evaluated, tt.expected) 273 | } 274 | } 275 | 276 | func TestFunctionObject(t *testing.T) { 277 | input := "fn(x) { x + 2; }" 278 | 279 | evaluated := testEval(t, input) 280 | fn, ok := evaluated.(*object.Function) 281 | if !ok { 282 | t.Fatalf("object is not *object.Function. got=%#v", evaluated) 283 | } 284 | 285 | if len(fn.Parameters) != 1 { 286 | t.Fatalf("function has wrong parameters. got=%+v", fn.Parameters) 287 | } 288 | 289 | if fn.Parameters[0].String() != "x" { 290 | t.Fatalf("parameter is not 'x'. got=%q", fn.Parameters[0]) 291 | } 292 | 293 | expectedBody := "(x + 2)" 294 | if body := fn.Body.String(); body != expectedBody { 295 | t.Fatalf("body is not %q. got=%q", expectedBody, body) 296 | } 297 | } 298 | 299 | func TestFunctionApplication(t *testing.T) { 300 | tests := []struct { 301 | input string 302 | expected int64 303 | }{ 304 | {"let identity = fn(x) { x; }; identity(5);", 5}, 305 | {"let identity = fn(x) { return x; }; identity(5);", 5}, 306 | {"let double = fn(x) { x * 2; }; double(5);", 10}, 307 | {"let add = fn(x, y) { x + y; }; add(5, 5);", 10}, 308 | {"let add = fn(x, y) { x + y; }; add(5 + 5, add(5, 5));", 20}, 309 | {"fn(x) { x; }(5);", 5}, 310 | } 311 | 312 | for _, tt := range tests { 313 | evaluated := testEval(t, tt.input) 314 | testIntegerObject(t, evaluated, tt.expected) 315 | } 316 | } 317 | 318 | func TestClosures(t *testing.T) { 319 | input := ` 320 | let newAdder = fn(x) { 321 | fn(y) { x + y }; 322 | }; 323 | 324 | let addTwo = newAdder(2); 325 | addTwo(2); 326 | ` 327 | 328 | evaluated := testEval(t, input) 329 | testIntegerObject(t, evaluated, 4) 330 | } 331 | 332 | func TestStringLiteralAndConcat(t *testing.T) { 333 | tests := []struct { 334 | input string 335 | expected string 336 | }{ 337 | {`"Hello World!";`, "Hello World!"}, 338 | {`"Hello" + " " + "World!";`, "Hello World!"}, 339 | } 340 | 341 | for _, tt := range tests { 342 | evaluated := testEval(t, tt.input) 343 | str, ok := evaluated.(*object.String) 344 | if !ok { 345 | t.Fatalf("object is not *object.String. got=%#v", evaluated) 346 | } 347 | 348 | if str.Value != tt.expected { 349 | t.Errorf("String has wrong value. want=%q, got=%q", tt.expected, str.Value) 350 | } 351 | } 352 | } 353 | 354 | func TestBuiltinFunctions(t *testing.T) { 355 | tests := []struct { 356 | input string 357 | expected interface{} 358 | }{ 359 | // len for strings 360 | {`len("")`, 0}, 361 | {`len("four")`, 4}, 362 | {`len("hello world")`, 11}, 363 | {`len("hello" + " " + "world")`, 11}, 364 | {`len(1)`, "argument to `len` not supported, got Integer"}, 365 | {`len("one", "two")`, "wrong number of arguments. want=1, got=2"}, 366 | // len for arrays 367 | {"len([])", 0}, 368 | {"len([1])", 1}, 369 | {"len([1, 1 + 2 * 3, true])", 3}, 370 | // first for arrays 371 | {"first([])", nil}, 372 | {"first([1])", 1}, 373 | {"first([1, 2])", 1}, 374 | {`first(1)`, "argument to `first` must be Array, got Integer"}, 375 | // last for arrays 376 | {"last([])", nil}, 377 | {"last([1])", 1}, 378 | {"last([1, 2])", 2}, 379 | {`last(1)`, "argument to `last` must be Array, got Integer"}, 380 | // rest for arrays 381 | {"rest([])", nil}, 382 | {"rest([1])", []int64{}}, 383 | {"rest([1, 2, 3])", []int64{2, 3}}, 384 | {`rest(1)`, "argument to `last` must be Array, got Integer"}, 385 | // push for arrays 386 | {"push([], 1)", []int64{1}}, 387 | {"push([1, 2], 3)", []int64{1, 2, 3}}, 388 | {"push([])", "wrong number of arguments. want=2, got=1"}, 389 | {"push(1, 2)", "first argument to `push` must be Array, got Integer"}, 390 | // puts 391 | {"puts(1)", nil}, 392 | } 393 | 394 | for _, tt := range tests { 395 | evaluated := testEval(t, tt.input) 396 | 397 | switch expected := tt.expected.(type) { 398 | case int: 399 | testIntegerObject(t, evaluated, int64(expected)) 400 | case string: 401 | errObj, ok := evaluated.(*object.Error) 402 | if !ok { 403 | t.Errorf("object is not *object.Error. got=%#v", evaluated) 404 | continue 405 | } 406 | if errObj.Message != expected { 407 | t.Errorf("wrong error message. expected=%q, got=%q", expected, errObj.Message) 408 | } 409 | case []int64: 410 | arrObj, ok := evaluated.(*object.Array) 411 | if !ok { 412 | t.Errorf("object is not *object.Array. got=%#v", evaluated) 413 | continue 414 | } 415 | if len(arrObj.Elements) != len(expected) { 416 | t.Errorf("wrong number of elements. want=%d, got=%d", 417 | len(arrObj.Elements), len(expected)) 418 | continue 419 | } 420 | for i, elem := range arrObj.Elements { 421 | testIntegerObject(t, elem, expected[i]) 422 | } 423 | case nil: 424 | testNilObject(t, evaluated) 425 | default: 426 | t.Errorf("unsupported evaluated value: %#v, want=%#v", evaluated, tt.expected) 427 | } 428 | } 429 | } 430 | 431 | func TestArrayLiterals(t *testing.T) { 432 | input := "[1, 2 * 2, 3 + 3]" 433 | 434 | evaluated := testEval(t, input) 435 | array, ok := evaluated.(*object.Array) 436 | if !ok { 437 | t.Fatalf("object is not *object.Array. got=%#v", evaluated) 438 | } 439 | 440 | if l := len(array.Elements); l != 3 { 441 | t.Fatalf("array has wrong number of elements. want=%d, got=%d", 3, l) 442 | } 443 | 444 | testIntegerObject(t, array.Elements[0], 1) 445 | testIntegerObject(t, array.Elements[1], 4) 446 | testIntegerObject(t, array.Elements[2], 6) 447 | } 448 | 449 | func TestArrayIndexExpressions(t *testing.T) { 450 | tests := []struct { 451 | input string 452 | expected interface{} 453 | }{ 454 | {"[1, 2, 3][0]", 1}, 455 | {"[1, 2, 3][1]", 2}, 456 | {"[1, 2, 3][2]", 3}, 457 | {"let i = 0; [1][i]", 1}, 458 | {"[1, 2, 3][1 + 1]", 3}, 459 | {"let arr = [1, 2, 3]; arr[2];", 3}, 460 | {"let arr = [1, 2, 3]; arr[0] + arr[1] + arr[2];", 6}, 461 | {"let arr = [1, 2, 3]; let i = arr[0]; arr[i]", 2}, 462 | {"[1, 2, 3][3]", nil}, 463 | {"[1, 2, 3][-1]", nil}, 464 | } 465 | 466 | for _, tt := range tests { 467 | evaluated := testEval(t, tt.input) 468 | if i, ok := tt.expected.(int); ok { 469 | testIntegerObject(t, evaluated, int64(i)) 470 | continue 471 | } 472 | testNilObject(t, evaluated) 473 | } 474 | } 475 | 476 | func TestHashLiterals(t *testing.T) { 477 | input := ` 478 | let two = "two"; 479 | { 480 | "one": 10 - 9, 481 | two: 1 + 1, 482 | "thr" + "ee": 6 / 2, 483 | 4: 4, 484 | true: 5, 485 | false: 6 486 | }; 487 | ` 488 | 489 | evaluated := testEval(t, input) 490 | hash, ok := evaluated.(*object.Hash) 491 | if !ok { 492 | t.Fatalf("object is not *object.Hash. got=%#v", evaluated) 493 | } 494 | 495 | expected := map[object.HashKey]int64{ 496 | (&object.String{Value: "one"}).HashKey(): 1, 497 | (&object.String{Value: "two"}).HashKey(): 2, 498 | (&object.String{Value: "three"}).HashKey(): 3, 499 | (&object.Integer{Value: 4}).HashKey(): 4, 500 | TrueValue.HashKey(): 5, 501 | FalseValue.HashKey(): 6, 502 | } 503 | 504 | if l := len(hash.Pairs); l != len(expected) { 505 | t.Fatalf("hash has wrong number of pairs. want=%d, got=%d", len(expected), l) 506 | } 507 | 508 | for key, value := range expected { 509 | pair, ok := hash.Pairs[key] 510 | if !ok { 511 | t.Errorf("no pair for given key in Pairs: %#v", key) 512 | continue 513 | } 514 | testIntegerObject(t, pair.Value, value) 515 | } 516 | } 517 | 518 | func TestHashIndexExpressions(t *testing.T) { 519 | tests := []struct { 520 | input string 521 | expected interface{} 522 | }{ 523 | {`{"foo": 2 + 3}["foo"]`, 5}, 524 | {`{"foo": 5}["bar"]`, nil}, 525 | {`let key = "foo"; {"foo": 5}[key]`, 5}, 526 | {`{}["foo"]`, nil}, 527 | {`{5: 5}[5]`, 5}, 528 | {`{true: 5}[true]`, 5}, 529 | {`{false: 5}[false]`, 5}, 530 | } 531 | 532 | for _, tt := range tests { 533 | evaluated := testEval(t, tt.input) 534 | if i, ok := tt.expected.(int); ok { 535 | testIntegerObject(t, evaluated, int64(i)) 536 | continue 537 | } 538 | testNilObject(t, evaluated) 539 | } 540 | } 541 | 542 | func TestQuote(t *testing.T) { 543 | tests := []struct { 544 | input string 545 | want string 546 | }{ 547 | {`quote(5)`, `5`}, 548 | {`quote(foobar)`, `foobar`}, 549 | {`quote(foobar + barfoo)`, `(foobar + barfoo)`}, 550 | } 551 | 552 | for _, tt := range tests { 553 | evaluated := testEval(t, tt.input) 554 | q, ok := evaluated.(*object.Quote) 555 | if !ok { 556 | t.Fatalf("expected *object.Quote, but got %T (%#v)", evaluated, evaluated) 557 | } 558 | 559 | if q.Node == nil { 560 | t.Fatalf("quote.node is nil") 561 | } 562 | 563 | got := q.Node.String() 564 | if got != tt.want { 565 | t.Errorf("expected %q, but got %q", tt.want, got) 566 | } 567 | } 568 | } 569 | -------------------------------------------------------------------------------- /eval/macro.go: -------------------------------------------------------------------------------- 1 | package eval 2 | 3 | import ( 4 | "github.com/skatsuta/monkey-interpreter/ast" 5 | "github.com/skatsuta/monkey-interpreter/object" 6 | ) 7 | 8 | // DefineMacros finds macro definitions in the program, saves them to a given environment and 9 | // removes them from the AST. 10 | func DefineMacros(program *ast.Program, env object.Environment) { 11 | defs := make([]int, 0) 12 | stmts := program.Statements 13 | 14 | for pos, stmt := range stmts { 15 | if isMacroDefinition(stmt) { 16 | addMacro(stmt, env) 17 | defs = append(defs, pos) 18 | } 19 | } 20 | 21 | for i := len(defs) - 1; i >= 0; i-- { 22 | pos := defs[i] 23 | program.Statements = append(stmts[:pos], stmts[pos+1:]...) 24 | } 25 | } 26 | 27 | func isMacroDefinition(node ast.Statement) bool { 28 | letStmt, ok := node.(*ast.LetStatement) 29 | if !ok { 30 | return false 31 | } 32 | 33 | _, ok = letStmt.Value.(*ast.MacroLiteral) 34 | return ok 35 | } 36 | 37 | func addMacro(stmt ast.Statement, env object.Environment) { 38 | letStmt := stmt.(*ast.LetStatement) 39 | macroLit := letStmt.Value.(*ast.MacroLiteral) 40 | macro := &object.Macro{ 41 | Parameters: macroLit.Parameters, 42 | Env: env, 43 | Body: macroLit.Body, 44 | } 45 | env.Set(letStmt.Name.Value, macro) 46 | } 47 | 48 | // ExpandMacros expands defined macros and replaces AST nodes with the result of macro expansion. 49 | func ExpandMacros(program ast.Node, env object.Environment) ast.Node { 50 | modifier := func(node ast.Node) ast.Node { 51 | call, ok := node.(*ast.CallExpression) 52 | if !ok { 53 | return node 54 | } 55 | 56 | macro, ok := isMacroCall(call, env) 57 | if !ok { 58 | return node 59 | } 60 | 61 | args := quoteArgs(call) 62 | evalEnv := extendMacroEnv(macro, args) 63 | 64 | quote, ok := Eval(macro.Body, evalEnv).(*object.Quote) 65 | if !ok { 66 | panic("we only support returning AST-nodes from macros") 67 | } 68 | 69 | return quote.Node 70 | } 71 | 72 | return ast.Modify(program, modifier) 73 | } 74 | 75 | func isMacroCall(call *ast.CallExpression, env object.Environment) (macro *object.Macro, ok bool) { 76 | ident, ok := call.Function.(*ast.Ident) 77 | if !ok { 78 | return nil, false 79 | } 80 | 81 | obj, ok := env.Get(ident.Value) 82 | if !ok { 83 | return nil, false 84 | } 85 | 86 | macro, ok = obj.(*object.Macro) 87 | return macro, ok 88 | } 89 | 90 | func quoteArgs(call *ast.CallExpression) []*object.Quote { 91 | args := make([]*object.Quote, 0, len(call.Arguments)) 92 | for _, arg := range call.Arguments { 93 | args = append(args, &object.Quote{Node: arg}) 94 | } 95 | return args 96 | } 97 | 98 | func extendMacroEnv(macro *object.Macro, args []*object.Quote) object.Environment { 99 | extended := object.NewEnclosedEnvironment(macro.Env) 100 | for i, param := range macro.Parameters { 101 | extended.Set(param.Value, args[i]) 102 | } 103 | return extended 104 | } 105 | -------------------------------------------------------------------------------- /eval/macro_test.go: -------------------------------------------------------------------------------- 1 | package eval 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/skatsuta/monkey-interpreter/ast" 7 | "github.com/skatsuta/monkey-interpreter/lexer" 8 | "github.com/skatsuta/monkey-interpreter/object" 9 | "github.com/skatsuta/monkey-interpreter/parser" 10 | ) 11 | 12 | func TestDefineMacros(t *testing.T) { 13 | input := ` 14 | let num = 1; 15 | let func = fn(x, y) { x + y }; 16 | let mymacro = macro(x, y) { x + y; }; 17 | ` 18 | 19 | env := object.NewEnvironment() 20 | program := testParseProgram(input) 21 | 22 | DefineMacros(program, env) 23 | 24 | stmts := program.Statements 25 | if len(stmts) != 2 { 26 | t.Fatalf("Wrong number of statements. got=%d", len(stmts)) 27 | } 28 | 29 | if _, ok := env.Get("num"); ok { 30 | t.Fatalf("`num` variable should not be defined") 31 | } 32 | 33 | if _, ok := env.Get("func"); ok { 34 | t.Fatalf("`func` variable should not be defined") 35 | } 36 | 37 | obj, ok := env.Get("mymacro") 38 | if !ok { 39 | t.Fatalf("mymacro not in the environment") 40 | } 41 | 42 | macro, ok := obj.(*object.Macro) 43 | if !ok { 44 | t.Fatalf("object is not Macro; got %T (%#v)", obj, obj) 45 | } 46 | 47 | params := macro.Parameters 48 | if len(params) != 2 { 49 | t.Fatalf("Wrong number of macro parameters; got %d", len(params)) 50 | } 51 | 52 | if params[0].String() != "x" { 53 | t.Fatalf("parameter is not 'x'; got %q", params[0]) 54 | } 55 | if params[1].String() != "y" { 56 | t.Fatalf("parameter is not 'y'; got %q", params[1]) 57 | } 58 | 59 | want := "(x + y)" 60 | 61 | got := macro.Body.String() 62 | if got != want { 63 | t.Errorf("expected body %q but got %q", want, got) 64 | } 65 | } 66 | 67 | func TestExpandMacros(t *testing.T) { 68 | tests := []struct { 69 | input string 70 | want string 71 | }{ 72 | { 73 | input: ` 74 | let infixExpr = macro() { quote(1 + 2); }; 75 | infixExpr(); 76 | `, 77 | want: `(1 + 2)`, 78 | }, 79 | { 80 | input: ` 81 | let reverse = macro(a, b) { quote(unquote(b) - unquote(a)); }; 82 | reverse(2 + 2, 10 - 5); 83 | `, 84 | want: `(10 - 5) - (2 + 2)`, 85 | }, 86 | { 87 | input: ` 88 | let unless = macro(condition, consequence, altenative) { 89 | quote( 90 | if (!(unquote(condition))) { 91 | unquote(consequence) 92 | } else { 93 | unquote(altenative) 94 | } 95 | ); 96 | }; 97 | 98 | unless(10 > 5, puts("not greater"), puts("greater")); 99 | `, 100 | want: ` 101 | if (!(10 > 5)) { 102 | puts("not greater") 103 | } else { 104 | puts("greater") 105 | } 106 | `, 107 | }, 108 | } 109 | 110 | for _, tt := range tests { 111 | program := testParseProgram(tt.input) 112 | env := object.NewEnvironment() 113 | DefineMacros(program, env) 114 | got := ExpandMacros(program, env).String() 115 | 116 | want := testParseProgram(tt.want).String() 117 | if got != want { 118 | t.Errorf("expected %q, but got %q", want, got) 119 | } 120 | } 121 | } 122 | 123 | func testParseProgram(input string) *ast.Program { 124 | return parser.New(lexer.New(input)).ParseProgram() 125 | } 126 | -------------------------------------------------------------------------------- /eval/quote.go: -------------------------------------------------------------------------------- 1 | package eval 2 | 3 | import ( 4 | "strconv" 5 | 6 | "github.com/skatsuta/monkey-interpreter/ast" 7 | "github.com/skatsuta/monkey-interpreter/object" 8 | "github.com/skatsuta/monkey-interpreter/token" 9 | ) 10 | 11 | const ( 12 | // FuncNameQuote is a name for quote function. 13 | FuncNameQuote = "quote" 14 | // FuncNameUnquote is a name for unquote function. 15 | FuncNameUnquote = "unquote" 16 | ) 17 | 18 | func quote(node ast.Node, env object.Environment) object.Object { 19 | node = evalUnquoteCalls(node, env) 20 | return &object.Quote{Node: node} 21 | } 22 | 23 | func evalUnquoteCalls(quoted ast.Node, env object.Environment) ast.Node { 24 | modifier := func(node ast.Node) ast.Node { 25 | call, ok := node.(*ast.CallExpression) 26 | if !ok || call.Function.TokenLiteral() != FuncNameUnquote || len(call.Arguments) != 1 { 27 | return node 28 | } 29 | 30 | unquoted := Eval(call.Arguments[0], env) 31 | return convertObjectToASTNode(unquoted) 32 | } 33 | return ast.Modify(quoted, modifier) 34 | } 35 | 36 | func convertObjectToASTNode(obj object.Object) ast.Node { 37 | switch obj := obj.(type) { 38 | case *object.Integer: 39 | base := 10 40 | t := token.Token{ 41 | Type: token.INT, 42 | Literal: strconv.FormatInt(obj.Value, base), 43 | } 44 | return &ast.IntegerLiteral{Token: t, Value: obj.Value} 45 | case *object.Boolean: 46 | var t token.Token 47 | if obj.Value { 48 | t = token.Token{Type: token.TRUE, Literal: "true"} 49 | } else { 50 | t = token.Token{Type: token.FALSE, Literal: "false"} 51 | } 52 | return &ast.Boolean{Token: t, Value: obj.Value} 53 | case *object.Quote: 54 | return obj.Node 55 | default: 56 | return nil 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /eval/quote_test.go: -------------------------------------------------------------------------------- 1 | package eval 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/skatsuta/monkey-interpreter/object" 7 | ) 8 | 9 | func TestQuoteUnquote(t *testing.T) { 10 | tests := []struct { 11 | input string 12 | want string 13 | }{ 14 | { 15 | `quote(unquote(4))`, 16 | `4`, 17 | }, 18 | { 19 | `quote(unquote(4 + 4))`, 20 | `8`, 21 | }, 22 | { 23 | `quote(8 + unquote(4 + 4))`, 24 | `(8 + 8)`, 25 | }, 26 | { 27 | `quote(unquote(4 + 4) + 8)`, 28 | `(8 + 8)`, 29 | }, 30 | { 31 | `let foobar = 8; quote(foobar)`, 32 | `foobar`, 33 | }, 34 | { 35 | `let foobar = 8; quote(unquote(foobar))`, 36 | `8`, 37 | }, 38 | { 39 | `quote(unquote(true))`, 40 | `true`, 41 | }, 42 | { 43 | `quote(unquote(true == false))`, 44 | `false`, 45 | }, 46 | { 47 | `quote(unquote(quote(4 + 4)))`, 48 | `(4 + 4)`, 49 | }, 50 | { 51 | `let quotedInfixExpr = quote(4 + 4); 52 | quote(unquote(4 + 4) + unquote(quotedInfixExpr))`, 53 | `(8 + (4 + 4))`, 54 | }, 55 | } 56 | 57 | for _, tt := range tests { 58 | evaluated := testEval(t, tt.input) 59 | q, ok := evaluated.(*object.Quote) 60 | if !ok { 61 | t.Fatalf("expected *object.Quote, but got %T (%#v)", evaluated, evaluated) 62 | } 63 | 64 | if q.Node == nil { 65 | t.Fatalf("quote.Node is nil") 66 | } 67 | 68 | got := q.Node.String() 69 | if got != tt.want { 70 | t.Errorf("expected %q, but got %q", tt.want, got) 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /lexer/lexer.go: -------------------------------------------------------------------------------- 1 | package lexer 2 | 3 | import "github.com/skatsuta/monkey-interpreter/token" 4 | 5 | // Lexer represents a lexer for Monkey programming language. 6 | type Lexer interface { 7 | // NextToken returns a next token. 8 | NextToken() token.Token 9 | } 10 | 11 | type lexer struct { 12 | input string 13 | // current position in input (points to current char) 14 | position int 15 | // current reading position in input (after current char) 16 | readPosition int 17 | // current char under examination 18 | ch byte 19 | } 20 | 21 | // New returns a new Lexer. 22 | func New(input string) Lexer { 23 | l := &lexer{input: input} 24 | l.readChar() 25 | return l 26 | } 27 | 28 | func (l *lexer) readChar() { 29 | if l.readPosition >= len(l.input) { 30 | l.ch = 0 31 | } else { 32 | l.ch = l.input[l.readPosition] 33 | } 34 | l.position = l.readPosition 35 | l.readPosition++ 36 | } 37 | 38 | func (l *lexer) NextToken() token.Token { 39 | l.skipWhitespace() 40 | 41 | // skip comments 42 | if l.ch == '/' && l.peekChar() == '/' { 43 | l.skipComment() 44 | } 45 | 46 | var tok token.Token 47 | switch l.ch { 48 | case '=': 49 | if l.peekChar() == '=' { 50 | ch := l.ch 51 | l.readChar() 52 | tok = token.Token{ 53 | Type: token.EQ, 54 | Literal: string(ch) + string(l.ch), 55 | } 56 | } else { 57 | tok = newToken(token.ASSIGN, l.ch) 58 | } 59 | case '!': 60 | if l.peekChar() == '=' { 61 | ch := l.ch 62 | l.readChar() 63 | tok = token.Token{ 64 | Type: token.NEQ, 65 | Literal: string(ch) + string(l.ch), 66 | } 67 | } else { 68 | tok = newToken(token.BANG, l.ch) 69 | } 70 | case ';': 71 | tok = newToken(token.SEMICOLON, l.ch) 72 | case ':': 73 | tok = newToken(token.COLON, l.ch) 74 | case '(': 75 | tok = newToken(token.LPAREN, l.ch) 76 | case ')': 77 | tok = newToken(token.RPAREN, l.ch) 78 | case ',': 79 | tok = newToken(token.COMMA, l.ch) 80 | case '+': 81 | tok = newToken(token.PLUS, l.ch) 82 | case '-': 83 | tok = newToken(token.MINUS, l.ch) 84 | case '*': 85 | tok = newToken(token.ASTARISK, l.ch) 86 | case '/': 87 | tok = newToken(token.SLASH, l.ch) 88 | case '<': 89 | tok = newToken(token.LT, l.ch) 90 | case '>': 91 | tok = newToken(token.GT, l.ch) 92 | case '{': 93 | tok = newToken(token.LBRACE, l.ch) 94 | case '}': 95 | tok = newToken(token.RBRACE, l.ch) 96 | case '[': 97 | tok = newToken(token.LBRACKET, l.ch) 98 | case ']': 99 | tok = newToken(token.RBRACKET, l.ch) 100 | case '"': 101 | tok.Type = token.STRING 102 | tok.Literal = l.readString() 103 | case 0: 104 | tok.Literal = "" 105 | tok.Type = token.EOF 106 | default: 107 | if isDigit(l.ch) { 108 | return l.readNumberToken() 109 | } 110 | 111 | if isLetter(l.ch) { 112 | tok.Literal = l.readIdent() 113 | tok.Type = token.LookupIdent(tok.Literal) 114 | return tok 115 | } 116 | 117 | tok = newToken(token.ILLEGAL, l.ch) 118 | } 119 | 120 | l.readChar() 121 | return tok 122 | } 123 | 124 | func (l *lexer) skipWhitespace() { 125 | for l.ch == ' ' || l.ch == '\t' || l.ch == '\n' || l.ch == '\r' { 126 | l.readChar() 127 | } 128 | } 129 | 130 | func (l *lexer) skipComment() { 131 | for l.ch != '\n' && l.ch != '\r' { 132 | l.readChar() 133 | } 134 | l.skipWhitespace() 135 | } 136 | 137 | func (l *lexer) peekChar() byte { 138 | if l.readPosition >= len(l.input) { 139 | return 0 140 | } 141 | return l.input[l.readPosition] 142 | } 143 | 144 | func (l *lexer) readString() string { 145 | position := l.position + 1 146 | for { 147 | l.readChar() 148 | if l.ch == '"' || l.ch == 0 { 149 | break 150 | } 151 | } 152 | return l.input[position:l.position] 153 | } 154 | 155 | func (l *lexer) read(checkFn func(byte) bool) string { 156 | position := l.position 157 | for checkFn(l.ch) { 158 | l.readChar() 159 | } 160 | return l.input[position:l.position] 161 | } 162 | 163 | func (l *lexer) readIdent() string { 164 | return l.read(isLetter) 165 | } 166 | 167 | func (l *lexer) readNumber() string { 168 | return l.read(isDigit) 169 | } 170 | 171 | func (l *lexer) readNumberToken() token.Token { 172 | intPart := l.readNumber() 173 | if l.ch != '.' { 174 | return token.Token{ 175 | Type: token.INT, 176 | Literal: intPart, 177 | } 178 | } 179 | 180 | l.readChar() 181 | fracPart := l.readNumber() 182 | return token.Token{ 183 | Type: token.FLOAT, 184 | Literal: intPart + "." + fracPart, 185 | } 186 | } 187 | 188 | func isLetter(ch byte) bool { 189 | return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' 190 | } 191 | 192 | func isDigit(ch byte) bool { 193 | return '0' <= ch && ch <= '9' 194 | } 195 | 196 | func newToken(tokenType token.Type, ch byte) token.Token { 197 | return token.Token{ 198 | Type: tokenType, 199 | Literal: string(ch), 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /lexer/lexer_test.go: -------------------------------------------------------------------------------- 1 | package lexer 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/skatsuta/monkey-interpreter/token" 7 | ) 8 | 9 | func TestNextToken(t *testing.T) { 10 | input := ` 11 | let five = 5; 12 | let ten = 10; 13 | let add = fn(x, y) { 14 | x + y; 15 | }; 16 | let result = add(five, ten); 17 | !-/*0; 18 | 2 < 10 > 7; 19 | 20 | if (5 < 10) { 21 | return true; 22 | } else { 23 | return false; 24 | } 25 | 26 | 10 == 10; 27 | 10 != 9; 28 | 29 | "foobar"; 30 | "foo bar"; 31 | 32 | [1, 2]; 33 | 34 | {"foo": "bar"}; 35 | 36 | // comment 37 | let a = 1; // inline comment 38 | 39 | let b = 123.45; 40 | let c = 0.678; 41 | let d = 9.0; 42 | 43 | macro(x, y) { x + y; }; 44 | ` 45 | 46 | tests := []struct { 47 | expectedType token.Type 48 | expectedLiteral string 49 | }{ 50 | {token.LET, "let"}, 51 | {token.IDENT, "five"}, 52 | {token.ASSIGN, "="}, 53 | {token.INT, "5"}, 54 | {token.SEMICOLON, ";"}, 55 | {token.LET, "let"}, 56 | {token.IDENT, "ten"}, 57 | {token.ASSIGN, "="}, 58 | {token.INT, "10"}, 59 | {token.SEMICOLON, ";"}, 60 | {token.LET, "let"}, 61 | {token.IDENT, "add"}, 62 | {token.ASSIGN, "="}, 63 | {token.FUNCTION, "fn"}, 64 | {token.LPAREN, "("}, 65 | {token.IDENT, "x"}, 66 | {token.COMMA, ","}, 67 | {token.IDENT, "y"}, 68 | {token.RPAREN, ")"}, 69 | {token.LBRACE, "{"}, 70 | {token.IDENT, "x"}, 71 | {token.PLUS, "+"}, 72 | {token.IDENT, "y"}, 73 | {token.SEMICOLON, ";"}, 74 | {token.RBRACE, "}"}, 75 | {token.SEMICOLON, ";"}, 76 | {token.LET, "let"}, 77 | {token.IDENT, "result"}, 78 | {token.ASSIGN, "="}, 79 | {token.IDENT, "add"}, 80 | {token.LPAREN, "("}, 81 | {token.IDENT, "five"}, 82 | {token.COMMA, ","}, 83 | {token.IDENT, "ten"}, 84 | {token.RPAREN, ")"}, 85 | {token.SEMICOLON, ";"}, 86 | {token.BANG, "!"}, 87 | {token.MINUS, "-"}, 88 | {token.SLASH, "/"}, 89 | {token.ASTARISK, "*"}, 90 | {token.INT, "0"}, 91 | {token.SEMICOLON, ";"}, 92 | {token.INT, "2"}, 93 | {token.LT, "<"}, 94 | {token.INT, "10"}, 95 | {token.GT, ">"}, 96 | {token.INT, "7"}, 97 | {token.SEMICOLON, ";"}, 98 | {token.IF, "if"}, 99 | {token.LPAREN, "("}, 100 | {token.INT, "5"}, 101 | {token.LT, "<"}, 102 | {token.INT, "10"}, 103 | {token.RPAREN, ")"}, 104 | {token.LBRACE, "{"}, 105 | {token.RETURN, "return"}, 106 | {token.TRUE, "true"}, 107 | {token.SEMICOLON, ";"}, 108 | {token.RBRACE, "}"}, 109 | {token.ELSE, "else"}, 110 | {token.LBRACE, "{"}, 111 | {token.RETURN, "return"}, 112 | {token.FALSE, "false"}, 113 | {token.SEMICOLON, ";"}, 114 | {token.RBRACE, "}"}, 115 | {token.INT, "10"}, 116 | {token.EQ, "=="}, 117 | {token.INT, "10"}, 118 | {token.SEMICOLON, ";"}, 119 | {token.INT, "10"}, 120 | {token.NEQ, "!="}, 121 | {token.INT, "9"}, 122 | {token.SEMICOLON, ";"}, 123 | {token.STRING, "foobar"}, 124 | {token.SEMICOLON, ";"}, 125 | {token.STRING, "foo bar"}, 126 | {token.SEMICOLON, ";"}, 127 | {token.LBRACKET, "["}, 128 | {token.INT, "1"}, 129 | {token.COMMA, ","}, 130 | {token.INT, "2"}, 131 | {token.RBRACKET, "]"}, 132 | {token.SEMICOLON, ";"}, 133 | {token.LBRACE, "{"}, 134 | {token.STRING, "foo"}, 135 | {token.COLON, ":"}, 136 | {token.STRING, "bar"}, 137 | {token.RBRACE, "}"}, 138 | {token.SEMICOLON, ";"}, 139 | {token.LET, "let"}, 140 | {token.IDENT, "a"}, 141 | {token.ASSIGN, "="}, 142 | {token.INT, "1"}, 143 | {token.SEMICOLON, ";"}, 144 | {token.LET, "let"}, 145 | {token.IDENT, "b"}, 146 | {token.ASSIGN, "="}, 147 | {token.FLOAT, "123.45"}, 148 | {token.SEMICOLON, ";"}, 149 | {token.LET, "let"}, 150 | {token.IDENT, "c"}, 151 | {token.ASSIGN, "="}, 152 | {token.FLOAT, "0.678"}, 153 | {token.SEMICOLON, ";"}, 154 | {token.LET, "let"}, 155 | {token.IDENT, "d"}, 156 | {token.ASSIGN, "="}, 157 | {token.FLOAT, "9.0"}, 158 | {token.SEMICOLON, ";"}, 159 | {token.MACRO, "macro"}, 160 | {token.LPAREN, "("}, 161 | {token.IDENT, "x"}, 162 | {token.COMMA, ","}, 163 | {token.IDENT, "y"}, 164 | {token.RPAREN, ")"}, 165 | {token.LBRACE, "{"}, 166 | {token.IDENT, "x"}, 167 | {token.PLUS, "+"}, 168 | {token.IDENT, "y"}, 169 | {token.SEMICOLON, ";"}, 170 | {token.RBRACE, "}"}, 171 | {token.SEMICOLON, ";"}, 172 | {token.EOF, ""}, 173 | } 174 | 175 | l := New(input) 176 | 177 | for i, tt := range tests { 178 | tok := l.NextToken() 179 | 180 | if tok.Type != tt.expectedType { 181 | t.Logf("tests[%d] - tok: %#v", i, tok) 182 | t.Fatalf("tests[%d] - token type wrong. expected=%q, got=%q", i, tt.expectedType, tok.Type) 183 | } 184 | 185 | if tok.Literal != tt.expectedLiteral { 186 | t.Logf("tests[%d] - tok: %#v", i, tok) 187 | t.Fatalf("tests[%d] - literal wrong. expected=%q, got=%q", i, tt.expectedLiteral, tok.Literal) 188 | } 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "fmt" 6 | "io" 7 | "io/ioutil" 8 | "os" 9 | 10 | "github.com/skatsuta/monkey-interpreter/eval" 11 | "github.com/skatsuta/monkey-interpreter/lexer" 12 | "github.com/skatsuta/monkey-interpreter/object" 13 | "github.com/skatsuta/monkey-interpreter/parser" 14 | "github.com/skatsuta/monkey-interpreter/repl" 15 | ) 16 | 17 | func main() { 18 | // Start Monkey REPL 19 | if len(os.Args) == 1 { 20 | fmt.Println("This is the Monkey programming language!") 21 | fmt.Println("Feel free to type in commands") 22 | repl.Start(os.Stdin, os.Stdout) 23 | return 24 | } 25 | 26 | // Run a Monkey script 27 | if err := runProgram(os.Args[1]); err != nil { 28 | fmt.Fprintln(os.Stderr, err) 29 | os.Exit(1) 30 | } 31 | } 32 | 33 | func runProgram(filename string) error { 34 | data, err := ioutil.ReadFile(filename) 35 | if err != nil { 36 | return fmt.Errorf("could not read %s: %v", filename, err) 37 | } 38 | 39 | p := parser.New(lexer.New(string(data))) 40 | program := p.ParseProgram() 41 | if len(p.Errors()) > 0 { 42 | return errors.New(p.Errors()[0]) 43 | } 44 | 45 | env := object.NewEnvironment() 46 | result := eval.Eval(program, env) 47 | if _, ok := result.(*object.Nil); ok { 48 | return nil 49 | } 50 | 51 | _, err = io.WriteString(os.Stdout, result.Inspect()+"\n") 52 | return err 53 | } 54 | -------------------------------------------------------------------------------- /object/environment.go: -------------------------------------------------------------------------------- 1 | package object 2 | 3 | // Environment associates values with variable names. 4 | type Environment interface { 5 | // Get retrieves the value of a variable named by the `name`. 6 | // If the variable is present in the environment the value is returned and the boolean is true. 7 | // Otherwise the returned value will be nil and the boolean will be false. 8 | Get(name string) (Object, bool) 9 | 10 | // Set sets the `val` of a variable named by the `name` and returns the `val` itself. 11 | Set(name string, val Object) Object 12 | } 13 | 14 | // environment implements Environment interface. 15 | // environment is not thread safe, so do not use it in multiple goroutines. 16 | type environment struct { 17 | store map[string]Object 18 | outer Environment 19 | } 20 | 21 | // NewEnvironment returns a new Environment. 22 | func NewEnvironment() Environment { 23 | return &environment{ 24 | store: make(map[string]Object), 25 | outer: nil, 26 | } 27 | } 28 | 29 | // Get retrieves the value of a variable named by the `name`. 30 | // If the variable is present in the environment the value is returned and the boolean is true. 31 | // Otherwise the returned value will be nil and the boolean will be false. 32 | func (e *environment) Get(name string) (Object, bool) { 33 | obj, exists := e.store[name] 34 | if !exists && e.outer != nil { 35 | obj, exists = e.outer.Get(name) 36 | } 37 | return obj, exists 38 | } 39 | 40 | // Set sets the `val` of a variable named by the `name` and returns the `val` itself. 41 | func (e *environment) Set(name string, val Object) Object { 42 | e.store[name] = val 43 | return val 44 | } 45 | 46 | // NewEnclosedEnvironment creates a new Environment which holds the given outer Environment. 47 | func NewEnclosedEnvironment(outer Environment) Environment { 48 | return &environment{ 49 | store: make(map[string]Object), 50 | outer: outer, 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /object/object.go: -------------------------------------------------------------------------------- 1 | package object 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "hash/fnv" 7 | "strconv" 8 | "strings" 9 | 10 | "github.com/skatsuta/monkey-interpreter/ast" 11 | ) 12 | 13 | // Type is a type of objects. 14 | type Type string 15 | 16 | const ( 17 | // IntegerType represents a type of integers. 18 | IntegerType Type = "Integer" 19 | // FloatType represents a type of floating point numbers. 20 | FloatType = "Float" 21 | // BooleanType represents a type of booleans. 22 | BooleanType = "Boolean" 23 | // NilType represents a type of nil. 24 | NilType = "Nil" 25 | // ReturnValueType represents a type of return values. 26 | ReturnValueType = "ReturnValue" 27 | // ErrorType represents a type of errors. 28 | ErrorType = "Error" 29 | // FunctionType represents a type of functions. 30 | FunctionType = "Function" 31 | // StringType represents a type of strings. 32 | StringType = "String" 33 | // BuiltinType represents a type of builtin functions. 34 | BuiltinType = "Builtin" 35 | // ArrayType represents a type of arrays. 36 | ArrayType = "Array" 37 | // HashType represents a type of hashes. 38 | HashType = "Hash" 39 | // QuoteType represents a type of quotes used for macros. 40 | QuoteType = "Quote" 41 | // MacroType represents a type of macros. 42 | MacroType = "Macro" 43 | ) 44 | 45 | // Object represents an object of Monkey language. 46 | type Object interface { 47 | Type() Type 48 | Inspect() string 49 | } 50 | 51 | // HashKey represents a key of a hash. 52 | type HashKey struct { 53 | Type Type 54 | Value uint64 55 | } 56 | 57 | // Hashable is the interface that is able to become a hash key. 58 | type Hashable interface { 59 | HashKey() HashKey 60 | } 61 | 62 | // Integer represents an integer. 63 | type Integer struct { 64 | Value int64 65 | } 66 | 67 | // Type returns the type of the Integer. 68 | func (i *Integer) Type() Type { 69 | return IntegerType 70 | } 71 | 72 | // Inspect returns a string representation of the Integer. 73 | func (i *Integer) Inspect() string { 74 | return strconv.FormatInt(i.Value, 10) 75 | } 76 | 77 | // HashKey returns a hash key object for i. 78 | func (i *Integer) HashKey() HashKey { 79 | return HashKey{ 80 | Type: i.Type(), 81 | Value: uint64(i.Value), 82 | } 83 | } 84 | 85 | // Float represents an integer. 86 | type Float struct { 87 | Value float64 88 | } 89 | 90 | // Type returns the type of f. 91 | func (f *Float) Type() Type { 92 | return FloatType 93 | } 94 | 95 | // Inspect returns a string representation of f. 96 | func (f *Float) Inspect() string { 97 | return strconv.FormatFloat(f.Value, 'f', -1, 64) 98 | } 99 | 100 | // HashKey returns a hash key object for f. 101 | func (f *Float) HashKey() HashKey { 102 | s := strconv.FormatFloat(f.Value, 'f', -1, 64) 103 | h := fnv.New64a() 104 | h.Write([]byte(s)) 105 | 106 | return HashKey{ 107 | Type: f.Type(), 108 | Value: h.Sum64(), 109 | } 110 | } 111 | 112 | // Boolean represents a boolean. 113 | type Boolean struct { 114 | Value bool 115 | } 116 | 117 | // Type returns the type of the Boolean. 118 | func (b *Boolean) Type() Type { 119 | return BooleanType 120 | } 121 | 122 | // Inspect returns a string representation of the Boolean. 123 | func (b *Boolean) Inspect() string { 124 | return strconv.FormatBool(b.Value) 125 | } 126 | 127 | // HashKey returns a hash key object for b. 128 | func (b *Boolean) HashKey() HashKey { 129 | key := HashKey{Type: b.Type()} 130 | if b.Value { 131 | key.Value = 1 132 | } 133 | return key 134 | } 135 | 136 | // Nil represents the absence of any value. 137 | type Nil struct{} 138 | 139 | // Type returns the type of the Nil. 140 | func (n *Nil) Type() Type { 141 | return NilType 142 | } 143 | 144 | // Inspect returns a string representation of the Nil. 145 | func (n *Nil) Inspect() string { 146 | return "nil" 147 | } 148 | 149 | // ReturnValue represents a return value. 150 | type ReturnValue struct { 151 | Value Object 152 | } 153 | 154 | // Type returns the type of the ReturnValue. 155 | func (rv *ReturnValue) Type() Type { 156 | return ReturnValueType 157 | } 158 | 159 | // Inspect returns a string representation of the ReturnValue. 160 | func (rv *ReturnValue) Inspect() string { 161 | return rv.Value.Inspect() 162 | } 163 | 164 | // Error represents an error. 165 | type Error struct { 166 | Message string 167 | } 168 | 169 | // Type returns the type of the Error. 170 | func (e *Error) Type() Type { 171 | return ErrorType 172 | } 173 | 174 | // Inspect returns a string representation of the Error. 175 | func (e *Error) Inspect() string { 176 | return "Error: " + e.Message 177 | } 178 | 179 | // Function represents a function. 180 | type Function struct { 181 | Parameters []*ast.Ident 182 | Body *ast.BlockStatement 183 | Env Environment 184 | } 185 | 186 | // Type returns the type of the Function. 187 | func (f *Function) Type() Type { 188 | return FunctionType 189 | } 190 | 191 | // Inspect returns a string representation of the Function. 192 | func (f *Function) Inspect() string { 193 | var out bytes.Buffer 194 | 195 | params := make([]string, 0, len(f.Parameters)) 196 | for _, p := range f.Parameters { 197 | params = append(params, p.String()) 198 | } 199 | 200 | out.WriteString("fn(") 201 | out.WriteString(strings.Join(params, ", ")) 202 | out.WriteString(") {\n") 203 | out.WriteString(f.Body.String()) 204 | out.WriteString("\n}") 205 | 206 | return out.String() 207 | } 208 | 209 | // String represents a string. 210 | type String struct { 211 | Value string 212 | } 213 | 214 | // Type returns the type of the String. 215 | func (s *String) Type() Type { 216 | return StringType 217 | } 218 | 219 | // Inspect returns a string representation of the String. 220 | func (s *String) Inspect() string { 221 | return s.Value 222 | } 223 | 224 | // HashKey returns a hash key object for s. 225 | func (s *String) HashKey() HashKey { 226 | h := fnv.New64a() 227 | h.Write([]byte(s.Value)) 228 | 229 | return HashKey{ 230 | Type: s.Type(), 231 | Value: h.Sum64(), 232 | } 233 | } 234 | 235 | // BuiltinFunction represents a function signature of builtin functions. 236 | type BuiltinFunction func(args ...Object) Object 237 | 238 | // Builtin represents a builtin function. 239 | type Builtin struct { 240 | Fn BuiltinFunction 241 | } 242 | 243 | // Type returns the type of the Builtin. 244 | func (b *Builtin) Type() Type { 245 | return BuiltinType 246 | } 247 | 248 | // Inspect returns a string representation of the Builtin. 249 | func (b *Builtin) Inspect() string { 250 | return "builtin function" 251 | } 252 | 253 | // Array represents an array. 254 | type Array struct { 255 | Elements []Object 256 | } 257 | 258 | // Type returns the type of the Array. 259 | func (*Array) Type() Type { 260 | return ArrayType 261 | } 262 | 263 | // Inspect returns a string representation of the Array. 264 | func (a *Array) Inspect() string { 265 | if a == nil { 266 | return "" 267 | } 268 | 269 | elements := make([]string, 0, len(a.Elements)) 270 | for _, e := range a.Elements { 271 | elements = append(elements, e.Inspect()) 272 | } 273 | 274 | var out bytes.Buffer 275 | out.WriteString("[") 276 | out.WriteString(strings.Join(elements, ", ")) 277 | out.WriteString("]") 278 | return out.String() 279 | } 280 | 281 | // HashPair represents a key-value pair in a hash. 282 | type HashPair struct { 283 | Key Object 284 | Value Object 285 | } 286 | 287 | // Hash represents a hash. 288 | type Hash struct { 289 | Pairs map[HashKey]HashPair 290 | } 291 | 292 | // Type returns the type of the Hash. 293 | func (*Hash) Type() Type { 294 | return HashType 295 | } 296 | 297 | // Inspect returns a string representation of the Hash. 298 | func (h *Hash) Inspect() string { 299 | if h == nil { 300 | return "" 301 | } 302 | 303 | pairs := make([]string, 0, len(h.Pairs)) 304 | for _, pair := range h.Pairs { 305 | pairs = append(pairs, pair.Key.Inspect()+": "+pair.Value.Inspect()) 306 | } 307 | 308 | var out bytes.Buffer 309 | out.WriteString("{") 310 | out.WriteString(strings.Join(pairs, ", ")) 311 | out.WriteString("}") 312 | return out.String() 313 | } 314 | 315 | // Quote represents a quote, i.e. an unevaluated expression. 316 | type Quote struct { 317 | ast.Node 318 | } 319 | 320 | // Type returns the type of `q`. 321 | func (q *Quote) Type() Type { 322 | return QuoteType 323 | } 324 | 325 | // Inspect returns a string representation of `q`. 326 | func (q *Quote) Inspect() string { 327 | return fmt.Sprintf("%s(%s)", QuoteType, q.Node.String()) 328 | } 329 | 330 | // Macro represents a macro. 331 | type Macro struct { 332 | Parameters []*ast.Ident 333 | Body *ast.BlockStatement 334 | Env Environment 335 | } 336 | 337 | // Type returns the type of `m`. 338 | func (m *Macro) Type() Type { 339 | return MacroType 340 | } 341 | 342 | // Inspect returns a string representation of `m`. 343 | func (m *Macro) Inspect() string { 344 | var out bytes.Buffer 345 | 346 | params := make([]string, 0, len(m.Parameters)) 347 | for _, p := range m.Parameters { 348 | params = append(params, p.String()) 349 | } 350 | 351 | out.WriteString("macro(") 352 | out.WriteString(strings.Join(params, ", ")) 353 | out.WriteString(") {\n") 354 | out.WriteString(m.Body.String()) 355 | out.WriteString("\n}") 356 | 357 | return out.String() 358 | } 359 | -------------------------------------------------------------------------------- /object/object_test.go: -------------------------------------------------------------------------------- 1 | package object 2 | 3 | import "testing" 4 | 5 | func TestStringHashKey(t *testing.T) { 6 | hello1 := &String{Value: "Hello World"} 7 | hello2 := &String{Value: "Hello World"} 8 | diff1 := &String{Value: "My name is johnny"} 9 | diff2 := &String{Value: "My name is johnny"} 10 | 11 | if hello1.HashKey() != hello2.HashKey() { 12 | t.Errorf("strings with same content have different hash keys: %#v != %#v", 13 | hello1.HashKey(), hello2.HashKey()) 14 | } 15 | 16 | if diff1.HashKey() != diff2.HashKey() { 17 | t.Errorf("strings with same content have different hash keys: %#v != %#v", 18 | diff1.HashKey(), diff2.HashKey()) 19 | } 20 | 21 | if hello1.HashKey() == diff1.HashKey() { 22 | t.Errorf("strings with different content have same hash keys: %#v != %#v", 23 | hello1.HashKey(), diff1.HashKey()) 24 | } 25 | } 26 | 27 | func TestBooleanHashKey(t *testing.T) { 28 | true1 := &Boolean{Value: true} 29 | true2 := &Boolean{Value: true} 30 | false1 := &Boolean{Value: false} 31 | false2 := &Boolean{Value: false} 32 | 33 | if true1.HashKey() != true2.HashKey() { 34 | t.Errorf("trues do not have the same hash keys: %#v != %#v", 35 | true1.HashKey(), true2.HashKey()) 36 | } 37 | 38 | if false1.HashKey() != false2.HashKey() { 39 | t.Errorf("falses do not have the same hash keys: %#v != %#v", 40 | false1.HashKey(), false2.HashKey()) 41 | } 42 | 43 | if true1.HashKey() == false1.HashKey() { 44 | t.Errorf("true has same hash key as false: %#v != %#v", 45 | true1.HashKey(), false1.HashKey()) 46 | } 47 | } 48 | 49 | func TestIntegerHashKey(t *testing.T) { 50 | one1 := &Integer{Value: 1} 51 | one2 := &Integer{Value: 1} 52 | two1 := &Integer{Value: 2} 53 | two2 := &Integer{Value: 2} 54 | 55 | if one1.HashKey() != one2.HashKey() { 56 | t.Errorf("integers with same content have different hash keys: %#v != %#v", 57 | one1.HashKey(), one2.HashKey()) 58 | } 59 | 60 | if two1.HashKey() != two2.HashKey() { 61 | t.Errorf("integers with same content have different hash keys: %#v != %#v", 62 | two1.HashKey(), two2.HashKey()) 63 | } 64 | 65 | if one1.HashKey() == two1.HashKey() { 66 | t.Errorf("integers with different content have same hash keys: %#v != %#v", 67 | one1.HashKey(), two1.HashKey()) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /parser/parser.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | 7 | "github.com/skatsuta/monkey-interpreter/ast" 8 | "github.com/skatsuta/monkey-interpreter/lexer" 9 | "github.com/skatsuta/monkey-interpreter/token" 10 | ) 11 | 12 | const ( 13 | _ int = iota 14 | // LOWEST represents the lowest precedence. 15 | LOWEST 16 | // EQUALS represents precedence of equals. 17 | EQUALS // == 18 | // LESSGREATER represents precedence of less than or greater than. 19 | LESSGREATER // > or < 20 | // SUM represents precedence of sum. 21 | SUM // + 22 | // PRODUCT represents precedence of product. 23 | PRODUCT // * 24 | // PREFIX represents precedence of prefix operator. 25 | PREFIX // -X or !X 26 | // CALL represents precedence of function call. 27 | CALL // myFunc(X) 28 | // INDEX represents precedence of array index operator. 29 | INDEX // array[index] 30 | ) 31 | 32 | var precedences = map[token.Type]int{ 33 | token.EQ: EQUALS, 34 | token.NEQ: EQUALS, 35 | token.LT: LESSGREATER, 36 | token.GT: LESSGREATER, 37 | token.PLUS: SUM, 38 | token.MINUS: SUM, 39 | token.SLASH: PRODUCT, 40 | token.ASTARISK: PRODUCT, 41 | token.LPAREN: CALL, 42 | token.LBRACKET: INDEX, 43 | } 44 | 45 | type ( 46 | prefixParseFn func() ast.Expression 47 | infixParseFn func(ast.Expression) ast.Expression 48 | ) 49 | 50 | // Parser is a parser of Monkey programming language. 51 | type Parser struct { 52 | l lexer.Lexer 53 | errors []string 54 | 55 | curToken token.Token 56 | peekToken token.Token 57 | 58 | prefixParseFns map[token.Type]prefixParseFn 59 | infixParseFns map[token.Type]infixParseFn 60 | } 61 | 62 | // New returns a new Parser. 63 | func New(l lexer.Lexer) *Parser { 64 | p := &Parser{ 65 | l: l, 66 | errors: []string{}, 67 | } 68 | 69 | p.prefixParseFns = map[token.Type]prefixParseFn{ 70 | token.IDENT: p.parseIdent, 71 | token.INT: p.parseIntegerLiteral, 72 | token.FLOAT: p.parseFloatLiteral, 73 | token.BANG: p.parsePrefixExpression, 74 | token.MINUS: p.parsePrefixExpression, 75 | token.TRUE: p.parseBoolean, 76 | token.FALSE: p.parseBoolean, 77 | token.LPAREN: p.parseGroupedExpression, 78 | token.IF: p.parseIfExpression, 79 | token.FUNCTION: p.parseFunctionLiteral, 80 | token.STRING: p.parseStringLiteral, 81 | token.LBRACKET: p.parseArrayLiteral, 82 | token.LBRACE: p.parseHashLiteral, 83 | token.MACRO: p.parseMacroLiteral, 84 | } 85 | 86 | p.infixParseFns = map[token.Type]infixParseFn{ 87 | token.PLUS: p.parseInfixExpression, 88 | token.MINUS: p.parseInfixExpression, 89 | token.ASTARISK: p.parseInfixExpression, 90 | token.SLASH: p.parseInfixExpression, 91 | token.EQ: p.parseInfixExpression, 92 | token.NEQ: p.parseInfixExpression, 93 | token.LT: p.parseInfixExpression, 94 | token.GT: p.parseInfixExpression, 95 | token.LPAREN: p.parseCallExpression, 96 | token.LBRACKET: p.parseIndexExpression, 97 | } 98 | 99 | // Read two tokens, so curToken and peekToken are both set 100 | p.nextToken() 101 | p.nextToken() 102 | 103 | return p 104 | } 105 | 106 | func (p *Parser) nextToken() { 107 | p.curToken = p.peekToken 108 | p.peekToken = p.l.NextToken() 109 | } 110 | 111 | // Errors returns error messages. 112 | func (p *Parser) Errors() []string { 113 | return p.errors 114 | } 115 | 116 | func (p *Parser) peekError(typ token.Type) { 117 | msg := fmt.Sprintf("expected next token to be %s, got %s instead", typ, p.peekToken.Type) 118 | p.errors = append(p.errors, msg) 119 | } 120 | 121 | func (p *Parser) curTokenIs(typ token.Type) bool { 122 | return p.curToken.Type == typ 123 | } 124 | 125 | func (p *Parser) peekTokenIs(typ token.Type) bool { 126 | return p.peekToken.Type == typ 127 | } 128 | 129 | func (p *Parser) expectPeek(typ token.Type) bool { 130 | if p.peekTokenIs(typ) { 131 | p.nextToken() 132 | return true 133 | } 134 | 135 | p.peekError(typ) 136 | return false 137 | } 138 | 139 | // ParseProgram parses a program and returns a new Program AST node. 140 | func (p *Parser) ParseProgram() *ast.Program { 141 | program := &ast.Program{ 142 | Statements: []ast.Statement{}, 143 | } 144 | 145 | for !p.curTokenIs(token.EOF) { 146 | stmt := p.parseStatement() 147 | if stmt != nil { 148 | program.Statements = append(program.Statements, stmt) 149 | } 150 | p.nextToken() 151 | } 152 | 153 | return program 154 | } 155 | 156 | func (p *Parser) parseStatement() ast.Statement { 157 | switch p.curToken.Type { 158 | case token.LET: 159 | return p.parseLetStatement() 160 | case token.RETURN: 161 | return p.parseReturnStatement() 162 | default: 163 | return p.parseExpressionStatement() 164 | } 165 | } 166 | 167 | func (p *Parser) parseLetStatement() *ast.LetStatement { 168 | stmt := &ast.LetStatement{Token: p.curToken} 169 | 170 | if !p.expectPeek(token.IDENT) { 171 | return nil 172 | } 173 | 174 | stmt.Name = &ast.Ident{ 175 | Token: p.curToken, 176 | Value: p.curToken.Literal, 177 | } 178 | 179 | if !p.expectPeek(token.ASSIGN) { 180 | return nil 181 | } 182 | 183 | p.nextToken() 184 | 185 | stmt.Value = p.parseExpression(LOWEST) 186 | 187 | for p.peekTokenIs(token.SEMICOLON) { 188 | p.nextToken() 189 | } 190 | 191 | return stmt 192 | } 193 | 194 | func (p *Parser) parseReturnStatement() *ast.ReturnStatement { 195 | stmt := &ast.ReturnStatement{ 196 | Token: p.curToken, 197 | } 198 | 199 | p.nextToken() 200 | 201 | stmt.ReturnValue = p.parseExpression(LOWEST) 202 | 203 | for p.peekTokenIs(token.SEMICOLON) { 204 | p.nextToken() 205 | } 206 | 207 | return stmt 208 | } 209 | 210 | func (p *Parser) parseExpressionStatement() *ast.ExpressionStatement { 211 | stmt := &ast.ExpressionStatement{ 212 | Token: p.curToken, 213 | Expression: p.parseExpression(LOWEST), 214 | } 215 | 216 | if p.peekTokenIs(token.SEMICOLON) { 217 | p.nextToken() 218 | } 219 | 220 | return stmt 221 | } 222 | 223 | func (p *Parser) parseExpression(precedence int) ast.Expression { 224 | prefix := p.prefixParseFns[p.curToken.Type] 225 | if prefix == nil { 226 | msg := fmt.Sprintf("no prefix parse function for %s found", p.curToken.Type) 227 | p.errors = append(p.errors, msg) 228 | return nil 229 | } 230 | 231 | leftExp := prefix() 232 | 233 | for !p.curTokenIs(token.SEMICOLON) && precedence < p.peekPrecedence() { 234 | infix := p.infixParseFns[p.peekToken.Type] 235 | if infix == nil { 236 | return leftExp 237 | } 238 | 239 | p.nextToken() 240 | 241 | leftExp = infix(leftExp) 242 | } 243 | 244 | return leftExp 245 | } 246 | 247 | func (p *Parser) parseIdent() ast.Expression { 248 | return &ast.Ident{ 249 | Token: p.curToken, 250 | Value: p.curToken.Literal, 251 | } 252 | } 253 | 254 | func (p *Parser) parseIntegerLiteral() ast.Expression { 255 | lit := &ast.IntegerLiteral{Token: p.curToken} 256 | 257 | val, err := strconv.ParseInt(p.curToken.Literal, 0, 64) 258 | if err != nil { 259 | msg := fmt.Sprintf("could not parse %q as integer", p.curToken.Literal) 260 | p.errors = append(p.errors, msg) 261 | return nil 262 | } 263 | 264 | lit.Value = val 265 | return lit 266 | } 267 | 268 | func (p *Parser) parseFloatLiteral() ast.Expression { 269 | val, err := strconv.ParseFloat(p.curToken.Literal, 64) 270 | if err != nil { 271 | msg := fmt.Sprintf("could not parse %q as float", p.curToken.Literal) 272 | p.errors = append(p.errors, msg) 273 | return nil 274 | } 275 | 276 | return &ast.FloatLiteral{ 277 | Token: p.curToken, 278 | Value: val, 279 | } 280 | } 281 | 282 | func (p *Parser) parsePrefixExpression() ast.Expression { 283 | expr := &ast.PrefixExpression{ 284 | Token: p.curToken, 285 | Operator: p.curToken.Literal, 286 | } 287 | 288 | p.nextToken() 289 | 290 | expr.Right = p.parseExpression(PREFIX) 291 | return expr 292 | } 293 | 294 | func (p *Parser) peekPrecedence() int { 295 | if p, ok := precedences[p.peekToken.Type]; ok { 296 | return p 297 | } 298 | return LOWEST 299 | } 300 | 301 | func (p *Parser) curPrecedence() int { 302 | if p, ok := precedences[p.curToken.Type]; ok { 303 | return p 304 | } 305 | return LOWEST 306 | } 307 | 308 | func (p *Parser) parseInfixExpression(left ast.Expression) ast.Expression { 309 | expr := &ast.InfixExpression{ 310 | Token: p.curToken, 311 | Operator: p.curToken.Literal, 312 | Left: left, 313 | } 314 | 315 | prec := p.curPrecedence() 316 | 317 | p.nextToken() 318 | 319 | expr.Right = p.parseExpression(prec) 320 | return expr 321 | } 322 | 323 | func (p *Parser) parseBoolean() ast.Expression { 324 | return &ast.Boolean{ 325 | Token: p.curToken, 326 | Value: p.curTokenIs(token.TRUE), 327 | } 328 | } 329 | 330 | func (p *Parser) parseGroupedExpression() ast.Expression { 331 | p.nextToken() 332 | 333 | expr := p.parseExpression(LOWEST) 334 | 335 | if !p.expectPeek(token.RPAREN) { 336 | return nil 337 | } 338 | 339 | return expr 340 | } 341 | 342 | func (p *Parser) parseIfExpression() ast.Expression { 343 | expr := &ast.IfExpression{Token: p.curToken} 344 | 345 | if !p.expectPeek(token.LPAREN) { 346 | return nil 347 | } 348 | 349 | p.nextToken() 350 | expr.Condition = p.parseExpression(LOWEST) 351 | 352 | if !p.expectPeek(token.RPAREN) { 353 | return nil 354 | } 355 | 356 | if !p.expectPeek(token.LBRACE) { 357 | return nil 358 | } 359 | 360 | expr.Consequence = p.parseBlockStatement() 361 | 362 | if p.peekTokenIs(token.ELSE) { 363 | p.nextToken() 364 | 365 | if !p.expectPeek(token.LBRACE) { 366 | return nil 367 | } 368 | 369 | expr.Alternative = p.parseBlockStatement() 370 | } 371 | 372 | return expr 373 | } 374 | 375 | func (p *Parser) parseBlockStatement() *ast.BlockStatement { 376 | block := &ast.BlockStatement{ 377 | Token: p.curToken, 378 | Statements: []ast.Statement{}, 379 | } 380 | 381 | p.nextToken() 382 | 383 | for !p.curTokenIs(token.RBRACE) && !p.curTokenIs(token.EOF) { 384 | stmt := p.parseStatement() 385 | if stmt != nil { 386 | block.Statements = append(block.Statements, stmt) 387 | } 388 | 389 | p.nextToken() 390 | } 391 | 392 | return block 393 | } 394 | 395 | func (p *Parser) parseFunctionLiteral() ast.Expression { 396 | lit := &ast.FunctionLiteral{Token: p.curToken} 397 | 398 | if !p.expectPeek(token.LPAREN) { 399 | return nil 400 | } 401 | 402 | lit.Parameters = p.parseFunctionParameters() 403 | 404 | if !p.expectPeek(token.LBRACE) { 405 | return nil 406 | } 407 | 408 | lit.Body = p.parseBlockStatement() 409 | 410 | return lit 411 | } 412 | 413 | func (p *Parser) parseFunctionParameters() []*ast.Ident { 414 | idents := []*ast.Ident{} 415 | 416 | if p.peekTokenIs(token.RPAREN) { 417 | p.nextToken() 418 | return idents 419 | } 420 | 421 | p.nextToken() 422 | 423 | ident := &ast.Ident{ 424 | Token: p.curToken, 425 | Value: p.curToken.Literal, 426 | } 427 | idents = append(idents, ident) 428 | 429 | for p.peekTokenIs(token.COMMA) { 430 | p.nextToken() 431 | p.nextToken() 432 | ident := &ast.Ident{ 433 | Token: p.curToken, 434 | Value: p.curToken.Literal, 435 | } 436 | idents = append(idents, ident) 437 | } 438 | 439 | if !p.expectPeek(token.RPAREN) { 440 | return nil 441 | } 442 | 443 | return idents 444 | } 445 | 446 | func (p *Parser) parseExpressionList(end token.Type) []ast.Expression { 447 | list := make([]ast.Expression, 0) 448 | 449 | if p.peekTokenIs(end) { 450 | p.nextToken() 451 | return list 452 | } 453 | 454 | p.nextToken() 455 | list = append(list, p.parseExpression(LOWEST)) 456 | 457 | for p.peekTokenIs(token.COMMA) { 458 | p.nextToken() 459 | p.nextToken() 460 | list = append(list, p.parseExpression(LOWEST)) 461 | } 462 | 463 | if !p.expectPeek(end) { 464 | return nil 465 | } 466 | 467 | return list 468 | } 469 | 470 | func (p *Parser) parseCallExpression(function ast.Expression) ast.Expression { 471 | return &ast.CallExpression{ 472 | Token: p.curToken, 473 | Function: function, 474 | Arguments: p.parseExpressionList(token.RPAREN), 475 | } 476 | } 477 | 478 | func (p *Parser) parseStringLiteral() ast.Expression { 479 | return &ast.StringLiteral{ 480 | Token: p.curToken, 481 | Value: p.curToken.Literal, 482 | } 483 | } 484 | 485 | func (p *Parser) parseArrayLiteral() ast.Expression { 486 | return &ast.ArrayLiteral{ 487 | Token: p.curToken, 488 | Elements: p.parseExpressionList(token.RBRACKET), 489 | } 490 | } 491 | 492 | func (p *Parser) parseIndexExpression(left ast.Expression) ast.Expression { 493 | expr := &ast.IndexExpression{ 494 | Token: p.curToken, 495 | Left: left, 496 | } 497 | 498 | p.nextToken() 499 | expr.Index = p.parseExpression(LOWEST) 500 | 501 | if !p.expectPeek(token.RBRACKET) { 502 | return nil 503 | } 504 | 505 | return expr 506 | } 507 | 508 | func (p *Parser) parseHashLiteral() ast.Expression { 509 | hash := &ast.HashLiteral{ 510 | Token: p.curToken, 511 | Pairs: make(map[ast.Expression]ast.Expression), 512 | } 513 | 514 | for !p.peekTokenIs(token.RBRACE) { 515 | p.nextToken() 516 | key := p.parseExpression(LOWEST) 517 | 518 | if !p.expectPeek(token.COLON) { 519 | return nil 520 | } 521 | 522 | p.nextToken() 523 | value := p.parseExpression(LOWEST) 524 | hash.Pairs[key] = value 525 | 526 | if !p.peekTokenIs(token.RBRACE) && !p.expectPeek(token.COMMA) { 527 | return nil 528 | } 529 | } 530 | 531 | if !p.expectPeek(token.RBRACE) { 532 | return nil 533 | } 534 | 535 | return hash 536 | } 537 | 538 | func (p *Parser) parseMacroLiteral() ast.Expression { 539 | tok := p.curToken 540 | 541 | if !p.expectPeek(token.LPAREN) { 542 | return nil 543 | } 544 | 545 | params := p.parseFunctionParameters() 546 | 547 | if !p.expectPeek(token.LBRACE) { 548 | return nil 549 | } 550 | 551 | body := p.parseBlockStatement() 552 | 553 | return &ast.MacroLiteral{ 554 | Token: tok, 555 | Parameters: params, 556 | Body: body, 557 | } 558 | } 559 | -------------------------------------------------------------------------------- /parser/parser_test.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/skatsuta/monkey-interpreter/ast" 8 | "github.com/skatsuta/monkey-interpreter/lexer" 9 | ) 10 | 11 | func TestLetStatements(t *testing.T) { 12 | tests := []struct { 13 | input string 14 | expectedIdent string 15 | expectedValue interface{} 16 | }{ 17 | {"let x = 5;", "x", 5}, 18 | {"let y = true;", "y", true}, 19 | {"let foobar = y;", "foobar", "y"}, 20 | } 21 | 22 | for _, tt := range tests { 23 | p := New(lexer.New(tt.input)) 24 | 25 | program := p.ParseProgram() 26 | if program == nil { 27 | t.Fatalf("ParseProgram() returned nil") 28 | } 29 | l := len(program.Statements) 30 | if l != 1 { 31 | t.Fatalf("program.Statements does not contain %d statements. got=%d", 1, l) 32 | } 33 | checkParserErrors(t, p) 34 | 35 | stmt := program.Statements[0] 36 | testLetStatement(t, stmt, tt.expectedIdent) 37 | 38 | val := stmt.(*ast.LetStatement).Value 39 | testLiteralExpression(t, val, tt.expectedValue) 40 | } 41 | } 42 | 43 | func checkParserErrors(t *testing.T, p *Parser) { 44 | errors := p.Errors() 45 | length := len(errors) 46 | if length == 0 { 47 | return 48 | } 49 | 50 | t.Errorf("parser has %d errors", length) 51 | for _, msg := range errors { 52 | t.Errorf("parser error: %q", msg) 53 | } 54 | t.FailNow() 55 | } 56 | 57 | func TestLetStatementErrors(t *testing.T) { 58 | tests := []struct { 59 | input string 60 | }{ 61 | {"let = 5;"}, 62 | {"let x = ;"}, 63 | {"let x 1;"}, 64 | } 65 | 66 | for _, tt := range tests { 67 | p := New(lexer.New(tt.input)) 68 | 69 | program := p.ParseProgram() 70 | if program == nil { 71 | t.Fatalf("ParseProgram() returned nil") 72 | } 73 | 74 | if len(p.Errors()) == 0 { 75 | t.Errorf("parser has no errors despite invalid statements.") 76 | } 77 | } 78 | } 79 | 80 | func testLetStatement(t *testing.T, s ast.Statement, name string) { 81 | if s.TokenLiteral() != "let" { 82 | t.Errorf("s.TokenLiteral not 'let'. got=%q", s.TokenLiteral()) 83 | } 84 | 85 | letStmt, ok := s.(*ast.LetStatement) 86 | if !ok { 87 | t.Errorf("s not *ast.LetStatement. got=%T", s) 88 | } 89 | 90 | if letStmt.Name.Value != name { 91 | t.Errorf("letStmt.Name.Value not '%s'. got=%s", name, letStmt.Name.Value) 92 | } 93 | 94 | if letStmt.Name.TokenLiteral() != name { 95 | t.Errorf("s.Name not '%s'. got=%s", name, letStmt.Name) 96 | } 97 | } 98 | 99 | func TestReturnStatement(t *testing.T) { 100 | tests := []struct { 101 | input string 102 | expectedValue interface{} 103 | }{ 104 | {"return 5;", 5}, 105 | {"return true;", true}, 106 | {"return x;", "x"}, 107 | } 108 | 109 | for _, tt := range tests { 110 | p := New(lexer.New(tt.input)) 111 | 112 | program := p.ParseProgram() 113 | l := len(program.Statements) 114 | if l != 1 { 115 | t.Fatalf("program.Statements does not contain %d statements. got=%d", 1, l) 116 | } 117 | checkParserErrors(t, p) 118 | 119 | for _, stmt := range program.Statements { 120 | returnStmt, ok := stmt.(*ast.ReturnStatement) 121 | if !ok { 122 | t.Errorf("stmt not *ast.returnStmt. got=%T", stmt) 123 | continue 124 | } 125 | if returnStmt.ReturnValue.String() != fmt.Sprintf("%v", tt.expectedValue) { 126 | t.Errorf("returnStmt.ReturnValue not %v, got %v", tt.expectedValue, returnStmt.ReturnValue) 127 | } 128 | if returnStmt.TokenLiteral() != "return" { 129 | t.Errorf("returnStmt.TokenLiteral not 'return', got %q", returnStmt.TokenLiteral()) 130 | } 131 | } 132 | } 133 | } 134 | 135 | func TestIdentifierExpression(t *testing.T) { 136 | input := "foobar" 137 | 138 | p := New(lexer.New(input)) 139 | program := p.ParseProgram() 140 | checkParserErrors(t, p) 141 | 142 | l := len(program.Statements) 143 | if l != 1 { 144 | t.Fatalf("program has not enough statements. got=%d", l) 145 | } 146 | 147 | stmt, ok := program.Statements[0].(*ast.ExpressionStatement) 148 | if !ok { 149 | t.Fatalf("program.Statements[0] is not *ast.ExpressionStatement. got=%T", program.Statements[0]) 150 | } 151 | 152 | testIdent(t, stmt.Expression, input) 153 | } 154 | 155 | func TestIntegerExpression(t *testing.T) { 156 | input := "5;" 157 | 158 | p := New(lexer.New(input)) 159 | program := p.ParseProgram() 160 | checkParserErrors(t, p) 161 | 162 | l := len(program.Statements) 163 | if l != 1 { 164 | t.Fatalf("program has not enough statements. got=%d", l) 165 | } 166 | 167 | stmt, ok := program.Statements[0].(*ast.ExpressionStatement) 168 | if !ok { 169 | t.Fatalf("program.Statements[0] is not *ast.ExpressionStatement. got=%T", 170 | program.Statements[0]) 171 | } 172 | 173 | testIntegerLiteral(t, stmt.Expression, 5) 174 | } 175 | 176 | func testFloatLiteral(t *testing.T, expr ast.Expression, value float64) { 177 | fl, ok := expr.(*ast.FloatLiteral) 178 | if !ok { 179 | t.Errorf("expr not *ast.FloatLiteral. got=%T", fl) 180 | return 181 | } 182 | 183 | if fl.Value != value { 184 | t.Errorf("fl.Value not %f. got=%f", value, fl.Value) 185 | } 186 | } 187 | 188 | func TestFloatExpression(t *testing.T) { 189 | tests := []struct { 190 | input string 191 | expected float64 192 | }{ 193 | {"12.34", 12.34}, 194 | {"0.56", 0.56}, 195 | {"78.00", 78.00}, 196 | } 197 | 198 | for _, tt := range tests { 199 | p := New(lexer.New(tt.input)) 200 | program := p.ParseProgram() 201 | checkParserErrors(t, p) 202 | 203 | if l := len(program.Statements); l != 1 { 204 | t.Errorf("program has not enough statements. got=%d", l) 205 | continue 206 | } 207 | 208 | stmt, ok := program.Statements[0].(*ast.ExpressionStatement) 209 | if !ok { 210 | t.Errorf("program.Statements[0] is not *ast.ExpressionStatement. got=%T", 211 | program.Statements[0]) 212 | continue 213 | } 214 | 215 | testFloatLiteral(t, stmt.Expression, tt.expected) 216 | } 217 | } 218 | 219 | func TestParsingPrefixExpressions(t *testing.T) { 220 | tests := []struct { 221 | input string 222 | operator string 223 | integerValue interface{} 224 | }{ 225 | {"!5;", "!", 5}, 226 | {"-15;", "-", 15}, 227 | {"!true", "!", true}, 228 | {"!false", "!", false}, 229 | } 230 | 231 | for _, tt := range tests { 232 | l := lexer.New(tt.input) 233 | p := New(l) 234 | program := p.ParseProgram() 235 | checkParserErrors(t, p) 236 | 237 | length := len(program.Statements) 238 | if length != 1 { 239 | t.Fatalf("program has not enough statements. got=%d", length) 240 | } 241 | 242 | stmt, ok := program.Statements[0].(*ast.ExpressionStatement) 243 | if !ok { 244 | t.Fatalf("program.Statements[0] is not *ast.ExpressionStatement. got=%T", 245 | program.Statements[0]) 246 | } 247 | 248 | exp, ok := stmt.Expression.(*ast.PrefixExpression) 249 | if !ok { 250 | t.Fatalf("exp not *ast.PrefixExpression. got=%T", stmt.Expression) 251 | } 252 | if exp.Operator != tt.operator { 253 | t.Errorf("exp.operator is not %s. got=%s", tt.operator, exp.Operator) 254 | } 255 | 256 | testLiteralExpression(t, exp.Right, tt.integerValue) 257 | } 258 | } 259 | 260 | func testIntegerLiteral(t *testing.T, il ast.Expression, value int64) { 261 | i, ok := il.(*ast.IntegerLiteral) 262 | if !ok { 263 | t.Fatalf("il not *ast.IntegerLiteral. got=%T", il) 264 | } 265 | 266 | if i.Value != value { 267 | t.Errorf("i.Value not %d. got=%d", value, i.Value) 268 | } 269 | 270 | if i.TokenLiteral() != fmt.Sprintf("%d", value) { 271 | t.Errorf("i.TokenLiteral() not %d. got=%s", value, i.TokenLiteral()) 272 | } 273 | } 274 | 275 | func testIdent(t *testing.T, expr ast.Expression, value string) { 276 | ident, ok := expr.(*ast.Ident) 277 | if !ok { 278 | t.Errorf("expr not *ast.Ident. got=%T", expr) 279 | } 280 | if ident.Value != value { 281 | t.Errorf("ident.Value not %s. got=%s", value, ident.Value) 282 | } 283 | if ident.TokenLiteral() != value { 284 | t.Errorf("ident.TokenLiteral() not %s. got=%s", value, ident.TokenLiteral()) 285 | } 286 | } 287 | 288 | func testLiteralExpression(t *testing.T, expr ast.Expression, expected interface{}) { 289 | switch v := expected.(type) { 290 | case int: 291 | testIntegerLiteral(t, expr, int64(v)) 292 | case int64: 293 | testIntegerLiteral(t, expr, v) 294 | case float64: 295 | testFloatLiteral(t, expr, v) 296 | case string: 297 | testIdent(t, expr, v) 298 | case bool: 299 | testBooleanLiteral(t, expr, v) 300 | default: 301 | t.Errorf("type of expr not handled. got=%T", expr) 302 | } 303 | } 304 | 305 | func testInfixExpression(t *testing.T, expr ast.Expression, left interface{}, operator string, 306 | right interface{}) { 307 | op, ok := expr.(*ast.InfixExpression) 308 | if !ok { 309 | t.Errorf("expr is not ast.OperatorExpression. got=%T(%s)", expr, expr) 310 | return 311 | } 312 | 313 | testLiteralExpression(t, op.Left, left) 314 | 315 | if op.Operator != operator { 316 | t.Errorf("expr.Operator is not %q. got=%q", operator, op.Operator) 317 | } 318 | 319 | testLiteralExpression(t, op.Right, right) 320 | } 321 | 322 | func TestParsingInfixExpressions(t *testing.T) { 323 | tests := []struct { 324 | input string 325 | leftValue interface{} 326 | operator string 327 | rightValue interface{} 328 | }{ 329 | {"5 + 5;", 5, "+", 5}, 330 | {"5 - 5;", 5, "-", 5}, 331 | {"5 * 5;", 5, "*", 5}, 332 | {"5 / 5;", 5, "/", 5}, 333 | {"5 > 5;", 5, ">", 5}, 334 | {"5 < 5;", 5, "<", 5}, 335 | {"5 == 5;", 5, "==", 5}, 336 | {"5 != 5;", 5, "!=", 5}, 337 | {"true == true", true, "==", true}, 338 | {"true != false", true, "!=", false}, 339 | {"false == false", false, "==", false}, 340 | {"5 + 5.1;", 5, "+", 5.1}, 341 | {"5.0 - 5.2;", 5.0, "-", 5.2}, 342 | {"5.3 * 5.4;", 5.3, "*", 5.4}, 343 | {"5.5 / 5.6;", 5.5, "/", 5.6}, 344 | {"5.7 > 5.8;", 5.7, ">", 5.8}, 345 | {"5.9 < 5;", 5.9, "<", 5}, 346 | {"5 == 5.0;", 5, "==", 5.0}, 347 | {"5.1 != 5.1;", 5.1, "!=", 5.1}, 348 | } 349 | 350 | for _, tt := range tests { 351 | p := New(lexer.New(tt.input)) 352 | program := p.ParseProgram() 353 | checkParserErrors(t, p) 354 | 355 | l := len(program.Statements) 356 | if l != 1 { 357 | t.Errorf("program.Statements does not contain %d statements. got=%d", 1, l) 358 | continue 359 | } 360 | 361 | stmt, ok := program.Statements[0].(*ast.ExpressionStatement) 362 | if !ok { 363 | t.Errorf("program.Statements[0] is not *ast.ExpressionStatement. got=%T", 364 | program.Statements[0]) 365 | continue 366 | } 367 | 368 | expr, ok := stmt.Expression.(*ast.InfixExpression) 369 | if !ok { 370 | t.Errorf("expr not *ast.InfixExpression. got=%T", stmt.Expression) 371 | continue 372 | } 373 | 374 | testLiteralExpression(t, expr.Left, tt.leftValue) 375 | 376 | if expr.Operator != tt.operator { 377 | t.Errorf("expr.Operator is not %q. got=%s", tt.operator, expr.Operator) 378 | } 379 | 380 | testLiteralExpression(t, expr.Right, tt.rightValue) 381 | } 382 | } 383 | 384 | func TestOperatorPrecedenceParsing(t *testing.T) { 385 | tests := []struct { 386 | input string 387 | expected string 388 | }{ 389 | {"-a * b", "((-a) * b)"}, 390 | {"!-a", "(!(-a))"}, 391 | {"a + b + c", "((a + b) + c)"}, 392 | {"a + b - c", "((a + b) - c)"}, 393 | {"a * b * c", "((a * b) * c)"}, 394 | {"a * b / c", "((a * b) / c)"}, 395 | {"a + b / c", "(a + (b / c))"}, 396 | {"a + b * c + d / e - f", "(((a + (b * c)) + (d / e)) - f)"}, 397 | {"3 + 4; -5 * 5", "(3 + 4)((-5) * 5)"}, 398 | {"5 > 4 == 3 < 4", "((5 > 4) == (3 < 4))"}, 399 | {"5 < 4 != 3 > 4", "((5 < 4) != (3 > 4))"}, 400 | {"3 + 4 * 5 == 3 * 1 + 4 * 5", "((3 + (4 * 5)) == ((3 * 1) + (4 * 5)))"}, 401 | {"true", "true"}, 402 | {"false", "false"}, 403 | {"3 > 5 == false", "((3 > 5) == false)"}, 404 | {"3 < 5 == true", "((3 < 5) == true)"}, 405 | {"1 + (2 + 3) + 4", "((1 + (2 + 3)) + 4)"}, 406 | {"(5 + 5) * 2", "((5 + 5) * 2)"}, 407 | {"2 / (5 + 5)", "(2 / (5 + 5))"}, 408 | {"-(5 + 5)", "(-(5 + 5))"}, 409 | {"!(true == true)", "(!(true == true))"}, 410 | {"a + add(b * c) + d", "((a + add((b * c))) + d)"}, 411 | { 412 | "add(a, b, 1, 2 * 3, 4 + 5, add(6, 7 * 8))", 413 | "add(a, b, 1, (2 * 3), (4 + 5), add(6, (7 * 8)))", 414 | }, 415 | {"add(a + b + c * d / f + g)", "add((((a + b) + ((c * d) / f)) + g))"}, 416 | {"a * [1, 2, 3, 4][b * c] * d", "((a * ([1, 2, 3, 4][(b * c)])) * d)"}, 417 | {"add(a * b[2], b[1], 2 * [1, 2][1])", "add((a * (b[2])), (b[1]), (2 * ([1, 2][1])))"}, 418 | } 419 | 420 | for _, tt := range tests { 421 | p := New(lexer.New(tt.input)) 422 | 423 | program := p.ParseProgram() 424 | checkParserErrors(t, p) 425 | 426 | actual := program.String() 427 | if actual != tt.expected { 428 | t.Errorf("expected=%q, got=%q", tt.expected, actual) 429 | } 430 | } 431 | } 432 | 433 | func testBooleanLiteral(t *testing.T, expr ast.Expression, value bool) { 434 | b, ok := expr.(*ast.Boolean) 435 | if !ok { 436 | t.Errorf("b not *ast.Boolean. got=%T", expr) 437 | } 438 | if b.Value != value { 439 | t.Errorf("b.Value not %t. got=%t", value, b.Value) 440 | } 441 | if b.TokenLiteral() != fmt.Sprintf("%t", value) { 442 | t.Errorf("b.TokenLiteral() not %t. got=%s", value, b.TokenLiteral()) 443 | } 444 | } 445 | 446 | func TestBooleanExpression(t *testing.T) { 447 | tests := []struct { 448 | input string 449 | expected bool 450 | }{ 451 | {"true", true}, 452 | {"false", false}, 453 | } 454 | 455 | for _, tt := range tests { 456 | p := New(lexer.New(tt.input)) 457 | program := p.ParseProgram() 458 | checkParserErrors(t, p) 459 | 460 | l := len(program.Statements) 461 | if l != 1 { 462 | t.Fatalf("program has not enough statements. got=%d", l) 463 | } 464 | 465 | stmt, ok := program.Statements[0].(*ast.ExpressionStatement) 466 | if !ok { 467 | t.Fatalf("program.Statements[0] is not *ast.ExpressionStatement. got=%T", 468 | program.Statements[0]) 469 | } 470 | 471 | testBooleanLiteral(t, stmt.Expression, tt.expected) 472 | } 473 | } 474 | 475 | func TestIfExpression(t *testing.T) { 476 | input := "if (x < y) { x }" 477 | 478 | p := New(lexer.New(input)) 479 | program := p.ParseProgram() 480 | checkParserErrors(t, p) 481 | 482 | l := len(program.Statements) 483 | if l != 1 { 484 | t.Fatalf("program.Body does not contain %d statements. got=%d", 1, l) 485 | } 486 | 487 | stmt, ok := program.Statements[0].(*ast.ExpressionStatement) 488 | if !ok { 489 | t.Fatalf("program.Statements[0] is not *ast.ExpressionStatement. got=%T", program.Statements[0]) 490 | } 491 | 492 | expr, ok := stmt.Expression.(*ast.IfExpression) 493 | if !ok { 494 | t.Errorf("stmt.Expression is not ast.Expression. got=%T", stmt.Expression) 495 | } 496 | 497 | testInfixExpression(t, expr.Condition, "x", "<", "y") 498 | 499 | l = len(expr.Consequence.Statements) 500 | if l != 1 { 501 | t.Errorf("consequence is not %d statements. got=%d\n", 1, l) 502 | } 503 | 504 | cons, ok := expr.Consequence.Statements[0].(*ast.ExpressionStatement) 505 | if !ok { 506 | t.Fatalf("Statements[0] is not *ast.ExpressionStatement. got=%T", 507 | expr.Consequence.Statements[0]) 508 | } 509 | 510 | testIdent(t, cons.Expression, "x") 511 | 512 | if expr.Alternative != nil { 513 | t.Errorf("expr.Alternative.Statements was not nil. got=%+v", expr.Alternative) 514 | } 515 | } 516 | 517 | func TestIfElseExpression(t *testing.T) { 518 | input := "if (x < y) { x } else { y }" 519 | 520 | p := New(lexer.New(input)) 521 | program := p.ParseProgram() 522 | checkParserErrors(t, p) 523 | 524 | l := len(program.Statements) 525 | if l != 1 { 526 | t.Fatalf("program.Body does not contain %d statements. got=%d", 1, l) 527 | } 528 | 529 | stmt, ok := program.Statements[0].(*ast.ExpressionStatement) 530 | if !ok { 531 | t.Fatalf("program.Statements[0] is not *ast.ExpressionStatement. got=%T", program.Statements[0]) 532 | } 533 | 534 | expr, ok := stmt.Expression.(*ast.IfExpression) 535 | if !ok { 536 | t.Errorf("stmt.Expression is not ast.Expression. got=%T", stmt.Expression) 537 | } 538 | 539 | testInfixExpression(t, expr.Condition, "x", "<", "y") 540 | 541 | l = len(expr.Consequence.Statements) 542 | if l != 1 { 543 | t.Errorf("consequence is not %d statements. got=%d\n", 1, l) 544 | } 545 | 546 | cons, ok := expr.Consequence.Statements[0].(*ast.ExpressionStatement) 547 | if !ok { 548 | t.Fatalf("Statements[0] is not *ast.ExpressionStatement. got=%T", 549 | expr.Consequence.Statements[0]) 550 | } 551 | 552 | testIdent(t, cons.Expression, "x") 553 | 554 | alt, ok := expr.Alternative.Statements[0].(*ast.ExpressionStatement) 555 | if !ok { 556 | t.Fatalf("Statements[0] is not *ast.ExpressionStatement. got=%T", 557 | expr.Alternative.Statements[0]) 558 | } 559 | 560 | testIdent(t, alt.Expression, "y") 561 | } 562 | 563 | func TestFunctionLiteralParsing(t *testing.T) { 564 | input := "fn(x, y) { x + y; }" 565 | 566 | p := New(lexer.New(input)) 567 | program := p.ParseProgram() 568 | checkParserErrors(t, p) 569 | 570 | l := len(program.Statements) 571 | if l != 1 { 572 | t.Fatalf("program.Body does not contain %d statements. got=%d", 1, l) 573 | } 574 | 575 | stmt, ok := program.Statements[0].(*ast.ExpressionStatement) 576 | if !ok { 577 | t.Fatalf("program.Statements[0] is not *ast.ExpressionStatement. got=%T", program.Statements[0]) 578 | } 579 | 580 | f, ok := stmt.Expression.(*ast.FunctionLiteral) 581 | if !ok { 582 | t.Errorf("stmt.Expression is not *ast.FunctionLiteral. got=%T", stmt.Expression) 583 | } 584 | 585 | l = len(f.Parameters) 586 | if l != 2 { 587 | t.Fatalf("function literal parameters wrong. want=%d, got=%d\n", 2, l) 588 | } 589 | 590 | testLiteralExpression(t, f.Parameters[0], "x") 591 | testLiteralExpression(t, f.Parameters[1], "y") 592 | 593 | l = len(f.Body.Statements) 594 | if l != 1 { 595 | t.Fatalf("f.Body.Statements has not %d statements. got=%d\n", 1, l) 596 | } 597 | 598 | bodyStmt, ok := f.Body.Statements[0].(*ast.ExpressionStatement) 599 | if !ok { 600 | t.Fatalf("f.Body.Statements[0] is not *ast.ExpressionStatement. got=%T", f.Body.Statements[0]) 601 | } 602 | 603 | testInfixExpression(t, bodyStmt.Expression, "x", "+", "y") 604 | } 605 | 606 | func TestFunctionParameterParsing(t *testing.T) { 607 | tests := []struct { 608 | input string 609 | expected []string 610 | }{ 611 | {"fn() {}", []string{}}, 612 | {"fn(x) {};", []string{"x"}}, 613 | {"fn(x, y, z) {};", []string{"x", "y", "z"}}, 614 | } 615 | 616 | for _, tt := range tests { 617 | p := New(lexer.New(tt.input)) 618 | program := p.ParseProgram() 619 | checkParserErrors(t, p) 620 | 621 | stmt := program.Statements[0].(*ast.ExpressionStatement) 622 | f := stmt.Expression.(*ast.FunctionLiteral) 623 | 624 | if len(f.Parameters) != len(tt.expected) { 625 | t.Errorf("length parameters wrong. want=%d, got=%d", len(tt.expected), len(f.Parameters)) 626 | } 627 | 628 | for i, ident := range tt.expected { 629 | testLiteralExpression(t, f.Parameters[i], ident) 630 | } 631 | } 632 | } 633 | 634 | func TestCallFunctionParsing(t *testing.T) { 635 | input := "add(1, 2 * 3, 4 + 5);" 636 | 637 | p := New(lexer.New(input)) 638 | program := p.ParseProgram() 639 | checkParserErrors(t, p) 640 | 641 | l := len(program.Statements) 642 | if l != 1 { 643 | t.Fatalf("program.Statements does not contain %d statements. got=%d", 1, l) 644 | } 645 | 646 | stmt, ok := program.Statements[0].(*ast.ExpressionStatement) 647 | if !ok { 648 | t.Fatalf("program.Statements[0] is not *ast.ExpressionStatement. got=%T", program.Statements[0]) 649 | } 650 | 651 | expr, ok := stmt.Expression.(*ast.CallExpression) 652 | if !ok { 653 | t.Errorf("stmt.Expression is not *ast.CallExpression. got=%T", stmt.Expression) 654 | } 655 | 656 | testIdent(t, expr.Function, "add") 657 | 658 | l = len(expr.Arguments) 659 | if l != 3 { 660 | t.Fatalf("wrong length of arguments. got=%d\n", l) 661 | } 662 | 663 | testLiteralExpression(t, expr.Arguments[0], 1) 664 | testInfixExpression(t, expr.Arguments[1], 2, "*", 3) 665 | testInfixExpression(t, expr.Arguments[2], 4, "+", 5) 666 | } 667 | 668 | func TestStringLiteralExpression(t *testing.T) { 669 | input := `"hello world";` 670 | 671 | p := New(lexer.New(input)) 672 | program := p.ParseProgram() 673 | checkParserErrors(t, p) 674 | 675 | if l := len(program.Statements); l != 1 { 676 | t.Fatalf("program has not 1 statement. got=%d", l) 677 | } 678 | 679 | stmt, ok := program.Statements[0].(*ast.ExpressionStatement) 680 | if !ok { 681 | t.Fatalf("program.Statements[0] is not *ast.ExpressionStatement. got=%T", 682 | program.Statements[0]) 683 | } 684 | 685 | literal, ok := stmt.Expression.(*ast.StringLiteral) 686 | if !ok { 687 | t.Fatalf("literal not *ast.StringLiteral. got=%T", stmt.Expression) 688 | } 689 | 690 | expected := "hello world" 691 | if literal.Value != expected { 692 | t.Errorf("literal.Value not %q. got=%q", expected, literal.Value) 693 | } 694 | } 695 | 696 | func TestParsingArrayLiterals(t *testing.T) { 697 | input := "[1, 2 * 2, 3 + 3]" 698 | 699 | p := New(lexer.New(input)) 700 | program := p.ParseProgram() 701 | checkParserErrors(t, p) 702 | 703 | if l := len(program.Statements); l != 1 { 704 | t.Fatalf("program has not 1 statement. got=%d", l) 705 | } 706 | 707 | stmt, ok := program.Statements[0].(*ast.ExpressionStatement) 708 | if !ok { 709 | t.Fatalf("program.Statements[0] is not *ast.ExpressionStatement. got=%T", 710 | program.Statements[0]) 711 | } 712 | 713 | array, ok := stmt.Expression.(*ast.ArrayLiteral) 714 | if !ok { 715 | t.Fatalf("array not *ast.ArrayLiteral. got=%T", stmt.Expression) 716 | } 717 | 718 | if l := len(array.Elements); l != 3 { 719 | t.Fatalf("len(array.Elements) not %d. got=%d", 3, l) 720 | } 721 | 722 | testIntegerLiteral(t, array.Elements[0], 1) 723 | testInfixExpression(t, array.Elements[1], 2, "*", 2) 724 | testInfixExpression(t, array.Elements[2], 3, "+", 3) 725 | } 726 | 727 | func TestParsingIndexExpressions(t *testing.T) { 728 | input := "myArray[1 + 1]" 729 | 730 | p := New(lexer.New(input)) 731 | program := p.ParseProgram() 732 | checkParserErrors(t, p) 733 | 734 | if l := len(program.Statements); l != 1 { 735 | t.Fatalf("program has not %d statement. got=%d", 1, l) 736 | } 737 | 738 | stmt, ok := program.Statements[0].(*ast.ExpressionStatement) 739 | if !ok { 740 | t.Fatalf("program.Statements[0] is not *ast.ExpressionStatement. got=%T", 741 | program.Statements[0]) 742 | } 743 | 744 | idxExpr, ok := stmt.Expression.(*ast.IndexExpression) 745 | if !ok { 746 | t.Fatalf("idxExpr not *ast.IndexExpression. got=%T", stmt.Expression) 747 | } 748 | 749 | testIdent(t, idxExpr.Left, "myArray") 750 | testInfixExpression(t, idxExpr.Index, 1, "+", 1) 751 | } 752 | 753 | func TestParsingHashLiterals(t *testing.T) { 754 | tests := []struct { 755 | input string 756 | expected interface{} 757 | }{ 758 | { 759 | input: "{}", 760 | expected: map[string]int64{}, 761 | }, 762 | { 763 | input: `{"one": 1, "two": 2, "three": 3}`, 764 | expected: map[string]int64{ 765 | "one": 1, 766 | "two": 2, 767 | "three": 3, 768 | }, 769 | }, 770 | { 771 | input: "{1: 1, 2: 2, 3: 3}", 772 | expected: map[int64]int64{ 773 | 1: 1, 774 | 2: 2, 775 | 3: 3, 776 | }, 777 | }, 778 | { 779 | input: "{true: 1, false: 2}", 780 | expected: map[bool]int64{ 781 | true: 1, 782 | false: 2, 783 | }, 784 | }, 785 | { 786 | input: `{"one": 0 + 1, "two": 10 - 8, "three": 15 / 5}`, 787 | expected: map[string]func(ast.Expression){ 788 | "one": func(e ast.Expression) { 789 | testInfixExpression(t, e, 0, "+", 1) 790 | }, 791 | "two": func(e ast.Expression) { 792 | testInfixExpression(t, e, 10, "-", 8) 793 | }, 794 | "three": func(e ast.Expression) { 795 | testInfixExpression(t, e, 15, "/", 5) 796 | }, 797 | }, 798 | }, 799 | } 800 | 801 | for _, tt := range tests { 802 | p := New(lexer.New(tt.input)) 803 | program := p.ParseProgram() 804 | checkParserErrors(t, p) 805 | 806 | if l := len(program.Statements); l != 1 { 807 | t.Fatalf("program has not 1 statement. got=%d", l) 808 | } 809 | 810 | stmt, ok := program.Statements[0].(*ast.ExpressionStatement) 811 | if !ok { 812 | t.Fatalf("program.Statements[0] is not *ast.ExpressionStatement. got=%T", 813 | program.Statements[0]) 814 | } 815 | 816 | hash, ok := stmt.Expression.(*ast.HashLiteral) 817 | if !ok { 818 | t.Fatalf("hash not *ast.HashLiteral. got=%T", stmt.Expression) 819 | } 820 | 821 | for key, value := range hash.Pairs { 822 | switch key := key.(type) { 823 | case *ast.StringLiteral: 824 | switch expected := tt.expected.(type) { 825 | case map[string]int64: 826 | if l := len(hash.Pairs); l != len(expected) { 827 | t.Errorf("hash.Pairs has wrong length. want=%d, got=%d", len(expected), l) 828 | continue 829 | } 830 | expectedValue := expected[key.Value] 831 | testIntegerLiteral(t, value, expectedValue) 832 | case map[string]func(ast.Expression): 833 | if l := len(hash.Pairs); l != len(expected) { 834 | t.Errorf("hash.Pairs has wrong length. want=%d, got=%d", len(expected), l) 835 | continue 836 | } 837 | testFunc := expected[key.Value] 838 | testFunc(value) 839 | } 840 | case *ast.IntegerLiteral: 841 | expected := tt.expected.(map[int64]int64) 842 | if l := len(hash.Pairs); l != len(expected) { 843 | t.Errorf("hash.Pairs has wrong length. want=%d, got=%d", len(expected), l) 844 | continue 845 | } 846 | expectedValue := expected[key.Value] 847 | testIntegerLiteral(t, value, expectedValue) 848 | case *ast.Boolean: 849 | expected := tt.expected.(map[bool]int64) 850 | if l := len(hash.Pairs); l != len(expected) { 851 | t.Errorf("hash.Pairs has wrong length. want=%d, got=%d", len(expected), l) 852 | continue 853 | } 854 | expectedValue := expected[key.Value] 855 | testIntegerLiteral(t, value, expectedValue) 856 | default: 857 | t.Errorf("unsupported key type: %T", key) 858 | } 859 | } 860 | } 861 | } 862 | 863 | func TestMacroLiteralParsing(t *testing.T) { 864 | input := `macro(x, y) { x + y; }` 865 | 866 | l := lexer.New(input) 867 | p := New(l) 868 | program := p.ParseProgram() 869 | checkParserErrors(t, p) 870 | 871 | stmts := program.Statements 872 | if len(stmts) != 1 { 873 | t.Fatalf("expect program.Statements to contain 1 statements, but got %d statements", len(stmts)) 874 | } 875 | 876 | stmt, ok := stmts[0].(*ast.ExpressionStatement) 877 | if !ok { 878 | t.Fatalf("statement is not *ast.ExpressionStatement; got %T", stmts[0]) 879 | } 880 | 881 | macro, ok := stmt.Expression.(*ast.MacroLiteral) 882 | if !ok { 883 | t.Fatalf("stmt.Expression is not *ast.MacroLiteral; got %T", stmt.Expression) 884 | } 885 | 886 | params := macro.Parameters 887 | if len(params) != 2 { 888 | t.Fatalf("macro literal parameters wrong. want 2, but got %d", len(params)) 889 | } 890 | 891 | testLiteralExpression(t, params[0], "x") 892 | testLiteralExpression(t, params[1], "y") 893 | 894 | stmts = macro.Body.Statements 895 | if len(stmts) != 1 { 896 | t.Fatalf("macro.Body.Statements has not 1 statements; got %d statements", len(stmts)) 897 | } 898 | 899 | bodyStmt, ok := stmts[0].(*ast.ExpressionStatement) 900 | if !ok { 901 | t.Fatalf("macro body stmt is not *ast.ExpressionStatement; got %T", stmts[0]) 902 | } 903 | 904 | testInfixExpression(t, bodyStmt.Expression, "x", "+", "y") 905 | } 906 | -------------------------------------------------------------------------------- /repl/repl.go: -------------------------------------------------------------------------------- 1 | package repl 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "io" 7 | 8 | "github.com/skatsuta/monkey-interpreter/eval" 9 | "github.com/skatsuta/monkey-interpreter/lexer" 10 | "github.com/skatsuta/monkey-interpreter/object" 11 | "github.com/skatsuta/monkey-interpreter/parser" 12 | ) 13 | 14 | const prompt = ">> " 15 | 16 | // Start starts Monkey REPL. 17 | func Start(in io.Reader, out io.Writer) { 18 | scanner := bufio.NewScanner(in) 19 | env := object.NewEnvironment() 20 | macroEnv := object.NewEnvironment() 21 | 22 | for { 23 | fmt.Print(prompt) 24 | if !scanner.Scan() { 25 | return 26 | } 27 | 28 | line := scanner.Text() 29 | l := lexer.New(line) 30 | p := parser.New(l) 31 | 32 | program := p.ParseProgram() 33 | if len(p.Errors()) != 0 { 34 | printParserErrors(out, p.Errors()) 35 | continue 36 | } 37 | 38 | // Process macros 39 | eval.DefineMacros(program, macroEnv) 40 | expanded := eval.ExpandMacros(program, macroEnv) 41 | 42 | // Evaluate AST 43 | evaluated := eval.Eval(expanded, env) 44 | if evaluated == nil { 45 | continue 46 | } 47 | 48 | io.WriteString(out, evaluated.Inspect()) 49 | io.WriteString(out, "\n") 50 | } 51 | } 52 | 53 | func printParserErrors(out io.Writer, errors []string) { 54 | for _, msg := range errors { 55 | io.WriteString(out, msg) 56 | io.WriteString(out, "\n") 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /token/token.go: -------------------------------------------------------------------------------- 1 | package token 2 | 3 | // Type is a token type. 4 | type Type string 5 | 6 | const ( 7 | // ILLEGAL is a token type for illegal tokens. 8 | ILLEGAL Type = "ILLEGAL" 9 | // EOF is a token type that represents end of file. 10 | EOF = "EOF" 11 | 12 | // IDENT is a token type for identifiers. 13 | IDENT = "IDENT" // add, foobar, x, y, ... 14 | // INT is a token type for integers. 15 | INT = "INT" 16 | // FLOAT is a token type for floating point numbers. 17 | FLOAT = "FLOAT" 18 | // STRING is a token type for strings. 19 | STRING = "STRING" 20 | 21 | // BANG is a token type for NOT operator. 22 | BANG = "!" 23 | // ASSIGN is a token type for assignment operators. 24 | ASSIGN = "=" 25 | // PLUS is a token type for addition. 26 | PLUS = "+" 27 | // MINUS is a token type for subtraction. 28 | MINUS = "-" 29 | // ASTARISK is a token type for multiplication. 30 | ASTARISK = "*" 31 | // SLASH is a token type for division. 32 | SLASH = "/" 33 | // LT is a token ype for 'less than' operator. 34 | LT = "<" 35 | // GT is a token ype for 'greater than' operator. 36 | GT = ">" 37 | // EQ is a token type for equality operator. 38 | EQ = "==" 39 | // NEQ is a token type for not equality operator. 40 | NEQ = "!=" 41 | 42 | // COMMA is a token type for commas. 43 | COMMA = "," 44 | // SEMICOLON is a token type for semicolons. 45 | SEMICOLON = ";" 46 | // COLON is a token type for colons. 47 | COLON = ":" 48 | 49 | // LPAREN is a token type for left parentheses. 50 | LPAREN = "(" 51 | // RPAREN is a token type for right parentheses. 52 | RPAREN = ")" 53 | // LBRACE is a token type for left braces. 54 | LBRACE = "{" 55 | // RBRACE is a token type for right braces. 56 | RBRACE = "}" 57 | // LBRACKET is a token type for left brackets. 58 | LBRACKET = "[" 59 | // RBRACKET is a token type for right brackets. 60 | RBRACKET = "]" 61 | 62 | // FUNCTION is a token type for functions. 63 | FUNCTION = "FUNCTION" 64 | // LET is a token type for lets. 65 | LET = "LET" 66 | // TRUE is a token type for true. 67 | TRUE = "TRUE" 68 | // FALSE is a token type for false. 69 | FALSE = "FALSE" 70 | // IF is a token type for if. 71 | IF = "IF" 72 | // ELSE is a token type for else. 73 | ELSE = "ELSE" 74 | // RETURN is a token type for return. 75 | RETURN = "RETURN" 76 | // MACRO is a token type for macros. 77 | MACRO = "MACRO" 78 | ) 79 | 80 | // Token represents a token which has a token type and literal. 81 | type Token struct { 82 | Type Type 83 | Literal string 84 | } 85 | 86 | // Language keywords 87 | var keywords = map[string]Type{ 88 | "fn": FUNCTION, 89 | "let": LET, 90 | "true": TRUE, 91 | "false": FALSE, 92 | "if": IF, 93 | "else": ELSE, 94 | "return": RETURN, 95 | "macro": MACRO, 96 | } 97 | 98 | // LookupIdent checks the language keywords to see whether the given identifier is a keyword. 99 | // If it is, it returns the keyword's Type constant. If it isn't, it just gets back IDENT. 100 | func LookupIdent(ident string) Type { 101 | if tok, ok := keywords[ident]; ok { 102 | return tok 103 | } 104 | return IDENT 105 | } 106 | -------------------------------------------------------------------------------- /wercker.yml: -------------------------------------------------------------------------------- 1 | box: golang 2 | 3 | build: 4 | steps: 5 | # Sets the go workspace and places you package 6 | # at the right place in the workspace tree 7 | - setup-go-workspace 8 | 9 | # Run golint 10 | - golint 11 | 12 | # Show go version 13 | - script: 14 | name: go version 15 | code: | 16 | go version 17 | 18 | # Get the dependencies 19 | - script: 20 | name: go get 21 | code: | 22 | go get -t -v ./... 23 | 24 | # Build the project 25 | - script: 26 | name: go build 27 | code: | 28 | go build ./... 29 | 30 | # Test the project 31 | - script: 32 | name: go test 33 | code: | 34 | go test ./... 35 | --------------------------------------------------------------------------------