| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 |
- package parser
- import (
- "fmt"
- "github/runnignwater/monkey/ast"
- "github/runnignwater/monkey/lexer"
- "log"
- "testing"
- )
- /**
- * @Author: simon
- * @Author: ynwdlxm@163.com
- * @Date: 2022/10/2 下午10:40
- * @Desc: LetStatement test case
- */
- func TestLetStatements(t *testing.T) {
- input := `
- let x = 5;
- let y = 10;
-
- let foo = 838383;
- `
- l := lexer.New(input)
- p := New(l)
- program := p.ParseProgram()
- checkParseErrors(t, p)
- if program == nil {
- t.Fatalf("ParseProgram() return nil")
- }
- if len(program.Statements) != 3 {
- t.Fatalf("Program.Statements does not contain 3 statements. got=%d", len(program.Statements))
- }
- tests := []struct {
- expectedIdentifies string
- }{
- {"x"},
- {"y"},
- {"foo"},
- }
- for i, tt := range tests {
- stmt := program.Statements[i]
- if !testLetStatement(t, stmt, tt.expectedIdentifies) {
- return
- }
- }
- }
- func TestReturnStatements(t *testing.T) {
- input := `
- return 5;
- return 10;
- return add(a,10);
- `
- l := lexer.New(input)
- p := New(l)
- program := p.ParseProgram()
- checkParseErrors(t, p)
- if len(program.Statements) != 3 {
- t.Fatalf("Program.Statements does not contain 3 statements. got=%d", len(program.Statements))
- }
- for _, stmt := range program.Statements {
- returnStmt, ok := stmt.(*ast.ReturnStatement)
- if !ok {
- t.Errorf("stmt not *ast.ReturnStatement. got=%T", stmt)
- continue
- }
- if returnStmt.TokenLiteral() != "return" {
- t.Errorf("returnStmt.TokenLiteral not 'return', got %q", returnStmt.TokenLiteral())
- }
- }
- }
- func checkParseErrors(t *testing.T, p *Parser) {
- errors := p.errors
- if len(errors) == 0 {
- return
- }
- t.Errorf("parse has %d errors.", len(errors))
- for _, msg := range errors {
- t.Errorf("parse error: %q", msg)
- }
- t.FailNow()
- }
- func testLetStatement(t *testing.T, s ast.Statement, name string) bool {
- if s.TokenLiteral() != "let" {
- t.Errorf("s.TokenLiteral() not 'let'. got =%q", s.TokenLiteral())
- return false
- }
- letStmt, ok := s.(*ast.LetStatement)
- if !ok {
- t.Errorf("s is not *ast.LetStatement. got=%T", s)
- return false
- }
- if letStmt.Name.Value != name {
- t.Errorf("letStmt.Name.Value not '%s'. got=%s", name, letStmt.Name.Value)
- return false
- }
- if letStmt.Name.TokenLiteral() != name {
- t.Errorf("s.name not '%s. got=%s", name, letStmt.Name)
- return false
- }
- return true
- }
- func TestIdentifier(t *testing.T) {
- input := "foobar;"
- l := lexer.New(input)
- p := New(l)
- program := p.ParseProgram()
- checkParseErrors(t, p)
- if len(program.Statements) != 1 {
- t.Fatalf("program has not enough statements. got=%d", len(program.Statements))
- }
- stmt, ok := program.Statements[0].(*ast.ExpressionStatement)
- if !ok {
- t.Fatalf("program.Statements[0] is not ast.ExpressionStatement. got=%T",
- program.Statements[0])
- }
- ident, ok := stmt.Expression.(*ast.Identifier)
- if !ok {
- t.Fatalf("exp not *ast.Identifier. got=%T", stmt.Expression)
- }
- if ident.Value != "foobar" {
- t.Fatalf("ident.Value not %s. got=%s", "foobar", ident.Value)
- }
- if ident.TokenLiteral() != "foobar" {
- t.Errorf("ident.TokenLiteral() not %s. got=%s", "foobar", ident.TokenLiteral())
- }
- }
- func TestIntegerLiteralExpression(t *testing.T) {
- input := "5;"
- l := lexer.New(input)
- p := New(l)
- program := p.ParseProgram()
- checkParseErrors(t, p)
- if len(program.Statements) != 1 {
- t.Fatalf("program has not enough statements. got=%d",
- len(program.Statements))
- }
- stmt, ok := program.Statements[0].(*ast.ExpressionStatement)
- if !ok {
- t.Fatalf("program.Statements[0] is not ast.ExpressionStatement. got=%T",
- program.Statements[0])
- }
- literal, ok := stmt.Expression.(*ast.IntegerLiteral)
- if !ok {
- t.Fatalf("exp not *ast.IntegerLiteral. got=%T", stmt.Expression)
- }
- if literal.Value != 5 {
- t.Errorf("literal.Value not %d. got=%d", 5, literal.Value)
- }
- if literal.TokenLiteral() != "5" {
- t.Errorf("literal.TokenLiteral not %s. got=%s", "5",
- literal.TokenLiteral())
- }
- }
- /**
- * Prefix Operators or "prefix expressions"
- * <prefix operator><expression>;
- * -5;
- * !foobar;
- * 5 + -10;
- */
- func TestParsingPrefixExpressions(t *testing.T) {
- prefixTests := []struct {
- input string
- operator string
- integerValue int64
- }{
- {"!5;", "!", 5},
- {"-15;", "-", 15},
- }
- for _, tt := range prefixTests {
- l := lexer.New(tt.input)
- p := New(l)
- program := p.ParseProgram()
- checkParseErrors(t, p)
- if len(program.Statements) != 1 {
- t.Fatalf("program.Statement does not contain %d statements. got=%d\n",
- 1, len(program.Statements))
- }
- stmt, ok := program.Statements[0].(*ast.ExpressionStatement)
- if !ok {
- t.Fatalf("program.Statements[0] is not ast.ExpressionStatement. got=%T",
- program.Statements[0])
- }
- exp, ok := stmt.Expression.(*ast.PrefixExpression)
- if !ok {
- log.Fatalf("stmt is not ast.PrefixExpression. got=%T", stmt.Expression)
- }
- if exp.Operator != tt.operator {
- t.Fatalf("exp.Operator is not '%s'. got=%s",
- tt.operator, exp.Operator)
- }
- if !testIntegerLiteral(t, exp.Right, tt.integerValue) {
- return
- }
- }
- }
- func testIntegerLiteral(t *testing.T, il ast.Expression, value int64) bool {
- integ, ok := il.(*ast.IntegerLiteral)
- if !ok {
- t.Errorf("il not *ast.IntegerLiteral. got=%T", il)
- return false
- }
- if integ.Value != value {
- t.Errorf("integ.Value not %d. get=%d", value, integ.Value)
- return false
- }
- if integ.TokenLiteral() != fmt.Sprintf("%d", value) {
- t.Errorf("integ.TokenLiteral not %d. got=%s", value, integ.TokenLiteral())
- return false
- }
- return true
- }
|