Exemple #1
0
        private static Result <EmitFunction> CompileCore(
            SdmapCompilerContext context,
            CoreSqlContext coreSql)
        {
            var fullName = NameUtil.GetFunctionName(coreSql);

            return(CoreSqlVisitor.CompileCore(
                       coreSql,
                       context,
                       fullName));
        }
Exemple #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());
        }
Exemple #3
0
        public override Result VisitIf([NotNull] IfContext context)
        {
            var coreSql = context.coreSql();
            var id      = NameUtil.GetFunctionName(coreSql);
            var result  = _context.TryGetEmiter(id, _context.CurrentNs);

            SqlEmiter emiter;

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

            var compileResult = emiter.EnsureCompiled(_context);

            if (compileResult.IsFailure)
            {
                return(compileResult);
            }

            return(new BoolVisitor(_il).Visit(context.boolExpression())
                   .OnSuccess(() =>
            {
                var ifSkip = _il.DefineLabel();
                _il.Emit(OpCodes.Ldc_I4_0);
                _il.Emit(OpCodes.Beq, ifSkip);

                _il.Emit(OpCodes.Ldarg_0);                                // ctx
                _il.Emit(OpCodes.Ldstr, id);                              // ctx id
                _il.Emit(OpCodes.Ldstr, _context.CurrentNs);              // ctx id ns
                _il.Emit(OpCodes.Call, typeof(SqlEmiterUtil).GetTypeInfo()
                         .GetMethod(nameof(SqlEmiterUtil.EmiterFromId))); // emiter
                _il.Emit(OpCodes.Ldarg_0);                                // emiter ctx
                _il.Emit(OpCodes.Ldarg_1);                                // emiter ctx obj
                _il.Emit(OpCodes.Call,                                    // result<str>
                         typeof(IfUtils).GetTypeInfo().GetMethod(nameof(IfUtils.ExecuteEmiter)));

                // convert result<str> to 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 strLocal = _il.DeclareLocal(typeof(string));
                _il.Emit(OpCodes.Stloc, strLocal);
                _il.Emit(OpCodes.Ldloc_0);
                _il.Emit(OpCodes.Ldloc, strLocal);
                _il.Emit(OpCodes.Call,
                         typeof(StringBuilder).GetTypeInfo().GetMethod(nameof(StringBuilder.Append),
                                                                       new[] { typeof(string), })); // sb+str
                _il.Emit(OpCodes.Pop);
                _il.MarkLabel(ifSkip);
                return Result.Ok();
            }));
        }
Exemple #4
0
        private Result WriteMacroParameters(MacroParameterContext[] parameterCtxs)
        {
            for (var i = 0; i < parameterCtxs.Length; ++i)
            {
                var parameter = parameterCtxs[i];

                if (parameter.nsSyntax() != null)
                {
                    _writer.Write(
                        SqlTextUtil.ToCSharpString(parameter.nsSyntax().GetText()));
                }
                else if (parameter.STRING() != null)
                {
                    var result = StringUtil.Parse(parameter.STRING().GetText());
                    if (result.IsFailure)
                    {
                        return(result);
                    }

                    _writer.Write(SqlTextUtil.ToCSharpString(result.Value));
                }
                else if (parameter.NUMBER() != null)
                {
                    // sdmap number are compatible with C# double
                    _writer.Write(parameter.NUMBER().GetText());
                }
                else if (parameter.DATE() != null)
                {
                    var result = DateUtil.Parse(parameter.DATE().GetText());
                    if (result.IsFailure)
                    {
                        return(result);
                    }
                    var date = result.Value;
                    _writer.Write(
                        $"new DateTime({date.Year}, {date.Month}, {date.Day})");
                }
                else if (parameter.Bool() != null)
                {
                    // sdmap bool are compatible with C# bool
                    _writer.Write(parameter.Bool().GetText());
                }
                else if (parameter.unnamedSql() != null)
                {
                    var parseTree = parameter.unnamedSql();
                    var id        = NameUtil.GetFunctionName(parseTree);
                    if (!_unnamedSqls.ContainsKey(id))
                    {
                        _unnamedSqls[id] = (writer) =>
                        {
                            return(Visit(parseTree.coreSql()));
                        };
                    }
                    _writer.Write($"{id}()");
                }

                // every parameter should follow by a "," separator,
                // except last parameter.
                if (i < parameterCtxs.Length - 1)
                {
                    _writer.Write(", ");
                }
            }
            _writer.WriteLine(");");
            return(Result.Ok());
        }
Exemple #5
0
        private Result EmitGetMacroParameter(MacroParameterContext arg)
        {
            if (arg.nsSyntax() != null)
            {
                _il.Emit(OpCodes.Ldstr, arg.nsSyntax().GetText());      // val
            }
            else if (arg.STRING() != null)
            {
                var result = StringUtil.Parse(arg.STRING().GetText());
                if (result.IsSuccess)
                {
                    _il.Emit(OpCodes.Ldstr, result.Value);              // val
                }
                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);             // num
                    _il.Emit(OpCodes.Box, typeof(double));              // box<num>
                }
                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());  // num
                    var ctor = typeof(DateTime).GetConstructor(new[] { typeof(long) });
                    _il.Emit(OpCodes.Newobj, ctor);                     // date
                    _il.Emit(OpCodes.Box, typeof(DateTime));            // box<date>
                }
                else
                {
                    return(result);
                }
            }
            else if (arg.Bool() != null)
            {
                _il.Emit(bool.Parse(arg.Bool().GetText()) ?
                         OpCodes.Ldc_I4_1 :
                         OpCodes.Ldc_I4_0);                             // bool
                _il.Emit(OpCodes.Box, typeof(bool));                    // box<bool>
            }
            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);                                // ctx
                _il.Emit(OpCodes.Call, OneCallContext.GetCompiler);       // compiler
                _il.Emit(OpCodes.Ldstr, id);                              // compiler id
                _il.Emit(OpCodes.Ldstr, _context.CurrentNs);              // compiler id ns
                _il.Emit(OpCodes.Call, typeof(SqlEmiterUtil)
                         .GetMethod(nameof(SqlEmiterUtil.EmiterFromId))); // emiter
            }
            else if (arg.macro() != null)
            {
                var result = EmitMacroResult(arg.macro(), topLevel: false);
                if (!result.IsSuccess)
                {
                    return(result);
                }
            }
            else
            {
                return(Result.Fail($"Unknown macro."));
            }

            return(Result.Ok());
        }