Пример #1
0
        /// <summary>
        /// Someone is accessing a method on our ROOT object. We do the translation to C++ here.
        /// </summary>
        /// <param name="expr"></param>
        /// <param name="result"></param>
        /// <param name="gc"></param>
        /// <returns></returns>
        /// <remarks>Static methods and instance methods are both handled correctly.</remarks>
        public IValue CodeMethodCall(MethodCallExpression expr, IGeneratedQueryCode gc, CompositionContainer container)
        {
            var           objRef = ExpressionToCPP.InternalGetExpression(expr.Object, gc, null, container);
            StringBuilder bld    = new StringBuilder();

            if (expr.Method.IsStatic && objRef != null)
            {
                throw new ArgumentException(string.Format("Call to ROOT instance method '{0}' where the instance is null", expr.Method.Name));
            }
            if (!expr.Method.IsStatic && objRef == null)
            {
                throw new ArgumentException(string.Format("Call to ROOT static method '{0}' where the instance is not null", expr.Method.Name));
            }

            //
            // Code up the local invocation or the static invocation to the method
            //

            if (objRef != null)
            {
                bld.AppendFormat("{0}.{1}", objRef.AsObjectReference(), expr.Method.Name);
            }
            else
            {
                bld.AppendFormat("{0}::{1}", expr.Method.DeclaringType.Name.Substring(1), expr.Method.Name);
            }

            //
            // Put in the arguments
            //

            var argDep = AddMethodArguments(expr.Arguments, gc, container, bld);

            return(new ValSimple(bld.ToString(), expr.Type, objRef == null ? argDep : objRef.Dependants.Concat(argDep)));
        }
        /// <summary>
        /// Called late to replace a constant expression of this type. By the time we get here these should not exist!
        /// The expression holder can't hold anything interesting (like parameters) - by the time we are here
        /// it is too late to do the parsing.
        /// </summary>
        /// <param name="expr"></param>
        /// <param name="codeEnv"></param>
        /// <param name="container"></param>
        /// <returns></returns>
        public IValue ProcessConstantReference(ConstantExpression expr, IGeneratedQueryCode codeEnv, CompositionContainer container)
        {
            var holder = expr.Value as IExpressionHolder;

            if (holder == null)
            {
                throw new InvalidOperationException("Can't get at the interface to get at the expression.");
            }

            var e = holder.HeldExpression;

            return(ExpressionToCPP.InternalGetExpression(e, codeEnv, null, container));
        }
Пример #3
0
        /// <summary>
        /// Convert something to a double. We don't actually do anything as long as this is an expression that we
        /// can naturally convert (int, float, etc.).
        ///
        /// We are expecting an expressio nthat is ToDouble(Convert()), so if we can't see the convert, then we bail.
        /// </summary>
        /// <param name="expr"></param>
        /// <param name="result"></param>
        /// <param name="gc"></param>
        /// <param name="context"></param>
        /// <param name="container"></param>
        /// <returns></returns>
        private static IValue ProcessToDouble(MethodCallExpression expr, IGeneratedQueryCode gc, CompositionContainer container)
        {
            var srcExpr = expr.Arguments[0];

            if (srcExpr.NodeType != ExpressionType.Convert)
            {
                throw new NotImplementedException("Expecting a Convert expression inside the call to Convert.ToDouble");
            }
            var cvtExpr = srcExpr as UnaryExpression;

            var result = ExpressionToCPP.InternalGetExpression(cvtExpr.Operand, gc, null, container);

            if (!result.Type.IsNumberType())
            {
                throw new NotImplementedException("Do not know how to convert '" + srcExpr.Type.Name + "' to a double!");
            }

            return(result);
        }
        /// <summary>
        /// Translate the method call
        /// </summary>
        /// <param name="expr"></param>
        /// <param name="result"></param>
        /// <param name="gc"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public IValue CodeMethodCall(MethodCallExpression expr, IGeneratedQueryCode gc, CompositionContainer container)
        {
            Init();

            ///
            /// First see if we can't locate the method call that at least matches in names
            ///

            var matchingMethodNames = from kt in _knownTypes
                                      where kt.Name == expr.Method.DeclaringType.Name
                                      from m in kt.Methods
                                      where m.Name == expr.Method.Name
                                      select new
            {
                theType   = kt,
                theMethod = m
            };

            ///
            /// Next, match with the arguments
            ///

            var matchingMethod = from m in matchingMethodNames
                                 where m.theMethod.Arguments.Length == expr.Arguments.Count
                                 where m.theMethod.Arguments.Zip(expr.Arguments, (us, them) => new Tuple <KnownTypeInfo.MechodArg, Expression>(us, them)).All(apair => apair.Item1.Type == apair.Item2.Type.FullName)
                                 select m;

            ///
            /// Ok, at this point, we should have only one guy. If we have more then just choose the first
            ///

            var method = matchingMethod.FirstOrDefault();

            if (method == null)
            {
                throw new ArgumentException("Could not find a matching method to translate for the call " + expr.ToString());
            }

            ///
            /// And now translate the call
            ///

            StringBuilder rawValue = new StringBuilder();

            rawValue.Append(method.theMethod.CPPName);
            rawValue.Append("(");
            bool first      = true;
            var  dependents = Enumerable.Empty <IDeclaredParameter>();

            foreach (var arg in expr.Arguments.Zip(method.theMethod.Arguments, (m, a) => Tuple.Create(m, a)))
            {
                if (!first)
                {
                    rawValue.Append(",");
                }
                first = false;
                var e = ExpressionToCPP.InternalGetExpression(arg.Item1, gc, null, container);
                rawValue.AppendFormat("({0}){1}", arg.Item2.CPPType, e.RawValue);
                dependents = dependents.Concat(e.Dependants);
            }
            rawValue.Append(")");

            var result = new ValSimple(rawValue.ToString(), expr.Type, dependents);

            ///
            /// Include files
            ///

            foreach (var ifile in method.theMethod.IncludeFiles)
            {
                gc.AddIncludeFile(ifile);
            }

            ///
            /// We aren't re-writing this expression, so just return it.
            ///

            return(result);
        }
Пример #5
0
        /// <summary>
        /// Build a code statement from the include files, the expression for the method call, and the generated lines of code.
        /// </summary>
        /// <param name="expr"></param>
        /// <param name="gc"></param>
        /// <param name="container"></param>
        /// <param name="includeFiles"></param>
        /// <param name="loc"></param>
        /// <returns></returns>
        public static IValue BuildCPPCodeStatement(MethodCallExpression expr, IGeneratedQueryCode gc, CompositionContainer container, string[] includeFiles, string[] loc)
        {
            // Get include files in.
            if (includeFiles != null)
            {
                foreach (var inc in includeFiles)
                {
                    gc.AddIncludeFile(inc);
                }
            }

            // Next, go after the lines of code. We have to first sort out what parameter names we are looking at,
            // and then force a translation of those parameters into simple values we can pass to the C++ code we
            // are going to pull back.
            var paramsTranslated = from p in expr.Arguments.Zip(expr.Method.GetParameters(), (arg, param) => Tuple.Create(arg, param))
                                   select new
            {
                Name       = p.Item2.Name,
                Translated = ExpressionToCPP.InternalGetExpression(p.Item1, gc, null, container)
            };
            var paramLookup = paramsTranslated.ToDictionary(v => v.Name, v => v.Translated.ApplyParensIfNeeded());

            // Parse out the list of variables that are used. We will be passing these up the line as needed
            // so that we can tell how to optimize things.
            var dependents = new HashSet <string>(FindDeclarableParameters.FindAll(expr).Select(e => e.RawValue));

            // We also need a return variable. Since this can be multiple lines of code and we don't
            // know how the result will be used, we have to declare it up front... and pray they
            // use it correctly! :-)

            var cppResult = DeclarableParameter.CreateDeclarableParameterExpression(expr.Type);

            var cppStatement = new CPPCodeStatement(expr.Method, cppResult, loc, dependents);

            gc.Add(cppStatement);
            gc.Add(cppResult);

            paramLookup.Add(expr.Method.Name, cppResult.RawValue);

            var result = new ValSimple(cppResult.RawValue, expr.Type, DeclarableParameter.CreateDeclarableParameterExpression(cppResult.RawValue, expr.Type).AsArray());

            // Make sure a result exists in here! This at least will prevent some bad C++ code from getting generated!
            var  lookForResult = new Regex(string.Format(@"\b{0}\b", expr.Method.Name));
            bool didReference  = loc.Any(l => lookForResult.Match(l).Success);

            if (!didReference)
            {
                throw new ArgumentException(string.Format("The C++ code attached to the method '{0}' doesn't seem to set a result.", expr.Method.Name));
            }

            // Figure out if there are any Unique variables. If there are, then we need to do
            // a replacement on them.
            var findUnique        = new Regex(@"\b\w*Unique\b");
            var varUniqueRequests = (from l in loc
                                     let matches = findUnique.Matches(l)
                                                   from m in Enumerable.Range(0, matches.Count)
                                                   select matches[m].Value).Distinct();

            foreach (var varRepl in varUniqueRequests)
            {
                var uniqueName       = varRepl.Substring(0, varRepl.Length - "Unique".Length);
                var uniqueTranslated = uniqueName + _uniqueCounter.ToString();
                cppStatement.AddUniqueVariable(varRepl, uniqueTranslated);
                _uniqueCounter++;
            }

            // Add the parameters that need to be translated here.
            foreach (var paramName in paramLookup)
            {
                cppStatement.AddParamReplacement(paramName.Key, paramName.Value);
            }

            return(result);
        }