Пример #1
0
        public static Expression GetArgAsBool(Expression argexp)
        {
            Expression bexp = ExCasts.UnwrapVariable(argexp);

            // see note in GetArgAsDouble
            //if (bexp.Type == typeof(object[]))
            //    bexp = Expression.ArrayIndex(bexp, Expression.Constant(0));
            return(ExCasts.GetCastExpression(Expression.Constant("c:b"), bexp));
        }
Пример #2
0
        public static Expression GetArgAsString(Expression argexp)
        {
            Expression sexp = ExCasts.UnwrapVariable(argexp);

            // see note in GetArgAsDouble
            //if (sexp.Type == typeof(object[]))
            //    sexp = Expression.ArrayIndex(sexp, Expression.Constant(0));
            return(Expression.Convert(sexp, typeof(string)));
        }
Пример #3
0
 public static Expression GetArgAsObject(Expression argexp)
 {
     // TODO: can we check for object[] here safely? it doesn't seem possible
     // may need an alternative to these special case object[] checks in the
     // getarg methods. The issue arrises when a library is passed in array args
     // or a:all and is expecting a single arg
     // maybe we could resolve this by always array-casting the args even if
     // there's only one, and then expecting the library to index ?
     return(Expression.Convert(ExCasts.UnwrapVariable(argexp), typeof(object)));
 }
Пример #4
0
        public static Expression GetArgIndexUnbox(Expression argexp, int index)
        {
            if (!(argexp is NewArrayExpression))
            {
                // need to do things the worse way, because we can't do this optimization
                return(Expression.ArrayAccess(ExCasts.UnwrapVariable(argexp), Expression.Constant(index)));
            }
            NewArrayExpression arx = argexp as NewArrayExpression;

            return(arx.Expressions[index]);
        }
Пример #5
0
        public static Expression GetArgAsDouble(Expression argexp)
        {
            // see below comment on GetArgAsInt
            Expression dexp = ExCasts.UnwrapVariable(argexp);

            // special case: in specifically the scenario where we are reading args for a library
            // method, if we expect only one arg and ask e.g. GetArgAsDouble(args), in some cases
            // the args may be represented as object[] { arg0 } rather than just arg0
            //if (dexp.Type == typeof(object[]))
            //    dexp = Expression.ArrayIndex(dexp, Expression.Constant(0));
            return(ExCasts.GetExpressionObjectAsDouble(dexp));
            //return Expression.Convert(ExCasts.UnwrapVariable(argexp), typeof(double));
        }
Пример #6
0
 public static Expression GetExpressionObjectAsDouble(Expression exp)
 {
     if (exp.Type == typeof(double))
     {
         return(exp);
     }
     if (exp.Type == typeof(int))
     {
         return(Expression.Convert(ExCasts.UnwrapVariable(exp), typeof(double)));
     }
     return(Expression.Call(typeof(ExCasts).GetTypeInfo().GetDeclaredMethod("GetObjectAsDouble"),
                            exp));
 }
Пример #7
0
        public static Expression GetArgAsInt(Expression argexp)
        {
            // so: going through convert directly means that auto-casting like double -> int
            //     is not done for us. If we use this instead, we can have that luxury
            // additionally, I want to move the logic for this out of exfuncs and into excasts
            // as that locale is more appropriate
            Expression iexp = ExCasts.UnwrapVariable(argexp);

            // see note in GetArgAsDouble
            //if (iexp.Type == typeof(object[]))
            //    iexp = Expression.ArrayIndex(iexp, Expression.Constant(0));
            return(ExCasts.GetExpressionObjectAsInt(iexp));
            //return Expression.Convert(ExCasts.UnwrapVariable(argexp), typeof(int));
        }
Пример #8
0
        public static Expression GetFunctionExpression(Expression funcexp, Expression argexp,
                                                       List <InputContext> compiledContexts, int scopeContext,
                                                       Expression argParams, ParameterExpression inputParams, ParameterExpression contextParams,
                                                       List <InputVar> compiledInputVarsList)
        {
            // special case: library function
            bool doDynamicLibraryCall = false;

            if (funcexp is ConstantExpression && funcexp.Type == typeof(LibraryFunctionIntermediate))
            {
                LibraryFunctionIntermediate lfi = (funcexp as ConstantExpression).Value as LibraryFunctionIntermediate;
                if (lfi.Library == null)
                {
                    // library hasn't been populated yet, so we have to do dynamic call
                    doDynamicLibraryCall = true;
                }
                else
                {
                    if (!(argexp is NewArrayExpression))
                    {
                        argexp = ExCasts.WrapArguments(argexp);
                    }
                    return(lfi.Library.GetFunctionExpression(lfi.FuncName,
                                                             argexp, argParams, inputParams,
                                                             Expression.ArrayIndex(contextParams, Expression.Constant(scopeContext)), compiledInputVarsList));
                }
            }
            else if (funcexp.Type == typeof(LibraryFunctionIntermediate))
            {
                doDynamicLibraryCall = true;
            }

            if (doDynamicLibraryCall)
            {
                // the dynamic case: the library function intermediate can't be rendered at compiled time
                // TODO: put some explanation here as to how and why this happens
                throw new Exception("Attempted to access library dynamically, which is not supported.");

                /*Expression argexparray = ExCasts.WrapArguments(argexp);
                 * return Expression.Call(
                 *  Expression.Field(funcexp, typeof(LibraryFunctionIntermediate), "LibraryPointer"),
                 *  typeof(LibraryPointer).GetRuntimeMethod(
                 *      "ExecuteFunction",
                 *      new[] { typeof(string), typeof(object[]), typeof(InputContext) }),
                 *  Expression.Field(funcexp, typeof(LibraryFunctionIntermediate), "FuncName"),
                 *  argexparray,
                 *  Expression.ArrayIndex(contextParams, Expression.Constant(scopeContext)));*/
            }

            // special case: object was accessed
            if (funcexp.Type == typeof(AccessorResult))
            {
                // this can't be rendered at compile time so we need to call out at runtime
                // to try to access the func that may be in the access result
                Expression argexparray = ExCasts.WrapArguments(argexp);
                return(Expression.Call(funcexp,
                                       typeof(AccessorResult).GetRuntimeMethod("ExecuteFunc", new Type[] { typeof(object[]) }),
                                       argexparray));
            }


            string funcname = (funcexp as ConstantExpression).Value as string;

            switch (funcname.ToLower())
            {
            //case "f:index":
            //    return Expression.ArrayIndex(argexp,
            //        Expression.Add(Expression.Constant(1), Expression.Convert(Expression.ArrayIndex(argexp, Expression.Constant(0)), typeof(int))));
            //        //Expression.Convert(Expression.ArrayIndex(argexp, Expression.Subtract(Expression.ArrayLength(argexp), Expression.Constant(1))), typeof(int)));
            case "f:print":
                return(Expression.Call(typeof(ExFuncs).GetTypeInfo().GetDeclaredMethod("Print"),
                                       GetArgAsString(argexp),
                                       Expression.ArrayIndex(contextParams, Expression.Constant(scopeContext))));

            case "f:return":
                // todo: make a returnlabel at the end of the expression and return to it
                //return Expression.Return()
                // this needs to be done with a special operator instead
                throw new Exception("TODO");

            case "f:import":
                // load a library
                // switching this so it happens at compiletime
                // doing some really convoluted unwrapping here...
                ExLibs.ImportLibrary(
                    (string)(((argexp as NewArrayExpression).Expressions[0] as UnaryExpression).Operand as ConstantExpression).Value,
                    (string)(((argexp as NewArrayExpression).Expressions[1] as UnaryExpression).Operand as ConstantExpression).Value,
                    compiledContexts[scopeContext]);
                return(Expression.Constant(0));

            /*return Expression.Call(typeof(ExLibs).GetTypeInfo().GetDeclaredMethod("ImportLibrary"),
             *  GetArgAsString(GetArgIndex(argexp, 0)),
             *  GetArgAsString(GetArgIndex(argexp, 1)),
             *  Expression.ArrayIndex(contextParams, Expression.Constant(scopeContext)));*/
            case "f:while":
                ParameterExpression whileresult = Expression.Parameter(typeof(object), "whileresult");
                LabelTarget         breaklabel  = Expression.Label("WhileBreak");
                return(Expression.Block(
                           new[] { whileresult },
                           Expression.Assign(whileresult,
                                             Expression.Convert(Expression.Constant(0), typeof(object))),
                           Expression.Loop(
                               Expression.IfThenElse(
                                   GetArgAsBool(GetArgIndexUnbox(argexp, 0)),
                                   Expression.Assign(whileresult,
                                                     Expression.Convert(GetArgIndexUnbox(argexp, 1), typeof(object))),
                                   Expression.Break(breaklabel, whileresult)
                                   ),
                               breaklabel
                               ),
                           whileresult
                           ));

            // TODO: evaluate performance loss of the above version vs this...
            // old version that returns 0 always:

            /*LabelTarget breaklabel = Expression.Label("WhileBreak");
             * return Expression.Block(
             *  Expression.Loop(
             *      Expression.IfThenElse(
             *          GetArgAsBool(GetArgIndexUnbox(argexp, 0)),
             *          GetArgIndexUnbox(argexp, 1),
             *          Expression.Break(breaklabel)
             *          ),
             *      breaklabel
             *      ),
             *  Expression.Constant(0)
             *  );*/
            case "f:for":
                throw new Exception("TODO");
                return(null);

            /*ParameterExpression foriterator = Expression.Parameter(typeof(int), "foriterator");
             * LabelTarget breakforlabel = Expression.Label("ForBreak");
             * return Expression.Block(
             *  Expression.Loop(
             *      Expression.IfThenElse(
             *          GetArgIndex(argexp, 0),
             *          GetArgIndex(argexp, 1),
             *          Expression.Break(breakforlabel)
             *          ),
             *      breakforlabel
             *      ),
             *  Expression.Constant(0)
             *  );*/
            case "f:if":
                ParameterExpression ifresult = Expression.Parameter(typeof(object), "ifresult");
                // if three args were given, divert to ifelse
                if (argexp is NewArrayExpression && (argexp as NewArrayExpression).Expressions.Count > 2)
                {
                    return(Expression.Block(
                               new[] { ifresult },
                               Expression.IfThenElse(
                                   GetArgAsBool(GetArgIndex(argexp, 0)),
                                   Expression.Assign(ifresult, GetArgAsObject(GetArgIndex(argexp, 1))),
                                   Expression.Assign(ifresult, GetArgAsObject(GetArgIndex(argexp, 2)))),
                               ifresult));
                }
                return(Expression.Block(
                           new[] { ifresult },
                           Expression.IfThenElse(
                               GetArgAsBool(GetArgIndex(argexp, 0)),
                               Expression.Assign(ifresult, GetArgAsObject(GetArgIndex(argexp, 1))),
                               Expression.Assign(ifresult, GetArgAsObject(Expression.Constant(0.0)))),
                           ifresult));

            case "f:ifelse":
                ParameterExpression ifelseresult = Expression.Parameter(typeof(object), "ifelseresult");
                return(Expression.Block(
                           new[] { ifelseresult },
                           Expression.IfThenElse(
                               GetArgAsBool(GetArgIndex(argexp, 0)),
                               Expression.Assign(ifelseresult, GetArgAsObject(GetArgIndex(argexp, 1))),
                               Expression.Assign(ifelseresult, GetArgAsObject(GetArgIndex(argexp, 2)))),
                           ifelseresult));

            case "f:newfunc":
                // branching behavior here:
                // if arg[1] is a string, we'll compile by text
                // if arg[1] is not a string, we'll treat it as the expression to use for the new func
                Expression newfuncarg1 = GetArgIndex(argexp, 1);
                // THOUGHT: I don't want to unwrap the var that returns from a func, right?
                // it would be better to return it as a var. Why were we unwrapping it here?
                // maybe we just thought that a func should return a primitive? that's not right
                //newfuncarg1 = ExCasts.UnwrapVariable(newfuncarg1);

                if (newfuncarg1.Type != typeof(string))
                // NOTE: disabling this case... this case would handle dynamic compilation where we
                // would allow a string to be constructed at runtime and then compiled, like
                // "f:newfunc(f:test, "a:0 +" + "51")"
                // but this makes compilation fail for string result functions
                // later we can reintroduce this with a special function name like f:newdynamicfunc
                // that will expect this behavior
                //&& !(newfuncarg1 is UnaryExpression && (newfuncarg1 as UnaryExpression).Operand.Type == typeof(string)))
                {
                    // TODO: remove this comments...
                    // left off here
                    // debating just doing a preproc to transform this arg into a string
                    // for this specific function so that we don't need to handle this case
                    // some downsides though:
                    // 1. may violate expectations?
                    // 2. will be much less efficient than if I can get this working
                    // but getting this working means
                    // 1. line needs to store its paramexpressions so they can be ref'd by other lines
                    // 2. need a way to pass this line thru to the method
                    // 3. (hardest) need a way to pass the Expression itself as an arg to the method...

                    // could I:
                    // 1. take the expression block HERE, outside of the exp. tree
                    // 2. compile it witohut using expression.call, so new funcs are compiled
                    //    at compile time
                    // 3. call a method and pass the resulting exline.Compiled lambda into it
                    // 4. that method just replaces the func's compiled with ^ this one
                    // would that actually violate anything?

                    CompileContext funcCompile = new CompileContext(newfuncarg1,
                                                                    (argParams as UnaryExpression).Operand as ParameterExpression, // this is because argparams
                                                                                                                                   // gets wrapped in a convert (object[]) , so we need to unwrap it here...
                                                                    inputParams, contextParams, compiledInputVarsList, compiledContexts.ToArray(), scopeContext);
                    return(Expression.Call(typeof(ExFuncs).GetTypeInfo().GetDeclaredMethod("NewFuncCompiled"),
                                           GetArgAsString(GetArgIndex(argexp, 0)),
                                           Expression.Constant(funcCompile),
                                           Expression.ArrayIndex(contextParams, Expression.Constant(scopeContext))));
                }
                return(Expression.Call(typeof(ExFuncs).GetTypeInfo().GetDeclaredMethod("NewFunc"),
                                       GetArgAsString(GetArgIndex(argexp, 0)),
                                       GetArgAsString(GetArgIndex(argexp, 1)),
                                       Expression.ArrayIndex(contextParams, Expression.Constant(scopeContext))));

            case "f:setfunc":
                Expression setfuncarg1 = GetArgIndex(argexp, 1);
                setfuncarg1 = ExCasts.UnwrapVariable(setfuncarg1);
                if (setfuncarg1.Type != typeof(string))
                // see above note for f:newfunc
                //&& !(setfuncarg1 is UnaryExpression && (setfuncarg1 as UnaryExpression).Operand.Type == typeof(string)))
                {
                    CompileContext funcCompile = new CompileContext(setfuncarg1,
                                                                    (argParams as UnaryExpression).Operand as ParameterExpression, // this is because argparams
                                                                                                                                   // gets wrapped in a convert (object[]) , so we need to unwrap it here...
                                                                    inputParams, contextParams, compiledInputVarsList, compiledContexts.ToArray(), scopeContext);
                    return(Expression.Call(typeof(ExFuncs).GetTypeInfo().GetDeclaredMethod("SetFuncCompiled"),
                                           GetArgAsString(GetArgIndex(argexp, 0)),
                                           Expression.Constant(funcCompile),
                                           Expression.ArrayIndex(contextParams, Expression.Constant(scopeContext))));
                }
                return(Expression.Call(typeof(ExFuncs).GetTypeInfo().GetDeclaredMethod("SetFunc"),
                                       GetArgAsString(GetArgIndex(argexp, 0)),
                                       GetArgAsString(GetArgIndex(argexp, 1)),
                                       Expression.ArrayIndex(contextParams, Expression.Constant(scopeContext))));

            case "f:newvar":
                // change: if possible, define at compiletime so we can store vars at compiletime
            {
                // remove this...

                /*Expression arg0 = (argexp as NewArrayExpression).Expressions[0];
                 * if (arg0 is UnaryExpression)
                 * {
                 *  // can only optimize here if the varname is constant
                 *  Expression arg0op = (arg0 as UnaryExpression).Operand;
                 *  if(arg0op is BinaryExpression)
                 *  {
                 *      InputVar argvar = compiledInputVarsList[(int)((arg0op as BinaryExpression).Right as ConstantExpression).Value];
                 *      compiledContexts[scopeContext].InsertVar(argvar);
                 *  }
                 * }*/
                return(Expression.Call(typeof(ExFuncs).GetTypeInfo().GetDeclaredMethod("NewVar"),
                                       GetArgAsInputVarName(GetArgIndex(argexp, 0)),
                                       GetArgAsObject(GetArgIndex(argexp, 1)),
                                       Expression.ArrayIndex(contextParams, Expression.Constant(scopeContext))));
            }

            case "f:setvar":
                return(Expression.Call(typeof(ExFuncs).GetTypeInfo().GetDeclaredMethod("SetVar"),
                                       GetArgAsInputVar(GetArgIndex(argexp, 0), Expression.ArrayIndex(contextParams, Expression.Constant(scopeContext))),
                                       GetArgAsObject(GetArgIndex(argexp, 1))));

            case "f:getvar":
                return(Expression.Call(typeof(ExFuncs).GetTypeInfo().GetDeclaredMethod("LookupVar"),
                                       GetArgAsString(argexp),
                                       Expression.ArrayIndex(contextParams, Expression.Constant(scopeContext))));

            case "f:array":
                return(Expression.Call(typeof(ExFuncs).GetTypeInfo().GetDeclaredMethod("Array"),
                                       ExCasts.WrapArguments(argexp)));

            default:
                // we didn't recognize the function, we should check if it's part of the
                // custom defined functions dictionary
                Expression argexparray = ExCasts.WrapArguments(argexp);
                return(Expression.Call(GetFuncExpression(
                                           Expression.ArrayIndex(contextParams, Expression.Constant(scopeContext)), funcexp),
                                       typeof(Exline).GetRuntimeMethod("Execute", new[] { typeof(object[]) }),
                                       argexparray));

                // no longer doing precompile function routing due to elimination of placeholders for scoping
                // may achieve performance gains in the future by reinstation placeholders to allow compiler
                // to find pointer to function ahead of runtime
                // TODO

                /*Exline exl = context.GetFunc(funcname.ToLower());
                 * if (exl != null)
                 * {
                 *  //Expression argexparray = Expression.NewArrayInit(typeof(object), Expression.Convert(argexp, typeof(object)));
                 *  //Expression argexparray = argexp;
                 *  //if (!(argexp is NewArrayExpression))
                 *  //    argexparray = Expression.NewArrayInit(typeof(object), Expression.Convert(argexp, typeof(object)));
                 *  //else
                 *  //argexparray = Expression.NewArrayInit(typeof(object), argexp);
                 *  //argexparray = Expression.Convert(argexp, typeof(object[]));
                 *  //Expression argexparray = Expression.Convert(argexp, typeof(object));
                 *  Expression argexparray = ExCasts.WrapArguments(argexp);
                 *  return Expression.Call(GetFuncExpression(Expression.Constant(context), funcexp),
                 *      exl.GetType().GetRuntimeMethod("Execute", new[] { typeof(object[]) }),
                 *      argexparray);
                 * }
                 * return Expression.Constant(0);*/
            }
        }