added functions till typechecker WIP

This commit is contained in:
Robin Bärtschi 2025-02-27 11:15:17 +01:00
parent b0b7ede252
commit 508b3fdc7a
13 changed files with 145 additions and 21 deletions

View File

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

View File

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

View File

@ -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
}

View File

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

View File

@ -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 {

View File

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

@ -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
};

View File

@ -33,6 +33,7 @@ const (
Semicolon TokenType = ";"
Colon TokenType = ":"
Comma TokenType = ","
Equal TokenType = "="
OpenParen TokenType = "("
CloseParen TokenType = ")"

View File

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

View File

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

View File

@ -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 {

View File

@ -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
}

15
update.md Normal file
View File

@ -0,0 +1,15 @@
# What to check if you updated or added something
- [x] Lexer
- [x] Parser
- [x] AST
- [x] TAST
- [x] Type Checker
- [x] Variable Resolution
- [x] Infer
- [x] Check
- [ ] TTIR
- [ ] TTIR Emit
- [ ] Backends
- [ ] Qbe
- [ ] Fasm