package ast import ( "bytes" "code.osinet.fr/fgm/waiig15/token" ) // The base Node interface // Node is the interface implemented by every node in the AST. It extends the // fmt.Stringer interface, allowing simple printing of nodes. type Node interface { // TokenLiteral returns the literal value of the token it's associated to. TokenLiteral() string String() string } // All statement nodes implement this // Statement extends Node and is only a way to differentiate between expressions // and statements. type Statement interface { Node statementNode() } // All expression nodes implement this // Expression extends Node and is only a way to differentiate between // expressions and statements. type Expression interface { // Expression extends Node. Node expressionNode() } // Program represents the outer structure of the parser program. type Program struct { Statements []Statement } // TokenLiteral returns the string contents of the first statement token, which // can be an empty string if the program is empty. func (p *Program) TokenLiteral() string { if len(p.Statements) > 0 { return p.Statements[0].TokenLiteral() } return "" } // String satisfies the Node and fmt.Stringer interfaces. func (p *Program) String() string { var out bytes.Buffer for _, s := range p.Statements { out.WriteString(s.String()) } return out.String() } // LetStatement is the Node type for Let statements. type LetStatement struct { Token token.Token // the token.LET token. Why do we need it ? Name *Identifier Value Expression } func (ls *LetStatement) statementNode() {} // TokenLiteral satisfies the Node interface. func (ls *LetStatement) TokenLiteral() string { return ls.Token.Literal } // String implements Node and fmt.Stringer. 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() } // ReturnStatement fulfills the Node and Statement interfaces. type ReturnStatement struct { Token token.Token // the token.RETURN token. Why do we need it ? Name *Identifier ReturnValue Expression } func (rs *ReturnStatement) statementNode() {} // TokenLiteral satisfies the Node interface. func (rs *ReturnStatement) TokenLiteral() string { return rs.Token.Literal } // String satisfies the Node and fmt.Stringer interfaces. 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() } // ExpressionStatement fulfills the Node and Statement interfaces. // It represents a statement made of a bare expression like: // x + 10; type ExpressionStatement struct { Token token.Token // the first token of the expression Expression Expression } func (es *ExpressionStatement) statementNode() {} // TokenLiteral satisfies the Node interface. func (es *ExpressionStatement) TokenLiteral() string { return es.Token.Literal } // String satisfies the Node and fmt.Stringer interfaces. func (es *ExpressionStatement) String() string { if es.Expression != nil { return es.Expression.String() } return "" } // BlockStatement fulfills the Node and Statement interfaces. // It represents a suite of statements. type BlockStatement struct { Token token.Token // the { token Statements []Statement } func (bs *BlockStatement) statementNode() {} // TokenLiteral satisfies the Node interface. func (bs *BlockStatement) TokenLiteral() string { return bs.Token.Literal } // String satisfies the Node and fmt.Stringer interfaces. func (bs *BlockStatement) String() string { var out bytes.Buffer for _, s := range bs.Statements { out.WriteString(s.String()) } return out.String() } // Identifier is the Node type for identifiers. type Identifier struct { Token token.Token // the token.IDENT token. Why do we need it ? Value string // The identifier string. } func (i *Identifier) expressionNode() {} // TokenLiteral satisfies the Node interface. func (i *Identifier) TokenLiteral() string { return i.Token.Literal } func (i *Identifier) String() string { return i.Value } // Boolean is the Node type for booleans. type Boolean struct { Token token.Token Value bool // true or false, for the equivalent Monkey tokens. } func (b *Boolean) expressionNode() {} func (b *Boolean) TokenLiteral() string { return b.Token.Literal } func (b *Boolean) String() string { return b.Token.Literal } // IntegerLiteral fulfills ast.Expression. type IntegerLiteral struct { Token token.Token Value int64 } func (il *IntegerLiteral) expressionNode() {} // TokenLiteral satisfies the Node interface. func (il *IntegerLiteral) TokenLiteral() string { return il.Token.Literal } func (il *IntegerLiteral) String() string { return il.Token.Literal } // PrefixExpression fulfills the Node and Expression interfaces. // It represents a prefixed expression like: // "-5;" type PrefixExpression struct { Token token.Token // The prefix token, e.g. ! Operator string Right Expression } func (pe *PrefixExpression) expressionNode() {} // TokenLiteral satisfies the Node interface. func (pe *PrefixExpression) TokenLiteral() string { return pe.Token.Literal } // String satisfies the Node and fmt.Stringer interfaces. 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() } // InfixExpression fulfills the Node and Expression interfaces. // It represents an infix expression like: // "5 + 6;" type InfixExpression struct { Token token.Token // The operator token, e.g. + Left Expression Operator string Right Expression } func (ie *InfixExpression) expressionNode() {} // TokenLiteral satisfies the Node interface. func (ie *InfixExpression) TokenLiteral() string { return ie.Token.Literal } // String satisfies the Node and fmt.Stringer interfaces. 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() } // IfExpression fulfills the Node and Expression interfaces. // It represents a condition expression like: // "if true 5 else 6;" // Note that if/else are expressions, not just statements. type IfExpression struct { Token token.Token // The "if" token Condition Expression Consequence *BlockStatement Alternative *BlockStatement } func (ie *IfExpression) expressionNode() {} // TokenLiteral satisfies the Node interface. func (ie *IfExpression) TokenLiteral() string { return ie.Token.Literal } // String satisfies the Node and fmt.Stringer interfaces. 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() }