-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2 from ryokosuge/feature/chapter-2
2章 構文解析
- Loading branch information
Showing
9 changed files
with
1,551 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,287 @@ | ||
package ast | ||
|
||
import ( | ||
"bytes" | ||
"monkey/token" | ||
"strings" | ||
) | ||
|
||
type Node interface { | ||
TokenLiteral() string | ||
String() string | ||
} | ||
|
||
type Statement interface { | ||
Node | ||
statementNode() | ||
} | ||
|
||
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() | ||
} | ||
|
||
type Identifier struct { | ||
Token token.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 LetStatement struct { | ||
Token token.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 // 'return'トークン | ||
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 | ||
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 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 | ||
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 | ||
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 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 IfExpression struct { | ||
Token token.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 BlockStatement struct { | ||
Token token.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() | ||
} | ||
|
||
type FunctionLiteral struct { | ||
Token token.Token // 'fn' トークン | ||
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 // '(' トークン | ||
Function Expression // Identifier または 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() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package ast | ||
|
||
import ( | ||
"monkey/token" | ||
"testing" | ||
) | ||
|
||
func TestString(t *testing.T) { | ||
program := &Program{ | ||
Statements: []Statement{ | ||
&LetStatement{ | ||
Token: token.Token{Type: token.LET, Literal: "let"}, | ||
Name: &Identifier{ | ||
Token: token.Token{Type: token.IDENT, Literal: "myVar"}, | ||
Value: "myVar", | ||
}, | ||
Value: &Identifier{ | ||
Token: token.Token{Type: token.IDENT, Literal: "anotherVar"}, | ||
Value: "anotherVar", | ||
}, | ||
}, | ||
}, | ||
} | ||
|
||
if program.String() != "let myVar = anotherVar;" { | ||
t.Errorf("program.String() wrong. got=%q", program.String()) | ||
} | ||
} |
Oops, something went wrong.