Ver código fonte

Parsing Return Statement--test case

runningwater 3 anos atrás
pai
commit
fe2b5b982c
2 arquivos alterados com 164 adições e 119 exclusões
  1. 82 65
      parser/parser.go
  2. 82 54
      parser/parser_test.go

+ 82 - 65
parser/parser.go

@@ -1,10 +1,10 @@
 package parser
 
 import (
-    "fmt"
-    "github/runnignwater/monkey/ast"
-    "github/runnignwater/monkey/lexer"
-    "github/runnignwater/monkey/token"
+	"fmt"
+	"github/runnignwater/monkey/ast"
+	"github/runnignwater/monkey/lexer"
+	"github/runnignwater/monkey/token"
 )
 
 /**
@@ -14,100 +14,117 @@ import (
  * @Desc:
  */
 type Parser struct {
-    l *lexer.Lexer // point to the instance of the lexer
+	l *lexer.Lexer // point to the instance of the lexer
 
-    curToken  token.Token // point to the current token
-    peekToken token.Token // point to the next token
+	curToken  token.Token // point to the current token
+	peekToken token.Token // point to the next token
 
-    errors []string
+	errors []string
 }
 
 func New(l *lexer.Lexer) *Parser {
-    p := &Parser{
-        l:      l,
-        errors: []string{},
-    }
+	p := &Parser{
+		l:      l,
+		errors: []string{},
+	}
 
-    // Read two tokens, so curToken and peekToken are both set
-    p.nextToken()
-    p.nextToken()
+	// Read two tokens, so curToken and peekToken are both set
+	p.nextToken()
+	p.nextToken()
 
-    return p
+	return p
 }
 
 func (p *Parser) Errors() []string {
-    return p.errors
+	return p.errors
 }
 
 func (p *Parser) peekError(t token.TypeToken) {
-    msg := fmt.Sprintf("exepected next token to be %s, got %s instead.", t, p.peekToken.Type)
-    p.errors = append(p.errors, msg)
+	msg := fmt.Sprintf("exepected next token to be %s, got %s instead.", t, p.peekToken.Type)
+	p.errors = append(p.errors, msg)
 }
 
 func (p *Parser) nextToken() {
-    p.curToken = p.peekToken
-    p.peekToken = p.l.NextToken()
+	p.curToken = p.peekToken
+	p.peekToken = p.l.NextToken()
 }
 
 func (p *Parser) ParseProgram() *ast.Program {
-    program := &ast.Program{}
-    program.Statements = []ast.Statement{}
-
-    for !p.curTokenIs(token.EOF) {
-        stmt := p.parseStatement()
-        if stmt != nil {
-            program.Statements = append(program.Statements, stmt)
-        }
-        p.nextToken()
-
-    }
-    return program
+	program := &ast.Program{}
+	program.Statements = []ast.Statement{}
+
+	for !p.curTokenIs(token.EOF) {
+		stmt := p.parseStatement()
+		if stmt != nil {
+			program.Statements = append(program.Statements, stmt)
+		}
+		p.nextToken()
+
+	}
+	return program
 }
 
 func (p *Parser) parseStatement() ast.Statement {
-    switch p.curToken.Type {
-    case token.LET:
-        return p.parseLetStatement()
-    default:
-        return nil
-    }
+	switch p.curToken.Type {
+	case token.LET:
+		return p.parseLetStatement()
+	case token.RETURN:
+		return p.parseReturnStatement()
+	default:
+		return nil
+	}
 }
 
 // let <identifier> = <expression>;
 func (p *Parser) parseLetStatement() *ast.LetStatement {
-    stmt := &ast.LetStatement{Token: p.curToken}
-
-    if !p.expectPeek(token.IDENT) {
-        return nil
-    }
-
-    stmt.Name = &ast.Identifier{Token: p.curToken, Value: p.curToken.Literal}
-    if !p.expectPeek(token.ASSIGN) {
-        return nil
-    }
-
-    // TODO: we're skipping the expression until we
-    //       we encounter a semicolon
-    for !p.curTokenIs(token.SEMICOLON) {
-        p.nextToken()
-    }
-    return stmt
+	stmt := &ast.LetStatement{Token: p.curToken}
+
+	if !p.expectPeek(token.IDENT) {
+		return nil
+	}
+
+	stmt.Name = &ast.Identifier{Token: p.curToken, Value: p.curToken.Literal}
+	if !p.expectPeek(token.ASSIGN) {
+		return nil
+	}
+
+	// TODO: we're skipping the expression until we
+	//       we encounter a semicolon
+	for !p.curTokenIs(token.SEMICOLON) {
+		p.nextToken()
+	}
+	return stmt
+}
+
+// return <expression>;
+func (p *Parser) parseReturnStatement() ast.Statement {
+	stmt := &ast.ReturnStatement{Token: p.curToken}
+
+	p.nextToken()
+
+	// TODO: we're skipping the expressions until we
+	//       encounter a semicolon
+	for !p.curTokenIs(token.SEMICOLON) {
+		p.nextToken()
+	}
+
+	return stmt
 }
 
 func (p *Parser) curTokenIs(t token.TypeToken) bool {
-    return p.curToken.Type == t
+	return p.curToken.Type == t
 }
 
 func (p *Parser) peekTokenIs(t token.TypeToken) bool {
-    return p.peekToken.Type == t
+	return p.peekToken.Type == t
 }
 
 func (p *Parser) expectPeek(t token.TypeToken) bool {
-    if p.peekTokenIs(t) {
-        p.nextToken()
-        return true
-    } else {
-        p.peekError(t)
-        return false
-    }
+	if p.peekTokenIs(t) {
+		p.nextToken()
+		return true
+	} else {
+		p.peekError(t)
+		return false
+	}
 }

+ 82 - 54
parser/parser_test.go

@@ -1,9 +1,9 @@
 package parser
 
 import (
-    "github/runnignwater/monkey/ast"
-    "github/runnignwater/monkey/lexer"
-    "testing"
+	"github/runnignwater/monkey/ast"
+	"github/runnignwater/monkey/lexer"
+	"testing"
 )
 
 /**
@@ -13,73 +13,101 @@ import (
  * @Desc: LetStatement test case
  */
 func TestLetStatements(t *testing.T) {
-    input := `
+	input := `
         let x = 5;
         let y = 10;
         
         let foo = 838383;
         `
-    l := lexer.New(input)
-    p := New(l)
+	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))
-    }
+	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"},
-    }
+	tests := []struct {
+		expectedIdentifies string
+	}{
+		{"x"},
+		{"y"},
+		{"foo"},
+	}
 
-    for i, tt := range tests {
-        stmt := program.Statements[i]
-        if !testLetStatement(t, stmt, tt.expectedIdentifies) {
-            return
-        }
-    }
+	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()
+	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
-    }
+	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
-    }
+	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.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
-    }
+	if letStmt.Name.TokenLiteral() != name {
+		t.Errorf("s.name not '%s. got=%s", name, letStmt.Name)
+		return false
+	}
 
-    return true
+	return true
 }