private static void GenerateMethodExpression(ScriptGenerator generator, MemberSymbol symbol, MethodExpression expression)
        {
            ScriptTextWriter writer = generator.Writer;

            if (expression.Method.SkipGeneration) {
                // If this method is to be skipped from generation, just generate the
                // left-hand-side object reference, and skip everything past it, including
                // the dot.

                GenerateExpression(generator, symbol, expression.ObjectReference);
                return;
            }

            if (expression.ObjectReference is BaseExpression) {
                Debug.Assert(symbol.Parent is ClassSymbol);
                Debug.Assert(expression.Method.IsGlobalMethod == false);

                writer.Write(((ClassSymbol)symbol.Parent).FullGeneratedName);
                writer.Write(".callBaseMethod(this, '");
                writer.Write(expression.Method.GeneratedName);
                writer.Write("'");
                if ((expression.Parameters != null) && (expression.Parameters.Count != 0)) {
                    writer.Write(",");
                    writer.WriteTrimmed(" [ ");
                    GenerateExpressionList(generator, symbol, expression.Parameters);
                    writer.WriteTrimmed(" ]");
                }
                writer.Write(")");
            }
            else {
                if (expression.Method.IsGlobalMethod) {
                    if (expression.Method.Parent is ClassSymbol) {
                        string mixinRoot = ((ClassSymbol)expression.Method.Parent).MixinRoot;
                        if (String.IsNullOrEmpty(mixinRoot) == false) {
                            writer.Write(mixinRoot);
                            writer.Write(".");
                        }
                    }
                }
                else {
                    GenerateExpression(generator, symbol, expression.ObjectReference);
                    if (expression.Method.GeneratedName.Length != 0) {
                        writer.Write(".");
                    }
                }

                if (expression.Method.GeneratedName.Length != 0) {
                    writer.Write(expression.Method.GeneratedName);
                }
                writer.Write("(");
                if (expression.Parameters != null) {
                    GenerateExpressionList(generator, symbol, expression.Parameters);
                }
                writer.Write(")");
            }
        }
Exemple #2
0
 public DelegateInvokeExpression(MethodExpression methodExpression)
     : base(ExpressionType.DelegateInvoke, methodExpression.ObjectReference, methodExpression.Method, methodExpression.GetParameters())
 {
 }
 public DelegateInvokeExpression(MethodExpression methodExpression)
     : base(ExpressionType.DelegateInvoke, methodExpression.ObjectReference, methodExpression.Method, methodExpression.GetParameters())
 {
 }
        private Expression ProcessOpenParenExpressionNode(BinaryExpressionNode node) {
            bool isDelegateInvoke = false;
            Expression leftExpression = BuildExpression(node.LeftChild);

            if (leftExpression is LocalExpression) {
                Debug.Assert(leftExpression.EvaluatedType.Type == SymbolType.Delegate);

                // Handle the implicit delegate invoke scenario by turning the expression
                // into an explicit call into the delegate's Invoke method

                MemberSymbol invokeMethodSymbol = leftExpression.EvaluatedType.GetMember("Invoke");
                Debug.Assert(invokeMethodSymbol != null);

                leftExpression = new MemberExpression(leftExpression, invokeMethodSymbol);
                isDelegateInvoke = true;
            }

            if (leftExpression.Type != ExpressionType.Member) {
                // A method call was evaluated into a non-member expression as part of building
                // the left node. For example, Nullable<T>.GetValueOrDefault() becomes a logical or expression.

                return leftExpression;
            }

            MemberExpression memberExpression = (MemberExpression)leftExpression;

            ExpressionListNode argNodes = null;
            List<Expression> args = null;
            if (node.RightChild != null) {
                Debug.Assert(node.RightChild is ExpressionListNode);

                argNodes = (ExpressionListNode)node.RightChild;
                args = BuildExpressionList(argNodes);
            }

            MethodExpression methodExpression = null;

            if (memberExpression.Member.Type != SymbolType.Method) {
                // A non-method member is being used in a method call; the member must be
                // a delegate...
                Debug.Assert(memberExpression.EvaluatedType.Type == SymbolType.Delegate);
                Expression instanceExpression = TransformMemberExpression(memberExpression);

                MethodSymbol invokeMethod =
                    (MethodSymbol)memberExpression.EvaluatedType.GetMember("Invoke");
                Debug.Assert(invokeMethod != null);

                methodExpression = new MethodExpression(instanceExpression, invokeMethod);
                isDelegateInvoke = true;
            }
            else {
                // The member being accessed is a method...

                // REVIEW: Uggh... this has become too complex over time with all the transformations
                //         added over time. Refactoring needed...

                MethodSymbol method = (MethodSymbol)memberExpression.Member;
                TypeSymbol objectType = _symbolSet.ResolveIntrinsicType(IntrinsicType.Object);
                TypeSymbol typeType = _symbolSet.ResolveIntrinsicType(IntrinsicType.Type);
                TypeSymbol dictionaryType = _symbolSet.ResolveIntrinsicType(IntrinsicType.Dictionary);
                TypeSymbol genericDictionaryType = _symbolSet.ResolveIntrinsicType(IntrinsicType.GenericDictionary);
                TypeSymbol numberType = _symbolSet.ResolveIntrinsicType(IntrinsicType.Number);
                TypeSymbol stringType = _symbolSet.ResolveIntrinsicType(IntrinsicType.String);
                TypeSymbol scriptType = _symbolSet.ResolveIntrinsicType(IntrinsicType.Script);
                TypeSymbol argsType = _symbolSet.ResolveIntrinsicType(IntrinsicType.Arguments);

                if ((method.Parent == objectType) &&
                    method.Name.Equals("GetType", StringComparison.Ordinal)) {
                    // Since we can't extend object's prototype, we need to transform the
                    // natural c# syntax into a static method.
                    // Object.GetType instance method becomes Type.GetInstanceType static method

                    TypeSymbol typeSymbol = typeType;

                    method = (MethodSymbol)typeSymbol.GetMember("GetInstanceType");
                    Debug.Assert(method != null);

                    methodExpression = new MethodExpression(new TypeExpression(typeSymbol, SymbolFilter.Public | SymbolFilter.StaticMembers),
                                                            method);
                    methodExpression.AddParameterValue(memberExpression.ObjectReference);
                    return methodExpression;
                }
                else if ((method.Parent == objectType) &&
                         (method.Name.Equals("ToString", StringComparison.Ordinal) ||
                          method.Name.Equals("ToLocaleString", StringComparison.Ordinal)) &&
                         (memberExpression.ObjectReference.EvaluatedType == stringType)) {
                    // No-op ToString calls on strings (this happens when performing a ToString
                    // on a named enum value.
                    return memberExpression.ObjectReference;
                }
                else if ((method.Parent == objectType) &&
                         (method.Name.Equals("ToString", StringComparison.Ordinal) ||
                          method.Name.Equals("ToLocaleString", StringComparison.Ordinal)) &&
                         (memberExpression.ObjectReference.EvaluatedType is EnumerationSymbol)) {
                    EnumerationSymbol enumSymbol = (EnumerationSymbol)memberExpression.ObjectReference.EvaluatedType;

                    if (enumSymbol.UseNamedValues) {
                        // If the enum value is a named enum, then it is already a string.
                        return memberExpression.ObjectReference;
                    }

                    return new MethodExpression(memberExpression.ObjectReference, method);
                }
                else if (((method.Parent == dictionaryType) || (method.Parent == genericDictionaryType)) &&
                         method.Name.Equals("ContainsKey", StringComparison.Ordinal)) {
                    // Switch the instance ContainsKey method on Dictionary to
                    // calls to the static KeyExists method.
                    Debug.Assert(args.Count == 1);

                    MethodSymbol keyExistsMethod = (MethodSymbol)dictionaryType.GetMember("KeyExists");
                    Debug.Assert(keyExistsMethod != null);

                    methodExpression = new MethodExpression(new TypeExpression(dictionaryType, SymbolFilter.Public | SymbolFilter.StaticMembers),
                                                            keyExistsMethod);
                    methodExpression.AddParameterValue(memberExpression.ObjectReference);
                    methodExpression.AddParameterValue(args[0]);

                    return methodExpression;
                }
                else if (((method.Parent == dictionaryType) || (method.Parent == genericDictionaryType)) &&
                         method.Name.Equals("Remove", StringComparison.Ordinal)) {
                    // Switch the instance Remove method on Dictionary to
                    // calls to the static DeleteKey method.
                    Debug.Assert(args.Count == 1);

                    return new LateBoundExpression(memberExpression.ObjectReference,
                                                   args[0], LateBoundOperation.DeleteField,
                                                   objectType);
                }
                else if (((method.Parent == dictionaryType) || (method.Parent == genericDictionaryType)) &&
                         method.Name.Equals("Clear")) {
                    // Switch the instance Clear method on Dictionary to
                    // calls to the static ClearKeys method.
                    MethodSymbol clearKeysMethod = (MethodSymbol)dictionaryType.GetMember("ClearKeys");
                    Debug.Assert(clearKeysMethod != null);

                    methodExpression = new MethodExpression(new TypeExpression(dictionaryType, SymbolFilter.Public | SymbolFilter.StaticMembers),
                                                            clearKeysMethod);
                    methodExpression.AddParameterValue(memberExpression.ObjectReference);
                    return methodExpression;
                }
                else if (((method.Parent == dictionaryType) || (((TypeSymbol)method.Parent).GenericType == genericDictionaryType)) &&
                         ((method.Visibility & MemberVisibility.Static) != 0) &&
                         method.Name.Equals("GetDictionary", StringComparison.Ordinal)) {
                    // Dictionary.GetDictionary is a no-op method; we're just interested
                    // in the object being passed in.
                    // However we'll re-evaluate the argument to be of dictionary type
                    // so that subsequent use of this expression sees it as a dictionary.
                    Debug.Assert(args.Count == 1);
                    args[0].Reevaluate((TypeSymbol)method.Parent);

                    return args[0];
                }
                else if ((method.Parent == stringType) &&
                         (method.Name.Equals("Escape", StringComparison.Ordinal) ||
                          method.Name.Equals("Unescape", StringComparison.Ordinal) ||
                          method.Name.Equals("EncodeUri", StringComparison.Ordinal) ||
                          method.Name.Equals("DecodeUri", StringComparison.Ordinal) ||
                          method.Name.Equals("EncodeUriComponent", StringComparison.Ordinal) ||
                          method.Name.Equals("DecodeUriComponent", StringComparison.Ordinal))) {
                    // String.<Method> becomes Script.<Method>, as its a global method in script
                    MethodSymbol scriptMethod = (MethodSymbol)scriptType.GetMember(method.Name);

                    methodExpression = new MethodExpression(new TypeExpression(scriptType, SymbolFilter.Public | SymbolFilter.StaticMembers),
                                                            scriptMethod);
                    methodExpression.AddParameterValue(memberExpression.ObjectReference);
                    return methodExpression;
                }
                else if ((method.Parent == scriptType) &&
                         method.Name.Equals("Literal", StringComparison.Ordinal)) {
                    // Convert a call to Script.Literal into a literal expression

                    Debug.Assert(args.Count >= 1);
                    string script = null;

                    if (args[0].Type == ExpressionType.Field) {
                        Debug.Assert(args[0].EvaluatedType == stringType);

                        FieldSymbol field = ((FieldExpression)args[0]).Field;
                        if (field.IsConstant) {
                            Debug.Assert(field.Value is string);
                            script = (string)field.Value;
                        }
                    }
                    else if (args[0].Type == ExpressionType.Literal) {
                        Debug.Assert(((LiteralExpression)args[0]).Value is string);
                        script = (string)((LiteralExpression)args[0]).Value;
                    }

                    if (script == null) {
                        // TODO: When we start raising errors at the expression level instead of the statement
                        //       level, we should return an ErrorExpression instead of a dummy expression.
                        Token argToken = argNodes.Expressions[0].Token;

                        _errorHandler.ReportError("The argument to Script.Literal must be a constant string.",
                                                  argToken.Location);
                        return new InlineScriptExpression("", objectType);
                    }

                    InlineScriptExpression scriptExpression = new InlineScriptExpression(script, objectType);
                    for (int i = 1; i < args.Count; i++) {
                        scriptExpression.AddParameterValue(args[i]);
                    }

                    return scriptExpression;
                }
                else if ((method.Parent == scriptType) &&
                         method.Name.Equals("Boolean", StringComparison.Ordinal)) {
                    Debug.Assert(args.Count == 1);

                    return new UnaryExpression(Operator.LogicalNot, new UnaryExpression(Operator.LogicalNot, args[0]));
                }
                else if ((method.Parent == scriptType) &&
                         method.Name.Equals("Value", StringComparison.Ordinal)) {
                    Debug.Assert(args.Count >= 2);

                    Expression expr = args[0];
                    for (int i = 1; i < args.Count; i++) {
                        expr = new BinaryExpression(Operator.LogicalOr, expr, args[i]);
                    }

                    expr.Reevaluate(args[0].EvaluatedType);
                    expr.AddParenthesisHint();

                    return expr;
                }
                else if (method.Parent == argsType) {
                    if (method.Name.Equals("GetArgument", StringComparison.Ordinal)) {
                        // Switch Arguments.GetArgument into Arguments[]
                        Debug.Assert(args.Count == 1);

                        IndexerExpression indexExpression =
                            new IndexerExpression(new LiteralExpression(typeType, method.Parent),
                                                  ((ClassSymbol)method.Parent).GetIndexer());
                        indexExpression.AddIndexParameterValue(args[0]);

                        return indexExpression;
                    }
                    else if (method.Name.Equals("ToArray", StringComparison.Ordinal)) {
                        // Switch Arguments.ToArray into Array.ToArray(arguments)

                        TypeSymbol arrayType = _symbolSet.ResolveIntrinsicType(IntrinsicType.Array);
                        MethodSymbol toArrayMethod = (MethodSymbol)arrayType.GetMember("ToArray");

                        InlineScriptExpression argsExpression =
                            new InlineScriptExpression("arguments", objectType, /* parenthesize */ false);
                        MethodExpression toArrayExpression =
                            new MethodExpression(new TypeExpression(arrayType, SymbolFilter.Public | SymbolFilter.StaticMembers),
                                                 toArrayMethod);
                        toArrayExpression.AddParameterValue(argsExpression);

                        return toArrayExpression;
                    }
                }
                else {
                    bool lateBound = false;

                    if (method.Parent == scriptType) {
                        LateBoundOperation lateBoundOperation = LateBoundOperation.InvokeMethod;

                        if (method.Name.Equals("InvokeMethod", StringComparison.Ordinal)) {
                            lateBound = true;
                        }
                        else if (method.Name.Equals("DeleteField", StringComparison.Ordinal)) {
                            lateBound = true;
                            lateBoundOperation = LateBoundOperation.DeleteField;
                        }
                        else if (method.Name.Equals("GetField", StringComparison.Ordinal)) {
                            lateBound = true;
                            lateBoundOperation = LateBoundOperation.GetField;
                        }
                        else if (method.Name.Equals("SetField", StringComparison.Ordinal)) {
                            lateBound = true;
                            lateBoundOperation = LateBoundOperation.SetField;
                        }
                        else if (method.Name.Equals("GetScriptType", StringComparison.Ordinal)) {
                            lateBound = true;
                            lateBoundOperation = LateBoundOperation.GetScriptType;
                        }
                        else if (method.Name.Equals("HasField", StringComparison.Ordinal)) {
                            lateBound = true;
                            lateBoundOperation = LateBoundOperation.HasField;
                        }
                        else if (method.Name.Equals("HasMethod", StringComparison.Ordinal)) {
                            lateBound = true;
                            lateBoundOperation = LateBoundOperation.HasMethod;
                        }
                        else if (method.Name.Equals("CreateInstance", StringComparison.Ordinal)) {
                            Debug.Assert(args.Count >= 1);

                            if ((args[0].Type == ExpressionType.MethodInvoke) ||
                                (args[0].Type == ExpressionType.PropertyGet)) {
                                // When using the result of a method call/property access directly
                                // with Type.CreateInstance, the following script would be generated:
                                //
                                // new method()()
                                // which is invalid. Instead we need to generate the following:
                                // var type = method();
                                // new type()

                                _errorHandler.ReportError("You must store the type returned from a method or property into a local variable to use with Type.CreateInstance.",
                                                          node.Token.Location);
                            }

                            NewExpression newExpression = new NewExpression(args[0], objectType);
                            if (args.Count > 1) {
                                bool first = true;
                                foreach (Expression paramExpr in args) {
                                    if (first) {
                                        first = false;
                                        continue;
                                    }
                                    newExpression.AddParameterValue(paramExpr);
                                }
                            }
                            return newExpression;
                        }

                        if (lateBound) {
                            // Switch explicit late-bound calls into implicit late-bound expressions
                            // in script
                            Debug.Assert((args != null) &&
                                         (((lateBoundOperation == LateBoundOperation.GetScriptType) && (args.Count == 1)) ||
                                          (args.Count >= 2)));

                            LateBoundExpression lateBoundExpression = null;
                            Expression instanceExpression = null;
                            Expression nameExpression = null;

                            foreach (Expression paramExpr in args) {
                                if (instanceExpression == null) {
                                    instanceExpression = paramExpr;

                                    if (lateBoundOperation == LateBoundOperation.GetScriptType) {
                                        // GetScriptType only takes an instance
                                        return new LateBoundExpression(instanceExpression, null,
                                                                       lateBoundOperation, objectType);
                                    }
                                    continue;
                                }
                                if (nameExpression == null) {
                                    nameExpression = paramExpr;

                                    Expression objectExpression = instanceExpression;
                                    if (lateBoundOperation == LateBoundOperation.InvokeMethod) {
                                        if ((instanceExpression.Type == ExpressionType.Literal) &&
                                            (((LiteralExpression)instanceExpression).Value == null)) {
                                            objectExpression = null;

                                            LiteralExpression literalExpression = nameExpression as LiteralExpression;
                                            if (literalExpression == null) {
                                                _errorHandler.ReportError("The name of a global method must be a constant string known at compile time.",
                                                                          argNodes.Expressions[0].Token.Location);
                                            }
                                            else if (!Utility.IsValidIdentifier((string)literalExpression.Value)) {
                                                _errorHandler.ReportError("The name of a global method must be a valid identifer.",
                                                                          argNodes.Expressions[0].Token.Location);
                                            }
                                        }
                                    }

                                    lateBoundExpression = new LateBoundExpression(objectExpression, nameExpression,
                                                                                  lateBoundOperation, objectType);
                                    continue;
                                }

                                lateBoundExpression.AddParameterValue(paramExpr);
                            }

                            Debug.Assert(lateBoundExpression != null);
                            return lateBoundExpression;
                        }
                    }

                    if (!method.MatchesConditions(_options.Defines)) {
                        return null;
                    }

                    methodExpression = new MethodExpression(memberExpression.ObjectReference,
                                                            method);
                }
            }

            if (args != null) {
                foreach (Expression paramExpr in args) {
                    methodExpression.AddParameterValue(paramExpr);
                }
            }

            if (isDelegateInvoke) {
                return new DelegateInvokeExpression(methodExpression);
            }
            return methodExpression;
        }
        private Expression ProcessDotExpressionNode(BinaryExpressionNode node) {
            SymbolFilter filter = SymbolFilter.All;
            MemberSymbol memberSymbol = null;

            Expression objectExpression = ProcessDotExpressionNode(node, filter, out memberSymbol);
            if (objectExpression == null) {
                // We didn't successfully create an expression. The first pass attempted to
                // process the right child as an instance member of the left child expression.
                // We need to process the left child again as a type so we can process the
                // right child as a static member this time around.
                filter &= ~SymbolFilter.Members;
                objectExpression = ProcessDotExpressionNode(node, filter, out memberSymbol);
            }
            Debug.Assert(objectExpression != null);

            TypeSymbol dictionaryType = _symbolSet.ResolveIntrinsicType(IntrinsicType.Dictionary);
            TypeSymbol genericDictionaryType = _symbolSet.ResolveIntrinsicType(IntrinsicType.GenericDictionary);
            TypeSymbol nullableType = _symbolSet.ResolveIntrinsicType(IntrinsicType.Nullable);

            if (memberSymbol.Type == SymbolType.Property) {
                if ((memberSymbol.Parent == dictionaryType) ||
                    (memberSymbol.Parent == genericDictionaryType)) {
                    MethodSymbol methodSymbol = null;

                    if (String.CompareOrdinal(memberSymbol.Name, "Count") == 0) {
                        methodSymbol = (MethodSymbol)dictionaryType.GetMember("GetKeyCount");
                        Debug.Assert(methodSymbol != null);
                    }
                    else if (String.CompareOrdinal(memberSymbol.Name, "Keys") == 0) {
                        methodSymbol = (MethodSymbol)dictionaryType.GetMember("GetKeys");
                        Debug.Assert(methodSymbol != null);
                    }

                    if (methodSymbol != null) {
                        MethodExpression methodExpression =
                            new MethodExpression(new TypeExpression(dictionaryType, SymbolFilter.Public | SymbolFilter.StaticMembers),
                                                 methodSymbol);
                        methodExpression.AddParameterValue(objectExpression);
                        return methodExpression;
                    }
                }
                else if (memberSymbol.Parent == nullableType) {
                    if (String.CompareOrdinal(memberSymbol.Name, "Value") == 0) {
                        // Nullable<T>.Value becomes Nullable<T>

                        TypeSymbol underlyingType = objectExpression.EvaluatedType.GenericArguments.First();
                        objectExpression.Reevaluate(underlyingType);

                        return objectExpression;
                    }
                    else if (String.CompareOrdinal(memberSymbol.Name, "HasValue") == 0) {
                        // Nullable<T>.Value becomes Script.IsValue(Nullable<T>)

                        TypeSymbol scriptType = _symbolSet.ResolveIntrinsicType(IntrinsicType.Script);
                        MethodSymbol isValueMethod = (MethodSymbol)scriptType.GetMember("IsValue");

                        MethodExpression methodExpression
                            = new MethodExpression(new TypeExpression(scriptType, SymbolFilter.Public | SymbolFilter.StaticMembers),
                                                   isValueMethod);
                        methodExpression.AddParameterValue(objectExpression);

                        return methodExpression;
                    }
                }
            }
            else if (memberSymbol.Type == SymbolType.Method) {
                if (memberSymbol.Parent == nullableType) {
                    // Nullable<T>.GetValueOrDefault() becomes Nullable<T> || 0|false

                    TypeSymbol underlyingType = objectExpression.EvaluatedType.GenericArguments.First();

                    object defaultValue = 0;
                    if (underlyingType == _symbolSet.ResolveIntrinsicType(IntrinsicType.Boolean)) {
                        defaultValue = false;
                    }
                    else if (underlyingType == _symbolSet.ResolveIntrinsicType(IntrinsicType.String)) {
                        defaultValue = String.Empty;
                    }

                    LiteralExpression literalExpression = new LiteralExpression(underlyingType, defaultValue);

                    BinaryExpression logicalOrExpression = new BinaryExpression(Operator.LogicalOr, objectExpression, literalExpression);
                    logicalOrExpression.Reevaluate(underlyingType);
                    logicalOrExpression.AddParenthesisHint();

                    return logicalOrExpression;
                }
            }

            string dependency = ((TypeSymbol)memberSymbol.Parent).DependencyName;
            if (String.IsNullOrEmpty(dependency) == false) {
                _options.AddExecutionDependency(dependency);
            }

            MemberExpression expression = new MemberExpression(objectExpression, memberSymbol);
            if ((memberSymbol.Type == SymbolType.Method) &&
                memberSymbol.AssociatedType.IsGeneric && (memberSymbol.AssociatedType.GenericArguments == null)) {
                Debug.Assert(node.RightChild.NodeType == ParseNodeType.GenericName);
                Debug.Assert(((GenericNameNode)node.RightChild).TypeArguments != null);

                List<TypeSymbol> typeArgs = new List<TypeSymbol>();
                foreach (ParseNode typeArgNode in ((GenericNameNode)node.RightChild).TypeArguments) {
                    typeArgs.Add(_symbolSet.ResolveType(typeArgNode, _symbolTable, _symbolContext));
                }

                TypeSymbol returnType = _symbolSet.CreateGenericTypeSymbol(memberSymbol.AssociatedType, typeArgs);
                if (returnType != null) {
                    MethodSymbol genericMethod = (MethodSymbol)memberSymbol;
                    MethodSymbol instanceMethod = new MethodSymbol(genericMethod.Name, (TypeSymbol)genericMethod.Parent, returnType);

                    if (genericMethod.IsTransformed) {
                        instanceMethod.SetTransformedName(genericMethod.GeneratedName);
                    }
                    instanceMethod.SetNameCasing(genericMethod.IsCasePreserved);

                    expression = new MemberExpression(objectExpression, instanceMethod);
                }
            }

            return expression;
        }
        private Expression ProcessCastNode(CastNode node) {
            Expression childExpression = BuildExpression(node.Child);
            if (childExpression.Type == ExpressionType.Member) {
                childExpression = TransformMemberExpression((MemberExpression)childExpression);
            }

            TypeSymbol typeSymbol = _symbolSet.ResolveType(node.TypeReference, _symbolTable, _symbolContext);
            Debug.Assert(typeSymbol != null);

            if ((typeSymbol == _symbolSet.ResolveIntrinsicType(IntrinsicType.Integer))) {
                if ((childExpression.EvaluatedType == _symbolSet.ResolveIntrinsicType(IntrinsicType.Double)) ||
                    (childExpression.EvaluatedType == _symbolSet.ResolveIntrinsicType(IntrinsicType.Single))) {
                    // A float or double is being cast to an int
                    // In regular .net this causes a truncation to happen, and we'd like
                    // to preserve that behavior.

                    TypeSymbol mathType =
                        (TypeSymbol)((ISymbolTable)_symbolSet.SystemNamespace).FindSymbol("Math", null, SymbolFilter.Types);
                    Debug.Assert(mathType != null);

                    MethodSymbol truncateMethod = (MethodSymbol)mathType.GetMember("Truncate");
                    Debug.Assert(truncateMethod != null);

                    MethodExpression truncateExpression =
                        new MethodExpression(new TypeExpression(mathType, SymbolFilter.Public | SymbolFilter.StaticMembers),
                                             truncateMethod);
                    truncateExpression.AddParameterValue(childExpression);

                    return truncateExpression;
                }
            }

            return new UnaryExpression(Operator.Cast, childExpression, typeSymbol, childExpression.MemberMask);
        }
        private static void GenerateMethodExpression(ScriptGenerator generator, MemberSymbol symbol, MethodExpression expression)
        {
            ScriptTextWriter writer = generator.Writer;

            if (expression.Method.SkipGeneration) {
                // If this method is to be skipped from generation, just generate the
                // left-hand-side object reference, and skip everything past it, including
                // the dot.

                GenerateExpression(generator, symbol, expression.ObjectReference);
                return;
            }

            if (expression.ObjectReference is BaseExpression) {
                Debug.Assert(expression.Method.IsExtension == false);

                writer.Write("ss.base(");
                writer.Write(generator.CurrentImplementation.ThisIdentifier);
                writer.Write(", '");
                writer.Write(expression.Method.GeneratedName);
                writer.Write("').call(");
                writer.Write(generator.CurrentImplementation.ThisIdentifier);
                if ((expression.Parameters != null) && (expression.Parameters.Count != 0)) {
                    writer.Write(", ");
                    GenerateExpressionList(generator, symbol, expression.Parameters);
                }
                writer.Write(")");
            }
            else {
                if (expression.Method.IsAliased) {
                    writer.Write(expression.Method.Alias);
                    writer.Write("(");
                    if ((expression.Method.Visibility & MemberVisibility.Static) == 0) {
                        GenerateExpression(generator, symbol, expression.ObjectReference);
                        if ((expression.Parameters != null) && (expression.Parameters.Count != 0)) {
                            writer.Write(", ");
                        }
                    }
                    if ((expression.Parameters != null) && (expression.Parameters.Count != 0)) {
                        GenerateExpressionList(generator, symbol, expression.Parameters);
                    }
                    writer.Write(")");
                }
                else {
                    if (expression.Method.IsExtension) {
                        Debug.Assert(expression.Method.Parent.Type == SymbolType.Class);

                        string extendee = ((ClassSymbol)expression.Method.Parent).Extendee;
                        Debug.Assert(String.IsNullOrEmpty(extendee) == false);

                        writer.Write(extendee);
                        writer.Write(".");
                    }
                    else {
                        GenerateExpression(generator, symbol, expression.ObjectReference);
                        if (expression.Method.GeneratedName.Length != 0) {
                            writer.Write(".");
                        }
                    }

                    if (expression.Method.GeneratedName.Length != 0) {
                        writer.Write(expression.Method.GeneratedName);
                    }
                    writer.Write("(");
                    if (expression.Parameters != null) {
                        GenerateExpressionList(generator, symbol, expression.Parameters);
                    }
                    writer.Write(")");
                }
            }
        }