mirror of
https://github.com/RoBaertschi/tt.git
synced 2025-04-19 23:33:30 +00:00
Compare commits
2 Commits
19c8cb9103
...
bcfa9fbde8
Author | SHA1 | Date | |
---|---|---|---|
bcfa9fbde8 | |||
22aa1ac3ed |
@ -64,9 +64,10 @@ type FunctionDeclaration struct {
|
|||||||
Body Expression
|
Body Expression
|
||||||
Name string
|
Name string
|
||||||
Parameters []Parameter
|
Parameters []Parameter
|
||||||
|
ReturnType Type
|
||||||
}
|
}
|
||||||
|
|
||||||
func ArgsToString(args []Parameter) string {
|
func ParamsToString(args []Parameter) string {
|
||||||
var b strings.Builder
|
var b strings.Builder
|
||||||
|
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
@ -80,7 +81,7 @@ 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) = %v;", fd.Name, ArgsToString(fd.Parameters), fd.Body.String())
|
return fmt.Sprintf("fn %v(%v): %v = %v;", fd.Name, ParamsToString(fd.Parameters), fd.ReturnType, fd.Body.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Represents a Expression that we failed to parse
|
// Represents a Expression that we failed to parse
|
||||||
|
@ -6,9 +6,8 @@ Playground for language design dessisions
|
|||||||
|
|
||||||
```tt
|
```tt
|
||||||
fn hi(arg1: i32, arg2: i32) = {
|
fn hi(arg1: i32, arg2: i32) = {
|
||||||
arg1 +
|
arg1 + arg2
|
||||||
// Hi
|
// Hi
|
||||||
arg2
|
|
||||||
};
|
};
|
||||||
|
|
||||||
fn main() = {
|
fn main() = {
|
||||||
|
@ -236,6 +236,14 @@ func (p *Parser) parseDeclaration() ast.Declaration {
|
|||||||
if ok, _ := p.expectPeek(token.CloseParen); !ok {
|
if ok, _ := p.expectPeek(token.CloseParen); !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
if ok, _ := p.expectPeek(token.Colon); !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
p.nextToken()
|
||||||
|
t, ok := p.parseType()
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
if ok, _ := p.expectPeek(token.Equal); !ok {
|
if ok, _ := p.expectPeek(token.Equal); !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -251,6 +259,7 @@ func (p *Parser) parseDeclaration() ast.Declaration {
|
|||||||
Name: name,
|
Name: name,
|
||||||
Body: expr,
|
Body: expr,
|
||||||
Parameters: params,
|
Parameters: params,
|
||||||
|
ReturnType: t,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
40
tast/tast.go
40
tast/tast.go
@ -52,12 +52,12 @@ func (p *Program) String() string {
|
|||||||
return builder.String()
|
return builder.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
type Argument struct {
|
type Parameter struct {
|
||||||
Name string
|
Name string
|
||||||
Type types.Type
|
Type types.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
func ArgsToString(args []Argument) string {
|
func ArgsToString(args []Parameter) string {
|
||||||
var b strings.Builder
|
var b strings.Builder
|
||||||
|
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
@ -71,7 +71,7 @@ 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
|
Parameters []Parameter
|
||||||
ReturnType types.Type
|
ReturnType types.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,7 +81,7 @@ 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): %v = %v;", fd.Name, ArgsToString(fd.Args), fd.ReturnType.Name(), fd.Body.String())
|
return fmt.Sprintf("fn %v(%v): %v = %v;", fd.Name, ArgsToString(fd.Parameters), fd.ReturnType.Name(), fd.Body.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
type IntegerExpression struct {
|
type IntegerExpression struct {
|
||||||
@ -252,3 +252,35 @@ func (ae *AssignmentExpression) Tok() token.Token { return ae.Token }
|
|||||||
func (ae *AssignmentExpression) String() string {
|
func (ae *AssignmentExpression) String() string {
|
||||||
return fmt.Sprintf("%s = %s", ae.Lhs.String(), ae.Rhs.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()
|
||||||
|
}
|
||||||
|
4
test.tt
4
test.tt
@ -1,4 +1,4 @@
|
|||||||
fn main() = {
|
fn main(): i64 = {
|
||||||
i := 5;
|
i := 5;
|
||||||
|
|
||||||
|
|
||||||
@ -11,7 +11,7 @@ fn main() = {
|
|||||||
test2(3)
|
test2(3)
|
||||||
};
|
};
|
||||||
|
|
||||||
fn test2(hello: i64) = {
|
fn test2(hello: i64): i64 = {
|
||||||
hello // Comment test
|
hello // Comment test
|
||||||
};
|
};
|
||||||
|
|
||||||
|
4
todo.md
4
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 asm, change all structs to pointer
|
||||||
- [ ] Fix inconsensity in Tests
|
- [ ] Fix inconsensity in Tests
|
||||||
- [ ] Find a better way todo tests, like to generate a test case
|
- [ ] Find a better way todo tests, like to generate a test case
|
||||||
|
@ -47,7 +47,7 @@ func emitFunction(function *tast.FunctionDeclaration) *Function {
|
|||||||
|
|
||||||
arguments := []string{}
|
arguments := []string{}
|
||||||
|
|
||||||
for _, arg := range function.Args {
|
for _, arg := range function.Parameters {
|
||||||
arguments = append(arguments, arg.Name)
|
arguments = append(arguments, arg.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,16 @@ import (
|
|||||||
|
|
||||||
type Variables map[string]types.Type
|
type Variables map[string]types.Type
|
||||||
|
|
||||||
|
func copyVars(vars Variables) Variables {
|
||||||
|
newVars := make(Variables)
|
||||||
|
|
||||||
|
for k, v := range vars {
|
||||||
|
newVars[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
return newVars
|
||||||
|
}
|
||||||
|
|
||||||
type Checker struct {
|
type Checker struct {
|
||||||
foundMain bool
|
foundMain bool
|
||||||
functionVariables map[string]Variables
|
functionVariables map[string]Variables
|
||||||
@ -152,6 +162,22 @@ func (c *Checker) checkExpression(vars Variables, expr tast.Expression) error {
|
|||||||
return nil
|
return nil
|
||||||
case *tast.VariableReference:
|
case *tast.VariableReference:
|
||||||
return nil
|
return nil
|
||||||
|
case *tast.FunctionCall:
|
||||||
|
functionType := vars[expr.Identifier].(*types.FunctionType)
|
||||||
|
if len(expr.Arguments) != len(functionType.Parameters) {
|
||||||
|
return c.error(expr.Token, "invalid amount of arguments for function %q, expected %d but got %d", expr.Identifier, len(functionType.Parameters), len(expr.Arguments))
|
||||||
|
}
|
||||||
|
|
||||||
|
errs := []error{}
|
||||||
|
|
||||||
|
for i, param := range functionType.Parameters {
|
||||||
|
e := expr.Arguments[i]
|
||||||
|
if !e.Type().IsSameType(param) {
|
||||||
|
errs = append(errs, c.error(e.Tok(), "invalid type for parameter, expected %q but got %q", param.Name(), e.Type().Name()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors.Join(errs...)
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("unexpected tast.Expression: %#v", expr))
|
panic(fmt.Sprintf("unexpected tast.Expression: %#v", expr))
|
||||||
}
|
}
|
||||||
|
@ -13,9 +13,41 @@ func (c *Checker) inferTypes(program *ast.Program) (*tast.Program, error) {
|
|||||||
c.functionVariables = make(map[string]Variables)
|
c.functionVariables = make(map[string]Variables)
|
||||||
decls := []tast.Declaration{}
|
decls := []tast.Declaration{}
|
||||||
errs := []error{}
|
errs := []error{}
|
||||||
|
vars := make(Variables)
|
||||||
|
|
||||||
|
funcToParams := make(map[string][]tast.Parameter)
|
||||||
|
|
||||||
for _, decl := range program.Declarations {
|
for _, decl := range program.Declarations {
|
||||||
decl, err := c.inferDeclaration(decl)
|
switch decl := decl.(type) {
|
||||||
|
case *ast.FunctionDeclaration:
|
||||||
|
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
|
||||||
|
parameters = append(parameters, tast.Parameter{Name: param.Name, Type: t})
|
||||||
|
}
|
||||||
|
|
||||||
|
t, ok := types.From(decl.ReturnType)
|
||||||
|
if !ok {
|
||||||
|
return nil, c.error(decl.Token, "invalid type %q", decl.ReturnType)
|
||||||
|
}
|
||||||
|
|
||||||
|
parameterTypes := []types.Type{}
|
||||||
|
|
||||||
|
for _, param := range parameters {
|
||||||
|
parameterTypes = append(parameterTypes, param.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
vars[decl.Name] = &types.FunctionType{ReturnType: t, Parameters: parameterTypes}
|
||||||
|
funcToParams[decl.Name] = parameters
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, decl := range program.Declarations {
|
||||||
|
decl, err := c.inferDeclaration(funcToParams, copyVars(vars), decl)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
decls = append(decls, decl)
|
decls = append(decls, decl)
|
||||||
} else {
|
} else {
|
||||||
@ -26,19 +58,9 @@ func (c *Checker) inferTypes(program *ast.Program) (*tast.Program, error) {
|
|||||||
return &tast.Program{Declarations: decls}, errors.Join(errs...)
|
return &tast.Program{Declarations: decls}, errors.Join(errs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Checker) inferDeclaration(decl ast.Declaration) (tast.Declaration, error) {
|
func (c *Checker) inferDeclaration(funcToParams map[string][]tast.Parameter, vars Variables, decl ast.Declaration) (tast.Declaration, error) {
|
||||||
switch decl := decl.(type) {
|
switch decl := decl.(type) {
|
||||||
case *ast.FunctionDeclaration:
|
case *ast.FunctionDeclaration:
|
||||||
vars := make(Variables)
|
|
||||||
arguments := []tast.Argument{}
|
|
||||||
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})
|
|
||||||
}
|
|
||||||
body, err := c.inferExpression(vars, decl.Body)
|
body, err := c.inferExpression(vars, decl.Body)
|
||||||
c.functionVariables[decl.Name] = vars
|
c.functionVariables[decl.Name] = vars
|
||||||
|
|
||||||
@ -46,7 +68,7 @@ func (c *Checker) inferDeclaration(decl ast.Declaration) (tast.Declaration, erro
|
|||||||
return nil, err
|
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, Parameters: funcToParams[decl.Name], Body: body, ReturnType: vars[decl.Name], Name: decl.Name}, nil
|
||||||
}
|
}
|
||||||
return nil, errors.New("unhandled declaration in type inferer")
|
return nil, errors.New("unhandled declaration in type inferer")
|
||||||
}
|
}
|
||||||
@ -173,6 +195,37 @@ func (c *Checker) inferExpression(vars Variables, expr ast.Expression) (tast.Exp
|
|||||||
vr.VariableType = t
|
vr.VariableType = t
|
||||||
|
|
||||||
return vr, nil
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
funcType, ok := t.(*types.FunctionType)
|
||||||
|
if !ok {
|
||||||
|
return fc, c.error(expr.Token, "tried to call non function variable %q with type %q", expr.Identifier, t.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
fc.ReturnType = funcType.ReturnType
|
||||||
|
|
||||||
|
args := []tast.Expression{}
|
||||||
|
errs := []error{}
|
||||||
|
|
||||||
|
for _, arg := range expr.Arguments {
|
||||||
|
inferredArg, err := c.inferExpression(vars, arg)
|
||||||
|
errs = append(errs, err)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
args = append(args, inferredArg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fc.Arguments = args
|
||||||
|
|
||||||
|
return fc, errors.Join(errs...)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("unexpected ast.Expression: %#v", expr))
|
panic(fmt.Sprintf("unexpected ast.Expression: %#v", expr))
|
||||||
}
|
}
|
||||||
|
@ -69,6 +69,15 @@ func (s *Scope) SetUniq(name string) string {
|
|||||||
|
|
||||||
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)
|
||||||
|
functions := Scope{Variables: make(map[string]Var)}
|
||||||
|
|
||||||
|
for _, d := range p.Declarations {
|
||||||
|
switch d := d.(type) {
|
||||||
|
case *ast.FunctionDeclaration:
|
||||||
|
functions.Set(d.Name, d.Name)
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, d := range p.Declarations {
|
for _, d := range p.Declarations {
|
||||||
switch d := d.(type) {
|
switch d := d.(type) {
|
||||||
@ -78,7 +87,7 @@ func VarResolve(p *ast.Program) (map[string]Scope, error) {
|
|||||||
return functionToScope, errorf(d.Token, "duplicate function name %q", d.Name)
|
return functionToScope, errorf(d.Token, "duplicate function name %q", d.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
s := Scope{Variables: make(map[string]Var)}
|
s := copyScope(&functions)
|
||||||
for i, param := range d.Parameters {
|
for i, param := range d.Parameters {
|
||||||
uniq := s.SetUniq(param.Name)
|
uniq := s.SetUniq(param.Name)
|
||||||
d.Parameters[i].Name = uniq
|
d.Parameters[i].Name = uniq
|
||||||
@ -163,6 +172,15 @@ func VarResolveExpr(s *Scope, e ast.Expression) error {
|
|||||||
e.Identifier = v.Name
|
e.Identifier = v.Name
|
||||||
case *ast.BooleanExpression:
|
case *ast.BooleanExpression:
|
||||||
case *ast.IntegerExpression:
|
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:
|
default:
|
||||||
panic(fmt.Sprintf("unexpected ast.Expression: %#v", e))
|
panic(fmt.Sprintf("unexpected ast.Expression: %#v", e))
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
import "robaertschi.xyz/robaertschi/tt/ast"
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"robaertschi.xyz/robaertschi/tt/ast"
|
||||||
|
)
|
||||||
|
|
||||||
type Type interface {
|
type Type interface {
|
||||||
// Checks if the two types are the same
|
// Checks if the two types are the same
|
||||||
@ -45,6 +49,51 @@ func (ti *TypeId) Name() string {
|
|||||||
return ti.name
|
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)
|
var types map[string]Type = make(map[string]Type)
|
||||||
|
|
||||||
func New(id int64, name string) Type {
|
func New(id int64, name string) Type {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user