diff --git a/design.md b/design.md index 59a7a0b..c5d71a9 100644 --- a/design.md +++ b/design.md @@ -6,9 +6,8 @@ Playground for language design dessisions ```tt fn hi(arg1: i32, arg2: i32) = { - arg1 + + arg1 + arg2 // Hi - arg2 }; fn main() = { diff --git a/tast/tast.go b/tast/tast.go index ff7f125..1902f13 100644 --- a/tast/tast.go +++ b/tast/tast.go @@ -252,3 +252,35 @@ 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()) } + +// identifier ( expressions... ) +type FunctionCall struct { + Token token.Token // The identifier + Identifier string + Arguments []Expression + ReturnType types.Type +} + +var _ Expression = &FunctionCall{} + +func (fc *FunctionCall) expressionNode() {} +func (fc *FunctionCall) Type() types.Type { return fc.ReturnType } +func (fc *FunctionCall) TokenLiteral() string { return fc.Token.Literal } +func (fc *FunctionCall) Tok() token.Token { return fc.Token } +func (fc *FunctionCall) String() string { + b := strings.Builder{} + + b.WriteString(fc.Identifier) + b.WriteRune('(') + + for i, arg := range fc.Arguments { + b.WriteString(arg.String()) + if i < (len(fc.Arguments) - 1) { + b.WriteRune(',') + } + } + + b.WriteRune(')') + + return b.String() +} diff --git a/todo.md b/todo.md index 64ef373..1854f4a 100644 --- a/todo.md +++ b/todo.md @@ -1,3 +1,7 @@ +# NOW +- [ ] Check for functions in check.go + +# Sometime - [ ] Fix inconsensity in asm, change all structs to pointer - [ ] Fix inconsensity in Tests - [ ] Find a better way todo tests, like to generate a test case diff --git a/typechecker/infer.go b/typechecker/infer.go index 6f5883b..0f2825f 100644 --- a/typechecker/infer.go +++ b/typechecker/infer.go @@ -30,15 +30,16 @@ func (c *Checker) inferDeclaration(decl ast.Declaration) (tast.Declaration, erro switch decl := decl.(type) { case *ast.FunctionDeclaration: vars := make(Variables) - arguments := []tast.Argument{} + parameters := []tast.Parameter{} for _, param := range decl.Parameters { t, ok := types.From(param.Type) if !ok { return nil, c.error(decl.Token, "could not find the type %q for argument %q", param.Type, param.Name) } vars[param.Name] = t - arguments = append(arguments, tast.Argument{Name: param.Name, Type: t}) + parameters = append(parameters, tast.Parameter{Name: param.Name, Type: t}) } + // vars[decl.Name] = &types.FunctionType{ReturnType: } body, err := c.inferExpression(vars, decl.Body) c.functionVariables[decl.Name] = vars @@ -46,7 +47,7 @@ func (c *Checker) inferDeclaration(decl ast.Declaration) (tast.Declaration, erro return nil, err } - return &tast.FunctionDeclaration{Token: decl.Token, Args: arguments, Body: body, ReturnType: body.Type(), Name: decl.Name}, nil + return &tast.FunctionDeclaration{Token: decl.Token, Args: parameters, Body: body, ReturnType: body.Type(), Name: decl.Name}, nil } return nil, errors.New("unhandled declaration in type inferer") } @@ -173,6 +174,13 @@ func (c *Checker) inferExpression(vars Variables, expr ast.Expression) (tast.Exp vr.VariableType = t return vr, nil + case *ast.FunctionCall: + fc := &tast.FunctionCall{Identifier: expr.Identifier, Token: expr.Token} + + t, ok := vars[expr.Identifier] + if !ok { + return fc, c.error(expr.Token, "could not get type for function %q", fc.Identifier) + } default: panic(fmt.Sprintf("unexpected ast.Expression: %#v", expr)) } diff --git a/typechecker/variable_resolution.go b/typechecker/variable_resolution.go index 15fa022..1730308 100644 --- a/typechecker/variable_resolution.go +++ b/typechecker/variable_resolution.go @@ -79,6 +79,7 @@ func VarResolve(p *ast.Program) (map[string]Scope, error) { } s := Scope{Variables: make(map[string]Var)} + s.Set(d.Name, d.Name) for i, param := range d.Parameters { uniq := s.SetUniq(param.Name) d.Parameters[i].Name = uniq @@ -163,6 +164,15 @@ func VarResolveExpr(s *Scope, e ast.Expression) error { e.Identifier = v.Name case *ast.BooleanExpression: case *ast.IntegerExpression: + case *ast.FunctionCall: + newName, ok := s.Get(e.Identifier) + if !ok { + return errorf(e.Token, "function %q not found", e.Identifier) + } + for _, arg := range e.Arguments { + VarResolveExpr(s, arg) + } + e.Identifier = newName.Name default: panic(fmt.Sprintf("unexpected ast.Expression: %#v", e)) } diff --git a/types/types.go b/types/types.go index 6aff11e..96e9204 100644 --- a/types/types.go +++ b/types/types.go @@ -1,6 +1,10 @@ package types -import "robaertschi.xyz/robaertschi/tt/ast" +import ( + "strings" + + "robaertschi.xyz/robaertschi/tt/ast" +) type Type interface { // Checks if the two types are the same @@ -45,6 +49,51 @@ func (ti *TypeId) Name() string { return ti.name } +type FunctionType struct { + ReturnType Type + Parameters []Type +} + +func (ft *FunctionType) SupportsBinaryOperator(op ast.BinaryOperator) bool { + return false +} + +func (ft *FunctionType) IsSameType(t Type) bool { + if ft2, ok := t.(*FunctionType); ok { + if !ft.ReturnType.IsSameType(ft2.ReturnType) { + return false + } + + if len(ft.Parameters) != len(ft2.Parameters) { + return false + } + + for i, t := range ft.Parameters { + if !t.IsSameType(ft2.Parameters[i]) { + return false + } + } + } + return false +} + +func (ft *FunctionType) Name() string { + b := strings.Builder{} + + b.WriteString("fn(") + + for i, param := range ft.Parameters { + b.WriteString(param.Name()) + if i < (len(ft.Parameters) - 1) { + b.WriteRune(',') + } + } + + b.WriteString("): " + ft.ReturnType.Name()) + + return b.String() +} + var types map[string]Type = make(map[string]Type) func New(id int64, name string) Type {