mirror of
https://github.com/RoBaertschi/tt.git
synced 2025-04-15 21:43:30 +00:00
a lot of stuff
This commit is contained in:
parent
ee26d1371c
commit
1b2ebd2361
20
ast/ast.go
20
ast/ast.go
@ -9,6 +9,7 @@ import (
|
||||
|
||||
type Node interface {
|
||||
TokenLiteral() string
|
||||
Tok() token.Token
|
||||
String() string
|
||||
}
|
||||
|
||||
@ -33,6 +34,13 @@ func (p *Program) TokenLiteral() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (p *Program) Tok() token.Token {
|
||||
if len(p.Declarations) > 0 {
|
||||
return p.Declarations[0].Tok()
|
||||
}
|
||||
return token.Token{}
|
||||
}
|
||||
|
||||
func (p *Program) String() string {
|
||||
var builder strings.Builder
|
||||
|
||||
@ -52,6 +60,7 @@ type FunctionDeclaration struct {
|
||||
|
||||
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())
|
||||
}
|
||||
@ -63,6 +72,7 @@ type ErrorExpression struct {
|
||||
|
||||
func (e *ErrorExpression) expressionNode() {}
|
||||
func (e *ErrorExpression) TokenLiteral() string { return e.InvalidToken.Literal }
|
||||
func (e *ErrorExpression) Tok() token.Token { return e.InvalidToken }
|
||||
func (e *ErrorExpression) String() string { return "<ERROR EXPR>" }
|
||||
|
||||
type IntegerExpression struct {
|
||||
@ -72,6 +82,7 @@ type IntegerExpression struct {
|
||||
|
||||
func (ie *IntegerExpression) expressionNode() {}
|
||||
func (ie *IntegerExpression) TokenLiteral() string { return ie.Token.Literal }
|
||||
func (ie *IntegerExpression) Tok() token.Token { return ie.Token }
|
||||
func (ie *IntegerExpression) String() string { return ie.Token.Literal }
|
||||
|
||||
type BooleanExpression struct {
|
||||
@ -81,6 +92,7 @@ type BooleanExpression struct {
|
||||
|
||||
func (be *BooleanExpression) expressionNode() {}
|
||||
func (be *BooleanExpression) TokenLiteral() string { return be.Token.Literal }
|
||||
func (be *BooleanExpression) Tok() token.Token { return be.Token }
|
||||
func (be *BooleanExpression) String() string { return be.Token.Literal }
|
||||
|
||||
//go:generate stringer -type=BinaryOperator
|
||||
@ -137,6 +149,7 @@ type BinaryExpression struct {
|
||||
|
||||
func (be *BinaryExpression) expressionNode() {}
|
||||
func (be *BinaryExpression) TokenLiteral() string { return be.Token.Literal }
|
||||
func (be *BinaryExpression) Tok() token.Token { return be.Token }
|
||||
func (be *BinaryExpression) String() string {
|
||||
return fmt.Sprintf("(%s %s %s)", be.Lhs, be.Operator.SymbolString(), be.Rhs)
|
||||
}
|
||||
@ -149,6 +162,7 @@ type BlockExpression struct {
|
||||
|
||||
func (be *BlockExpression) expressionNode() {}
|
||||
func (be *BlockExpression) TokenLiteral() string { return be.Token.Literal }
|
||||
func (be *BlockExpression) Tok() token.Token { return be.Token }
|
||||
func (be *BlockExpression) String() string {
|
||||
var builder strings.Builder
|
||||
|
||||
@ -170,12 +184,13 @@ type IfExpression struct {
|
||||
Token token.Token // The 'if' token
|
||||
Condition Expression
|
||||
Then Expression
|
||||
// Can be nil
|
||||
// NOTE: Can be nil
|
||||
Else Expression
|
||||
}
|
||||
|
||||
func (ie *IfExpression) expressionNode() {}
|
||||
func (ie *IfExpression) TokenLiteral() string { return ie.Token.Literal }
|
||||
func (ie *IfExpression) Tok() token.Token { return ie.Token }
|
||||
func (ie *IfExpression) String() string {
|
||||
var builder strings.Builder
|
||||
|
||||
@ -200,6 +215,7 @@ type VariableDeclaration struct {
|
||||
|
||||
func (vd *VariableDeclaration) expressionNode() {}
|
||||
func (vd *VariableDeclaration) TokenLiteral() string { return vd.Token.Literal }
|
||||
func (vd *VariableDeclaration) Tok() token.Token { return vd.Token }
|
||||
func (vd *VariableDeclaration) String() string {
|
||||
return fmt.Sprintf("%s : %v = %s", vd.Identifier, vd.Type, vd.InitializingExpression)
|
||||
}
|
||||
@ -211,6 +227,7 @@ type VariableReference struct {
|
||||
|
||||
func (vr *VariableReference) expressionNode() {}
|
||||
func (vr *VariableReference) TokenLiteral() string { return vr.Token.Literal }
|
||||
func (vr *VariableReference) Tok() token.Token { return vr.Token }
|
||||
func (vr *VariableReference) String() string {
|
||||
return fmt.Sprintf("%s", vr.Identifier)
|
||||
}
|
||||
@ -223,6 +240,7 @@ type AssignmentExpression struct {
|
||||
|
||||
func (ae *AssignmentExpression) expressionNode() {}
|
||||
func (ae *AssignmentExpression) TokenLiteral() string { return ae.Token.Literal }
|
||||
func (ae *AssignmentExpression) Tok() token.Token { return ae.Token }
|
||||
func (ae *AssignmentExpression) String() string {
|
||||
return fmt.Sprintf("%s = %s", ae.Lhs.String(), ae.Rhs.String())
|
||||
}
|
||||
|
@ -145,7 +145,14 @@ func (rft *funcTask) WithName(name string) {
|
||||
rft.name = name
|
||||
}
|
||||
|
||||
func build(outputWriter io.Writer, input string, output string, toPrint ToPrintFlags, backend asm.Backend) error {
|
||||
func build(outputWriter io.Writer, input string, output string, toPrint ToPrintFlags, backend asm.Backend) (err error) {
|
||||
|
||||
defer func() {
|
||||
if panicErr := recover(); panicErr != nil {
|
||||
err = fmt.Errorf("panic in build: %#v", panicErr)
|
||||
}
|
||||
}()
|
||||
|
||||
file, err := os.Open(input)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not open file %q because: %v", input, err)
|
||||
@ -217,7 +224,7 @@ func build(outputWriter io.Writer, input string, output string, toPrint ToPrintF
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
type taskResult struct {
|
||||
|
@ -27,7 +27,7 @@ type Lexer struct {
|
||||
}
|
||||
|
||||
func New(input string, file string) (*Lexer, error) {
|
||||
l := &Lexer{input: input, file: file}
|
||||
l := &Lexer{input: input, file: file, lineCount: 1}
|
||||
if err := l.readChar(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
4
main.go
4
main.go
@ -59,7 +59,7 @@ func main() {
|
||||
toPrint |= build.PrintIr
|
||||
}
|
||||
|
||||
logger := log.New(os.Stderr, "", log.Lshortfile)
|
||||
_ = log.New(os.Stderr, "", log.Lshortfile)
|
||||
|
||||
backend := asm.Fasm
|
||||
if *qbe {
|
||||
@ -68,7 +68,7 @@ func main() {
|
||||
|
||||
err := build.NewSourceProgram(input, output).Build(backend, *emitAsmOnly, build.ToPrintFlags(toPrint))
|
||||
if err != nil {
|
||||
logger.Fatalln(err)
|
||||
os.Stderr.WriteString(fmt.Sprintf("%v\n", err.Error()))
|
||||
term.Exit(1)
|
||||
}
|
||||
}
|
||||
|
26
tast/tast.go
26
tast/tast.go
@ -15,6 +15,7 @@ import (
|
||||
|
||||
type Node interface {
|
||||
TokenLiteral() string
|
||||
Tok() token.Token
|
||||
String() string
|
||||
}
|
||||
|
||||
@ -62,6 +63,7 @@ var _ Declaration = &FunctionDeclaration{}
|
||||
|
||||
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 = %v;", fd.Name, fd.ReturnType.Name(), fd.Body.String())
|
||||
}
|
||||
@ -78,6 +80,7 @@ func (ie *IntegerExpression) Type() types.Type {
|
||||
return types.I64
|
||||
}
|
||||
func (ie *IntegerExpression) TokenLiteral() string { return ie.Token.Literal }
|
||||
func (ie *IntegerExpression) Tok() token.Token { return ie.Token }
|
||||
func (ie *IntegerExpression) String() string { return ie.Token.Literal }
|
||||
|
||||
type BooleanExpression struct {
|
||||
@ -92,6 +95,7 @@ func (ie *BooleanExpression) Type() types.Type {
|
||||
return types.Bool
|
||||
}
|
||||
func (be *BooleanExpression) TokenLiteral() string { return be.Token.Literal }
|
||||
func (be *BooleanExpression) Tok() token.Token { return be.Token }
|
||||
func (be *BooleanExpression) String() string { return be.Token.Literal }
|
||||
|
||||
type BinaryExpression struct {
|
||||
@ -108,6 +112,7 @@ func (be *BinaryExpression) Type() types.Type {
|
||||
return be.ResultType
|
||||
}
|
||||
func (be *BinaryExpression) TokenLiteral() string { return be.Token.Literal }
|
||||
func (be *BinaryExpression) Tok() token.Token { return be.Token }
|
||||
func (be *BinaryExpression) String() string {
|
||||
return fmt.Sprintf("(%s %s %s :> %s)", be.Lhs, be.Operator.SymbolString(), be.Rhs, be.ResultType.Name())
|
||||
}
|
||||
@ -119,11 +124,14 @@ type BlockExpression struct {
|
||||
ReturnType types.Type
|
||||
}
|
||||
|
||||
var _ Expression = &BlockExpression{}
|
||||
|
||||
func (be *BlockExpression) expressionNode() {}
|
||||
func (be *BlockExpression) Type() types.Type {
|
||||
return be.ReturnType
|
||||
}
|
||||
func (be *BlockExpression) TokenLiteral() string { return be.Token.Literal }
|
||||
func (be *BlockExpression) Tok() token.Token { return be.Token }
|
||||
func (be *BlockExpression) String() string {
|
||||
var builder strings.Builder
|
||||
|
||||
@ -150,11 +158,14 @@ type IfExpression struct {
|
||||
ReturnType types.Type
|
||||
}
|
||||
|
||||
var _ Expression = &IfExpression{}
|
||||
|
||||
func (ie *IfExpression) expressionNode() {}
|
||||
func (ie *IfExpression) Type() types.Type {
|
||||
return ie.ReturnType
|
||||
}
|
||||
func (ie *IfExpression) TokenLiteral() string { return ie.Token.Literal }
|
||||
func (ie *IfExpression) Tok() token.Token { return ie.Token }
|
||||
func (ie *IfExpression) String() string {
|
||||
var builder strings.Builder
|
||||
|
||||
@ -177,13 +188,16 @@ type VariableDeclaration struct {
|
||||
Identifier string
|
||||
}
|
||||
|
||||
var _ Expression = &VariableDeclaration{}
|
||||
|
||||
func (vd *VariableDeclaration) expressionNode() {}
|
||||
func (vd *VariableDeclaration) Type() types.Type {
|
||||
return vd.VariableType
|
||||
return types.Unit
|
||||
}
|
||||
func (vd *VariableDeclaration) TokenLiteral() string { return vd.Token.Literal }
|
||||
func (vd *VariableDeclaration) Tok() token.Token { return vd.Token }
|
||||
func (vd *VariableDeclaration) String() string {
|
||||
return fmt.Sprintf("%s : %v = %s", vd.Identifier, vd.Type().Name(), vd.InitializingExpression)
|
||||
return fmt.Sprintf("%s : %v = %s", vd.Identifier, vd.VariableType.Name(), vd.InitializingExpression)
|
||||
}
|
||||
|
||||
type VariableReference struct {
|
||||
@ -192,14 +206,17 @@ type VariableReference struct {
|
||||
VariableType types.Type
|
||||
}
|
||||
|
||||
var _ Expression = &VariableReference{}
|
||||
|
||||
func (vr *VariableReference) expressionNode() {}
|
||||
func (vr *VariableReference) Type() types.Type {
|
||||
return vr.VariableType
|
||||
}
|
||||
|
||||
func (vr *VariableReference) TokenLiteral() string { return vr.Token.Literal }
|
||||
func (vr *VariableReference) Tok() token.Token { return vr.Token }
|
||||
func (vr *VariableReference) String() string {
|
||||
return fmt.Sprintf("%s", vr.Identifier)
|
||||
return fmt.Sprintf("(%s :> %s)", vr.Identifier, vr.Type().Name())
|
||||
}
|
||||
|
||||
type AssignmentExpression struct {
|
||||
@ -208,11 +225,14 @@ type AssignmentExpression struct {
|
||||
Rhs Expression
|
||||
}
|
||||
|
||||
var _ Expression = &AssignmentExpression{}
|
||||
|
||||
func (ae *AssignmentExpression) expressionNode() {}
|
||||
func (ae *AssignmentExpression) Type() types.Type {
|
||||
return types.Unit
|
||||
}
|
||||
func (ae *AssignmentExpression) TokenLiteral() string { return ae.Token.Literal }
|
||||
func (ae *AssignmentExpression) Tok() token.Token { return ae.Token }
|
||||
func (ae *AssignmentExpression) String() string {
|
||||
return fmt.Sprintf("%s = %s", ae.Lhs.String(), ae.Rhs.String())
|
||||
}
|
||||
|
2
test.tt
2
test.tt
@ -1,5 +1,5 @@
|
||||
fn main() = {
|
||||
hi: i64 = 4;
|
||||
hi := 4;
|
||||
|
||||
if hi == 2 in hi = 3
|
||||
else hi = 2;
|
||||
|
@ -121,6 +121,10 @@ func emitExpression(expr tast.Expression) (Operand, []Instruction) {
|
||||
}
|
||||
instructions = append(instructions, Label(endOfIfLabel))
|
||||
return dst, instructions
|
||||
case *tast.AssignmentExpression:
|
||||
case *tast.VariableDeclaration:
|
||||
case *tast.VariableReference:
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected tast.Expression: %#v", expr))
|
||||
}
|
||||
panic("unhandled tast.Expression case in ir emitter")
|
||||
}
|
||||
|
@ -10,8 +10,11 @@ import (
|
||||
"robaertschi.xyz/robaertschi/tt/types"
|
||||
)
|
||||
|
||||
type Variables map[string]types.Type
|
||||
|
||||
type Checker struct {
|
||||
foundMain bool
|
||||
foundMain bool
|
||||
functionVariables map[string]Variables
|
||||
}
|
||||
|
||||
func New() *Checker {
|
||||
@ -52,7 +55,7 @@ func (c *Checker) CheckProgram(program *ast.Program) (*tast.Program, error) {
|
||||
func (c *Checker) checkDeclaration(decl tast.Declaration) error {
|
||||
switch decl := decl.(type) {
|
||||
case *tast.FunctionDeclaration:
|
||||
err := c.checkExpression(decl.Body)
|
||||
err := c.checkExpression(c.functionVariables[decl.Name], decl.Body)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
@ -67,15 +70,15 @@ func (c *Checker) checkDeclaration(decl tast.Declaration) error {
|
||||
return errors.New("unhandled declaration in type checker")
|
||||
}
|
||||
|
||||
func (c *Checker) checkExpression(expr tast.Expression) error {
|
||||
func (c *Checker) checkExpression(vars Variables, expr tast.Expression) error {
|
||||
switch expr := expr.(type) {
|
||||
case *tast.IntegerExpression:
|
||||
return nil
|
||||
case *tast.BooleanExpression:
|
||||
return nil
|
||||
case *tast.BinaryExpression:
|
||||
lhsErr := c.checkExpression(expr.Lhs)
|
||||
rhsErr := c.checkExpression(expr.Rhs)
|
||||
lhsErr := c.checkExpression(vars, expr.Lhs)
|
||||
rhsErr := c.checkExpression(vars, expr.Rhs)
|
||||
var operandErr error
|
||||
if lhsErr == nil && rhsErr == nil {
|
||||
if !expr.Lhs.Type().IsSameType(expr.Rhs.Type()) {
|
||||
@ -90,32 +93,62 @@ func (c *Checker) checkExpression(expr tast.Expression) error {
|
||||
errs := []error{}
|
||||
|
||||
for _, expr := range expr.Expressions {
|
||||
errs = append(errs, c.checkExpression(expr))
|
||||
errs = append(errs, c.checkExpression(vars, expr))
|
||||
}
|
||||
if expr.ReturnExpression != nil {
|
||||
errs = append(errs, c.checkExpression(expr.ReturnExpression))
|
||||
errs = append(errs, c.checkExpression(vars, expr.ReturnExpression))
|
||||
}
|
||||
return errors.Join(errs...)
|
||||
case *tast.IfExpression:
|
||||
condErr := c.checkExpression(expr.Condition)
|
||||
condErr := c.checkExpression(vars, expr.Condition)
|
||||
if condErr == nil {
|
||||
if !expr.Condition.Type().IsSameType(types.Bool) {
|
||||
condErr = c.error(expr.Token, "the condition in the if should be a boolean, but got %q", expr.Condition.Type().Name())
|
||||
}
|
||||
}
|
||||
thenErr := c.checkExpression(expr.Then)
|
||||
thenErr := c.checkExpression(vars, expr.Then)
|
||||
|
||||
if expr.Else == nil {
|
||||
return errors.Join(condErr, thenErr)
|
||||
}
|
||||
|
||||
elseErr := c.checkExpression(expr.Else)
|
||||
elseErr := c.checkExpression(vars, expr.Else)
|
||||
if thenErr == nil && elseErr == nil {
|
||||
if !expr.Then.Type().IsSameType(expr.Else.Type()) {
|
||||
thenErr = c.error(expr.Token, "the then branch of type %q does not match with the else branch of type %q", expr.Then.Type().Name(), expr.Else.Type().Name())
|
||||
}
|
||||
}
|
||||
return errors.Join(condErr, thenErr, elseErr)
|
||||
case *tast.AssignmentExpression:
|
||||
varRef, ok := expr.Lhs.(*tast.VariableReference)
|
||||
if !ok {
|
||||
return c.error(expr.Token, "not a valid assignment target")
|
||||
}
|
||||
|
||||
if !expr.Lhs.Type().IsSameType(expr.Lhs.Type()) {
|
||||
return c.error(
|
||||
expr.Rhs.Tok(),
|
||||
"the assignment rhs has the wrong type, variable %q has type %q but got %q",
|
||||
varRef.Identifier,
|
||||
varRef.Type().Name(),
|
||||
expr.Rhs.String(),
|
||||
)
|
||||
}
|
||||
return nil
|
||||
case *tast.VariableDeclaration:
|
||||
if !expr.VariableType.IsSameType(expr.InitializingExpression.Type()) {
|
||||
return c.error(expr.InitializingExpression.Tok(),
|
||||
"initializing expression for variable %q has wrong type, expected %q but got %q",
|
||||
expr.Identifier,
|
||||
expr.VariableType.Name(),
|
||||
expr.InitializingExpression.Type().Name(),
|
||||
)
|
||||
}
|
||||
return nil
|
||||
case *tast.VariableReference:
|
||||
return nil
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected tast.Expression: %#v", expr))
|
||||
}
|
||||
return fmt.Errorf("unhandled expression %T in type checker", expr)
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func (c *Checker) inferTypes(program *ast.Program) (*tast.Program, error) {
|
||||
c.functionVariables = make(map[string]Variables)
|
||||
decls := []tast.Declaration{}
|
||||
errs := []error{}
|
||||
|
||||
@ -28,7 +29,9 @@ func (c *Checker) inferTypes(program *ast.Program) (*tast.Program, error) {
|
||||
func (c *Checker) inferDeclaration(decl ast.Declaration) (tast.Declaration, error) {
|
||||
switch decl := decl.(type) {
|
||||
case *ast.FunctionDeclaration:
|
||||
body, err := c.inferExpression(decl.Body)
|
||||
vars := make(Variables)
|
||||
body, err := c.inferExpression(vars, decl.Body)
|
||||
c.functionVariables[decl.Name] = vars
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -39,7 +42,7 @@ func (c *Checker) inferDeclaration(decl ast.Declaration) (tast.Declaration, erro
|
||||
return nil, errors.New("unhandled declaration in type inferer")
|
||||
}
|
||||
|
||||
func (c *Checker) inferExpression(expr ast.Expression) (tast.Expression, error) {
|
||||
func (c *Checker) inferExpression(vars Variables, expr ast.Expression) (tast.Expression, error) {
|
||||
switch expr := expr.(type) {
|
||||
case *ast.IntegerExpression:
|
||||
return &tast.IntegerExpression{Token: expr.Token, Value: expr.Value}, nil
|
||||
@ -48,8 +51,8 @@ func (c *Checker) inferExpression(expr ast.Expression) (tast.Expression, error)
|
||||
case *ast.ErrorExpression:
|
||||
return nil, c.error(expr.InvalidToken, "invalid expression")
|
||||
case *ast.BinaryExpression:
|
||||
lhs, lhsErr := c.inferExpression(expr.Lhs)
|
||||
rhs, rhsErr := c.inferExpression(expr.Rhs)
|
||||
lhs, lhsErr := c.inferExpression(vars, expr.Lhs)
|
||||
rhs, rhsErr := c.inferExpression(vars, expr.Rhs)
|
||||
var resultType types.Type
|
||||
if lhsErr == nil && rhsErr == nil {
|
||||
if expr.Operator.IsBooleanOperator() {
|
||||
@ -65,7 +68,7 @@ func (c *Checker) inferExpression(expr ast.Expression) (tast.Expression, error)
|
||||
errs := []error{}
|
||||
|
||||
for _, expr := range expr.Expressions {
|
||||
newExpr, err := c.inferExpression(expr)
|
||||
newExpr, err := c.inferExpression(vars, expr)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
} else {
|
||||
@ -76,7 +79,7 @@ func (c *Checker) inferExpression(expr ast.Expression) (tast.Expression, error)
|
||||
var returnExpr tast.Expression
|
||||
var returnType types.Type
|
||||
if expr.ReturnExpression != nil {
|
||||
expr, err := c.inferExpression(expr.ReturnExpression)
|
||||
expr, err := c.inferExpression(vars, expr.ReturnExpression)
|
||||
returnExpr = expr
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
@ -95,15 +98,74 @@ func (c *Checker) inferExpression(expr ast.Expression) (tast.Expression, error)
|
||||
}, errors.Join(errs...)
|
||||
|
||||
case *ast.IfExpression:
|
||||
cond, condErr := c.inferExpression(expr.Condition)
|
||||
then, thenErr := c.inferExpression(expr.Then)
|
||||
cond, condErr := c.inferExpression(vars, expr.Condition)
|
||||
then, thenErr := c.inferExpression(vars, expr.Then)
|
||||
|
||||
if expr.Else != nil {
|
||||
elseExpr, elseErr := c.inferExpression(expr.Else)
|
||||
elseExpr, elseErr := c.inferExpression(vars, expr.Else)
|
||||
|
||||
return &tast.IfExpression{Token: expr.Token, Condition: cond, Then: then, Else: elseExpr, ReturnType: then.Type()}, errors.Join(condErr, thenErr, elseErr)
|
||||
}
|
||||
return &tast.IfExpression{Token: expr.Token, Condition: cond, Then: then, Else: nil, ReturnType: types.Unit}, errors.Join(condErr, thenErr)
|
||||
case *ast.AssignmentExpression:
|
||||
varRef, ok := expr.Lhs.(*ast.VariableReference)
|
||||
if !ok {
|
||||
return &tast.AssignmentExpression{}, c.error(expr.Token, "not a valid assignment target")
|
||||
}
|
||||
|
||||
rhs, err := c.inferExpression(vars, expr.Rhs)
|
||||
if err != nil {
|
||||
return &tast.AssignmentExpression{}, err
|
||||
}
|
||||
|
||||
varRefT, err := c.inferExpression(vars, varRef)
|
||||
return &tast.AssignmentExpression{Lhs: varRefT, Rhs: rhs, Token: expr.Token}, err
|
||||
case *ast.VariableDeclaration:
|
||||
vd := &tast.VariableDeclaration{}
|
||||
var t types.Type
|
||||
var initializingExpr tast.Expression
|
||||
|
||||
if expr.Type != "" {
|
||||
var ok bool
|
||||
t, ok = types.From(expr.Type)
|
||||
if !ok {
|
||||
return vd, c.error(expr.Token, "could not find the type %q", expr.Type)
|
||||
}
|
||||
var err error
|
||||
initializingExpr, err = c.inferExpression(vars, expr.InitializingExpression)
|
||||
if err != nil {
|
||||
return vd, err
|
||||
}
|
||||
} else {
|
||||
var err error
|
||||
initializingExpr, err = c.inferExpression(vars, expr.InitializingExpression)
|
||||
if err != nil {
|
||||
return vd, err
|
||||
}
|
||||
|
||||
t = initializingExpr.Type()
|
||||
}
|
||||
|
||||
vd.VariableType = t
|
||||
vars[expr.Identifier] = t
|
||||
|
||||
vd.InitializingExpression = initializingExpr
|
||||
vd.Token = expr.Token
|
||||
vd.Identifier = expr.Identifier
|
||||
return vd, nil
|
||||
case *ast.VariableReference:
|
||||
vr := &tast.VariableReference{Identifier: expr.Identifier, Token: expr.Token}
|
||||
|
||||
t, ok := vars[expr.Identifier]
|
||||
if !ok {
|
||||
return vr, c.error(expr.Token, "could not get type for variable %q", vr.Identifier)
|
||||
}
|
||||
|
||||
vr.VariableType = t
|
||||
|
||||
return vr, nil
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected ast.Expression: %#v", expr))
|
||||
}
|
||||
return nil, fmt.Errorf("unhandled expression in type inferer")
|
||||
}
|
||||
|
@ -1,77 +1,149 @@
|
||||
package typechecker
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"robaertschi.xyz/robaertschi/tt/ast"
|
||||
"robaertschi.xyz/robaertschi/tt/types"
|
||||
"robaertschi.xyz/robaertschi/tt/token"
|
||||
)
|
||||
|
||||
type Variable struct {
|
||||
Name string
|
||||
Type types.Type
|
||||
type Var struct {
|
||||
Name string
|
||||
FromCurrentScope bool
|
||||
}
|
||||
|
||||
type Scope struct {
|
||||
Variables map[string]Variable
|
||||
ParentScope *Scope
|
||||
Variables map[string]Var
|
||||
UniqueId int64
|
||||
}
|
||||
|
||||
func (s *Scope) Get(name string) (Variable, bool) {
|
||||
func errorf(t token.Token, format string, args ...any) error {
|
||||
return fmt.Errorf("%s:%d:%d %s", t.Loc.File, t.Loc.Line, t.Loc.Col, fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
func copyScope(s *Scope) Scope {
|
||||
newVars := make(map[string]Var)
|
||||
|
||||
for k, v := range s.Variables {
|
||||
newVars[k] = Var{Name: v.Name, FromCurrentScope: false}
|
||||
}
|
||||
|
||||
return Scope{Variables: newVars}
|
||||
}
|
||||
|
||||
func (s *Scope) Get(name string) (Var, bool) {
|
||||
v, ok := s.Variables[name]
|
||||
|
||||
if ok {
|
||||
return v, true
|
||||
}
|
||||
|
||||
if s.ParentScope != nil {
|
||||
return s.ParentScope.Get(name)
|
||||
}
|
||||
|
||||
return Variable{}, false
|
||||
return Var{}, false
|
||||
}
|
||||
|
||||
func (s *Scope) Set(name string, t types.Type) {
|
||||
s.Variables[name] = Variable{Name: name, Type: t}
|
||||
func (s *Scope) Set(name string, uniqName string) {
|
||||
s.Variables[name] = Var{Name: uniqName, FromCurrentScope: true}
|
||||
}
|
||||
|
||||
func (s *Scope) Has(name string) bool {
|
||||
_, ok := s.Variables[name]
|
||||
|
||||
if !ok && s.ParentScope != nil {
|
||||
return s.ParentScope.Has(name)
|
||||
}
|
||||
|
||||
return ok
|
||||
}
|
||||
|
||||
func VarResolve(p *ast.Program) (Scope, error) {
|
||||
s := Scope{Variables: make(map[string]Variable)}
|
||||
func (s *Scope) HasInCurrent(name string) bool {
|
||||
v, ok := s.Variables[name]
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return v.FromCurrentScope
|
||||
}
|
||||
|
||||
func VarResolve(p *ast.Program) (map[string]Scope, error) {
|
||||
functionToScope := make(map[string]Scope)
|
||||
|
||||
for _, d := range p.Declarations {
|
||||
switch d := d.(type) {
|
||||
case *ast.FunctionDeclaration:
|
||||
s := Scope{Variables: make(map[string]Var)}
|
||||
err := VarResolveExpr(&s, d.Body)
|
||||
functionToScope[d.Name] = s
|
||||
if err != nil {
|
||||
return s, err
|
||||
return functionToScope, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s, nil
|
||||
return functionToScope, nil
|
||||
}
|
||||
|
||||
func VarResolveExpr(s *Scope, e ast.Expression) error {
|
||||
switch e := e.(type) {
|
||||
case *ast.ErrorExpression:
|
||||
// NOTE: The Checker will take care of this
|
||||
return nil
|
||||
case *ast.AssignmentExpression:
|
||||
err := VarResolveExpr(s, e.Lhs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = VarResolveExpr(s, e.Rhs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
case *ast.BinaryExpression:
|
||||
err := VarResolveExpr(s, e.Lhs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = VarResolveExpr(s, e.Rhs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case *ast.BlockExpression:
|
||||
case *ast.BooleanExpression:
|
||||
newS := copyScope(s)
|
||||
errs := []error{}
|
||||
for _, e := range e.Expressions {
|
||||
errs = append(errs, VarResolveExpr(&newS, e))
|
||||
}
|
||||
errs = append(errs, VarResolveExpr(&newS, e.ReturnExpression))
|
||||
|
||||
return errors.Join(errs...)
|
||||
case *ast.IfExpression:
|
||||
case *ast.IntegerExpression:
|
||||
err := VarResolveExpr(s, e.Condition)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = VarResolveExpr(s, e.Then)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if e.Else != nil {
|
||||
err = VarResolveExpr(s, e.Else)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case *ast.VariableDeclaration:
|
||||
if s.HasInCurrent(e.Identifier) {
|
||||
return errorf(e.Token, "variable %q redifinded", e.Identifier)
|
||||
}
|
||||
|
||||
uniqName := fmt.Sprintf("%s.%d", e.Identifier, s.UniqueId)
|
||||
s.UniqueId += 1
|
||||
s.Set(e.Identifier, uniqName)
|
||||
case *ast.VariableReference:
|
||||
v, ok := s.Get(e.Identifier)
|
||||
if !ok {
|
||||
return errorf(e.Token, "variable %q is not declared", e.Identifier)
|
||||
}
|
||||
|
||||
e.Identifier = v.Name
|
||||
case *ast.BooleanExpression:
|
||||
case *ast.IntegerExpression:
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected ast.Expression: %#v", e))
|
||||
}
|
||||
|
@ -45,6 +45,15 @@ func (ti *TypeId) Name() string {
|
||||
return ti.name
|
||||
}
|
||||
|
||||
var types map[string]Type = make(map[string]Type)
|
||||
|
||||
func New(id int64, name string) Type {
|
||||
return &TypeId{id: id, name: name}
|
||||
typeId := &TypeId{id: id, name: name}
|
||||
types[name] = typeId
|
||||
return typeId
|
||||
}
|
||||
|
||||
func From(name string) (Type, bool) {
|
||||
t, ok := types[name]
|
||||
return t, ok
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user