diff --git a/src/core/CompileAssign.go b/src/core/CompileAssign.go index 2126f45..5d2263b 100644 --- a/src/core/CompileAssign.go +++ b/src/core/CompileAssign.go @@ -1,8 +1,12 @@ package core import ( + "fmt" + + "git.urbach.dev/cli/q/src/asm" "git.urbach.dev/cli/q/src/ast" "git.urbach.dev/cli/q/src/errors" + "git.urbach.dev/cli/q/src/eval" "git.urbach.dev/cli/q/src/token" ) @@ -11,33 +15,54 @@ func (f *Function) CompileAssign(node *ast.Assign) error { left := node.Expression.Children[0] right := node.Expression.Children[1] - if left.IsLeaf() { - name := left.Token.Text(f.File.Bytes) - variable := f.VariableByName(name) - - if variable == nil { - return errors.New(&errors.UnknownIdentifier{Name: name}, f.File, left.Token.Position) + if left.Token.Kind == token.Separator { + if right.Token.Kind == token.Div { + return f.CompileAssignDivision(node.Expression) } - defer f.UseVariable(variable) - return f.Execute(node.Expression.Token, variable.Value.Register, right) - } + if right.Token.Kind == token.Call { + return f.MultiAssign(left, right) + } - if left.Token.Kind == token.Dot { - return f.CompileAssignField(node) - } - - if left.Token.Kind == token.Array { - return f.CompileAssignArray(node) - } - - if left.Token.Kind == token.Separator && right.Token.Kind == token.Div { - return f.CompileAssignDivision(node.Expression) - } - - if !ast.IsFunctionCall(right) { return errors.New(errors.NotImplemented, f.File, node.Expression.Token.Position) } - return f.MultiAssign(left, right) + leftValue, err := f.Evaluate(left) + + if err != nil { + return err + } + + operation := node.Expression.Token + + switch leftValue := leftValue.(type) { + case eval.Register: + f.Execute(operation, leftValue.Register, right) + case eval.Memory: + if operation.Kind == token.Assign { + rightValue, err := f.Evaluate(right) + + if err != nil { + return err + } + + f.ValueToMemory(rightValue, leftValue.Memory) + return nil + } + + tmp := f.NewRegister() + f.ValueToRegister(leftValue, tmp) + err := f.Execute(operation, tmp, right) + + if err != nil { + return err + } + + f.MemoryRegister(asm.STORE, leftValue.Memory, tmp) + f.FreeRegister(tmp) + default: + panic(fmt.Errorf("%s: not implemented: %v", f.UniqueName, leftValue)) + } + + return nil } diff --git a/src/core/CompileAssignArray.go b/src/core/CompileAssignArray.go deleted file mode 100644 index 05244e0..0000000 --- a/src/core/CompileAssignArray.go +++ /dev/null @@ -1,56 +0,0 @@ -package core - -import ( - "fmt" - "math" - - "git.urbach.dev/cli/q/src/asm" - "git.urbach.dev/cli/q/src/ast" - "git.urbach.dev/cli/q/src/errors" - "git.urbach.dev/cli/q/src/eval" - "git.urbach.dev/cli/q/src/types" -) - -// CompileAssignArray compiles an assign statement for array elements. -func (f *Function) CompileAssignArray(node *ast.Assign) error { - left := node.Expression.Children[0] - right := node.Expression.Children[1] - name := left.Children[0].Token.Text(f.File.Bytes) - variable := f.VariableByName(name) - - if variable == nil { - return errors.New(&errors.UnknownIdentifier{Name: name}, f.File, left.Children[0].Token.Position) - } - - defer f.UseVariable(variable) - - memory := asm.Memory{ - Base: variable.Value.Register, - Offset: 0, - OffsetRegister: math.MaxUint8, - Length: byte(1), - } - - indexExpr := left.Children[1] - index, err := f.Evaluate(indexExpr) - - if err != nil { - return err - } - - if !types.Is(index.Type(), types.AnyInt) { - return errors.New(&errors.TypeMismatch{Encountered: index.Type().Name(), Expected: types.AnyInt.Name()}, f.File, indexExpr.Token.Position) - } - - switch index := index.(type) { - case eval.Number: - memory.Offset = int8(index.Number) - case eval.Register: - memory.OffsetRegister = index.Register - default: - panic(fmt.Errorf("%s: not implemented: %v", f.UniqueName, index)) - } - - _, err = f.ExpressionToMemory(right, memory) - return err -} diff --git a/src/core/CompileAssignField.go b/src/core/CompileAssignField.go deleted file mode 100644 index bc965c6..0000000 --- a/src/core/CompileAssignField.go +++ /dev/null @@ -1,42 +0,0 @@ -package core - -import ( - "math" - - "git.urbach.dev/cli/q/src/asm" - "git.urbach.dev/cli/q/src/ast" - "git.urbach.dev/cli/q/src/errors" - "git.urbach.dev/cli/q/src/types" -) - -// CompileAssignField compiles a memory write to a struct field. -func (f *Function) CompileAssignField(node *ast.Assign) error { - destination := node.Expression.Children[0] - value := node.Expression.Children[1] - name := destination.Children[0].Token.Text(f.File.Bytes) - fieldName := destination.Children[1].Token.Text(f.File.Bytes) - variable := f.VariableByName(name) - - if variable == nil { - return errors.New(&errors.UnknownIdentifier{Name: name}, f.File, destination.Children[0].Token.Position) - } - - defer f.UseVariable(variable) - pointer := variable.Value.Typ.(*types.Pointer) - structure := pointer.To.(*types.Struct) - field := structure.FieldByName(fieldName) - - if field == nil { - return errors.New(&errors.UnknownStructField{StructName: structure.Name(), FieldName: fieldName}, f.File, destination.Children[1].Token.Position) - } - - memory := asm.Memory{ - Base: variable.Value.Register, - Offset: int8(field.Offset), - OffsetRegister: math.MaxUint8, - Length: byte(field.Type.Size()), - } - - _, err := f.ExpressionToMemory(value, memory) - return err -} diff --git a/src/core/EvaluateArray.go b/src/core/EvaluateArray.go index 72ef764..5844015 100644 --- a/src/core/EvaluateArray.go +++ b/src/core/EvaluateArray.go @@ -14,16 +14,16 @@ import ( // EvaluateArray evaluates an array access. func (f *Function) EvaluateArray(expr *expression.Expression) (eval.Memory, error) { name := expr.Children[0].Token.Text(f.File.Bytes) - array := f.VariableByName(name) + base := f.VariableByName(name) - if array == nil { + if base == nil { return eval.Memory{}, errors.New(&errors.UnknownIdentifier{Name: name}, f.File, expr.Children[0].Token.Position) } - defer f.UseVariable(array) + defer f.UseVariable(base) memory := asm.Memory{ - Base: array.Value.Register, + Base: base.Value.Register, Offset: 0, OffsetRegister: math.MaxUint8, Length: byte(1), @@ -49,10 +49,27 @@ func (f *Function) EvaluateArray(expr *expression.Expression) (eval.Memory, erro panic(fmt.Errorf("%s: not implemented: %v", f.UniqueName, index)) } - value := eval.Memory{ - Typ: array.Value.Typ.(*types.Array).Of, - Memory: memory, + array, isArray := base.Value.Typ.(*types.Array) + + if isArray { + value := eval.Memory{ + Typ: array.Of, + Memory: memory, + } + + return value, nil } - return value, nil + pointer, isPointer := base.Value.Typ.(*types.Pointer) + + if isPointer { + value := eval.Memory{ + Typ: pointer.To, + Memory: memory, + } + + return value, nil + } + + panic("invalid type") } diff --git a/src/core/EvaluateDot.go b/src/core/EvaluateDot.go index 71aeebe..ca73d88 100644 --- a/src/core/EvaluateDot.go +++ b/src/core/EvaluateDot.go @@ -20,7 +20,14 @@ func (f *Function) EvaluateDot(expr *expression.Expression) (eval.Value, error) variable := f.VariableByName(leftText) if variable != nil { - field := variable.Value.Typ.(*types.Pointer).To.(*types.Struct).FieldByName(rightText) + f.UseVariable(variable) + pointer := variable.Value.Typ.(*types.Pointer) + structure := pointer.To.(*types.Struct) + field := structure.FieldByName(rightText) + + if field == nil { + return nil, errors.New(&errors.UnknownStructField{StructName: structure.Name(), FieldName: rightText}, f.File, right.Token.Position) + } value := eval.Memory{ Typ: field.Type,