Skip to content

Commit

Permalink
Support for member and variable asignment expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
tlaceby committed Apr 14, 2024
1 parent 3d273d1 commit d5edd71
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 9 deletions.
9 changes: 8 additions & 1 deletion examples/test.br
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ struct Circle {
radius: r,
};
}

fn setRadius (r: number) -> Circle {
self.radius = r;
}
}

const message = combine <string>("Hello ", "world");
let message = combine <string>("Hello ", "world");
message = "Hello ";

const foo = message + "world";
2 changes: 2 additions & 0 deletions src/analysis/analysis.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ func typecheck_expr(expr ast.Expr, env *SymbolTable) Type {
return tc_binary_expr(e, env)
case ast.MemberExpr:
return tc_member_expr(e, env)
case ast.AssignmentExpr:
return tc_assignment_expr(e, env)
case ast.StaticMemberExpr:
return tc_static_member_expr(e, env)
case ast.CallExpr:
Expand Down
58 changes: 56 additions & 2 deletions src/analysis/tc_exprs.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package analysis
import (
"fmt"

"github.com/sanity-io/litter"
"github.com/tlaceby/bedrock/src/ast"
"github.com/tlaceby/bedrock/src/helpers"
"github.com/tlaceby/bedrock/src/lexer"
Expand Down Expand Up @@ -132,8 +133,6 @@ func tc_member_expr(e ast.MemberExpr, env *SymbolTable) Type {
memberType := typecheck_expr(e.Member, env)
propertyName := e.Property

panic("here")

switch member := memberType.(type) {
case StructType:
var propertyType Type
Expand Down Expand Up @@ -282,3 +281,58 @@ func tc_call_expr(e ast.CallExpr, env *SymbolTable) Type {

return fnInstanceType.ReturnType
}

func tc_assignment_expr(e ast.AssignmentExpr, env *SymbolTable) Type {
assigne := typecheck_expr(e.Assigne, env)
value := typecheck_expr(e.AssignedValue, env)

// Make sure we are assigning valid things.
switch lhs := e.Assigne.(type) {
case ast.SymbolExpr:
varname := lhs.Value
// make sure symbol exists and is not constant
varInfo, varEnv := env.findNearestSymbolEnv(varname)

// Make sure variable exists
if varInfo == nil || varEnv == nil {
panic(fmt.Sprintf("Cannot perform assignment on %s as it does not exist.", varname))
}

// Avoid Constant Assignment
if varInfo.IsConstant {
panic(fmt.Sprintf("Cannot perform assignment on %s as it declared as constant.", varname))
}

// Make sure types match
if !typesSame(varInfo.Type, assigne) {
panic(fmt.Sprintf("Invalid assignment of %s with %s = %s\n", varname, varInfo.Type.str(), value.str()))
}

// Update assignment and access count
varInfo.AccessedCount-- // When performing the lookup it adds an access. Remove it.
varInfo.AssignmentCount++

varEnv.Symbols[varname] = *varInfo

return value

case ast.MemberExpr:
memberExpr := typecheck_expr(lhs.Member, env)

switch member := memberExpr.(type) {
case StructType:
propertyName := lhs.Property
propertyValue := member.getPropertyByName(propertyName)

// Make sure types match
if !typesSame(propertyValue, value) {
panic(fmt.Sprintf("Mismatched types. Invalid assignment of %s.%s with %s. Expected type is %s.\n", member.StructName, propertyName, value.str(), propertyValue.str()))
}

return value
}
}

litter.Dump(e)
panic(fmt.Sprintf("Invalid assignment expression. Cannot assign %s to %s\n", assigne.str(), value.str()))
}
2 changes: 0 additions & 2 deletions src/analysis/tc_stmts.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,6 @@ func tc_struct_declaration_stmt(s ast.StructDeclarationStmt, env *SymbolTable) T
var staticMethods = map[string]FnType{}
var methods = map[string]FnType{}
var properties = map[string]Type{}
var publicMembers = []string{}

// Make sure struct is only defined inside global/module scope
if !env.IsGlobal && !env.IsModule {
Expand All @@ -225,7 +224,6 @@ func tc_struct_declaration_stmt(s ast.StructDeclarationStmt, env *SymbolTable) T
StaticMethods: staticMethods,
Properties: properties,
Methods: methods,
PublicMembers: publicMembers,
}

env.DefinedTypes[structName] = structType
Expand Down
12 changes: 10 additions & 2 deletions src/analysis/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,19 @@ func (t ModuleType) str() string {

type StructType struct {
StructName string
Generics []string
Generics []string // TODO: Remove when creating GenericStructType
Properties map[string]Type
Methods map[string]FnType
StaticMethods map[string]FnType
PublicMembers []string // Names of all public struct properties/methods. // TODO:
}

func (t StructType) getPropertyByName(propertyName string) Type {
value, exists := t.Properties[propertyName]
if exists {
return value
}

return nil
}

func (t StructType) str() string {
Expand Down
3 changes: 1 addition & 2 deletions src/bedrock.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"os"
"time"

"github.com/sanity-io/litter"
"github.com/tlaceby/bedrock/src/analysis"
"github.com/tlaceby/bedrock/src/parser"
)
Expand All @@ -16,7 +15,7 @@ func main() {
ast := parser.Parse(string(sourceBytes), "test.br")
duration := time.Since(start)

litter.Dump(ast)
// litter.Dump(ast)
println()
globalEnv := analysis.CreateSymbolTable(nil, false, false, false, "global")
analysis.Typecheck(ast, globalEnv)
Expand Down

0 comments on commit d5edd71

Please sign in to comment.