Skip to content

Commit

Permalink
Refactor typechecker and main logic: update file paths, enhance error…
Browse files Browse the repository at this point in the history
… messages, and improve area calculation in Rectangle implementation
  • Loading branch information
itsfuad committed Dec 5, 2024
1 parent 68a32c8 commit 2f8df29
Show file tree
Hide file tree
Showing 8 changed files with 34 additions and 49 deletions.
4 changes: 3 additions & 1 deletion language/types.wal
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ type Rectangle struct {

impl Rectangle {
fn area() -> f32 {
ret 1.0;
ret this.width * this.height;
}
}

Expand All @@ -29,6 +29,7 @@ let cir := @Circle{radius: 10.0};

type Rec Rectangle;
type Rec2 Rec;
type Rec2 Rectangle;

let rec1 : Rectangle = @Rec{width: 89.234, height: 23.4};
let rec2 : Rec2 = @Rectangle{width: 61.6, height: 54.4};
Expand All @@ -37,6 +38,7 @@ let cir2 : Circle = @Rec2{width: 10.0}; // [property 'height' is required on str

fn draw(shape: IShape) {
let area := shape.area();
let area := 4.3;
}

draw(rec);
Expand Down
7 changes: 3 additions & 4 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,15 @@ package main
import (
"walrus/errgen"
"walrus/lexer"
parseMachine "walrus/parser"
"walrus/parser"
"walrus/typechecker"
)

func main() {

filePath := "language/expressions.wal"
filePath := "language/types.wal"
tokens := lexer.Tokenize(filePath, true)
parser := parseMachine.NewParser(filePath, tokens)
tree := parser.Parse(false)
tree := parser.NewParser(filePath, tokens).Parse(false)

tc := typechecker.ProgramEnv(filePath)

Expand Down
29 changes: 15 additions & 14 deletions typechecker/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ package typechecker

import (
"fmt"
"os"
"walrus/utils"
)

type SCOPE_TYPE int
Expand Down Expand Up @@ -33,6 +31,14 @@ var typeDefinitions = map[string]TcValue{
string(VOID_TYPE): NewVoid(),
}

var builtinValues = map[string]TcValue{
"true": NewBool(),
"false": NewBool(),
"null": NewNull(),
"void": NewVoid(),
"PI": NewFloat(32),
}

type TypeEnvironment struct {
parent *TypeEnvironment
scopeType SCOPE_TYPE
Expand All @@ -46,21 +52,9 @@ type TypeEnvironment struct {

func ProgramEnv(filepath string) *TypeEnvironment {
env := NewTypeENV(nil, GLOBAL_SCOPE, "global", filepath)
initVar(env, "true", NewBool(), true, false)
initVar(env, "false", NewBool(), true, false)
initVar(env, "null", NewNull(), true, false)
initVar(env, "PI", NewFloat(32), true, false)
return env
}

func initVar(env *TypeEnvironment, name string, typeVar TcValue, isConst bool, isOptional bool) {
err := env.DeclareVar(name, typeVar, isConst, isOptional)
if err != nil {
utils.RED.Println(err)
os.Exit(-1)
}
}

func NewTypeENV(parent *TypeEnvironment, scope SCOPE_TYPE, scopeName string, filePath string) *TypeEnvironment {
return &TypeEnvironment{
parent: parent,
Expand Down Expand Up @@ -113,10 +107,17 @@ func (t *TypeEnvironment) DeclareVar(name string, typeVar TcValue, isConst bool,

if _, ok := typeDefinitions[name]; ok && name != "null" && name != "void" {
return fmt.Errorf("type name '%s' cannot be used as variable name", name)
//errgen.AddError(t.filePath, loc.Start.Line, loc.End.Line, loc.Start.Column, loc.End.Column, fmt.Sprintf("type name '%s' cannot be used as variable name", name), errgen.ERROR_CRITICAL)
}

if _, ok := builtinValues[name]; ok {
return fmt.Errorf("'%s' is a builtin value and cannot be redeclared", name)
//errgen.AddError(t.filePath, loc.Start.Line, loc.End.Line, loc.Start.Column, loc.End.Column, fmt.Sprintf("'%s' is a builtin value and cannot be redeclared", name), errgen.ERROR_CRITICAL)
}

//should not be declared
if scope, err := t.ResolveVar(name); err == nil && scope == t {
//errgen.AddError(t.filePath, loc.Start.Line, loc.End.Line, loc.Start.Column, loc.End.Column, fmt.Sprintf("'%s' is already declared in this scope", name), errgen.ERROR_NORMAL)
return fmt.Errorf("'%s' is already declared in this scope", name)
}

Expand Down
24 changes: 8 additions & 16 deletions typechecker/functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,8 @@ func CheckAndDeclareFunction(funcNode ast.FunctionLiteral, name string, env *Typ
//declare the function
err := env.DeclareVar(name, fn, true, false)
if err != nil {

errgen.AddError(env.filePath, funcNode.Start.Line, funcNode.End.Line, funcNode.Start.Column, funcNode.End.Column, err.Error(), errgen.ERROR_NORMAL)
errgen.AddError(env.filePath, funcNode.Start.Line, funcNode.End.Line, funcNode.Start.Column, funcNode.End.Column, "error declaring function. " + err.Error(), errgen.ERROR_CRITICAL)
}

//check the function body
for _, stmt := range funcNode.Body.Contents {
CheckAST(stmt, fnEnv)
Expand All @@ -48,8 +46,7 @@ func checkandDeclareParamaters(params []ast.FunctionParam, fnEnv *TypeEnvironmen
for _, param := range params {

if fnEnv.isDeclared(param.Identifier.Name) {

errgen.AddError(fnEnv.filePath, param.Identifier.Start.Line, param.Identifier.End.Line, param.Identifier.Start.Column, param.Identifier.End.Column, fmt.Sprintf("Parameter %s is already declared", param.Identifier.Name), errgen.ERROR_NORMAL)
errgen.AddError(fnEnv.filePath, param.Identifier.Start.Line, param.Identifier.End.Line, param.Identifier.Start.Column, param.Identifier.End.Column, fmt.Sprintf("parameter %s is already declared", param.Identifier.Name), errgen.ERROR_NORMAL)
}

paramType := evaluateTypeName(param.Type, fnEnv)
Expand All @@ -59,15 +56,13 @@ func checkandDeclareParamaters(params []ast.FunctionParam, fnEnv *TypeEnvironmen
defaultValue := CheckAST(param.DefaultValue, fnEnv)
err := matchTypes(paramType, defaultValue)
if err != nil {

errgen.AddError(fnEnv.filePath, param.DefaultValue.StartPos().Line, param.DefaultValue.EndPos().Line, param.DefaultValue.StartPos().Column, param.DefaultValue.EndPos().Column, err.Error(), errgen.ERROR_NORMAL)
errgen.AddError(fnEnv.filePath, param.DefaultValue.StartPos().Line, param.DefaultValue.EndPos().Line, param.DefaultValue.StartPos().Column, param.DefaultValue.EndPos().Column, fmt.Sprintf("error declaring parameter. %s", err.Error()), errgen.ERROR_NORMAL)
}
}

err := fnEnv.DeclareVar(param.Identifier.Name, paramType, false, param.IsOptional)
if err != nil {

errgen.AddError(fnEnv.filePath, param.Identifier.Start.Line, param.Identifier.End.Line, param.Identifier.Start.Column, param.Identifier.End.Column, err.Error(), errgen.ERROR_NORMAL)
errgen.AddError(fnEnv.filePath, param.Identifier.Start.Line, param.Identifier.End.Line, param.Identifier.Start.Column, param.Identifier.End.Column, fmt.Sprintf("error declaring parameter. %s", err.Error()), errgen.ERROR_CRITICAL)
}

fmt.Printf("Declared parameter %s of type %s\n", param.Identifier.Name, paramType.DType())
Expand All @@ -87,8 +82,7 @@ func checkFunctionCall(callNode ast.FunctionCallExpr, env *TypeEnvironment) TcVa
fn, err := userDefinedToFn(caller)

if err != nil {

errgen.AddError(env.filePath, callNode.Caller.StartPos().Line, callNode.Caller.EndPos().Line, callNode.Caller.StartPos().Column, callNode.Caller.EndPos().Column, err.Error(), errgen.ERROR_NORMAL)
errgen.AddError(env.filePath, callNode.Caller.StartPos().Line, callNode.Caller.EndPos().Line, callNode.Caller.StartPos().Column, callNode.Caller.EndPos().Column, err.Error(), errgen.ERROR_CRITICAL)
}

fnParams := fn.Params
Expand All @@ -101,12 +95,10 @@ func checkFunctionCall(callNode ast.FunctionCallExpr, env *TypeEnvironment) TcVa
}
}
if len(callNode.Arguments) < len(fnParams)-optionalParams {

errgen.AddError(env.filePath, callNode.Start.Line, callNode.End.Line, callNode.Start.Column, callNode.End.Column, fmt.Sprintf("Function expects at least %d arguments, got %d", len(fnParams)-optionalParams, len(callNode.Arguments)), errgen.ERROR_NORMAL)
errgen.AddError(env.filePath, callNode.Start.Line, callNode.End.Line, callNode.Start.Column, callNode.End.Column, fmt.Sprintf("function expects at least %d arguments, got %d", len(fnParams)-optionalParams, len(callNode.Arguments)), errgen.ERROR_NORMAL)
}
if len(callNode.Arguments) > len(fnParams) {

errgen.AddError(env.filePath, callNode.Start.Line, callNode.End.Line, callNode.Start.Column, callNode.End.Column, fmt.Sprintf("Function expects at most %d arguments, got %d", len(fnParams), len(callNode.Arguments)), errgen.ERROR_NORMAL)
errgen.AddError(env.filePath, callNode.Start.Line, callNode.End.Line, callNode.Start.Column, callNode.End.Column, fmt.Sprintf("function expects at most %d arguments, got %d", len(fnParams), len(callNode.Arguments)), errgen.ERROR_NORMAL)
}
}

Expand Down Expand Up @@ -152,8 +144,8 @@ func checkFunctionDeclStmt(funcNode ast.FunctionDeclStmt, env *TypeEnvironment)

func getFunctionReturnValue(env *TypeEnvironment, returnNode ast.Node) TcValue {
funcParent, err := env.ResolveFunctionEnv()
if err != nil {

if err != nil {
errgen.AddError(env.filePath, returnNode.StartPos().Line, returnNode.EndPos().Line, returnNode.StartPos().Column, returnNode.EndPos().Column, err.Error(), errgen.ERROR_NORMAL)
}

Expand Down
4 changes: 1 addition & 3 deletions typechecker/impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ func checkImplStmt(implStmt ast.ImplStmt, env *TypeEnvironment) TcValue {

// if the method name is in the struct's elements, throw an error
if _, ok := implForType.StructScope.variables[name]; ok {

errgen.AddError(env.filePath, method.Start.Line, method.End.Line, method.Start.Column, method.End.Column, fmt.Sprintf("name '%s' already exists in struct", name), errgen.ERROR_CRITICAL)
}

Expand All @@ -100,8 +99,7 @@ func checkImplStmt(implStmt ast.ImplStmt, env *TypeEnvironment) TcValue {
//declare the method on the struct's environment and then check the body
err := implForType.StructScope.DeclareVar(name, methodToDeclare, false, false)
if err != nil {

errgen.AddError(env.filePath, method.Start.Line, method.End.Line, method.Start.Column, method.End.Column, err.Error(), errgen.ERROR_CRITICAL)
errgen.AddError(env.filePath, method.Start.Line, method.End.Line, method.Start.Column, method.End.Column, fmt.Sprintf("cannot declare method '%s': %s", method.Identifier.Name, err.Error()), errgen.ERROR_CRITICAL)
}

//check the function body
Expand Down
7 changes: 2 additions & 5 deletions typechecker/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ func checkStructLiteral(structLit ast.StructLiteral, env *TypeEnvironment) TcVal
continue
}
if _, ok := structLit.Properties[propname]; !ok {

errgen.AddError(env.filePath, structLit.StartPos().Line, structLit.EndPos().Line, structLit.StartPos().Column, structLit.EndPos().Column, fmt.Sprintf("property '%s' is required on struct '%s'", propname, sName.Name), errgen.ERROR_NORMAL)
}
}
Expand Down Expand Up @@ -130,12 +129,10 @@ func checkStructTypeDecl(name string, structType ast.StructType, env *TypeEnviro
IsPrivate: propval.IsPrivate,
Type: propType,
}
//props[propname] = property
//declare the property on the struct environment
err := structEnv.DeclareVar(propname, property, false, false)
if err != nil {

errgen.AddError(env.filePath, propval.Prop.Start.Line, propval.Prop.End.Line, propval.Prop.Start.Column, propval.Prop.End.Column, err.Error(), errgen.ERROR_NORMAL)
errgen.AddError(env.filePath, propval.PropType.StartPos().Line, propval.PropType.EndPos().Line, propval.PropType.StartPos().Column, propval.PropType.EndPos().Column, fmt.Sprintf("error declaring property '%s': %s", propname, err.Error()), errgen.ERROR_CRITICAL)
}
}

Expand All @@ -148,7 +145,7 @@ func checkStructTypeDecl(name string, structType ast.StructType, env *TypeEnviro
//declare 'this' variable to be used in the struct's methods
err := structEnv.DeclareVar("this", structTypeValue, true, false)
if err != nil {
errgen.AddError(env.filePath, structType.Start.Line, structType.End.Line, structType.Start.Column, structType.End.Column, err.Error(), errgen.ERROR_NORMAL)
errgen.AddError(env.filePath, structType.StartPos().Line, structType.EndPos().Line, structType.StartPos().Column, structType.EndPos().Column, err.Error(), errgen.ERROR_CRITICAL)
}

return structTypeValue
Expand Down
2 changes: 0 additions & 2 deletions typechecker/typedecl.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package typechecker

import (
"fmt"
"walrus/ast"
"walrus/errgen"
"walrus/utils"
Expand Down Expand Up @@ -33,7 +32,6 @@ func checkTypeDeclaration(node ast.TypeDeclStmt, env *TypeEnvironment) TcValue {

err := DeclareType(node.UDTypeName, typeVal)
if err != nil {
fmt.Printf("cannot declare type %s: %s\n", node.UDTypeName, err.Error())
errgen.AddError(env.filePath, node.Start.Line, node.End.Line, node.Start.Column, node.End.Column, err.Error(), errgen.ERROR_NORMAL)
}

Expand Down
6 changes: 2 additions & 4 deletions typechecker/variables.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,13 @@ func checkVariableDeclaration(node ast.VarDeclStmt, env *TypeEnvironment) TcValu
providedValue := CheckAST(varToDecl.Value, env)
err := matchTypes(expectedTypeInterface, providedValue)
if err != nil {
errgen.AddError(env.filePath, varToDecl.Value.StartPos().Line, varToDecl.Value.EndPos().Line, varToDecl.Value.StartPos().Column, varToDecl.Value.EndPos().Column, err.Error(), errgen.ERROR_NORMAL)
errgen.AddError(env.filePath, varToDecl.Value.StartPos().Line, varToDecl.Value.EndPos().Line, varToDecl.Value.StartPos().Column, varToDecl.Value.EndPos().Column, fmt.Sprintf("error declaring variable '%s'. %s", varToDecl.Identifier.Name, err.Error()), errgen.ERROR_CRITICAL)
}
}

err := env.DeclareVar(varToDecl.Identifier.Name, expectedTypeInterface, node.IsConst, false)
if err != nil {
errgen.AddError(env.filePath, varToDecl.Start.Line, varToDecl.End.Line, varToDecl.Start.Column, varToDecl.End.Column, err.Error(), errgen.ERROR_CRITICAL)
errgen.AddError(env.filePath, varToDecl.Identifier.StartPos().Line, varToDecl.Identifier.EndPos().Line, varToDecl.Identifier.StartPos().Column, varToDecl.Identifier.EndPos().Column, err.Error(), errgen.ERROR_CRITICAL)
}

if node.IsConst {
Expand All @@ -107,8 +107,6 @@ func checkVariableDeclaration(node ast.VarDeclStmt, env *TypeEnvironment) TcValu
fmt.Print(" of type ")
utils.PURPLE.Println(tcValueToString(expectedTypeInterface))
}

//return the type of the variable
}
return NewVoid()
}

0 comments on commit 2f8df29

Please sign in to comment.