mirror of
https://github.com/RoBaertschi/tt.git
synced 2025-04-16 05:53:30 +00:00
added functions till typechecker WIP
This commit is contained in:
parent
b0b7ede252
commit
508b3fdc7a
@ -7,7 +7,7 @@ tt Programming Language Backend Architecture
|
|||||||
|
|
||||||
# Architecture
|
# Architecture
|
||||||
|
|
||||||
AST --> Type Checking --> TAST --> IR Emission --> TTIR --> Codegen --> TTASM --> Emit --> FASM -> Binary
|
AST --> Type Checking --> TAST --> IR Emission --> TTIR --> Codegen --> ASM --> Emit --> FASM -> Binary
|
||||||
|
|
||||||
TTIR: TT Intermediate Representation is the Representation that the AST gets turned into. This will be mostly be used for optimissing and abstracting away from Assembly
|
TTIR: TT Intermediate Representation is the Representation that the AST gets turned into. This will be mostly be used for optimissing and abstracting away from Assembly
|
||||||
TAST: Typed Ast
|
TAST: Typed Ast
|
||||||
|
@ -5,6 +5,15 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var callConvArgs map[int]Register = map[int]Register{
|
||||||
|
1: DI,
|
||||||
|
2: SI,
|
||||||
|
3: DX,
|
||||||
|
4: CX,
|
||||||
|
5: R8,
|
||||||
|
6: R9,
|
||||||
|
}
|
||||||
|
|
||||||
type Program struct {
|
type Program struct {
|
||||||
Functions []Function
|
Functions []Function
|
||||||
MainFunction *Function
|
MainFunction *Function
|
||||||
@ -169,6 +178,12 @@ type Register int
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
AX Register = iota
|
AX Register = iota
|
||||||
|
CX
|
||||||
|
DX
|
||||||
|
DI
|
||||||
|
SI
|
||||||
|
R8
|
||||||
|
R9
|
||||||
R10
|
R10
|
||||||
R11
|
R11
|
||||||
|
|
||||||
|
22
ast/ast.go
22
ast/ast.go
@ -52,17 +52,35 @@ func (p *Program) String() string {
|
|||||||
return builder.String()
|
return builder.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Type string
|
||||||
|
|
||||||
|
type Argument struct {
|
||||||
|
Name string
|
||||||
|
Type Type
|
||||||
|
}
|
||||||
|
|
||||||
type FunctionDeclaration struct {
|
type FunctionDeclaration struct {
|
||||||
Token token.Token // The token.FN
|
Token token.Token // The token.FN
|
||||||
Body Expression
|
Body Expression
|
||||||
Name string
|
Name string
|
||||||
|
Args []Argument
|
||||||
|
}
|
||||||
|
|
||||||
|
func ArgsToString(args []Argument) string {
|
||||||
|
var b strings.Builder
|
||||||
|
|
||||||
|
for _, arg := range args {
|
||||||
|
b.WriteString(fmt.Sprintf("%s %s,", arg.Name, arg.Type))
|
||||||
|
}
|
||||||
|
|
||||||
|
return b.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fd *FunctionDeclaration) declarationNode() {}
|
func (fd *FunctionDeclaration) declarationNode() {}
|
||||||
func (fd *FunctionDeclaration) TokenLiteral() string { return fd.Token.Literal }
|
func (fd *FunctionDeclaration) TokenLiteral() string { return fd.Token.Literal }
|
||||||
func (fd *FunctionDeclaration) Tok() token.Token { return fd.Token }
|
func (fd *FunctionDeclaration) Tok() token.Token { return fd.Token }
|
||||||
func (fd *FunctionDeclaration) String() string {
|
func (fd *FunctionDeclaration) String() string {
|
||||||
return fmt.Sprintf("fn %v() = %v;", fd.Name, fd.Body.String())
|
return fmt.Sprintf("fn %v(%v) = %v;", fd.Name, ArgsToString(fd.Args), fd.Body.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Represents a Expression that we failed to parse
|
// Represents a Expression that we failed to parse
|
||||||
@ -209,7 +227,7 @@ func (ie *IfExpression) String() string {
|
|||||||
type VariableDeclaration struct {
|
type VariableDeclaration struct {
|
||||||
Token token.Token // The Identifier token
|
Token token.Token // The Identifier token
|
||||||
InitializingExpression Expression
|
InitializingExpression Expression
|
||||||
Type string
|
Type Type
|
||||||
Identifier string
|
Identifier string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,6 +63,8 @@ func (l *Lexer) NextToken() token.Token {
|
|||||||
tok.Loc = l.loc()
|
tok.Loc = l.loc()
|
||||||
|
|
||||||
switch l.ch {
|
switch l.ch {
|
||||||
|
case ',':
|
||||||
|
tok = l.newToken(token.Comma)
|
||||||
case ';':
|
case ';':
|
||||||
tok = l.newToken(token.Semicolon)
|
tok = l.newToken(token.Semicolon)
|
||||||
case ':':
|
case ':':
|
||||||
|
@ -178,6 +178,38 @@ func (p *Parser) ParseProgram() *ast.Program {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *Parser) parseType() (t ast.Type, ok bool) {
|
||||||
|
if ok, _ := p.expect(token.Ident); !ok {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
return ast.Type(p.curToken.Literal), true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) parseArgumentList() ([]ast.Argument, bool) {
|
||||||
|
args := []ast.Argument{}
|
||||||
|
|
||||||
|
for p.peekTokenIs(token.Ident) {
|
||||||
|
p.nextToken()
|
||||||
|
name := p.curToken.Literal
|
||||||
|
p.nextToken()
|
||||||
|
t, ok := p.parseType()
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return args, false
|
||||||
|
}
|
||||||
|
|
||||||
|
args = append(args, ast.Argument{Type: t, Name: name})
|
||||||
|
|
||||||
|
if !p.peekTokenIs(token.Comma) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
p.nextToken()
|
||||||
|
}
|
||||||
|
|
||||||
|
return args, true
|
||||||
|
}
|
||||||
|
|
||||||
func (p *Parser) parseDeclaration() ast.Declaration {
|
func (p *Parser) parseDeclaration() ast.Declaration {
|
||||||
if ok, _ := p.expect(token.Fn); !ok {
|
if ok, _ := p.expect(token.Fn); !ok {
|
||||||
return nil
|
return nil
|
||||||
@ -191,6 +223,13 @@ func (p *Parser) parseDeclaration() ast.Declaration {
|
|||||||
if ok, _ := p.expectPeek(token.OpenParen); !ok {
|
if ok, _ := p.expectPeek(token.OpenParen); !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
args, ok := p.parseArgumentList()
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
if ok, _ := p.expectPeek(token.CloseParen); !ok {
|
if ok, _ := p.expectPeek(token.CloseParen); !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -208,6 +247,7 @@ func (p *Parser) parseDeclaration() ast.Declaration {
|
|||||||
Token: tok,
|
Token: tok,
|
||||||
Name: name,
|
Name: name,
|
||||||
Body: expr,
|
Body: expr,
|
||||||
|
Args: args,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -371,7 +411,7 @@ func (p *Parser) parseVariableDeclaration() ast.Expression {
|
|||||||
|
|
||||||
if p.peekTokenIs(token.Ident) {
|
if p.peekTokenIs(token.Ident) {
|
||||||
p.nextToken()
|
p.nextToken()
|
||||||
variable.Type = p.curToken.Literal
|
variable.Type = ast.Type(p.curToken.Literal)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ok, errExpr := p.expectPeek(token.Equal); !ok {
|
if ok, errExpr := p.expectPeek(token.Equal); !ok {
|
||||||
|
@ -52,10 +52,16 @@ func (p *Program) String() string {
|
|||||||
return builder.String()
|
return builder.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Argument struct {
|
||||||
|
Name string
|
||||||
|
Type types.Type
|
||||||
|
}
|
||||||
|
|
||||||
type FunctionDeclaration struct {
|
type FunctionDeclaration struct {
|
||||||
Token token.Token // The token.FN
|
Token token.Token // The token.FN
|
||||||
Body Expression
|
Body Expression
|
||||||
Name string
|
Name string
|
||||||
|
Args []Argument
|
||||||
ReturnType types.Type
|
ReturnType types.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
10
test.tt
10
test.tt
@ -1,9 +1,13 @@
|
|||||||
fn main() = {
|
fn main() = {
|
||||||
hi := 4;
|
hi := 4;
|
||||||
|
|
||||||
if hi == 4 in
|
if hi == 4 {
|
||||||
|
test2 := 3;
|
||||||
hi = 0
|
hi = 0
|
||||||
else hi = 1;
|
}
|
||||||
|
else {
|
||||||
|
hi = 1
|
||||||
|
};
|
||||||
|
|
||||||
hi
|
test2
|
||||||
};
|
};
|
||||||
|
@ -33,6 +33,7 @@ const (
|
|||||||
|
|
||||||
Semicolon TokenType = ";"
|
Semicolon TokenType = ";"
|
||||||
Colon TokenType = ":"
|
Colon TokenType = ":"
|
||||||
|
Comma TokenType = ","
|
||||||
Equal TokenType = "="
|
Equal TokenType = "="
|
||||||
OpenParen TokenType = "("
|
OpenParen TokenType = "("
|
||||||
CloseParen TokenType = ")"
|
CloseParen TokenType = ")"
|
||||||
|
@ -26,6 +26,11 @@ func (c *Checker) error(t token.Token, format string, args ...any) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Checker) CheckProgram(program *ast.Program) (*tast.Program, error) {
|
func (c *Checker) CheckProgram(program *ast.Program) (*tast.Program, error) {
|
||||||
|
_, err := VarResolve(program)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
newProgram, err := c.inferTypes(program)
|
newProgram, err := c.inferTypes(program)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -30,6 +30,13 @@ func (c *Checker) inferDeclaration(decl ast.Declaration) (tast.Declaration, erro
|
|||||||
switch decl := decl.(type) {
|
switch decl := decl.(type) {
|
||||||
case *ast.FunctionDeclaration:
|
case *ast.FunctionDeclaration:
|
||||||
vars := make(Variables)
|
vars := make(Variables)
|
||||||
|
for _, arg := range decl.Args {
|
||||||
|
t, ok := types.From(arg.Type)
|
||||||
|
if !ok {
|
||||||
|
return nil, c.error(decl.Token, "could not find the type %q for argument %q", arg.Type, arg.Name)
|
||||||
|
}
|
||||||
|
vars[arg.Name] = t
|
||||||
|
}
|
||||||
body, err := c.inferExpression(vars, decl.Body)
|
body, err := c.inferExpression(vars, decl.Body)
|
||||||
c.functionVariables[decl.Name] = vars
|
c.functionVariables[decl.Name] = vars
|
||||||
|
|
||||||
|
@ -29,17 +29,13 @@ func copyScope(s *Scope) Scope {
|
|||||||
newVars[k] = Var{Name: v.Name, FromCurrentScope: false}
|
newVars[k] = Var{Name: v.Name, FromCurrentScope: false}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Scope{Variables: newVars}
|
return Scope{Variables: newVars, UniqueId: s.UniqueId}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Scope) Get(name string) (Var, bool) {
|
func (s *Scope) Get(name string) (Var, bool) {
|
||||||
v, ok := s.Variables[name]
|
v, ok := s.Variables[name]
|
||||||
|
|
||||||
if ok {
|
return v, ok
|
||||||
return v, true
|
|
||||||
}
|
|
||||||
|
|
||||||
return Var{}, false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Scope) Set(name string, uniqName string) {
|
func (s *Scope) Set(name string, uniqName string) {
|
||||||
@ -59,6 +55,18 @@ func (s *Scope) HasInCurrent(name string) bool {
|
|||||||
return v.FromCurrentScope
|
return v.FromCurrentScope
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Scope) Uniq(name string) string {
|
||||||
|
uniqName := fmt.Sprintf("%s.%d", name, s.UniqueId)
|
||||||
|
s.UniqueId += 1
|
||||||
|
return uniqName
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Scope) SetUniq(name string) string {
|
||||||
|
uniq := s.Uniq(name)
|
||||||
|
s.Set(name, uniq)
|
||||||
|
return uniq
|
||||||
|
}
|
||||||
|
|
||||||
func VarResolve(p *ast.Program) (map[string]Scope, error) {
|
func VarResolve(p *ast.Program) (map[string]Scope, error) {
|
||||||
functionToScope := make(map[string]Scope)
|
functionToScope := make(map[string]Scope)
|
||||||
|
|
||||||
@ -66,6 +74,9 @@ func VarResolve(p *ast.Program) (map[string]Scope, error) {
|
|||||||
switch d := d.(type) {
|
switch d := d.(type) {
|
||||||
case *ast.FunctionDeclaration:
|
case *ast.FunctionDeclaration:
|
||||||
s := Scope{Variables: make(map[string]Var)}
|
s := Scope{Variables: make(map[string]Var)}
|
||||||
|
for _, arg := range d.Args {
|
||||||
|
s.SetUniq(arg.Name)
|
||||||
|
}
|
||||||
err := VarResolveExpr(&s, d.Body)
|
err := VarResolveExpr(&s, d.Body)
|
||||||
functionToScope[d.Name] = s
|
functionToScope[d.Name] = s
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -116,25 +127,25 @@ func VarResolveExpr(s *Scope, e ast.Expression) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = VarResolveExpr(s, e.Then)
|
thenS := copyScope(s)
|
||||||
|
err = VarResolveExpr(&thenS, e.Then)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
elseS := copyScope(s)
|
||||||
if e.Else != nil {
|
if e.Else != nil {
|
||||||
err = VarResolveExpr(s, e.Else)
|
err = VarResolveExpr(&elseS, e.Else)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case *ast.VariableDeclaration:
|
case *ast.VariableDeclaration:
|
||||||
if s.HasInCurrent(e.Identifier) {
|
if s.HasInCurrent(e.Identifier) {
|
||||||
return errorf(e.Token, "variable %q redifinded", e.Identifier)
|
return errorf(e.Token, "variable %q redefined", e.Identifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
uniqName := fmt.Sprintf("%s.%d", e.Identifier, s.UniqueId)
|
s.SetUniq(e.Identifier)
|
||||||
s.UniqueId += 1
|
|
||||||
s.Set(e.Identifier, uniqName)
|
|
||||||
case *ast.VariableReference:
|
case *ast.VariableReference:
|
||||||
v, ok := s.Get(e.Identifier)
|
v, ok := s.Get(e.Identifier)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -53,7 +53,7 @@ func New(id int64, name string) Type {
|
|||||||
return typeId
|
return typeId
|
||||||
}
|
}
|
||||||
|
|
||||||
func From(name string) (Type, bool) {
|
func From(name ast.Type) (Type, bool) {
|
||||||
t, ok := types[name]
|
t, ok := types[string(name)]
|
||||||
return t, ok
|
return t, ok
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user