ast
This commit is contained in:
parent
c57c38bc81
commit
ff2ff3d417
109
2
Normal file
109
2
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
package ast
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"git.robaertschi.xyz/robaertschi/thorgot/token"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Optional[T any] struct {
|
||||||
|
HasValue bool
|
||||||
|
Value T
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o Optional[T]) OrElse(other T) T {
|
||||||
|
if o.HasValue {
|
||||||
|
return o.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
return other
|
||||||
|
}
|
||||||
|
|
||||||
|
type Indentation int
|
||||||
|
|
||||||
|
func (i Indentation) indent() string {
|
||||||
|
return strings.Repeat(" ", int(i*4))
|
||||||
|
}
|
||||||
|
|
||||||
|
type Node interface {
|
||||||
|
TokenLiteral() string
|
||||||
|
String(Indentation) string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExpressionNode interface {
|
||||||
|
Node
|
||||||
|
expressionNode()
|
||||||
|
}
|
||||||
|
|
||||||
|
type StatementNode interface {
|
||||||
|
Node
|
||||||
|
statementNode()
|
||||||
|
}
|
||||||
|
|
||||||
|
type Type string
|
||||||
|
|
||||||
|
func (t Type) String() string {
|
||||||
|
return string(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Block struct {
|
||||||
|
Token token.Token // the RBrace token
|
||||||
|
Statements []StatementNode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Block) TokenLiteral() string { return b.Token.Literal }
|
||||||
|
func (b *Block) String(i Indentation) string {
|
||||||
|
var out strings.Builder
|
||||||
|
|
||||||
|
ind := i.indent()
|
||||||
|
|
||||||
|
out.WriteString(ind + "{\n")
|
||||||
|
for _, statement := range b.Statements {
|
||||||
|
out.WriteString(statement.String(i + 1))
|
||||||
|
}
|
||||||
|
out.WriteString(ind + "}\n")
|
||||||
|
|
||||||
|
return out.String()
|
||||||
|
}
|
||||||
|
func (b *Block) statementNode() {}
|
||||||
|
|
||||||
|
type FunctionArgument struct {
|
||||||
|
Name string
|
||||||
|
Type Type
|
||||||
|
}
|
||||||
|
|
||||||
|
type Function struct {
|
||||||
|
Token token.Token // the Fn token
|
||||||
|
Name string
|
||||||
|
Arguments []FunctionArgument
|
||||||
|
ReturnType Type
|
||||||
|
HasReturnType bool
|
||||||
|
Block Block
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Function) TokenLiteral() string { return f.Token.Literal }
|
||||||
|
func (f *Function) String(i Indentation) string {
|
||||||
|
var out strings.Builder
|
||||||
|
|
||||||
|
ind := i.indent()
|
||||||
|
out.WriteString(ind + "fn " + f.Name + "(")
|
||||||
|
for i, arg := range f.Arguments {
|
||||||
|
out.WriteString(arg.Name + " " + arg.Type.String())
|
||||||
|
if i != len(f.Arguments)-1 {
|
||||||
|
out.WriteString(", ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.WriteString(") ")
|
||||||
|
|
||||||
|
if f.HasReturnType {
|
||||||
|
out.WriteString(f.ReturnType.String() + " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
out.WriteString(f.Block.String(i))
|
||||||
|
|
||||||
|
return out.String()
|
||||||
|
}
|
||||||
|
func (f *Function) statementNode() {}
|
||||||
|
|
||||||
|
type VariableDefiniton struct {
|
||||||
|
}
|
124
ast/ast.go
Normal file
124
ast/ast.go
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
package ast
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"git.robaertschi.xyz/robaertschi/thorgot/token"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Statements should start with the specified Indentation, Expression should only do that on new lines
|
||||||
|
type Indentation int
|
||||||
|
|
||||||
|
func (i Indentation) indent() string {
|
||||||
|
return strings.Repeat(" ", int(i*4))
|
||||||
|
}
|
||||||
|
|
||||||
|
type Node interface {
|
||||||
|
TokenLiteral() string
|
||||||
|
String(Indentation) string
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExpressionNode interface {
|
||||||
|
Node
|
||||||
|
expressionNode()
|
||||||
|
}
|
||||||
|
|
||||||
|
type StatementNode interface {
|
||||||
|
Node
|
||||||
|
statementNode()
|
||||||
|
}
|
||||||
|
|
||||||
|
type Type string
|
||||||
|
|
||||||
|
func (t Type) String() string {
|
||||||
|
return string(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Block struct {
|
||||||
|
Token token.Token // the RBrace token
|
||||||
|
Statements []StatementNode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Block) TokenLiteral() string { return b.Token.Literal }
|
||||||
|
func (b *Block) String(i Indentation) string {
|
||||||
|
var out strings.Builder
|
||||||
|
|
||||||
|
ind := i.indent()
|
||||||
|
|
||||||
|
out.WriteString(ind + "{\n")
|
||||||
|
for _, statement := range b.Statements {
|
||||||
|
out.WriteString(statement.String(i + 1))
|
||||||
|
}
|
||||||
|
out.WriteString(ind + "}\n")
|
||||||
|
|
||||||
|
return out.String()
|
||||||
|
}
|
||||||
|
func (b *Block) statementNode() {}
|
||||||
|
|
||||||
|
type FunctionArgument struct {
|
||||||
|
Name string
|
||||||
|
Type Type
|
||||||
|
}
|
||||||
|
|
||||||
|
type Function struct {
|
||||||
|
Token token.Token // the Fn token
|
||||||
|
Name string
|
||||||
|
Arguments []FunctionArgument
|
||||||
|
ReturnType Type
|
||||||
|
HasReturnType bool
|
||||||
|
Block Block
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *Function) TokenLiteral() string { return f.Token.Literal }
|
||||||
|
func (f *Function) String(i Indentation) string {
|
||||||
|
var out strings.Builder
|
||||||
|
|
||||||
|
ind := i.indent()
|
||||||
|
out.WriteString(ind + "fn " + f.Name + "(")
|
||||||
|
for i, arg := range f.Arguments {
|
||||||
|
out.WriteString(arg.Name + " " + arg.Type.String())
|
||||||
|
if i != len(f.Arguments)-1 {
|
||||||
|
out.WriteString(", ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out.WriteString(") ")
|
||||||
|
|
||||||
|
if f.HasReturnType {
|
||||||
|
out.WriteString(f.ReturnType.String() + " ")
|
||||||
|
}
|
||||||
|
|
||||||
|
out.WriteString(f.Block.String(i))
|
||||||
|
|
||||||
|
return out.String()
|
||||||
|
}
|
||||||
|
func (f *Function) statementNode() {}
|
||||||
|
|
||||||
|
type ImplicitVariableDefiniton struct {
|
||||||
|
Token token.Token // The Identifier token
|
||||||
|
Name string
|
||||||
|
Value ExpressionNode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ivd *ImplicitVariableDefiniton) TokenLiteral() string {
|
||||||
|
return ivd.Token.Literal
|
||||||
|
}
|
||||||
|
func (ivd *ImplicitVariableDefiniton) String(i Indentation) string {
|
||||||
|
var out strings.Builder
|
||||||
|
|
||||||
|
out.WriteString(i.indent() + ivd.Name + " := ")
|
||||||
|
out.WriteString(ivd.Value.String(i))
|
||||||
|
out.WriteString("\n")
|
||||||
|
|
||||||
|
return out.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ivd *ImplicitVariableDefiniton) statementNode() {}
|
||||||
|
|
||||||
|
type IntegerLiteral struct {
|
||||||
|
Token token.Token
|
||||||
|
Value int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (il *IntegerLiteral) TokenLiteral() string { return il.Token.Literal }
|
||||||
|
func (il *IntegerLiteral) String(i Indentation) string { return il.Token.Literal }
|
||||||
|
func (il *IntegerLiteral) expressionNode() {}
|
3
get_to_work.th
Normal file
3
get_to_work.th
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fn main() {
|
||||||
|
a := 2
|
||||||
|
}
|
@ -1,6 +1,8 @@
|
|||||||
package lexer
|
package lexer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"git.robaertschi.xyz/robaertschi/thorgot/token"
|
"git.robaertschi.xyz/robaertschi/thorgot/token"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -24,6 +26,10 @@ func New(input string) Lexer {
|
|||||||
return lexer
|
return lexer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l Lexer) String() string {
|
||||||
|
return fmt.Sprintf("Lexer{input: \"%v\", ch: '%c', pos: %v, readPos: %v, col: %v, line: %v}", l.input, l.ch, l.pos, l.readPos, l.col, l.line)
|
||||||
|
}
|
||||||
|
|
||||||
func (l *Lexer) readChar() {
|
func (l *Lexer) readChar() {
|
||||||
if l.readPos >= len(l.input) {
|
if l.readPos >= len(l.input) {
|
||||||
l.ch = 0
|
l.ch = 0
|
||||||
@ -92,11 +98,12 @@ func (l *Lexer) readNumber() token.Token {
|
|||||||
func (l *Lexer) NextToken() token.Token {
|
func (l *Lexer) NextToken() token.Token {
|
||||||
l.skipWhitespace()
|
l.skipWhitespace()
|
||||||
var tok token.Token
|
var tok token.Token
|
||||||
|
tok.Loc = token.Loc{Line: l.line, Col: l.col}
|
||||||
tok.Literal = string(l.ch)
|
tok.Literal = string(l.ch)
|
||||||
|
|
||||||
switch l.ch {
|
switch l.ch {
|
||||||
case '\n':
|
case '\n':
|
||||||
tok.Token = token.EndLine
|
tok.Token = token.NewLine
|
||||||
case ';':
|
case ';':
|
||||||
tok.Token = token.Semicolon
|
tok.Token = token.Semicolon
|
||||||
case ':':
|
case ':':
|
||||||
|
@ -14,13 +14,17 @@ func TestCorrectTokens(t *testing.T) {
|
|||||||
}{{
|
}{{
|
||||||
expectedTokens: []token.Token{{Token: token.Eof, Literal: "", Loc: token.Loc{Line: 1, Col: 1}}},
|
expectedTokens: []token.Token{{Token: token.Eof, Literal: "", Loc: token.Loc{Line: 1, Col: 1}}},
|
||||||
input: "",
|
input: "",
|
||||||
}, {input: "hello 1234 ; () {}",
|
}, {input: "hello 1234 ; () {}\n",
|
||||||
expectedTokens: []token.Token{
|
expectedTokens: []token.Token{
|
||||||
{Token: token.Identifier, Literal: "hello", Loc: token.Loc{Line: 1, Col: 1}},
|
{Token: token.Identifier, Literal: "hello", Loc: token.Loc{Line: 1, Col: 1}},
|
||||||
{Token: token.Integer, Literal: "1234", Loc: token.Loc{Line: 1, Col: 7}},
|
{Token: token.Integer, Literal: "1234", Loc: token.Loc{Line: 1, Col: 7}},
|
||||||
{Token: token.Semicolon, Literal: ";", Loc: token.Loc{Line: 1, Col: 12}},
|
{Token: token.Semicolon, Literal: ";", Loc: token.Loc{Line: 1, Col: 12}},
|
||||||
{Token: token.LParen, Literal: "(", Loc: token.Loc{Line: 1, Col: 14}},
|
{Token: token.LParen, Literal: "(", Loc: token.Loc{Line: 1, Col: 14}},
|
||||||
{Token: token.RParen, Literal: ")", Loc: token.Loc{Line: 1, Col: 15}},
|
{Token: token.RParen, Literal: ")", Loc: token.Loc{Line: 1, Col: 15}},
|
||||||
|
{Token: token.LBrace, Literal: "{", Loc: token.Loc{Line: 1, Col: 17}},
|
||||||
|
{Token: token.RBrace, Literal: "}", Loc: token.Loc{Line: 1, Col: 18}},
|
||||||
|
{Token: token.NewLine, Literal: "\n", Loc: token.Loc{Line: 2, Col: 1}},
|
||||||
|
{Token: token.Eof, Literal: "", Loc: token.Loc{Line: 2, Col: 2}},
|
||||||
}}}
|
}}}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
|
1
parser/parser.go
Normal file
1
parser/parser.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package parser
|
@ -17,7 +17,7 @@ const (
|
|||||||
Illegal TokenType = "Illegal"
|
Illegal TokenType = "Illegal"
|
||||||
Eof = "Eof"
|
Eof = "Eof"
|
||||||
|
|
||||||
EndLine = "EndLine"
|
NewLine = "NewLine"
|
||||||
|
|
||||||
Semicolon = "Semicolon" // ;
|
Semicolon = "Semicolon" // ;
|
||||||
Colon = "Colon" // :
|
Colon = "Colon" // :
|
||||||
|
Loading…
x
Reference in New Issue
Block a user