package ast import ( "bytes" "fmt" "monkey/internal/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 s strings.Builder for _, stmt := range p.Statements { s.WriteString(stmt.String()) } return s.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 } // Null represents a null value type Null struct { Token token.Token } func (n *Null) expressionNode() {} func (n *Null) TokenLiteral() string { return n.Token.Literal } func (n *Null) String() string { return n.Token.Literal } 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 } // IntegerLiteral represents a literal integer number and holds an int64 value 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 } // FloatLiteral represents a literal floating point number and holds an float64 value type FloatLiteral struct { Token token.Token Value float64 } func (fl *FloatLiteral) expressionNode() {} // TokenLiteral prints the literal value of the token associated with this node func (fl *FloatLiteral) TokenLiteral() string { return fl.Token.Literal } // String returns a stringified version of the AST for debugging func (fl *FloatLiteral) String() string { return fl.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 (ie *InfixExpression) expressionNode() {} func (ie *InfixExpression) TokenLiteral() string { return ie.Token.Literal } func (ie *InfixExpression) String() string { var out bytes.Buffer out.WriteString("(") out.WriteString(ie.Left.String()) out.WriteString(" " + ie.Operator + " ") out.WriteString(ie.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 Name string } 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()) if fl.Name != "" { out.WriteString(fmt.Sprintf("<%s>", fl.Name)) } 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() } type StringLiteral struct { Token token.Token Value string } func (sl *StringLiteral) TokenLiteral() string { return sl.Token.Literal } func (sl *StringLiteral) String() string { return sl.Token.Literal } func (sl *StringLiteral) expressionNode() {} type ArrayLiteral struct { Token token.Token // the '[' token Elements []Expression } func (al *ArrayLiteral) TokenLiteral() string { return al.Token.Literal } func (al *ArrayLiteral) String() string { var out bytes.Buffer elements := []string{} for _, el := range al.Elements { elements = append(elements, el.String()) } out.WriteString("[") out.WriteString(strings.Join(elements, ", ")) out.WriteString("]") return out.String() } func (al *ArrayLiteral) expressionNode() {} type IndexExpression struct { Token token.Token // The [ token Left Expression Index Expression } func (ie *IndexExpression) TokenLiteral() string { return ie.Token.Literal } func (ie *IndexExpression) String() string { var out bytes.Buffer out.WriteString("(") out.WriteString(ie.Left.String()) out.WriteString("[") out.WriteString(ie.Index.String()) out.WriteString("])") return out.String() } func (ie *IndexExpression) expressionNode() {} type HashLiteral struct { Token token.Token // the '{' token Pairs map[Expression]Expression } func (hl *HashLiteral) TokenLiteral() string { return hl.Token.Literal } func (hl *HashLiteral) String() string { var out bytes.Buffer pairs := []string{} for key, value := range hl.Pairs { pairs = append(pairs, key.String()+":"+value.String()) } out.WriteString("{") out.WriteString(strings.Join(pairs, ", ")) out.WriteString("}") return out.String() } func (hl *HashLiteral) expressionNode() {} type WhileExpression struct { Token token.Token // The 'while' token Condition Expression Consequence *BlockStatement } func (we *WhileExpression) expressionNode() {} // TokenLiteral prints the literal value of the token associated with this node func (we *WhileExpression) TokenLiteral() string { return we.Token.Literal } // String returns a stringified version of the AST for debugging func (we *WhileExpression) String() string { var out bytes.Buffer out.WriteString("while") out.WriteString(we.Condition.String()) out.WriteString(" ") out.WriteString(we.Consequence.String()) return out.String() } // BindExpression represents an assignment expression of the form: // x := 1 type BindExpression struct { Token token.Token // the := token Left Expression Value Expression } func (be *BindExpression) TokenLiteral() string { return be.Token.Literal } func (be *BindExpression) String() string { var out bytes.Buffer out.WriteString(be.Left.String()) out.WriteString(be.TokenLiteral()) out.WriteString(be.Value.String()) return out.String() } func (be *BindExpression) expressionNode() {} // AssignmentExpression represents an assignment expression of the form: // x = 1 or xs[1] = 2 type AssignmentExpression struct { Token token.Token // the token.ASSIGN token Left Expression Value Expression } func (as *AssignmentExpression) TokenLiteral() string { return as.Token.Literal } func (as *AssignmentExpression) String() string { var out bytes.Buffer out.WriteString(as.Left.String()) out.WriteString(as.TokenLiteral()) out.WriteString(as.Value.String()) return out.String() } func (as *AssignmentExpression) expressionNode() {} // Comment a comment type Comment struct { Token token.Token // the token.COMMENT token Value string } func (c *Comment) statementNode() {} // TokenLiteral prints the literal value of the token associated with this node func (c *Comment) TokenLiteral() string { return c.Token.Literal } // String returns a stringified version of the AST for debugging func (c *Comment) String() string { var out bytes.Buffer out.WriteString(c.TokenLiteral() + " ") out.WriteString(c.Value) return out.String() } // ImportExpression represents an `import` expression and holds the name // of the module being imported. type ImportExpression struct { Token token.Token // The 'import' token Name Expression } func (ie *ImportExpression) TokenLiteral() string { return ie.Token.Literal } func (ie *ImportExpression) String() string { var out bytes.Buffer out.WriteString(ie.TokenLiteral()) out.WriteString("(") out.WriteString(fmt.Sprintf("\"%s\"", ie.Name)) out.WriteString(")") return out.String() } func (ie *ImportExpression) expressionNode() {}