aboutsummaryrefslogtreecommitdiff
path: root/ast/ast.go
diff options
context:
space:
mode:
Diffstat (limited to 'ast/ast.go')
-rw-r--r--ast/ast.go266
1 files changed, 266 insertions, 0 deletions
diff --git a/ast/ast.go b/ast/ast.go
new file mode 100644
index 0000000..e8c133f
--- /dev/null
+++ b/ast/ast.go
@@ -0,0 +1,266 @@
+package ast
+
+import (
+ "bytes"
+ "monkey/token"
+ "strings"
+)
+
+// The base Node interface
+type Node interface {
+ TokenLiteral() string
+ String() string
+}
+
+// All statement nodes implement this
+type Statement interface {
+ Node
+ statementNode()
+}
+
+// All expression nodes implement this
+type Expression interface {
+ Node
+ expressionNode()
+}
+
+type Program struct {
+ Statements []Statement
+}
+
+func (p *Program) TokenLiteral() string {
+ if len(p.Statements) > 0 {
+ return p.Statements[0].TokenLiteral()
+ } else {
+ return ""
+ }
+}
+
+func (p *Program) String() string {
+ var out bytes.Buffer
+
+ for _, s := range p.Statements {
+ out.WriteString(s.String())
+ }
+
+ return out.String()
+}
+
+// Statements
+type LetStatement struct {
+ Token token.Token // the token.LET token
+ Name *Identifier
+ Value Expression
+}
+
+func (ls *LetStatement) statementNode() {}
+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()
+}
+
+type ReturnStatement struct {
+ Token token.Token // the 'return' token
+ ReturnValue Expression
+}
+
+func (rs *ReturnStatement) statementNode() {}
+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()
+}
+
+type ExpressionStatement struct {
+ Token token.Token // the first token of the expression
+ Expression Expression
+}
+
+func (es *ExpressionStatement) statementNode() {}
+func (es *ExpressionStatement) TokenLiteral() string { return es.Token.Literal }
+func (es *ExpressionStatement) String() string {
+ if es.Expression != nil {
+ return es.Expression.String()
+ }
+ return ""
+}
+
+type BlockStatement struct {
+ Token token.Token // the { token
+ Statements []Statement
+}
+
+func (bs *BlockStatement) statementNode() {}
+func (bs *BlockStatement) TokenLiteral() string { return bs.Token.Literal }
+func (bs *BlockStatement) String() string {
+ var out bytes.Buffer
+
+ for _, s := range bs.Statements {
+ out.WriteString(s.String())
+ }
+
+ return out.String()
+}
+
+// Expressions
+type Identifier struct {
+ Token token.Token // the token.IDENT token
+ Value string
+}
+
+func (i *Identifier) expressionNode() {}
+func (i *Identifier) TokenLiteral() string { return i.Token.Literal }
+func (i *Identifier) String() string { return i.Value }
+
+type Boolean struct {
+ Token token.Token
+ Value bool
+}
+
+func (b *Boolean) expressionNode() {}
+func (b *Boolean) TokenLiteral() string { return b.Token.Literal }
+func (b *Boolean) String() string { return b.Token.Literal }
+
+type IntegerLiteral struct {
+ Token token.Token
+ Value int64
+}
+
+func (il *IntegerLiteral) expressionNode() {}
+func (il *IntegerLiteral) TokenLiteral() string { return il.Token.Literal }
+func (il *IntegerLiteral) String() string { return il.Token.Literal }
+
+type PrefixExpression struct {
+ Token token.Token // The prefix token, e.g. !
+ Operator string
+ Right Expression
+}
+
+func (pe *PrefixExpression) expressionNode() {}
+func (pe *PrefixExpression) TokenLiteral() string { return pe.Token.Literal }
+func (pe *PrefixExpression) String() string {
+ var out bytes.Buffer
+
+ out.WriteString("(")
+ out.WriteString(pe.Operator)
+ out.WriteString(pe.Right.String())
+ out.WriteString(")")
+
+ return out.String()
+}
+
+type InfixExpression struct {
+ Token token.Token // The operator token, e.g. +
+ Left Expression
+ Operator string
+ Right Expression
+}
+
+func (oe *InfixExpression) expressionNode() {}
+func (oe *InfixExpression) TokenLiteral() string { return oe.Token.Literal }
+func (oe *InfixExpression) String() string {
+ var out bytes.Buffer
+
+ out.WriteString("(")
+ out.WriteString(oe.Left.String())
+ out.WriteString(" " + oe.Operator + " ")
+ out.WriteString(oe.Right.String())
+ out.WriteString(")")
+
+ return out.String()
+}
+
+type IfExpression struct {
+ Token token.Token // The 'if' token
+ Condition Expression
+ Consequence *BlockStatement
+ Alternative *BlockStatement
+}
+
+func (ie *IfExpression) expressionNode() {}
+func (ie *IfExpression) TokenLiteral() string { return ie.Token.Literal }
+func (ie *IfExpression) String() string {
+ var out bytes.Buffer
+
+ out.WriteString("if")
+ out.WriteString(ie.Condition.String())
+ out.WriteString(" ")
+ out.WriteString(ie.Consequence.String())
+
+ if ie.Alternative != nil {
+ out.WriteString("else ")
+ out.WriteString(ie.Alternative.String())
+ }
+
+ return out.String()
+}
+
+type FunctionLiteral struct {
+ Token token.Token // The 'fn' token
+ Parameters []*Identifier
+ Body *BlockStatement
+}
+
+func (fl *FunctionLiteral) expressionNode() {}
+func (fl *FunctionLiteral) TokenLiteral() string { return fl.Token.Literal }
+func (fl *FunctionLiteral) String() string {
+ var out bytes.Buffer
+
+ params := []string{}
+ for _, p := range fl.Parameters {
+ params = append(params, p.String())
+ }
+
+ out.WriteString(fl.TokenLiteral())
+ out.WriteString("(")
+ out.WriteString(strings.Join(params, ", "))
+ out.WriteString(") ")
+ out.WriteString(fl.Body.String())
+
+ return out.String()
+}
+
+type CallExpression struct {
+ Token token.Token // The '(' token
+ Function Expression // Identifier or FunctionLiteral
+ Arguments []Expression
+}
+
+func (ce *CallExpression) expressionNode() {}
+func (ce *CallExpression) TokenLiteral() string { return ce.Token.Literal }
+func (ce *CallExpression) String() string {
+ var out bytes.Buffer
+
+ args := []string{}
+ for _, a := range ce.Arguments {
+ args = append(args, a.String())
+ }
+
+ out.WriteString(ce.Function.String())
+ out.WriteString("(")
+ out.WriteString(strings.Join(args, ", "))
+ out.WriteString(")")
+
+ return out.String()
+}