Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions src/monkey/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,11 @@ func (p *Parser) parseLetStatement() *ast.LetStatement {
return nil
}

for !p.curTokenIs(token.SEMICOLON) {
p.nextToken()

stmt.Value = p.parseExpression(LOWEST)

if p.peekTokenIs(token.SEMICOLON) {
p.nextToken()
}

Expand All @@ -146,8 +150,8 @@ func (p *Parser) parseReturnStatement() *ast.ReturnStatement {
defer untrace(trace("parseReturnStatement"))
stmt := &ast.ReturnStatement{Token: p.curToken}
p.nextToken()
// TODO: セミコロンに遭遇するまで式を読み飛ばしてしまっている
for !p.curTokenIs(token.SEMICOLON) {
stmt.ReturnValue = p.parseExpression(LOWEST)
if p.peekTokenIs(token.SEMICOLON) {
p.nextToken()
}
return stmt
Expand Down
85 changes: 44 additions & 41 deletions src/monkey/parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,69 +8,72 @@ import (
)

func TestLetStatements(t *testing.T) {
input := `
let x = 5;
let y = 10;
let foobar = 383838;
`
l := lexer.New(input)
p := New(l)

program := p.ParseProgram()
checkParserErrors(t, p)

if program == nil {
t.Fatalf("ParseProgram() returned nil.")
}

if len(program.Statements) != 3 {
t.Fatalf("program.Statements dose not contain 3 statements. got=%d.", len(program.Statements))
}

tests := []struct {
input string
expectedIdentifier string
expectedValue interface{}
}{
{"x"},
{"y"},
{"foobar"},
{"let x = 5;", "x", 5},
{"let y = true;", "y", true},
{"let foobar = y;", "foobar", "y"},
}

for i, tt := range tests {
stmt := program.Statements[i]
for _, tt := range tests {
l := lexer.New(tt.input)
p := New(l)
program := p.ParseProgram()
checkParserErrors(t, p)

if len(program.Statements) != 1 {
t.Fatalf("program.Statements does not contain 1 statements. got=%d\n", len(program.Statements))
}

stmt := program.Statements[0]
if !testLetStatement(t, stmt, tt.expectedIdentifier) {
return
}

val := stmt.(*ast.LetStatement).Value
if !testLiteralExpression(t, val, tt.expectedValue) {
return
}
}
}

func TestReturnStatement(t *testing.T) {
input := `
return 5;
return 10;
return 993322;
`
l := lexer.New(input)
p := New(l)
tests := []struct {
input string
expectedValue interface{}
}{
{"return 5;", 5},
{"return true;", true},
{"return foobar;", "foobar"},
}

program := p.ParseProgram()
checkParserErrors(t, p)
for _, tt := range tests {
l := lexer.New(tt.input)
p := New(l)
program := p.ParseProgram()
checkParserErrors(t, p)

if len(program.Statements) != 3 {
t.Fatalf("program.Statements dose not contain 3 statements. got=%d", len(program.Statements))
}
if len(program.Statements) != 1 {
t.Fatalf("program.Statements does not contain 1 statements. got=%d", len(program.Statements))
}

for _, stmt := range program.Statements {
stmt := program.Statements[0]
returnStmt, ok := stmt.(*ast.ReturnStatement)
if !ok {
t.Errorf("stmt not *ast.ReturnStatement. got=%T", stmt)
continue
t.Fatalf("stmt not *ast.ReturnStatement. got=%T", stmt)
}

if returnStmt.TokenLiteral() != "return" {
t.Errorf("returnStmt.TokenLiteral not 'return', got %q", returnStmt.TokenLiteral())
t.Fatalf("returnStmt.TokenLiteral not 'return', got %q", returnStmt.TokenLiteral())
}
}

if !testLiteralExpression(t, returnStmt.ReturnValue, tt.expectedValue) {
return
}
}
}

func TestIdentifierExpression(t *testing.T) {
Expand Down