From c8b5c4dbfe01eb620934150b7d52b1848c202bf2 Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Fri, 14 Feb 2025 00:26:48 +0100 Subject: [PATCH] Added more tests --- src/core/CompileAssignArray.go | 10 ++++--- src/core/CompileDefinition.go | 7 +++-- src/core/ExpressionToRegister.go | 46 +++++++++++++++++++++++++++++--- src/errors/Common.go | 3 +-- tests/errors/TypeMismatch3.q | 7 +++++ tests/errors/TypeMismatch4.q | 6 +++++ tests/errors/UntypedExpression.q | 6 +++++ tests/errors_test.go | 1 + 8 files changed, 73 insertions(+), 13 deletions(-) create mode 100644 tests/errors/TypeMismatch3.q create mode 100644 tests/errors/TypeMismatch4.q create mode 100644 tests/errors/UntypedExpression.q diff --git a/src/core/CompileAssignArray.go b/src/core/CompileAssignArray.go index 1cab08a..2fee834 100644 --- a/src/core/CompileAssignArray.go +++ b/src/core/CompileAssignArray.go @@ -7,7 +7,7 @@ import ( "git.akyoto.dev/cli/q/src/ast" "git.akyoto.dev/cli/q/src/cpu" "git.akyoto.dev/cli/q/src/errors" - "git.akyoto.dev/cli/q/src/token" + "git.akyoto.dev/cli/q/src/types" ) // CompileAssignArray compiles an assign statement for array elements. @@ -33,7 +33,7 @@ func (f *Function) CompileAssignArray(node *ast.Assign) error { index := left.Children[1] - if index.Token.Kind == token.Number { + if index.Token.IsNumeric() { offset, err := f.Number(index.Token) if err != nil { @@ -42,12 +42,16 @@ func (f *Function) CompileAssignArray(node *ast.Assign) error { memory.Offset = int8(offset) } else { - _, indexRegister, isTemporary, err := f.Evaluate(index) + typ, indexRegister, isTemporary, err := f.Evaluate(index) if err != nil { return err } + if !types.Is(typ, types.Int) { + return errors.New(&errors.TypeMismatch{Encountered: typ.Name(), Expected: types.Int.Name()}, f.File, index.Token.Position) + } + memory.OffsetRegister = indexRegister if isTemporary { diff --git a/src/core/CompileDefinition.go b/src/core/CompileDefinition.go index 0887e0f..1143315 100644 --- a/src/core/CompileDefinition.go +++ b/src/core/CompileDefinition.go @@ -25,12 +25,11 @@ func (f *Function) CompileDefinition(node *ast.Define) error { return err } - variable.Type = typ - - if variable.Type == nil { - return errors.New(errors.CouldNotInferType, f.File, node.Expression.Token.End()) + if typ == nil { + return errors.New(errors.UntypedExpression, f.File, node.Expression.Token.End()) } + variable.Type = typ f.AddVariable(variable) return nil } diff --git a/src/core/ExpressionToRegister.go b/src/core/ExpressionToRegister.go index d690f7f..4e52cc9 100644 --- a/src/core/ExpressionToRegister.go +++ b/src/core/ExpressionToRegister.go @@ -1,6 +1,8 @@ package core import ( + "math" + "git.akyoto.dev/cli/q/src/asm" "git.akyoto.dev/cli/q/src/ast" "git.akyoto.dev/cli/q/src/cpu" @@ -40,10 +42,46 @@ func (f *Function) ExpressionToRegister(node *expression.Expression, register cp } if node.Token.Kind == token.Array { - array := f.VariableByName(node.Children[0].Token.Text(f.File.Bytes)) - offset, err := f.Number(node.Children[1].Token) - f.MemoryRegister(asm.LOAD, asm.Memory{Base: array.Register, Offset: int8(offset), Length: 1}, register) - return types.Int, err + name := node.Children[0].Token.Text(f.File.Bytes) + array := f.VariableByName(name) + + if array == nil { + return nil, errors.New(&errors.UnknownIdentifier{Name: name}, f.File, node.Children[0].Token.Position) + } + + index := node.Children[1] + + memory := asm.Memory{ + Base: array.Register, + Offset: 0, + OffsetRegister: cpu.Register(math.MaxUint8), + Length: byte(1), + } + + if index.Token.IsNumeric() { + offset, err := f.Number(index.Token) + + if err != nil { + return nil, err + } + + memory.Offset = int8(offset) + } else { + typ, err := f.ExpressionToRegister(index, register) + + if err != nil { + return nil, err + } + + if !types.Is(typ, types.Int) { + return nil, errors.New(&errors.TypeMismatch{Encountered: typ.Name(), Expected: types.Int.Name()}, f.File, index.Token.Position) + } + + memory.OffsetRegister = register + } + + f.MemoryRegister(asm.LOAD, memory, register) + return types.Int, nil } if node.Token.Kind == token.Period { diff --git a/src/errors/Common.go b/src/errors/Common.go index 7b00ddd..d4199e4 100644 --- a/src/errors/Common.go +++ b/src/errors/Common.go @@ -1,9 +1,7 @@ package errors var ( - CouldNotInferType = &Base{"Couldn't infer type"} EmptySwitch = &Base{"Empty switch"} - ExpectedFunctionName = &Base{"Expected function name"} ExpectedFunctionParameters = &Base{"Expected function parameters"} ExpectedFunctionDefinition = &Base{"Expected function definition"} ExpectedIfBeforeElse = &Base{"Expected an 'if' block before 'else'"} @@ -24,4 +22,5 @@ var ( MissingParameter = &Base{"Missing parameter"} MissingType = &Base{"Missing type"} NotImplemented = &Base{"Not implemented"} + UntypedExpression = &Base{"Untyped expression"} ) diff --git a/tests/errors/TypeMismatch3.q b/tests/errors/TypeMismatch3.q new file mode 100644 index 0000000..06d0075 --- /dev/null +++ b/tests/errors/TypeMismatch3.q @@ -0,0 +1,7 @@ +import mem + +main() { + a := mem.alloc(16) + b := a["not a number"] + b += 1 +} \ No newline at end of file diff --git a/tests/errors/TypeMismatch4.q b/tests/errors/TypeMismatch4.q new file mode 100644 index 0000000..708c19a --- /dev/null +++ b/tests/errors/TypeMismatch4.q @@ -0,0 +1,6 @@ +import mem + +main() { + a := mem.alloc(16) + a["not a number"] = 42 +} \ No newline at end of file diff --git a/tests/errors/UntypedExpression.q b/tests/errors/UntypedExpression.q new file mode 100644 index 0000000..f63d553 --- /dev/null +++ b/tests/errors/UntypedExpression.q @@ -0,0 +1,6 @@ +main() { + a := unknown() + a += 1 +} + +unknown() {} \ No newline at end of file diff --git a/tests/errors_test.go b/tests/errors_test.go index f861d26..0386339 100644 --- a/tests/errors_test.go +++ b/tests/errors_test.go @@ -57,6 +57,7 @@ var errs = []struct { {"UnknownIdentifier3.q", &errors.UnknownIdentifier{Name: "x"}}, {"UnknownPackage.q", &errors.UnknownPackage{Name: "sys"}}, {"UnknownStructField.q", &errors.UnknownStructField{StructName: "A", FieldName: "x"}}, + {"UntypedExpression.q", errors.UntypedExpression}, {"UnusedImport.q", &errors.UnusedImport{Package: "sys"}}, {"UnusedVariable.q", &errors.UnusedVariable{Name: "x"}}, {"VariableAlreadyExists.q", &errors.VariableAlreadyExists{Name: "x"}},