예제 #1
0
        private Result EmitMacroResult(MacroContext context, bool topLevel)
        {
            string macroName = context.GetToken(SYNTAX, 0).GetText();

            _il.Emit(OpCodes.Ldarg_0);                                      // ctx
            _il.Emit(OpCodes.Ldstr, macroName);                             // ctx name
            _il.Emit(OpCodes.Ldstr, _context.CurrentNs);                    // ctx name ns
            _il.Emit(OpCodes.Ldarg_0);                                      // ctx name ns ctx
            _il.Emit(OpCodes.Call, OneCallContext.GetObj);                  // ctx name ns self

            var contexts = context.GetRuleContexts <MacroParameterContext>();

            _il.Emit(OpCodes.Ldc_I4, contexts.Length);                      // ctx name ns self
            _il.Emit(OpCodes.Newarr, typeof(object));                       // ctx name ns self args
            for (var i = 0; i < contexts.Length; ++i)
            {
                MacroParameterContext arg = contexts[i];

                _il.Emit(OpCodes.Dup);                                      // .. -> args
                _il.Emit(OpCodes.Ldc_I4, i);                                // .. -> args idx

                var result = EmitGetMacroParameter(arg);                    // .. -> args idx val
                if (!result.IsSuccess)
                {
                    return(result);
                }

                _il.Emit(OpCodes.Stelem_Ref);                               // ctx name ns self args
            }

            _il.Emit(OpCodes.Call, typeof(MacroManager)
                     .GetMethod(nameof(MacroManager.Execute)));             // result<str>
            _il.Emit(OpCodes.Dup);                                          // result<str> x 2
            _il.Emit(OpCodes.Call, typeof(Result)
                     .GetMethod("get_" + nameof(Result.IsSuccess)));        // result<str> bool
            _il.Emit(OpCodes.Ldc_I4_1);                                     // result<str> bool true
            var ifIsSuccess = _il.DefineLabel();

            _il.Emit(OpCodes.Beq, ifIsSuccess);                             // result<str> (jmp if equal)
            if (topLevel)
            {
                _il.Emit(OpCodes.Ret);                                         // [exit-returned]
                _il.MarkLabel(ifIsSuccess);                                    // ifIsSuccess:
                _il.Emit(OpCodes.Call, typeof(Result <string>)
                         .GetMethod("get_" + nameof(Result <string> .Value))); // str
            }
            else
            {
                var exit = _il.DefineLabel();
                _il.Emit(OpCodes.Br_S, exit);
                _il.MarkLabel(ifIsSuccess);                                    // ifIsSuccess:
                _il.Emit(OpCodes.Call, typeof(Result <string>)
                         .GetMethod("get_" + nameof(Result <string> .Value))); // str
                _il.MarkLabel(exit);
            }

            return(Result.Ok());
        }
예제 #2
0
        public override Result VisitMacro([NotNull] MacroContext context)
        {
            var macroName = context.GetToken(SYNTAX, 0).GetText();

            _il.Emit(OpCodes.Ldarg_0);                                      // ctx
            _il.Emit(OpCodes.Ldstr, macroName);                             // ctx name
            _il.Emit(OpCodes.Ldstr, _context.CurrentNs);                    // ctx name ns
            _il.Emit(OpCodes.Ldarg_1);                                      // ctx name ns self

            var contexts = context.GetRuleContexts <MacroParameterContext>();

            _il.Emit(OpCodes.Ldc_I4, contexts.Length);                      // ctx name ns self
            _il.Emit(OpCodes.Newarr, typeof(object));                       // ctx name ns self args
            for (var i = 0; i < contexts.Length; ++i)
            {
                var arg = contexts[i];

                _il.Emit(OpCodes.Dup);                                      // .. -> args
                _il.Emit(OpCodes.Ldc_I4, i);                                // .. -> args idx

                if (arg.nsSyntax() != null)
                {
                    _il.Emit(OpCodes.Ldstr, arg.nsSyntax().GetText());      // .. -> args idx ele
                }
                else if (arg.STRING() != null)
                {
                    var result = StringUtil.Parse(arg.STRING().GetText());  // .. -> args idx ele
                    if (result.IsSuccess)
                    {
                        _il.Emit(OpCodes.Ldstr, result.Value);              // .. -> args idx ele
                    }
                    else
                    {
                        return(result);
                    }
                }
                else if (arg.NUMBER() != null)
                {
                    var result = NumberUtil.Parse(arg.NUMBER().GetText());
                    if (result.IsSuccess)
                    {
                        _il.Emit(OpCodes.Ldc_R8, result.Value);             // .. -> args idx vele
                        _il.Emit(OpCodes.Box, typeof(double));              // .. -> args idx rele
                    }
                    else
                    {
                        return(result);
                    }
                }
                else if (arg.DATE() != null)
                {
                    var result = DateUtil.Parse(arg.DATE().GetText());
                    if (result.IsSuccess)
                    {
                        _il.Emit(OpCodes.Ldc_I8, result.Value.ToBinary());  // .. -> args idx int64
                        var ctor = typeof(DateTime).GetTypeInfo().GetConstructor(new[] { typeof(long) });
                        _il.Emit(OpCodes.Newobj, ctor);                     // .. -> args idx date
                        _il.Emit(OpCodes.Box, typeof(DateTime));            // .. -> args idx rele
                    }
                    else
                    {
                        return(result);
                    }
                }
                else if (arg.Bool() != null)
                {
                    _il.Emit(bool.Parse(arg.Bool().GetText()) ?
                             OpCodes.Ldc_I4_1 :
                             OpCodes.Ldc_I4_0);                             // .. -> args idx bool
                    _il.Emit(OpCodes.Box, typeof(bool));                    // .. -> args idx rele
                }
                else if (arg.unnamedSql() != null)
                {
                    var parseTree = arg.unnamedSql();
                    var id        = NameUtil.GetFunctionName(parseTree);
                    var result    = _context.TryGetEmiter(id, _context.CurrentNs);

                    SqlEmiter emiter;
                    if (result.IsSuccess)
                    {
                        emiter = result.Value;
                    }
                    else
                    {
                        emiter = SqlEmiterUtil.CreateUnnamed(parseTree, _context.CurrentNs);
                        var ok = _context.TryAdd(id, emiter);
                        if (ok.IsFailure)
                        {
                            return(ok);
                        }
                    }

                    var compileResult = emiter.EnsureCompiled(_context);
                    if (compileResult.IsFailure)
                    {
                        return(compileResult);
                    }

                    _il.Emit(OpCodes.Ldarg_0);                                // .. -> args idx ctx
                    _il.Emit(OpCodes.Ldstr, id);                              // .. -> args idx ctx id
                    _il.Emit(OpCodes.Ldstr, _context.CurrentNs);              // .. -> args idx ctx id ns
                    _il.Emit(OpCodes.Call, typeof(SqlEmiterUtil).GetTypeInfo()
                             .GetMethod(nameof(SqlEmiterUtil.EmiterFromId))); // .. -> args idx emiter
                }
                else
                {
                    throw new InvalidOperationException();
                }

                _il.Emit(OpCodes.Stelem_Ref);                               // -> ctx name ns self args
            }

            _il.Emit(OpCodes.Call, typeof(MacroManager).GetTypeInfo()
                     .GetMethod(nameof(MacroManager.Execute)));             // result<str>
            _il.Emit(OpCodes.Dup);                                          // result<str> x 2
            _il.Emit(OpCodes.Call, typeof(Result).GetTypeInfo()
                     .GetMethod("get_" + nameof(Result.IsSuccess)));        // result<str> bool
            _il.Emit(OpCodes.Ldc_I4_1);                                     // result<str> bool true
            var ifIsSuccess = _il.DefineLabel();

            _il.Emit(OpCodes.Beq, ifIsSuccess);                             // result<str> (jmp if equal)
            _il.Emit(OpCodes.Ret);                                          // [exit-returned]

            _il.MarkLabel(ifIsSuccess);                                     // ifIsSuccess:
            _il.Emit(OpCodes.Call, typeof(Result <string>).GetTypeInfo()
                     .GetMethod("get_" + nameof(Result <string> .Value)));  // str
            var strValue = _il.DeclareLocal(typeof(string));

            _il.Emit(OpCodes.Stloc, strValue);                              // [empty]
            _il.Emit(OpCodes.Ldloc_0);                                      // sb
            _il.Emit(OpCodes.Ldloc, strValue);                              // sb str
            _il.Emit(OpCodes.Call, typeof(StringBuilder)
                     .GetTypeInfo().GetMethod(nameof(StringBuilder.Append),
                                              new[] { typeof(string), }));  // sb+str
            _il.Emit(OpCodes.Pop);                                          // [empty]

            return(Result.Ok());
        }