diff --git a/ast/ast.go b/ast/ast.go index 0b9e983..d4e4599 100644 --- a/ast/ast.go +++ b/ast/ast.go @@ -191,7 +191,6 @@ func (ie *IfExpression) String() string { return builder.String() } -// This is still a expression, because making it some other type of node would be to much work type VariableDeclaration struct { Token token.Token // The Identifier token InitializingExpression Expression diff --git a/tast/tast.go b/tast/tast.go index d1e8bcd..f061941 100644 --- a/tast/tast.go +++ b/tast/tast.go @@ -170,7 +170,6 @@ func (ie *IfExpression) String() string { return builder.String() } -// This is still a expression, because making it some other type of node would be to much work type VariableDeclaration struct { Token token.Token // The Identifier token InitializingExpression Expression @@ -197,7 +196,23 @@ 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) String() string { return fmt.Sprintf("%s", vr.Identifier) } + +type AssignmentExpression struct { + Token token.Token // The Equal + Lhs Expression + Rhs Expression +} + +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) String() string { + return fmt.Sprintf("%s = %s", ae.Lhs.String(), ae.Rhs.String()) +} diff --git a/typechecker/variable_resolution.go b/typechecker/variable_resolution.go index 97aa2fb..86e60b2 100644 --- a/typechecker/variable_resolution.go +++ b/typechecker/variable_resolution.go @@ -1 +1,80 @@ package typechecker + +import ( + "fmt" + + "robaertschi.xyz/robaertschi/tt/ast" + "robaertschi.xyz/robaertschi/tt/types" +) + +type Variable struct { + Name string + Type types.Type +} + +type Scope struct { + Variables map[string]Variable + ParentScope *Scope +} + +func (s *Scope) Get(name string) (Variable, bool) { + v, ok := s.Variables[name] + + if ok { + return v, true + } + + if s.ParentScope != nil { + return s.ParentScope.Get(name) + } + + return Variable{}, false +} + +func (s *Scope) Set(name string, t types.Type) { + s.Variables[name] = Variable{Name: name, Type: t} +} + +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)} + + for _, d := range p.Declarations { + switch d := d.(type) { + case *ast.FunctionDeclaration: + err := VarResolveExpr(&s, d.Body) + if err != nil { + return s, err + } + } + } + + return s, nil +} + +func VarResolveExpr(s *Scope, e ast.Expression) error { + switch e := e.(type) { + case *ast.ErrorExpression: + case *ast.AssignmentExpression: + case *ast.BinaryExpression: + case *ast.BlockExpression: + case *ast.BooleanExpression: + case *ast.IfExpression: + case *ast.IntegerExpression: + case *ast.VariableDeclaration: + case *ast.VariableReference: + default: + panic(fmt.Sprintf("unexpected ast.Expression: %#v", e)) + } + + return nil +}