示例#1
0
        private bool TryEmitExpression(
            Expression expression, 
            CompilerContext context, 
            Scope scope, 
            MethodImpl method, 
            out TypeDefinition valueType)
        {
            LiteralExpression literalExpr = expression as LiteralExpression;
            if (literalExpr != null)
            {
                return this.TryEmitLiteralExpression(literalExpr, context, scope, method, out valueType);
            }

            CallReferenceExpression callExpr = expression as CallReferenceExpression;
            if (callExpr != null)
            {
                int argSize = 0;
                int argStatementStart = method.Statements.Count;
                Expression[] arguments = callExpr.Arguments.ToArray();
                List<TypeDefinition> argTypes = new List<TypeDefinition>();
                for (int i = arguments.Length - 1; i >= 0; i--)
                {
                    TypeDefinition argType = null;
                    if (!this.TryEmitExpression(arguments[i], context, scope, method, out argType))
                    {
                        valueType = null;
                        return false;
                    }

                    argTypes.Insert(0, argType);
                    argSize += ((argType.Size + 3) / 4) * 4;
                    this.PushResult(method, argType);
                }

                string callLoc = null;
                TypeDefinition storageType = null;
                MethodInfo calleeMethod = null;
                if (!this.TryEmitReference(callExpr.Inner, context, scope, method, out callLoc, out storageType, out calleeMethod))
                {
                    valueType = null;
                    return false;
                }

                // fix up calling overloads here vs. inside TryEmitReference.
                if (calleeMethod != null)
                {
                    MethodInfo overload = calleeMethod.Type.FindMethod(calleeMethod.Name, argTypes);
                    if (overload != null)
                    {
                        if (string.CompareOrdinal(calleeMethod.MangledName, callLoc) == 0)
                        {
                            callLoc = overload.MangledName;
                        }

                        method.Module.AddProto(overload);
                        calleeMethod = overload;
                        storageType = overload.ReturnType;
                    }
                }

                if (storageType != null)
                {
                    if (callLoc == null)
                    {
                        // must be a constructor call.
                        MethodInfo constructor = storageType.FindConstructor(argTypes);
                        if (constructor == null)
                        {
                            string message = string.Format(
                                System.Globalization.CultureInfo.CurrentCulture,
                                Properties.Resources.CodeGenerator_CannotFindConstructor,
                                storageType.FullName);
                            log.Write(new Message(
                                callExpr.Start.Path,
                                callExpr.Start.Line,
                                callExpr.Start.Column,
                                Severity.Error,
                                message));
                            valueType = null;
                            return false;
                        }

                        calleeMethod = constructor;
                        callLoc = constructor.MangledName;
                        method.Module.AddProto(constructor);

                        // create room on the stack for the result.
                        AsmStatement resultPush = new AsmStatement { Instruction = string.Format("sub esp,{0}", storageType.Size) };
                        method.Statements.Insert(argStatementStart, resultPush);

                        // push the ref to the storage for the class on the stack.
                        method.Statements.Add(new AsmStatement { Instruction = string.Format("lea eax,[esp+{0}]", argSize) });
                        method.Statements.Add(new AsmStatement { Instruction = "push eax" });
                    }
                    else if (storageType.IsClass || !storageType.IsFloatingPoint && storageType.Size > 8)
                    {
                        // create room on the stack for the result.
                        AsmStatement resultPush = new AsmStatement { Instruction = string.Format("sub esp,{0}", storageType.Size) };
                        method.Statements.Insert(argStatementStart, resultPush);

                        // push the ref to the storage for the class on the stack.
                        method.Statements.Add(new AsmStatement { Instruction = string.Format(
                            "lea ebx,[esp+{0}]",
                            calleeMethod.IsStatic ? argSize : argSize + 4) });
                        method.Statements.Add(new AsmStatement { Instruction = "push ebx" });
                        argSize += 4;
                    }
                }

                if (calleeMethod.IsVirtual && callExpr.Inner.UseVirtualDispatch)
                {
                    FieldInfo vtablePtr = calleeMethod.Type.GetVTablePointer();
                    if (string.CompareOrdinal(callLoc, "[eax]") != 0)
                    {
                        method.Statements.Add(new AsmStatement { Instruction = string.Format("lea eax,{0}", callLoc) });
                    }

                    if (vtablePtr.Offset > 0)
                    {
                        method.Statements.Add(new AsmStatement { Instruction = string.Format("add eax,{0}", vtablePtr.Offset) });
                    }

                    method.Statements.Add(new AsmStatement { Instruction = "mov ecx,[eax]" });
                    if (calleeMethod.VTableIndex > 0)
                    {
                        method.Statements.Add(new AsmStatement { Instruction = string.Format("add ecx,{0}", calleeMethod.VTableIndex * 4) });
                    }

                    method.Statements.Add(new AsmStatement { Instruction = "call dword ptr [ecx]" });
                }
                else
                {
                    method.Statements.Add(new AsmStatement { Instruction = "call " + callLoc });
                }

                if (!calleeMethod.IsStatic)
                {
                    argSize += 4;
                }

                if (argSize > 0)
                {
                    method.Statements.Add(new AsmStatement { Instruction = "add esp," + argSize.ToString() });
                }

                if (calleeMethod.Parameters.Count != argTypes.Count)
                {
                    string message = string.Format(
                        System.Globalization.CultureInfo.InvariantCulture,
                        Properties.Resources.CodeGenerator_UnexpectedArgumentCount,
                        calleeMethod.Name,
                        calleeMethod.Parameters.Count,
                        argTypes.Count);
                    this.log.Write(new Message(
                        expression.Start.Path,
                        expression.Start.Line,
                        expression.Start.Column,
                        Severity.Error,
                        message));
                    valueType = null;
                    return false;
                }

                bool argsValid = true;
                for (int i = 0; i < calleeMethod.Parameters.Count; i++)
                {
                    if (!this.ValidateCanCast(expression, calleeMethod.Parameters[i].Type, argTypes[i]))
                    {
                        argsValid = false;
                    }
                }

                valueType = storageType;
                return argsValid;
            }

            ReferenceExpression refExpr = expression as ReferenceExpression;
            if (refExpr != null)
            {
                string location = null;
                TypeDefinition storageType = null;
                MethodInfo calleeMethod = null;
                if (!this.TryEmitReference(refExpr, context, scope, method, out location, out storageType, out calleeMethod))
                {
                    valueType = null;
                    return false;
                }

                if (storageType.IsFloatingPoint)
                {
                    if (storageType.Size == 8)
                    {
                        method.Statements.Add(new AsmStatement { Instruction = "fld qword ptr " + location });
                    }
                    else if (storageType.Size == 4)
                    {
                        method.Statements.Add(new AsmStatement { Instruction = "fld dword ptr " + location });
                    }
                    else
                    {
                        method.Statements.Add(new AsmStatement { Instruction = "fld tword ptr " + location });
                    }
                }
                else if (storageType.IsArray)
                {
                    if (storageType.ArrayElementCount > 0)
                    {
                        method.Statements.Add(new AsmStatement { Instruction = "lea eax," + location });
                        valueType = context.GetArrayType(storageType.InnerType, 0);
                        return true;
                    }
                    else
                    {
                        method.Statements.Add(new AsmStatement { Instruction = "mov eax," + location });
                    }
                }
                else if (storageType.Size <= 8 && !storageType.IsClass)
                {
                    switch (storageType.Size)
                    {
                        case 8:
                            method.Statements.Add(new AsmStatement { Instruction = "lea ecx, " + location });
                            method.Statements.Add(new AsmStatement { Instruction = "mov eax,[ecx]" });
                            method.Statements.Add(new AsmStatement { Instruction = "add ecx,4" });
                            method.Statements.Add(new AsmStatement { Instruction = "mov edx,[ecx]" });
                            break;
                        case 4:
                            method.Statements.Add(new AsmStatement { Instruction = "mov eax,dword ptr " + location });
                            break;
                        case 2:
                            method.Statements.Add(new AsmStatement { Instruction = "mov ax,word ptr " + location });
                            break;
                        case 1:
                            method.Statements.Add(new AsmStatement { Instruction = "mov al,byte ptr " + location });
                            break;
                    }
                }
                else if (storageType.IsClass)
                {
                    // construct a new copy on the stack.
                    method.Statements.Add(new AsmStatement { Instruction = string.Format("lea eax,{0}", location) });
                    method.Statements.Add(new AsmStatement { Instruction = string.Format("sub esp,{0}", storageType.Size) });
                    MethodInfo copyConstructor = storageType.GetCopyConstructor(context);
                    if (copyConstructor != null)
                    {
                        method.Module.AddProto(copyConstructor);
                        method.Statements.Add(new AsmStatement { Instruction = "lea ecx,[esp]" });
                        method.Statements.Add(new AsmStatement { Instruction = "push eax" });
                        method.Statements.Add(new AsmStatement { Instruction = "push ecx" });
                        method.Statements.Add(new AsmStatement { Instruction = "call " + copyConstructor.MangledName });
                        method.Statements.Add(new AsmStatement { Instruction = "add esp,8" });
                    }
                    else
                    {
                        // raw copy.
                        method.Statements.Add(new AsmStatement { Instruction = "mov edi,esp" });
                        method.Statements.Add(new AsmStatement { Instruction = "mov esi,eax" });
                        method.Statements.Add(new AsmStatement { Instruction = string.Format("mov ecx,{0}", storageType.Size) });
                        method.Statements.Add(new AsmStatement { Instruction = "cld" });
                        method.Statements.Add(new AsmStatement { Instruction = "rep movsb" });
                    }
                }

                valueType = storageType;
                return true;
            }

            SimpleExpression simpleExpr = expression as SimpleExpression;
            if (simpleExpr != null)
            {
                return this.TryEmitSimpleExpression(simpleExpr, context, scope, method, out valueType);
            }

            TermExpression termExpr = expression as TermExpression;
            if (termExpr != null)
            {
                return this.TryEmitTermExpression(termExpr, context, scope, method, out valueType);
            }

            RelationalExpression relExpr = expression as RelationalExpression;
            if (relExpr != null)
            {
                return this.TryEmitRelationExpresion(relExpr, context, scope, method, out valueType);
            }

            AddressExpression addrExpr = expression as AddressExpression;
            if (addrExpr != null)
            {
                return this.TryEmitAddressExpression(addrExpr, context, scope, method, out valueType);
            }

            NewExpression newExpr = expression as NewExpression;
            if (newExpr != null)
            {
                return this.TryEmitNewExpression(newExpr, context, scope, method, out valueType);
            }

            NotExpression notExpr = expression as NotExpression;
            if (notExpr != null)
            {
                return this.TryEmitNotExpression(notExpr, context, scope, method, out valueType);
            }

            NegativeExpression negExpr = expression as NegativeExpression;
            if (negExpr != null)
            {
                return this.TryEmitNegativeExpression(negExpr, context, scope, method, out valueType);
            }

            valueType = null;
            return false;
        }
示例#2
0
        public FieldInfo AddVTablePointer(CompilerContext context, int offset)
        {
            TypeDefinition ptrType = null;
            context.TryFindTypeByName("^", out ptrType);
            FieldInfo field = new FieldInfo
            {
                Name = VTablePointerFieldName,
                IsPublic = true,
                Offset = offset,
                Type = context.GetArrayType(ptrType, 0)
            };

            this.fields.Add(field);
            return field;
        }
示例#3
0
        private bool TryResolveTypeReference(
            CompilerContext context, 
            TypeReference typeRef, 
            out TypeDefinition typeDef)
        {
            NamedTypeReference namedType = typeRef as NamedTypeReference;
            if (namedType != null)
            {
                if (!context.TryFindTypeByName(namedType.TypeName, out typeDef))
                {
                    string message = string.Format(
                        Properties.Resources.CodeGenerator_UndefinedType,
                        namedType.TypeName);
                    this.log.Write(new Message(
                        namedType.Start.Path,
                        namedType.Start.Line,
                        namedType.Start.Column,
                        Severity.Error,
                        message));
                    return false;
                }

                return true;
            }

            PointerTypeReference pointerType = typeRef as PointerTypeReference;
            if (pointerType != null)
            {
                TypeDefinition innerType = null;
                if (!this.TryResolveTypeReference(context, pointerType.ElementType, out innerType))
                {
                    typeDef = null;
                    return false;
                }

                typeDef = context.GetPointerType(innerType);
                return true;
            }

            ArrayTypeReference arrayType = typeRef as ArrayTypeReference;
            if (arrayType != null)
            {
                TypeDefinition innerType = null;
                if (!this.TryResolveTypeReference(context, arrayType.ElementType, out innerType))
                {
                    typeDef = null;
                    return false;
                }

                int elementCount = 0;
                if (arrayType.ElementCount != null)
                {
                    LiteralExpression litElementCount = arrayType.ElementCount as LiteralExpression;
                    if (litElementCount == null || !(litElementCount.Value is int))
                    {
                        log.Write(new Message(
                            arrayType.ElementCount.Start.Path,
                            arrayType.ElementCount.Start.Line,
                            arrayType.ElementCount.Start.Column,
                            Severity.Error,
                            Properties.Resources.CodeGenerator_ArrayTypeIntElementExpected));
                        typeDef = null;
                        return false;
                    }

                    elementCount = (int)(litElementCount.Value);
                }

                typeDef = context.GetArrayType(innerType, elementCount);
                return true;
            }

            typeDef = null;
            return false;
        }