This commit is contained in:
Robin 2024-11-13 21:30:28 +01:00
parent c57c38bc81
commit ff2ff3d417
7 changed files with 251 additions and 3 deletions

109
2 Normal file
View 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
View 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
View File

@ -0,0 +1,3 @@
fn main() {
a := 2
}

View File

@ -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 ':':

View File

@ -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
View File

@ -0,0 +1 @@
package parser

View File

@ -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" // :