if, or, and, env
This commit is contained in:
		
							parent
							
								
									124537b781
								
							
						
					
					
						commit
						5de730af97
					
				
					 9 changed files with 250 additions and 35 deletions
				
			
		|  | @ -62,6 +62,24 @@ func (as *AstStringer) visitAssignment(a *Assign) any { | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (as *AstStringer) visitLogicalOr(l *LogicalOr) any { | ||||||
|  | 	as.str.WriteString("(or ") | ||||||
|  | 	l.left.accept(as) | ||||||
|  | 	as.str.WriteString(" ") | ||||||
|  | 	l.right.accept(as) | ||||||
|  | 	as.str.WriteString(")") | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (as *AstStringer) visitLogicalAnd(l *LogicalAnd) any { | ||||||
|  | 	as.str.WriteString("(and ") | ||||||
|  | 	l.left.accept(as) | ||||||
|  | 	as.str.WriteString(" ") | ||||||
|  | 	l.right.accept(as) | ||||||
|  | 	as.str.WriteString(")") | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (as *AstStringer) visitPrintStmt(p *PrintStmt) { | func (as *AstStringer) visitPrintStmt(p *PrintStmt) { | ||||||
| 	as.str.WriteString("(print ") | 	as.str.WriteString("(print ") | ||||||
| 	p.val.accept(as) | 	p.val.accept(as) | ||||||
|  | @ -92,3 +110,19 @@ func (as *AstStringer) visitBlockStmt(b *BlockStmt) { | ||||||
| 	as.str.WriteString(")") | 	as.str.WriteString(")") | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func (as *AstStringer) visitIfStmt(i *IfStmt) { | ||||||
|  | 	as.str.WriteString("(if ") | ||||||
|  | 	i.expr.accept(as) | ||||||
|  | 	as.str.WriteString(" ") | ||||||
|  | 	i.then.accept(as) | ||||||
|  | 	if i.or != nil { | ||||||
|  | 		as.str.WriteString(" ") | ||||||
|  | 		i.or.accept(as) | ||||||
|  | 	} | ||||||
|  | 	as.str.WriteString(")") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (as *AstStringer) visitEnvStmt(e *EnvStmt) { | ||||||
|  | 	as.str.WriteString("(env)") | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										36
									
								
								expr.go
									
										
									
									
									
								
							
							
						
						
									
										36
									
								
								expr.go
									
										
									
									
									
								
							|  | @ -6,7 +6,9 @@ type ExprVisitor interface { | ||||||
| 	visitLiteral(l *Literal) any | 	visitLiteral(l *Literal) any | ||||||
| 	visitGrouping(g *Grouping) any | 	visitGrouping(g *Grouping) any | ||||||
| 	visitVariable(v *Variable) any | 	visitVariable(v *Variable) any | ||||||
|  | 	visitLogicalOr(l *LogicalOr) any | ||||||
| 	visitAssignment(a *Assign) any | 	visitAssignment(a *Assign) any | ||||||
|  | 	visitLogicalAnd(l *LogicalAnd) any | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type Expr interface { | type Expr interface { | ||||||
|  | @ -42,12 +44,26 @@ type Assign struct { | ||||||
| 	value    Expr | 	value    Expr | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (u *Unary) expr()    {} | type LogicalOr struct { | ||||||
| func (b *Binary) expr()   {} | 	left  Expr | ||||||
| func (l *Literal) expr()  {} | 	or    Token | ||||||
| func (g *Grouping) expr() {} | 	right Expr | ||||||
| func (v *Variable) expr() {} | } | ||||||
| func (a *Assign) expr()   {} | 
 | ||||||
|  | type LogicalAnd struct { | ||||||
|  | 	left  Expr | ||||||
|  | 	and   Token | ||||||
|  | 	right Expr | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (u *Unary) expr()      {} | ||||||
|  | func (a *Assign) expr()     {} | ||||||
|  | func (b *Binary) expr()     {} | ||||||
|  | func (l *Literal) expr()    {} | ||||||
|  | func (g *Grouping) expr()   {} | ||||||
|  | func (v *Variable) expr()   {} | ||||||
|  | func (l *LogicalOr) expr()  {} | ||||||
|  | func (l *LogicalAnd) expr() {} | ||||||
| 
 | 
 | ||||||
| func (u *Unary) accept(v ExprVisitor) any { | func (u *Unary) accept(v ExprVisitor) any { | ||||||
| 	return v.visitUnary(u) | 	return v.visitUnary(u) | ||||||
|  | @ -72,3 +88,11 @@ func (va *Variable) accept(v ExprVisitor) any { | ||||||
| func (a *Assign) accept(v ExprVisitor) any { | func (a *Assign) accept(v ExprVisitor) any { | ||||||
| 	return v.visitAssignment(a) | 	return v.visitAssignment(a) | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func (l *LogicalOr) accept(v ExprVisitor) any { | ||||||
|  | 	return v.visitLogicalOr(l) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (l *LogicalAnd) accept(v ExprVisitor) any { | ||||||
|  | 	return v.visitLogicalAnd(l) | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										14
									
								
								expr_rpn.go
									
										
									
									
									
								
							
							
						
						
									
										14
									
								
								expr_rpn.go
									
										
									
									
									
								
							|  | @ -54,3 +54,17 @@ func (as *ExprToRPN) visitAssignment(a *Assign) any { | ||||||
| 	as.str.WriteString(fmt.Sprintf("%v %s =", a.value, a.variable.lexeme)) | 	as.str.WriteString(fmt.Sprintf("%v %s =", a.value, a.variable.lexeme)) | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func (as *ExprToRPN) visitLogicalOr(lo *LogicalOr) any { | ||||||
|  | 	lo.left.accept(as) | ||||||
|  | 	lo.right.accept(as) | ||||||
|  | 	as.str.WriteString(" or") | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (as *ExprToRPN) visitLogicalAnd(la *LogicalAnd) any { | ||||||
|  | 	la.left.accept(as) | ||||||
|  | 	la.right.accept(as) | ||||||
|  | 	as.str.WriteString(" and") | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -4,6 +4,7 @@ import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"log" | 	"log" | ||||||
| 	"reflect" | 	"reflect" | ||||||
|  | 	"slices" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type Interpreter struct { | type Interpreter struct { | ||||||
|  | @ -119,13 +120,11 @@ func (i *Interpreter) visitUnary(u *Unary) any { | ||||||
| 
 | 
 | ||||||
| func (i *Interpreter) visitVariable(v *Variable) any { | func (i *Interpreter) visitVariable(v *Variable) any { | ||||||
| 
 | 
 | ||||||
| 	val := i.env.get(v.name.lexeme) | 	if !i.env.exists(v.name.lexeme) { | ||||||
| 
 | 		i.panic(&RuntimeError{v.name, fmt.Sprintf("Can't assign: undefined variable '%s'.", v.name.lexeme)}) | ||||||
| 	if val == nil { |  | ||||||
| 		i.panic(&RuntimeError{v.name, fmt.Sprintf("Can't evaluate: Undefined variable '%s'.", v.name.lexeme)}) |  | ||||||
| 		return nil |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	val := i.env.get(v.name.lexeme) | ||||||
| 	return val | 	return val | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -133,8 +132,6 @@ func (i *Interpreter) visitAssignment(a *Assign) any { | ||||||
| 
 | 
 | ||||||
| 	if !i.env.exists(a.variable.lexeme) { | 	if !i.env.exists(a.variable.lexeme) { | ||||||
| 		i.panic(&RuntimeError{a.variable, fmt.Sprintf("Can't assign: undefined variable '%s'.", a.variable.lexeme)}) | 		i.panic(&RuntimeError{a.variable, fmt.Sprintf("Can't assign: undefined variable '%s'.", a.variable.lexeme)}) | ||||||
| 
 |  | ||||||
| 		return nil |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	val := i.evaluate(a.value) | 	val := i.evaluate(a.value) | ||||||
|  | @ -144,6 +141,14 @@ func (i *Interpreter) visitAssignment(a *Assign) any { | ||||||
| 	return val | 	return val | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (i *Interpreter) visitLogicalOr(lo *LogicalOr) any { | ||||||
|  | 	return isTruthy(i.evaluate(lo.left)) || isTruthy(i.evaluate(lo.right)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (i *Interpreter) visitLogicalAnd(la *LogicalAnd) any { | ||||||
|  | 	return isTruthy(i.evaluate(la.left)) && isTruthy(i.evaluate(la.right)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (i *Interpreter) visitPrintStmt(p *PrintStmt) { | func (i *Interpreter) visitPrintStmt(p *PrintStmt) { | ||||||
| 	fmt.Printf("%v\n", i.evaluate(p.val)) | 	fmt.Printf("%v\n", i.evaluate(p.val)) | ||||||
| } | } | ||||||
|  | @ -175,6 +180,33 @@ func (i *Interpreter) visitBlockStmt(b *BlockStmt) { | ||||||
| 	i.env = parentEnv | 	i.env = parentEnv | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func (i *Interpreter) visitIfStmt(iff *IfStmt) { | ||||||
|  | 	if isTruthy(i.evaluate(iff.expr)) { | ||||||
|  | 		iff.then.accept(i) | ||||||
|  | 
 | ||||||
|  | 	} else if iff.or != nil { | ||||||
|  | 		iff.or.accept(i) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (i *Interpreter) visitEnvStmt(e *EnvStmt) { | ||||||
|  | 
 | ||||||
|  | 	walker := i.env | ||||||
|  | 
 | ||||||
|  | 	flatten := []*Environment{} | ||||||
|  | 
 | ||||||
|  | 	for walker != nil { | ||||||
|  | 		flatten = slices.Insert(flatten, 0, walker) | ||||||
|  | 		walker = walker.parent | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for ident, e := range flatten { | ||||||
|  | 		fmt.Printf("%*s", ident, "") | ||||||
|  | 		fmt.Printf("%+v\n", *e) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (i *Interpreter) panic(re *RuntimeError) { | func (i *Interpreter) panic(re *RuntimeError) { | ||||||
| 	i.errors = append(i.errors, re) | 	i.errors = append(i.errors, re) | ||||||
| 	log.Println(re) | 	log.Println(re) | ||||||
|  | @ -198,6 +230,11 @@ func (i *Interpreter) checkIfFloats(op Token, a any, b any) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func isFloats(a any, b any) bool { | func isFloats(a any, b any) bool { | ||||||
|  | 
 | ||||||
|  | 	if a == nil || b == nil { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	ltype := reflect.TypeOf(a) | 	ltype := reflect.TypeOf(a) | ||||||
| 	rtype := reflect.TypeOf(b) | 	rtype := reflect.TypeOf(b) | ||||||
| 
 | 
 | ||||||
|  | @ -205,6 +242,11 @@ func isFloats(a any, b any) bool { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func isStrings(a any, b any) bool { | func isStrings(a any, b any) bool { | ||||||
|  | 
 | ||||||
|  | 	if a == nil || b == nil { | ||||||
|  | 		return false | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	ltype := reflect.TypeOf(a) | 	ltype := reflect.TypeOf(a) | ||||||
| 	rtype := reflect.TypeOf(b) | 	rtype := reflect.TypeOf(b) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										78
									
								
								parser.go
									
										
									
									
									
								
							
							
						
						
									
										78
									
								
								parser.go
									
										
									
									
									
								
							|  | @ -66,7 +66,7 @@ func (p *Parser) varDecl() Stmt { | ||||||
| 	return &VarStmt{name, initializer} | 	return &VarStmt{name, initializer} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // statement -> exprStmt | printStmt | block | // statement -> exprStmt | printStmt | block | ifStmt | env | ||||||
| func (p *Parser) statement() Stmt { | func (p *Parser) statement() Stmt { | ||||||
| 	if p.match(PRINT) { | 	if p.match(PRINT) { | ||||||
| 		return p.printStmt() | 		return p.printStmt() | ||||||
|  | @ -76,6 +76,14 @@ func (p *Parser) statement() Stmt { | ||||||
| 		return p.block() | 		return p.block() | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if p.match(IF) { | ||||||
|  | 		return p.ifStmt() | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if p.match(ENV) { | ||||||
|  | 		return p.envStmt() | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	return p.exprStmt() | 	return p.exprStmt() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -83,12 +91,22 @@ func (p *Parser) statement() Stmt { | ||||||
| func (p *Parser) exprStmt() Stmt { | func (p *Parser) exprStmt() Stmt { | ||||||
| 	expr := p.expression() | 	expr := p.expression() | ||||||
| 	p.consume(SEMICOLON, "Expect ';' after expression.") | 	p.consume(SEMICOLON, "Expect ';' after expression.") | ||||||
|  | 
 | ||||||
|  | 	if expr == nil { | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	return &ExprStmt{expr} | 	return &ExprStmt{expr} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // printStmt -> "print" expression ";" | // printStmt -> "print" expression ";" | ||||||
| func (p *Parser) printStmt() Stmt { | func (p *Parser) printStmt() Stmt { | ||||||
| 	expr := p.expression() | 	expr := p.expression() | ||||||
|  | 
 | ||||||
|  | 	if expr == nil { | ||||||
|  | 		p.panic(&ParseError{p.previous(), "Expect expression after 'print'"}) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	p.consume(SEMICOLON, "Expect ';' after expression.") | 	p.consume(SEMICOLON, "Expect ';' after expression.") | ||||||
| 	return &PrintStmt{expr} | 	return &PrintStmt{expr} | ||||||
| } | } | ||||||
|  | @ -97,7 +115,7 @@ func (p *Parser) printStmt() Stmt { | ||||||
| func (p *Parser) block() Stmt { | func (p *Parser) block() Stmt { | ||||||
| 
 | 
 | ||||||
| 	stmts := []Stmt{} | 	stmts := []Stmt{} | ||||||
| 	for !p.check(RIGHT_BRACE) { | 	for !p.check(RIGHT_BRACE) && !p.isAtEnd() { | ||||||
| 		stmts = append(stmts, p.declaration()) | 		stmts = append(stmts, p.declaration()) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -106,14 +124,36 @@ func (p *Parser) block() Stmt { | ||||||
| 	return &BlockStmt{stmts} | 	return &BlockStmt{stmts} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // if -> "if" "(" expression ")" statement ("else" statement)? | ||||||
|  | func (p *Parser) ifStmt() Stmt { | ||||||
|  | 	name := p.previous() | ||||||
|  | 	p.consume(LEFT_PAREN, "Expect '(' after 'if'.") | ||||||
|  | 	expr := p.expression() | ||||||
|  | 	p.consume(RIGHT_PAREN, "Expect ')' after 'if' condition.") | ||||||
|  | 	then := p.statement() | ||||||
|  | 
 | ||||||
|  | 	var or Stmt = nil | ||||||
|  | 	if p.match(ELSE) { | ||||||
|  | 		or = p.statement() | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return &IfStmt{name, expr, then, or} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // env -> "env" ";" | ||||||
|  | func (p *Parser) envStmt() Stmt { | ||||||
|  | 	p.consume(SEMICOLON, "Expect ';' after 'env'.") | ||||||
|  | 	return &EnvStmt{} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // expression -> assignment | // expression -> assignment | ||||||
| func (p *Parser) expression() Expr { | func (p *Parser) expression() Expr { | ||||||
| 	return p.assignment() | 	return p.assignment() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // assignment -> IDENTIFIER "=" assignment | equality | // assignment -> IDENTIFIER "=" assignment | logicalOr | ||||||
| func (p *Parser) assignment() Expr { | func (p *Parser) assignment() Expr { | ||||||
| 	expr := p.equality() | 	expr := p.logicalOr() | ||||||
| 
 | 
 | ||||||
| 	if p.match(EQUAL) { | 	if p.match(EQUAL) { | ||||||
| 		eq := p.previous() | 		eq := p.previous() | ||||||
|  | @ -129,6 +169,34 @@ func (p *Parser) assignment() Expr { | ||||||
| 	return expr | 	return expr | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // logicalOr -> logicalAnd ( "or" logicalAnd )* | ||||||
|  | func (p *Parser) logicalOr() Expr { | ||||||
|  | 	left := p.logicalAnd() | ||||||
|  | 
 | ||||||
|  | 	for p.match(OR) { | ||||||
|  | 		or := p.previous() | ||||||
|  | 		right := p.logicalAnd() | ||||||
|  | 
 | ||||||
|  | 		left = &LogicalOr{left, or, right} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return left | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // logicalAnd -> equality ( "and" equality )* | ||||||
|  | func (p *Parser) logicalAnd() Expr { | ||||||
|  | 	left := p.equality() | ||||||
|  | 
 | ||||||
|  | 	for p.match(AND) { | ||||||
|  | 		or := p.previous() | ||||||
|  | 		right := p.equality() | ||||||
|  | 
 | ||||||
|  | 		left = &LogicalAnd{left, or, right} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return left | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // equality -> comparison ( ( "==" | "!=" ) comparison )* | // equality -> comparison ( ( "==" | "!=" ) comparison )* | ||||||
| func (p *Parser) equality() Expr { | func (p *Parser) equality() Expr { | ||||||
| 	expr := p.comparison() | 	expr := p.comparison() | ||||||
|  | @ -289,7 +357,7 @@ func (p *Parser) synchronize() { | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		switch p.peek().typ { | 		switch p.peek().typ { | ||||||
| 		case CLASS, FOR, FUN, IF, PRINT, RETURN, VAR, WHILE: | 		case CLASS, FOR, FUN, IF, PRINT, RETURN, VAR, WHILE, ENV: | ||||||
| 			return | 			return | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -44,6 +44,7 @@ const ( | ||||||
| 	// keywords | 	// keywords | ||||||
| 	AND | 	AND | ||||||
| 	CLASS | 	CLASS | ||||||
|  | 	ENV | ||||||
| 	ELSE | 	ELSE | ||||||
| 	FALSE | 	FALSE | ||||||
| 	FUN | 	FUN | ||||||
|  | @ -79,6 +80,7 @@ var keywords = map[string]TokenType{ | ||||||
| 	"true":   TRUE, | 	"true":   TRUE, | ||||||
| 	"var":    VAR, | 	"var":    VAR, | ||||||
| 	"while":  WHILE, | 	"while":  WHILE, | ||||||
|  | 	"env":    ENV, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type Token struct { | type Token struct { | ||||||
|  |  | ||||||
							
								
								
									
										21
									
								
								stmt.go
									
										
									
									
									
								
							
							
						
						
									
										21
									
								
								stmt.go
									
										
									
									
									
								
							|  | @ -1,10 +1,12 @@ | ||||||
| package main | package main | ||||||
| 
 | 
 | ||||||
| type StmtVisitor interface { | type StmtVisitor interface { | ||||||
|  | 	visitIfStmt(i *IfStmt) | ||||||
| 	visitVarStmt(v *VarStmt) | 	visitVarStmt(v *VarStmt) | ||||||
| 	visitExprStmt(es *ExprStmt) | 	visitExprStmt(es *ExprStmt) | ||||||
| 	visitPrintStmt(p *PrintStmt) | 	visitPrintStmt(p *PrintStmt) | ||||||
| 	visitBlockStmt(b *BlockStmt) | 	visitBlockStmt(b *BlockStmt) | ||||||
|  | 	visitEnvStmt(e *EnvStmt) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type Stmt interface { | type Stmt interface { | ||||||
|  | @ -29,10 +31,21 @@ type BlockStmt struct { | ||||||
| 	stmts []Stmt | 	stmts []Stmt | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | type EnvStmt struct{} | ||||||
|  | 
 | ||||||
|  | type IfStmt struct { | ||||||
|  | 	name Token | ||||||
|  | 	expr Expr | ||||||
|  | 	then Stmt | ||||||
|  | 	or   Stmt | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (i *IfStmt) stmt()    {} | ||||||
| func (vs *VarStmt) stmt()  {} | func (vs *VarStmt) stmt()  {} | ||||||
| func (es *ExprStmt) stmt() {} | func (es *ExprStmt) stmt() {} | ||||||
| func (p *PrintStmt) stmt() {} | func (p *PrintStmt) stmt() {} | ||||||
| func (b *BlockStmt) stmt() {} | func (b *BlockStmt) stmt() {} | ||||||
|  | func (e *EnvStmt) stmt()   {} | ||||||
| 
 | 
 | ||||||
| func (p *PrintStmt) accept(v StmtVisitor) { | func (p *PrintStmt) accept(v StmtVisitor) { | ||||||
| 	v.visitPrintStmt(p) | 	v.visitPrintStmt(p) | ||||||
|  | @ -49,3 +62,11 @@ func (vs *VarStmt) accept(v StmtVisitor) { | ||||||
| func (b *BlockStmt) accept(v StmtVisitor) { | func (b *BlockStmt) accept(v StmtVisitor) { | ||||||
| 	v.visitBlockStmt(b) | 	v.visitBlockStmt(b) | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func (i *IfStmt) accept(v StmtVisitor) { | ||||||
|  | 	v.visitIfStmt(i) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (e *EnvStmt) accept(v StmtVisitor) { | ||||||
|  | 	v.visitEnvStmt(e) | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										9
									
								
								tests/env.lox
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								tests/env.lox
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | ||||||
|  | var a = 1; | ||||||
|  | { | ||||||
|  |     var b = 2;  | ||||||
|  |     { | ||||||
|  |         var c =3; | ||||||
|  |         env; | ||||||
|  |     } | ||||||
|  |     env; | ||||||
|  | } | ||||||
|  | @ -32,26 +32,27 @@ func _() { | ||||||
| 	_ = x[NUMBER-21] | 	_ = x[NUMBER-21] | ||||||
| 	_ = x[AND-22] | 	_ = x[AND-22] | ||||||
| 	_ = x[CLASS-23] | 	_ = x[CLASS-23] | ||||||
| 	_ = x[ELSE-24] | 	_ = x[ENV-24] | ||||||
| 	_ = x[FALSE-25] | 	_ = x[ELSE-25] | ||||||
| 	_ = x[FUN-26] | 	_ = x[FALSE-26] | ||||||
| 	_ = x[FOR-27] | 	_ = x[FUN-27] | ||||||
| 	_ = x[IF-28] | 	_ = x[FOR-28] | ||||||
| 	_ = x[NIL-29] | 	_ = x[IF-29] | ||||||
| 	_ = x[OR-30] | 	_ = x[NIL-30] | ||||||
| 	_ = x[PRINT-31] | 	_ = x[OR-31] | ||||||
| 	_ = x[RETURN-32] | 	_ = x[PRINT-32] | ||||||
| 	_ = x[SUPER-33] | 	_ = x[RETURN-33] | ||||||
| 	_ = x[THIS-34] | 	_ = x[SUPER-34] | ||||||
| 	_ = x[TRUE-35] | 	_ = x[THIS-35] | ||||||
| 	_ = x[VAR-36] | 	_ = x[TRUE-36] | ||||||
| 	_ = x[WHILE-37] | 	_ = x[VAR-37] | ||||||
| 	_ = x[EOF-38] | 	_ = x[WHILE-38] | ||||||
|  | 	_ = x[EOF-39] | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const _TokenType_name = "LEFT_PARENRIGHT_PARENLEFT_BRACERIGHT_BRACECOMMADOTMINUSPLUSSEMICOLONSLASHSTARBANGBANG_EQUALEQUALEQUAL_EQUALGREATERGREATER_EQUALLESSLESS_EQUALIDENTIFIERSTRINGNUMBERANDCLASSELSEFALSEFUNFORIFNILORPRINTRETURNSUPERTHISTRUEVARWHILEEOF" | const _TokenType_name = "LEFT_PARENRIGHT_PARENLEFT_BRACERIGHT_BRACECOMMADOTMINUSPLUSSEMICOLONSLASHSTARBANGBANG_EQUALEQUALEQUAL_EQUALGREATERGREATER_EQUALLESSLESS_EQUALIDENTIFIERSTRINGNUMBERANDCLASSENVELSEFALSEFUNFORIFNILORPRINTRETURNSUPERTHISTRUEVARWHILEEOF" | ||||||
| 
 | 
 | ||||||
| var _TokenType_index = [...]uint8{0, 10, 21, 31, 42, 47, 50, 55, 59, 68, 73, 77, 81, 91, 96, 107, 114, 127, 131, 141, 151, 157, 163, 166, 171, 175, 180, 183, 186, 188, 191, 193, 198, 204, 209, 213, 217, 220, 225, 228} | var _TokenType_index = [...]uint8{0, 10, 21, 31, 42, 47, 50, 55, 59, 68, 73, 77, 81, 91, 96, 107, 114, 127, 131, 141, 151, 157, 163, 166, 171, 174, 178, 183, 186, 189, 191, 194, 196, 201, 207, 212, 216, 220, 223, 228, 231} | ||||||
| 
 | 
 | ||||||
| func (i TokenType) String() string { | func (i TokenType) String() string { | ||||||
| 	if i < 0 || i >= TokenType(len(_TokenType_index)-1) { | 	if i < 0 || i >= TokenType(len(_TokenType_index)-1) { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue