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; }
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; }
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; }