From 912b60f0cd6cd21e8af8eca64d4f8896db8eb9f8 Mon Sep 17 00:00:00 2001 From: Houcine EL ADDALI Date: Mon, 11 Dec 2023 15:25:44 +0100 Subject: [PATCH] feat: Integer literals parsing; and tests --- AST/ast_imp.go | 28 +++++++++++++++++++++++++++- parser/parser.go | 31 ++++++++++++++++++++++++++++--- parser/parser_test.go | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 94 insertions(+), 4 deletions(-) diff --git a/AST/ast_imp.go b/AST/ast_imp.go index db17b53..836041f 100644 --- a/AST/ast_imp.go +++ b/AST/ast_imp.go @@ -97,6 +97,7 @@ type ReturnStatement struct{ Token token.Token // the token is "return" ReturnValue Expression } + //Node interface methods func (reStm *ReturnStatement) TokenLiteral() string{ // satisfies the node interface return reStm.Token.Value @@ -111,6 +112,7 @@ func (resStm *ReturnStatement) ToString() string { bf.WriteString(";") return bf.String() } + // statements imp func (reStm *ReturnStatement) statementNode() { } // satisfies the statement interface @@ -129,6 +131,7 @@ type ExpressionStatement struct{ func (exStm *ExpressionStatement) TokenLiteral() string{ return exStm.Token.Value } + func (exStm *ExpressionStatement) ToString() string{ var bf bytes.Buffer if exStm.Expression !=nil { @@ -137,4 +140,27 @@ func (exStm *ExpressionStatement) ToString() string{ return bf.String() } -func (exStm *ExpressionStatement) statementNode(){} \ No newline at end of file +func (exStm *ExpressionStatement) statementNode(){} + + + + +/* +* Integer Literals Node +* they can Occur in different type of expression's +*/ +type IntegerLiteral struct { + Token token.Token + Value int // we do not specify int size to make it platform independent (32,64) +} + +func (intLiteral *IntegerLiteral) TokenLiteral() string{ + return intLiteral.Token.Value +} + +func (intLiteral *IntegerLiteral) expressionNode() {} + +func (intLiteral *IntegerLiteral) ToString() string { + return intLiteral.Token.Value +} + diff --git a/parser/parser.go b/parser/parser.go index e5ab3be..87ebd5a 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -2,6 +2,7 @@ package parser import ( "fmt" + "strconv" ast "github.com/houcine7/JIPL/AST" "github.com/houcine7/JIPL/lexer" @@ -45,6 +46,7 @@ func InitParser(l *lexer.Lexer) *Parser{ // init ParseFunctions maps p.prefixParseFuncs = make(map[token.TokenType]prefixParse) p.addPrefixFn(token.IDENTIFIER,p.parseIdentifier) + p.addPrefixFn(token.INT,p.parserInt) return p; } @@ -79,9 +81,9 @@ func (p *Parser) Parse() *ast.Program{ for !p.currentTokenEquals(token.FILE_ENDED) { stm := p.parseStmt() //fmt.Println(stm.TokenLiteral()) - if stm !=nil { - program.Statements =append(program.Statements, stm ) - } + // if stm !=nil { + program.Statements =append(program.Statements, stm ) + // } // Advance with token p.NextToken() } @@ -175,6 +177,29 @@ func (p *Parser) parseIdentifier() ast.Expression{ return &ast.Identifier{Token: p.currToken,Value: p.currToken.Value} } +func (p *Parser) parserInt() ast.Expression { + exp := &ast.IntegerLiteral{Token: p.currToken} + val,err := strconv.ParseInt(p.currToken.Value,0,0) + + if err !=nil { + errMsg := fmt.Sprintf("Parsing error, couldn't parse string %s to Integer value", + p.currToken.Value) + p.errors = append(p.errors, errMsg) + return nil + } + + exp.Value = int(val) + + return exp +} + + + + + + +//Helper functions + func (p *Parser) currentTokenEquals(t token.TokenType) bool{ return p.currToken.Type == t; } diff --git a/parser/parser_test.go b/parser/parser_test.go index bf2497c..6be8c43 100644 --- a/parser/parser_test.go +++ b/parser/parser_test.go @@ -116,6 +116,45 @@ func TestIdentifier(t *testing.T){ } } + +// Integer literals test +func TestIntegerLiteral(t *testing.T){ + input :="81;" + + lexer := lexer.InitLexer(input) + parser := InitParser(lexer) + + pr :=parser.Parse() + checkParserErrors(parser,t) + checkIsProgramStmLengthValid(pr,t,1) + + stm,ok := pr.Statements[0].(*ast.ExpressionStatement) + if !ok { + t.Fatalf("program.statement[0] is not of type expressionStatement instead got=%T", + pr.Statements[0]) + } + + intLiteral,ok :=stm.Expression.(*ast.IntegerLiteral) + if !ok{ + t.Fatalf("stm.Expression is not of type *ast.IntegerLiteral instead got=%T", + stm.Expression) + } + + if intLiteral.Value != int(81){ + t.Errorf("the Integer literal value is not correct, expected=%d instead got=%d", + 81,intLiteral.Value) + } + + if intLiteral.TokenLiteral() !="81" { + t.Errorf("the TokenLiteral value is not correct, expected=%s instead got=%s", + "81",intLiteral.TokenLiteral()) + } + +} + + + +// Tests helper functions func checkIsProgramStmLengthValid(program *ast.Program,t *testing.T,length int){ if len(program.Statements) !=length { t.Fatalf("the program.Statements doesn't not contain 3 statements, instead we got %d",