diff --git a/ast/ast.go b/ast/ast.go index 612849f..881ffde 100644 --- a/ast/ast.go +++ b/ast/ast.go @@ -1,9 +1,13 @@ package ast -import "monkey/token" +import ( + "bytes" + "monkey/token" +) type Node interface { TokenLiteral() string + String() string } type Statement interface { @@ -16,6 +20,14 @@ type Expression interface { expression_node() } +func (l_program *Program) String() string { + var out bytes.Buffer + for _, s := range l_program.Statements { + out.WriteString(s.String()) + } + return out.String() +} + type Program struct { Statements []Statement } @@ -36,18 +48,43 @@ type ReturnStatement struct { ReturnValue Expression } +type ExpressionStatement struct { + Token token.Token // the first token in the expression + Expression Expression +} + +// Let Statements func (ls *LetStatement) statement_node() {} func (ls *LetStatement) TokenLiteral() string { return ls.Token.Literal } +func (ls *LetStatement) String() string { + var out bytes.Buffer + out.WriteString(ls.TokenLiteral() + " ") + out.WriteString(ls.Name.String()) + out.WriteString(" = ") + + if ls.Value != nil { + out.WriteString(ls.Value.String()) + } + out.WriteString(";") + return out.String() +} + +// Identifier func (i *Identifier) expression_node() {} func (i *Identifier) TokenLiteral() string { return i.Token.Literal } +func (i *Identifier) String() string { + return i.Value +} + +// Program func (p *Program) TokenLiteral() string { if len(p.Statements) > 0 { return p.Statements[0].TokenLiteral() @@ -56,8 +93,33 @@ func (p *Program) TokenLiteral() string { } } +// Return Statements func (rs *ReturnStatement) statement_node() {} func (rs *ReturnStatement) TokenLiteral() string { return rs.Token.Literal } + +func (rs *ReturnStatement) String() string { + var out bytes.Buffer + out.WriteString(rs.TokenLiteral() + " ") + if rs.ReturnValue != nil { + out.WriteString(rs.ReturnValue.String()) + } + out.WriteString(";") + return out.String() +} + +// Expression Statement +func (es *ExpressionStatement) statement_node() {} + +func (es *ExpressionStatement) TokenLiteral() string { + return es.Token.Literal +} + +func (es *ExpressionStatement) String() string { + if es.Expression != nil { + return es.Expression.String() + } + return "" +} diff --git a/ast/ast_test.go b/ast/ast_test.go new file mode 100644 index 0000000..7d2addd --- /dev/null +++ b/ast/ast_test.go @@ -0,0 +1,28 @@ +package ast + +import ( + "monkey/token" + "testing" +) + +func TestString(l_test *testing.T) { + program := &Program{ + Statements: []Statement{ + &LetStatement{ + Token: token.Token{Type: token.LET, Literal: "let"}, + Name: &Identifier{ + Token: token.Token{Type: token.IDENT, Literal: "my_var"}, + Value: "my_var", + }, + Value: &Identifier{ + Token: token.Token{Type: token.IDENT, Literal: "another_var"}, + Value: "another_var", + }, + }, + }, + } + + if program.String() != "let my_var = another_var;" { + l_test.Errorf("program.String() wrong, got=%q", program.String()) + } +} diff --git a/main.go b/main.go index 53a02aa..bf97f45 100644 --- a/main.go +++ b/main.go @@ -1,10 +1,9 @@ /* TODO(tijani): - - - add quit command to the repl. - - remove semicolons from the language to mark the end of a statement. - - add line and position reporting in the lexer when a lexing or parsing error occurs. -*/ +- add quit command to the repl. +- remove semicolons from the language to mark the end of a statement. +- add line and position reporting in the lexer when a lexing or parsing error occurs. +*/ package main