Ancestry.QueryProcessor.Type.ScalarType.CompileExtractExpression C# (CSharp) Method

CompileExtractExpression() public method

public CompileExtractExpression ( Compiler compiler, Frame frame, ExpressionContext left, Parse expression, BaseType typeHint ) : ExpressionContext
compiler Compiler
frame Frame
left Ancestry.QueryProcessor.Compile.ExpressionContext
expression Parse
typeHint BaseType
return Ancestry.QueryProcessor.Compile.ExpressionContext
        public override ExpressionContext CompileExtractExpression(Compiler compiler, Frame frame, ExpressionContext left, Parse.ExtractExpression expression, BaseType typeHint)
        {
            var local = compiler.AddFrame(frame, expression);
            var alreadyOptional = left.Type is OptionalType;
            var memberNative = left.Type.GetNative(compiler.Emitter);
            var resultType = alreadyOptional ? left.Type : new OptionalType(left.Type);
            var resultNative = resultType.GetNative(compiler.Emitter);

            // Register value symbol
            LocalBuilder valueLocal = null;
            var localSymbol = new Object();
            local.Add(expression.Condition, Name.FromComponents(Parse.ReservedWords.Value), localSymbol);
            compiler.ContextsBySymbol.Add
            (
                localSymbol,
                new ExpressionContext
                (
                    null,
                    left.Type,
                    left.Characteristics,
                    m => { m.IL.Emit(OpCodes.Ldloc, valueLocal); }
                )
            );

            var condition = compiler.CompileExpression(local, expression.Condition, SystemTypes.Boolean);
            if (!(condition.Type is BooleanType))
                throw new CompilerException(expression.Condition, CompilerException.Codes.IncorrectType, condition.Type, "Boolean");

            return
                new ExpressionContext
                (
                    expression,
                    resultType,
                    Compiler.MergeCharacteristics(left.Characteristics, condition.Characteristics),
                    m =>
                    {
                        var nullLabel = m.IL.DefineLabel();
                        var endLabel = m.IL.DefineLabel();

                        // Register value argument
                        valueLocal = m.DeclareLocal(expression, memberNative, Parse.ReservedWords.Value);
                        left.EmitGet(m);
                        m.IL.Emit(OpCodes.Stloc, valueLocal);

                        condition.EmitGet(m);
                        m.IL.Emit(OpCodes.Brfalse, nullLabel);

                        // Passed condition
                        if (!alreadyOptional && memberNative.IsValueType)
                        {
                            var optionalLocal = m.DeclareLocal(expression, resultNative, Parse.ReservedWords.Value);
                            m.IL.Emit(OpCodes.Ldloca, optionalLocal);
                            m.IL.Emit(OpCodes.Ldloc, valueLocal);
                            m.IL.Emit(OpCodes.Call, resultNative.GetConstructor(new System.Type[] { left.Type.GetNative(compiler.Emitter) }));
                            m.IL.Emit(OpCodes.Ldloc, optionalLocal);
                        }
                        else
                            m.IL.Emit(OpCodes.Ldloc, valueLocal);
                        m.IL.Emit(OpCodes.Br, endLabel);

                        // Failed condition
                        m.IL.MarkLabel(nullLabel);
                        if (!alreadyOptional && memberNative.IsValueType)
                        {
                            var optionalLocal = m.DeclareLocal(expression, resultNative, Parse.ReservedWords.Value);
                            m.IL.Emit(OpCodes.Ldloca, optionalLocal);
                            m.IL.Emit(OpCodes.Initobj, resultNative);
                            m.IL.Emit(OpCodes.Ldloc, optionalLocal);
                        }
                        else if (alreadyOptional && memberNative.IsValueType)
                        {
                            m.IL.Emit(OpCodes.Ldloca, valueLocal);
                            m.IL.Emit(OpCodes.Initobj, resultNative);
                            m.IL.Emit(OpCodes.Ldloc, valueLocal);
                        }
                        else
                            m.IL.Emit(OpCodes.Ldnull);

                        m.IL.MarkLabel(endLabel);
                    }
                );
        }