package core import ( "git.urbach.dev/cli/q/src/errors" "git.urbach.dev/cli/q/src/expression" "git.urbach.dev/cli/q/src/ssa" "git.urbach.dev/cli/q/src/token" "git.urbach.dev/cli/q/src/types" ) // define gives a value an identifier. func (f *Function) define(left *expression.Expression, right *expression.Expression, isAssign bool) error { rightValue, err := f.evaluateRight(right) if err != nil { return err } name := left.String(f.File.Bytes) if name == "_" { return nil } root := left.Parent if isAssign && root.Token.Kind != token.Assign { operator := removeAssign(root.Token.Kind) leftValueDeref, err := f.evaluateRight(left) if err != nil { return err } rightValue = f.Append(&ssa.BinaryOp{ Op: operator, Left: leftValueDeref, Right: rightValue, Source: root.Source(), }) } leftValue, err := f.validateLeft(left, right, name, rightValue.Type(), isAssign) if err != nil { return err } call, isCall := rightValue.(*ssa.Call) if isCall && len(call.Func.Typ.Output) != 1 { return errors.New(&DefinitionCountMismatch{Function: call.Func.String(), Count: 1, ExpectedCount: len(call.Func.Typ.Output)}, f.File, left.Source()) } // If the value we got was a value that is stored in a variable, // it must have been returned from the optimizer as a cached value. // We want to assure that every named variable creates a copy of // another named variable instead of using the cached value itself // because it could lead to incorrect optimizations. if f.IsIdentified(rightValue) { _, isResource := rightValue.Type().(*types.Resource) if isResource { f.Block().Unidentify(rightValue) } else { rightValue = f.copy(rightValue, right.Source(), isIdentifierRead(right)) } } global, isGlobal := leftValue.(*ssa.Global) if isGlobal { zero := f.Append(&ssa.Int{Int: 0}) memory := &ssa.Memory{ Typ: global.Typ.(*types.Pointer).To, Address: global, Index: zero, Source: global.Source, } return f.store(memory, rightValue) } if !isCall { structure, isStructType := rightValue.(*ssa.Struct) if isStructType { for i, field := range types.Unwrap(structure.Typ).(*types.Struct).Fields { f.Block().Identify(name+"."+field.Name, structure.Arguments[i]) } } f.Block().Identify(name, rightValue) return nil } structure, isStructType := types.Unwrap(rightValue.Type()).(*types.Struct) if !isStructType { f.Block().Identify(name, rightValue) return nil } composite := f.makeStructFromTuple(rightValue, rightValue.Type(), structure, name, left.Source()) f.Block().Identify(name, composite) return nil }