Skip to content

Commit

Permalink
parse return statements
Browse files Browse the repository at this point in the history
  • Loading branch information
Houcine EL ADDALI committed Dec 9, 2023
1 parent 62a1749 commit 1905c25
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 27 deletions.
37 changes: 27 additions & 10 deletions AST/ast_imp.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,22 @@ func (prog *Program) TokenLiteral() string{
/*
* Def statement Node (def x = add(1,2) - 1 + (10/5))
*/
type DefStatement struct {
Token token.Token // toke.DEF token
Name *Identifier
Value Expression
}
// method satisfies the Node interface
func (defSt *DefStatement) TokenLiteral() string{
return defSt.Token.Value;
}
// satisfies the statement interface
func (defSt *DefStatement) statementNode() {}


/*
* Identifier node as an expression node
*/
type Identifier struct{ //
Token token.Token // token.IDENTIFIER token
Value string
Expand All @@ -38,16 +54,17 @@ func (ident *Identifier) TokenLiteral() string {
//parts they does provide a value
func (ident *Identifier) expressionNode() {}

/*
* return statement node
* return 5; || return f1(1,2); ==> return <expression>;
*/
type ReturnStatement struct{
Token token.Token // the token is "return"
ReturnValue Expression
}


type DefStatement struct {
Token token.Token // toke.DEF token
Name *Identifier
Value Expression
func (reStm *ReturnStatement) TokenLiteral() string{ // satisfies the node interface
return reStm.Token.Value
}
// method satisfies the Node interface
func (defSt *DefStatement) TokenLiteral() string{
return defSt.Token.Value;
func (reStm *ReturnStatement) statementNode() { // satisfies the statement interface
}
// satisfies the statement interface
func (defSt *DefStatement) statementNode() {}
20 changes: 17 additions & 3 deletions parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ func (p *Parser) parseStmt() ast.Statement{
switch p.currToken.Type {
case token.DEF:
return p.parseDefStmt()
case token.RETURN:
return p.parserReturnStmt()
default:
return nil
}
Expand All @@ -89,7 +91,6 @@ func (p *Parser) parseStmt() ast.Statement{
/*
* function used to parse def statement
*/

func (p *Parser) parseDefStmt() *ast.DefStatement {
stm := &ast.DefStatement{Token: p.currToken}

Expand All @@ -109,10 +110,24 @@ func (p *Parser) parseDefStmt() *ast.DefStatement {
p.NextToken();
}

return stm
}

func (p *Parser) parserReturnStmt() *ast.ReturnStatement {
stm := &ast.ReturnStatement{Token: p.currToken}

p.NextToken()

//TODO:
for !p.currentTokenEquals(token.S_COLON) {
p.NextToken()
}

return stm

}


func (p *Parser) currentTokenEquals(t token.TokenType) bool{
return p.currToken.Type == t;
}
Expand All @@ -123,7 +138,7 @@ func (p *Parser) peekTokenEquals(t token.TokenType) bool {

/*
* function checks if the given token is the next token
* if it is returns true and advances the token
* returns true and advances the tokens pointers of the parser
* if not returns false
*/
func (p *Parser) expectedNextToken(t token.Token) bool{
Expand All @@ -148,5 +163,4 @@ func (p *Parser) peekedError(encounteredToken token.Token) {

// append message to the errors array
p.errors =append(p.errors, errorMessage)

}
61 changes: 47 additions & 14 deletions parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@ import (
"github.com/houcine7/JIPL/lexer"
)

/*TEST functions*/

// test def statement
func TestDefStatement(t *testing.T) {

input := `
def num1 = 13;
def num2 = 0;
def foobar = 5321;
def total= 0;
def a= 5321;
`
l := lexer.InitLexer(input)

Expand All @@ -27,21 +30,15 @@ def foobar = 5321;
// check parser errors
checkParserErrors(parser,t)

if program==nil{
t.Fatalf("parse returned a nil value")
}

if len(program.Statements) !=3 {
t.Fatalf("the program.Statements doesn't not contain 3 statements, instead we got %d",
len(program.Statements))
}
//check is length of the program statement slice is 3
checkIsProgramStmLengthValid(program,t,3)

tests := []struct{
expectedIdentifier string
}{
{"num1"},
{"num2"},
{"foobar"},
{"total"},
{"a"},
}

for i,t1 := range tests{
Expand All @@ -54,7 +51,44 @@ def foobar = 5321;
}
}

// test return statement
func TestReturnStatement(t *testing.T){
input :=`
return 545;
return 101232;
return 0;
`

l :=lexer.InitLexer(input)
parser := InitParser(l)

pr := parser.Parse()

//check is length of the program statement slice is 3
checkIsProgramStmLengthValid(pr, t,3)

for _,stm := range pr.Statements {
returnStm,ok := stm.(*ast.ReturnStatement)
if !ok {
t.Errorf("statement not *ast.ReturnStatement type got:%T",stm)
continue
}

if returnStm.TokenLiteral() !="return" {
t.Errorf("returnStatement token literal is not 'return' instead got: %s",
returnStm.TokenLiteral())
}

}
}


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",
len(program.Statements))
}
}

func checkParserErrors(p *Parser,t *testing.T){
errors := p.Errors()
Expand All @@ -75,14 +109,13 @@ func checkParserErrors(p *Parser,t *testing.T){
t.FailNow() // mark tests as failed and stop execution
}


func testDefStatement(t *testing.T, stm ast.Statement, name string) bool {
if stm.TokenLiteral() !="def" {
t.Errorf("s.tokenLiteral is not 'def'. got instead:%q",stm.TokenLiteral())
return false
}

defStm, ok := stm.(*ast.DefStatement)
defStm, ok := stm.(*ast.DefStatement) // type assertion (casting if stm is of type *ast.Statement)

if !ok {
t.Errorf("s not *ast.DefStatement. got=%T", stm)
Expand Down

0 comments on commit 1905c25

Please sign in to comment.