Skip to content

Commit

Permalink
Added member expressions for computed expressions to typechecking
Browse files Browse the repository at this point in the history
  • Loading branch information
tlaceby committed Apr 14, 2024
1 parent a354ba6 commit 9988b0e
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 8 deletions.
10 changes: 8 additions & 2 deletions examples/test.br
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
// main.br
fn add <T> (a: T, b: T) -> T {
return a + b;
}

struct Combinable<T> {
data: T;
Expand All @@ -21,6 +24,9 @@ struct Combinable<T> {
}

fn main () {
const c1 = Combinable<number>::new(10.5).setData(10);
const numbers = [1, 2, 3, 4];
const names = []string{"john", "sydney"};
const numbers = []number{1, 2, 3, 4, 2, 3, 4};

const john = names[0];
const num = numbers[2];
}
4 changes: 4 additions & 0 deletions src/analysis/analysis.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ func typecheck_expr(expr ast.Expr, env *SymbolTable) Type {
return tc_call_expr(e, env)
case ast.StructInstantiationExpr:
return tc_struct_instantation_expr(e, env)
case ast.ArrayLiteral:
return tc_array_literal_expr(e, env)
case ast.ComputedExpr:
return tc_computed_expr(e, env)
default:
litter.Dump(expr)
panic("^^^^^^ Unknown ast.Expr encountered! ^^^^^^\n")
Expand Down
47 changes: 47 additions & 0 deletions src/analysis/tc_exprs.go
Original file line number Diff line number Diff line change
Expand Up @@ -381,3 +381,50 @@ func tc_assignment_expr(e ast.AssignmentExpr, env *SymbolTable) Type {
litter.Dump(e)
panic(fmt.Sprintf("Invalid assignment expression. Cannot assign %s to %s\n", assigne.str(), value.str()))
}

func tc_computed_expr(e ast.ComputedExpr, env *SymbolTable) Type {
var member Type = typecheck_expr(e.Member, env)
var computedExpr = typecheck_expr(e.Property, env)
var arr ArrayType

if !helpers.TypesMatchT[ArrayType](member) {
panic(fmt.Sprintf("Cannot perform computed expression on %s. Expected an array instead.", member.str()))
}

if !typesSame(computedExpr, NumType{}) {
panic(fmt.Sprintf("Computed member must be a number. Recieved %s indtead in computed expression of %s", computedExpr.str(), member.str()))
}

arr = helpers.ExpectType[ArrayType](member)
return arr.Underlying
}

func tc_array_literal_expr(e ast.ArrayLiteral, env *SymbolTable) Type {
var expectedUnderlyingType = typecheck_type(e.UnderlyingType, env)
var capacity = e.Capacity
var initialValues = []Type{}

// Verify all components have the same type
for _, val := range e.Contents {
valType := typecheck_expr(val, env)

if !typesSame(valType, expectedUnderlyingType) {
panic(fmt.Sprintf("Expected array of %s but reciveed %s inside array instatiation.", expectedUnderlyingType.str(), valType.str()))
}

initialValues = append(initialValues, valType)
}

if capacity == -1 {
capacity = len(initialValues)
}

if capacity < len(initialValues) {
panic(fmt.Sprintf("Capacity of %d is smaller then length of array literal (%d).", capacity, len(initialValues)))
}

return ArrayType{
Underlying: expectedUnderlyingType,
Capacity: uint(capacity),
}
}
1 change: 1 addition & 0 deletions src/analysis/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ func (t AnyType) str() string {
}

type ArrayType struct {
Capacity uint
Underlying Type
}

Expand Down
4 changes: 3 additions & 1 deletion src/ast/expressions.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,9 @@ type FunctionExpr struct {
func (n FunctionExpr) expr() {}

type ArrayLiteral struct {
Contents []Expr
UnderlyingType Type
Capacity int // -1 represents none a inferable size
Contents []Expr
}

func (n ArrayLiteral) expr() {}
Expand Down
30 changes: 25 additions & 5 deletions src/parser/expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,21 +122,41 @@ func parse_static_member_expr(p *parser, left ast.Expr, bp binding_power) ast.Ex
}

func parse_array_literal_expr(p *parser) ast.Expr {
var underlyingType ast.Type
var capacity = -1
var arrayContents = make([]ast.Expr, 0)
p.expect(lexer.OPEN_BRACKET)
arrayContents := make([]ast.Expr, 0)

for p.hasTokens() && p.currentTokenKind() != lexer.CLOSE_BRACKET {
// Check Capacity
if p.currentTokenKind() != lexer.CLOSE_BRACKET {
capacityStr := p.expectError(lexer.NUMBER, "Expected capacity inside array literal inatantiation.").Value
capacityVal, err := strconv.Atoi(capacityStr)

if err != nil || capacityVal < 0 {
panic(fmt.Sprintf("Capacity must be a positive integer value. Recieved %s instead.", capacityStr))
}

capacity = capacityVal
}

p.expect(lexer.CLOSE_BRACKET)
underlyingType = parse_type(p, defalt_bp)

p.expect(lexer.OPEN_CURLY)
for p.hasTokens() && p.currentTokenKind() != lexer.CLOSE_CURLY {
arrayContents = append(arrayContents, parse_expr(p, logical))

if !p.currentToken().IsOneOfMany(lexer.EOF, lexer.CLOSE_BRACKET) {
if !p.currentToken().IsOneOfMany(lexer.EOF, lexer.CLOSE_CURLY) {
p.expect(lexer.COMMA)
}
}

p.expect(lexer.CLOSE_BRACKET)
p.expect(lexer.CLOSE_CURLY)

return ast.ArrayLiteral{
Contents: arrayContents,
UnderlyingType: underlyingType,
Capacity: capacity,
Contents: arrayContents,
}
}

Expand Down

0 comments on commit 9988b0e

Please sign in to comment.