Browse Source

§2.6 Parsint int literals. Makefile. One pass of goimports.

Frederic G. MARAND 5 years ago
parent
commit
0dfd853a8a

+ 11 - 0
.gitignore

@@ -1,2 +1,13 @@
+# IDE files.
 .idea/workspace.xml
+
+# Generated coverage.
 coverage.out
+
+# Binaries, expected or plausible.
+## Someone ran go "build main.go"
+main
+## Someone ran "make" or "make monkey"
+monkey
+## Someone ran "go build"
+waiig15

+ 5 - 0
.idea/codeStyles/codeStyleConfig.xml

@@ -0,0 +1,5 @@
+<component name="ProjectCodeStyleConfiguration">
+  <state>
+    <option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
+  </state>
+</component>

+ 16 - 0
Makefile

@@ -0,0 +1,16 @@
+all: monkey
+
+monkey:
+	go build -o monkey main.go
+
+clean:
+	rm -f coverage.out main monkey waiig15
+
+cover: coverage.out
+	go tool cover -html=coverage.out
+
+coverage.out:
+	make test
+
+test:
+	go test -covermode=count -coverprofile=coverage.out ./...

+ 3 - 1
ast/ast.go

@@ -1,6 +1,8 @@
 package ast
 
-import "bytes"
+import (
+	"bytes"
+)
 
 // Node is the interface implemented by every node in the AST. It extends the
 // fmt.Stringer interface, allowing simple printing of nodes.

+ 1 - 1
ast/expression.go

@@ -16,7 +16,7 @@ func (es *ExpressionStatement) String() string {
 		return es.Expression.String()
 	}
 
-	return "";
+	return ""
 }
 
 func (es *ExpressionStatement) statementNode() {}

+ 0 - 1
ast/identifier.go

@@ -18,4 +18,3 @@ func (i *Identifier) expressionNode() {}
 func (i *Identifier) TokenLiteral() string {
 	return i.Token.Literal
 }
-

+ 19 - 0
ast/int.go

@@ -0,0 +1,19 @@
+package ast
+
+import "code.osinet.fr/fgm/waiig15/token"
+
+// IntegerLiteral fulfills ast.Expression.
+type IntegerLiteral struct {
+	Token token.Token
+	Value int64
+}
+
+func (il *IntegerLiteral) expressionNode() {}
+
+// TokenLiteral satisfies the Node interface.
+func (il *IntegerLiteral) TokenLiteral() string {
+	return il.Token.Literal
+}
+func (il *IntegerLiteral) String() string {
+	return il.Token.Literal
+}

+ 2 - 1
ast/let.go

@@ -1,8 +1,9 @@
 package ast
 
 import (
-	"code.osinet.fr/fgm/waiig15/token"
 	"bytes"
+
+	"code.osinet.fr/fgm/waiig15/token"
 )
 
 // LetStatement is the Node type for Let statements.

+ 2 - 1
ast/return.go

@@ -1,8 +1,9 @@
 package ast
 
 import (
-	"code.osinet.fr/fgm/waiig15/token"
 	"bytes"
+
+	"code.osinet.fr/fgm/waiig15/token"
 )
 
 // ReturnStatement fulfills the Node and Statement interfaces.

+ 2 - 1
lexer/lexer_test.go

@@ -1,8 +1,9 @@
 package lexer
 
 import (
-	"code.osinet.fr/fgm/waiig15/token"
 	"testing"
+
+	"code.osinet.fr/fgm/waiig15/token"
 )
 
 func TestNextToken(t *testing.T) {

+ 2 - 2
main.go

@@ -1,10 +1,11 @@
 package main
 
 import (
-	"code.osinet.fr/fgm/waiig15/repl"
 	"fmt"
 	"os"
 	"os/user"
+
+	"code.osinet.fr/fgm/waiig15/repl"
 )
 
 func main() {
@@ -16,5 +17,4 @@ func main() {
 		user.Username)
 	fmt.Printf("Feel free to type in commands\n")
 	repl.Start(os.Stdin, os.Stdout)
-
 }

+ 1 - 0
parser/parser.go

@@ -47,6 +47,7 @@ func New(l *lexer.Lexer) *Parser {
 
 	p.prefixParseFns = make(map[token.TokenType]prefixParseFn)
 	p.registerPrefix(token.IDENT, p.parseIdentifier)
+	p.registerPrefix(token.INT, p.parseIntegerLiteral)
 
 	// Read two tokens, so curToken and peeToken are both set.
 	p.nextToken()

+ 1 - 2
parser/parser_expression.go

@@ -5,7 +5,7 @@ import (
 	"code.osinet.fr/fgm/waiig15/token"
 )
 
-func (p *Parser) parseExpression(precedent int) ast.Expression {
+func (p *Parser) parseExpression(precedence int) ast.Expression {
 	prefix := p.prefixParseFns[p.curToken.Type]
 	if prefix == nil {
 		return nil
@@ -13,7 +13,6 @@ func (p *Parser) parseExpression(precedent int) ast.Expression {
 
 	leftExp := prefix()
 
-
 	return leftExp
 }
 

+ 26 - 0
parser/parser_int.go

@@ -0,0 +1,26 @@
+package parser
+
+import (
+	"fmt"
+	"strconv"
+
+	"code.osinet.fr/fgm/waiig15/ast"
+)
+
+func (p *Parser) parseIntegerLiteral() ast.Expression {
+	lit := &ast.IntegerLiteral{
+		Token: p.curToken,
+	}
+
+	// Base 0 allows straight interpretation of octal 0755 or hex 0xABCD.
+	value, err := strconv.ParseInt(p.curToken.Literal, 0, 64)
+	if err != nil {
+		msg := fmt.Sprintf("could not parse %q as integer",
+			p.curToken.Literal)
+		p.errors = append(p.errors, msg)
+		return nil
+	}
+
+	lit.Value = value
+	return lit
+}

+ 40 - 0
parser/parser_int_test.go

@@ -0,0 +1,40 @@
+package parser
+
+import (
+	"testing"
+
+	"code.osinet.fr/fgm/waiig15/ast"
+	"code.osinet.fr/fgm/waiig15/lexer"
+)
+
+func TestIntegerLiteralExpression(t *testing.T) {
+	input := "5;"
+
+	l := lexer.New(input)
+	p := New(l)
+
+	program := p.ParseProgram()
+	checkParserErrors(t, p)
+
+	if len(program.Statements) != 1 {
+		t.Fatalf("program does not have 1 statement. 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("expression not *ast.IntegerLiteral. got=%T",
+			stmt.Expression)
+	}
+
+	if literal.Value != 5 {
+		t.Errorf("literal.Value not %s. got=%s", "5",
+			literal.TokenLiteral())
+	}
+}

+ 2 - 2
parser/parser_let_test.go

@@ -2,8 +2,9 @@ package parser
 
 import (
 	"testing"
-	"code.osinet.fr/fgm/waiig15/lexer"
+
 	"code.osinet.fr/fgm/waiig15/ast"
+	"code.osinet.fr/fgm/waiig15/lexer"
 )
 
 func TestLetStatements(t *testing.T) {
@@ -70,4 +71,3 @@ func testLetStatement(t *testing.T, s ast.Statement, name string) bool {
 
 	return true
 }
-

+ 0 - 1
parser/parser_return.go

@@ -29,4 +29,3 @@ func (p *Parser) registerInfix(tokenType token.TokenType, fn infixParseFn) {
 func (p *Parser) registerPrefix(tokenType token.TokenType, fn prefixParseFn) {
 	p.prefixParseFns[tokenType] = fn
 }
-

+ 2 - 1
parser/parser_return_test.go

@@ -2,8 +2,9 @@ package parser
 
 import (
 	"testing"
-	"code.osinet.fr/fgm/waiig15/lexer"
+
 	"code.osinet.fr/fgm/waiig15/ast"
+	"code.osinet.fr/fgm/waiig15/lexer"
 )
 
 func TestReturnStatements(t *testing.T) {

+ 2 - 2
parser/parser_test.go

@@ -1,13 +1,13 @@
 package parser
 
 import (
-			"testing"
+	"testing"
 )
 
 func checkParserErrors(t *testing.T, p *Parser) {
 	errors := p.Errors()
 	if len(errors) == 0 {
-		return;
+		return
 	}
 
 	t.Errorf("parser has %d errors", len(errors))

+ 3 - 2
parser/parset_identifier_test.go

@@ -1,9 +1,10 @@
 package parser
 
 import (
-		"testing"
-	"code.osinet.fr/fgm/waiig15/lexer"
+	"testing"
+
 	"code.osinet.fr/fgm/waiig15/ast"
+	"code.osinet.fr/fgm/waiig15/lexer"
 )
 
 func TestIdentifierExpression(t *testing.T) {

+ 3 - 2
repl/repl.go

@@ -2,10 +2,11 @@ package repl
 
 import (
 	"bufio"
-	"code.osinet.fr/fgm/waiig15/lexer"
-	"code.osinet.fr/fgm/waiig15/token"
 	"fmt"
 	"io"
+
+	"code.osinet.fr/fgm/waiig15/lexer"
+	"code.osinet.fr/fgm/waiig15/token"
 )
 
 // PROMPT is the prompt shown to the user of the REPL to invite them to type

+ 0 - 1
token/token.go

@@ -3,7 +3,6 @@ package token
 // TokenType is the string representation of the Token types.
 type TokenType string
 
-
 // Token represents a Parser token.
 type Token struct {
 	Type    TokenType