mirror of
https://github.com/RoBaertschi/tt.git
synced 2025-04-15 21:43: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
|
||||
|
||||
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
|
||||
TAST: Typed Ast
|
||||
|
@ -5,6 +5,15 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
var callConvArgs map[int]Register = map[int]Register{
|
||||
1: DI,
|
||||
2: SI,
|
||||
3: DX,
|
||||
4: CX,
|
||||
5: R8,
|
||||
6: R9,
|
||||
}
|
||||
|
||||
type Program struct {
|
||||
Functions []Function
|
||||
MainFunction *Function
|
||||
@ -169,6 +178,12 @@ type Register int
|
||||
|
||||
const (
|
||||
AX Register = iota
|
||||
CX
|
||||
DX
|
||||
DI
|
||||
SI
|
||||
R8
|
||||
R9
|
||||
R10
|
||||
R11
|
||||
|
||||
|
22
ast/ast.go
22
ast/ast.go
@ -52,17 +52,35 @@ func (p *Program) String() string {
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
type Type string
|
||||
|
||||
type Argument struct {
|
||||
Name string
|
||||
Type Type
|
||||
}
|
||||
|
||||
type FunctionDeclaration struct {
|
||||
Token token.Token // The token.FN
|
||||
Body Expression
|
||||
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) TokenLiteral() string { return fd.Token.Literal }
|
||||
func (fd *FunctionDeclaration) Tok() token.Token { return fd.Token }
|
||||
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
|
||||
@ -209,7 +227,7 @@ func (ie *IfExpression) String() string {
|
||||
type VariableDeclaration struct {
|
||||
Token token.Token // The Identifier token
|
||||
InitializingExpression Expression
|
||||
Type string
|
||||
Type Type
|
||||
Identifier string
|
||||
}
|
||||
|
||||
|
@ -63,6 +63,8 @@ func (l *Lexer) NextToken() token.Token {
|
||||
tok.Loc = l.loc()
|
||||
|
||||
switch l.ch {
|
||||
case ',':
|
||||
tok = l.newToken(token.Comma)
|
||||
case ';':
|
||||
tok = l.newToken(token.Semicolon)
|
||||
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 {
|
||||
if ok, _ := p.expect(token.Fn); !ok {
|
||||
return nil
|
||||
@ -191,6 +223,13 @@ func (p *Parser) parseDeclaration() ast.Declaration {
|
||||
if ok, _ := p.expectPeek(token.OpenParen); !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
args, ok := p.parseArgumentList()
|
||||
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if ok, _ := p.expectPeek(token.CloseParen); !ok {
|
||||
return nil
|
||||
}
|
||||
@ -208,6 +247,7 @@ func (p *Parser) parseDeclaration() ast.Declaration {
|
||||
Token: tok,
|
||||
Name: name,
|
||||
Body: expr,
|
||||
Args: args,
|
||||
}
|
||||
}
|
||||
|
||||
@ -371,7 +411,7 @@ func (p *Parser) parseVariableDeclaration() ast.Expression {
|
||||
|
||||
if p.peekTokenIs(token.Ident) {
|
||||
p.nextToken()
|
||||
variable.Type = p.curToken.Literal
|
||||
variable.Type = ast.Type(p.curToken.Literal)
|
||||
}
|
||||
|
||||
if ok, errExpr := p.expectPeek(token.Equal); !ok {
|
||||
|
@ -52,10 +52,16 @@ func (p *Program) String() string {
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
type Argument struct {
|
||||
Name string
|
||||
Type types.Type
|
||||
}
|
||||
|
||||
type FunctionDeclaration struct {
|
||||
Token token.Token // The token.FN
|
||||
Body Expression
|
||||
Name string
|
||||
Args []Argument
|
||||
ReturnType types.Type
|
||||
}
|
||||
|
||||
|
12
test.tt
12
test.tt
@ -1,9 +1,13 @@
|
||||
fn main() = {
|
||||
hi := 4;
|
||||
|
||||
if hi == 4 in
|
||||
if hi == 4 {
|
||||
test2 := 3;
|
||||
hi = 0
|
||||
else hi = 1;
|
||||
|
||||
hi
|
||||
}
|
||||
else {
|
||||
hi = 1
|
||||
};
|
||||
|
||||
test2
|
||||
};
|
||||
|
@ -33,6 +33,7 @@ const (
|
||||
|
||||
Semicolon TokenType = ";"
|
||||
Colon TokenType = ":"
|
||||
Comma TokenType = ","
|
||||
Equal TokenType = "="
|
||||
OpenParen 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) {
|
||||
_, err := VarResolve(program)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newProgram, err := c.inferTypes(program)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -30,6 +30,13 @@ func (c *Checker) inferDeclaration(decl ast.Declaration) (tast.Declaration, erro
|
||||
switch decl := decl.(type) {
|
||||
case *ast.FunctionDeclaration:
|
||||
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)
|
||||
c.functionVariables[decl.Name] = vars
|
||||
|
||||
|
@ -29,17 +29,13 @@ func copyScope(s *Scope) Scope {
|
||||
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) {
|
||||
v, ok := s.Variables[name]
|
||||
|
||||
if ok {
|
||||
return v, true
|
||||
}
|
||||
|
||||
return Var{}, false
|
||||
return v, ok
|
||||
}
|
||||
|
||||
func (s *Scope) Set(name string, uniqName string) {
|
||||
@ -59,6 +55,18 @@ func (s *Scope) HasInCurrent(name string) bool {
|
||||
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) {
|
||||
functionToScope := make(map[string]Scope)
|
||||
|
||||
@ -66,6 +74,9 @@ func VarResolve(p *ast.Program) (map[string]Scope, error) {
|
||||
switch d := d.(type) {
|
||||
case *ast.FunctionDeclaration:
|
||||
s := Scope{Variables: make(map[string]Var)}
|
||||
for _, arg := range d.Args {
|
||||
s.SetUniq(arg.Name)
|
||||
}
|
||||
err := VarResolveExpr(&s, d.Body)
|
||||
functionToScope[d.Name] = s
|
||||
if err != nil {
|
||||
@ -116,25 +127,25 @@ func VarResolveExpr(s *Scope, e ast.Expression) error {
|
||||
return err
|
||||
}
|
||||
|
||||
err = VarResolveExpr(s, e.Then)
|
||||
thenS := copyScope(s)
|
||||
err = VarResolveExpr(&thenS, e.Then)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
elseS := copyScope(s)
|
||||
if e.Else != nil {
|
||||
err = VarResolveExpr(s, e.Else)
|
||||
err = VarResolveExpr(&elseS, e.Else)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case *ast.VariableDeclaration:
|
||||
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.UniqueId += 1
|
||||
s.Set(e.Identifier, uniqName)
|
||||
s.SetUniq(e.Identifier)
|
||||
case *ast.VariableReference:
|
||||
v, ok := s.Get(e.Identifier)
|
||||
if !ok {
|
||||
|
@ -53,7 +53,7 @@ func New(id int64, name string) Type {
|
||||
return typeId
|
||||
}
|
||||
|
||||
func From(name string) (Type, bool) {
|
||||
t, ok := types[name]
|
||||
func From(name ast.Type) (Type, bool) {
|
||||
t, ok := types[string(name)]
|
||||
return t, ok
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user