123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307 |
- 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()
- }
|