private static bool MatchArgs(MethodInfo method, IList<TypeDefinition> argTypes) { if (method.Parameters.Count != argTypes.Count) { return false; } bool match = true; for (int i = 0; i < method.Parameters.Count; i++) { if (string.CompareOrdinal(method.Parameters[i].Type.FullName, argTypes[i].FullName) != 0) { match = false; break; } } return match; }
public void AddProto(MethodInfo proto) { string mangledName = proto.MangledName; foreach (var existing in this.protoList) { if (string.CompareOrdinal(existing.MangledName, mangledName) == 0) { return; } } this.protoList.Add(proto); }
private bool TryCreateMethod( CompilerContext context, TypeDefinition type, MethodDeclaration methodDecl, out MethodInfo methodInfo) { methodInfo = new MethodInfo(type) { Name = methodDecl.MethodName, IsStatic = methodDecl.IsStatic, IsVirtual = methodDecl.IsVirtual || methodDecl.IsAbstract, IsAbstract = methodDecl.IsAbstract }; TypeDefinition returnType = null; if (methodDecl.ReturnType != null) { if (!this.TryResolveTypeReference(context, methodDecl.ReturnType, out returnType)) { return false; } methodInfo.ReturnType = returnType; } foreach (ParameterDeclaration paramDecl in methodDecl.Parameters) { TypeDefinition paramDef = null; if (!this.TryResolveTypeReference(context, paramDecl.Type, out paramDef)) { return false; } foreach (string name in paramDecl.ParameterNames) { ParameterInfo paramInfo = new ParameterInfo { Name = name, Type = paramDef }; methodInfo.Parameters.Add(paramInfo); } } if (methodInfo.IsVirtual) { methodInfo.AssignVTableIndex(); } return true; }
private bool TryEmitReference( ReferenceExpression referenceExpression, CompilerContext context, Scope scope, MethodImpl method, out string location, out TypeDefinition storageType, out MethodInfo calleeMethod) { calleeMethod = null; NamedReferenceExpression namedRef = referenceExpression as NamedReferenceExpression; if (namedRef != null) { SymbolEntry symbol = null; if (scope.TryLookup(namedRef.Identifier, out symbol)) { storageType = symbol.Type; LocalVariable localVar = symbol as LocalVariable; if (localVar != null) { location = string.Format("_{0}$[ebp]", localVar.Name); return true; } else { ParameterVariable parVar = symbol as ParameterVariable; if (parVar != null) { location = string.Format("_{0}$[ebp]", parVar.Name); return true; } } } foreach (var field in method.Method.Type.Fields) { if (string.CompareOrdinal(field.Name, namedRef.Identifier) == 0) { SymbolEntry symThis = null; if(!scope.TryLookup("this", out symThis)) { storageType = null; location = null; return false; } method.Statements.Add( new AsmStatement { Instruction = "mov ecx,_this$[ebp]" }); if (field.Offset > 0) { method.Statements.Add( new AsmStatement { Instruction = "add ecx," + field.Offset }); } storageType = field.Type; location = "[ecx]"; return true; } } foreach (var memberMethod in method.Method.Type.Methods) { if (string.CompareOrdinal(memberMethod.Name, namedRef.Identifier) == 0) { method.Module.AddProto(memberMethod); if (!memberMethod.IsStatic) { SymbolEntry symThis = null; if (!scope.TryLookup("this", out symThis)) { storageType = null; location = null; return false; } method.Statements.Add( new AsmStatement { Instruction = "mov ecx,_this$[ebp]" }); method.Statements.Add(new AsmStatement { Instruction = "push ecx" }); } if (memberMethod.IsVirtual) { location = "[ecx]"; } else { location = memberMethod.MangledName; } storageType = memberMethod.ReturnType; calleeMethod = memberMethod; return true; } } if (context.TryFindTypeByName(namedRef.Identifier, out storageType)) { location = null; return true; } string message = string.Format( Properties.Resources.CodeGenerator_UndeclaredIdentifier, namedRef.Identifier); log.Write(new Message( namedRef.Start.Path, namedRef.Start.Line, namedRef.Start.Column, Severity.Error, message)); } MemberReferenceExpression memberRef = referenceExpression as MemberReferenceExpression; if (memberRef != null) { string innerLoc = null; TypeDefinition innerType = null; MethodInfo innerCalleeMethod = null; if (this.TryEmitReference(memberRef.Inner, context, scope, method, out innerLoc, out innerType, out innerCalleeMethod)) { foreach (var field in innerType.Fields) { if (string.CompareOrdinal(field.Name, memberRef.MemberName) == 0) { method.Statements.Add( new AsmStatement { Instruction = string.Format("lea ecx,{0}", innerLoc) }); if (field.Offset > 0) { method.Statements.Add( new AsmStatement { Instruction = "add ecx," + field.Offset }); } storageType = field.Type; location = "[ecx]"; return true; } } foreach (var memberMethod in innerType.Methods) { if (string.CompareOrdinal(memberMethod.Name, memberRef.MemberName) == 0) { method.Module.AddProto(memberMethod); if (!memberMethod.IsStatic) { method.Statements.Add(new AsmStatement { Instruction = string.Format("lea eax,{0}", innerLoc) }); method.Statements.Add(new AsmStatement { Instruction = "push eax" }); } if (memberMethod.IsVirtual && memberRef.UseVirtualDispatch) { location = "[eax]"; } else { location = memberMethod.MangledName; } storageType = memberMethod.ReturnType; calleeMethod = memberMethod; return true; } } string message = string.Format( Properties.Resources.CodeGenerator_UndeclaredMember, memberRef.MemberName, innerType.FullName); log.Write(new Message( memberRef.Start.Path, memberRef.Start.Line, memberRef.Start.Column, Severity.Error, message)); } } CallReferenceExpression callExpr = referenceExpression as CallReferenceExpression; if (callExpr != null) { location = null; return this.TryEmitExpression(callExpr, context, scope, method, out storageType); } ArrayIndexReferenceExpression arrayIndexExpr = referenceExpression as ArrayIndexReferenceExpression; if (arrayIndexExpr != null) { TypeDefinition indexType = null; if (!this.TryEmitExpression( arrayIndexExpr.Index, context, scope, method, out indexType)) { location = null; storageType = null; return false; } if (indexType.IsFloatingPoint || indexType.IsArray || indexType.IsClass || indexType.IsPointer) { this.log.Write(new Message( arrayIndexExpr.Index.Start.Path, arrayIndexExpr.Index.Start.Line, arrayIndexExpr.Index.Start.Column, Severity.Error, Properties.Resources.CodeGenerator_ArrayIndexIntExpected)); location = null; storageType = null; return false; } method.Statements.Add(new AsmStatement { Instruction = "push eax" }); string innerLoc = null; TypeDefinition innerType = null; MethodInfo arrayCalleeMethod = null; if (!this.TryEmitReference( arrayIndexExpr.Inner, context, scope, method, out innerLoc, out innerType, out arrayCalleeMethod)) { location = null; storageType = null; return false; } if (!innerType.IsArray) { log.Write(new Message( arrayIndexExpr.Inner.Start.Path, arrayIndexExpr.Inner.Start.Line, arrayIndexExpr.Inner.Start.Column, Severity.Error, Properties.Resources.CodeGenerator_ArrayTypeExpected)); location = null; storageType = null; return false; } if (innerType.Size > 4) { method.Statements.Add(new AsmStatement { Instruction = "lea ecx," + innerLoc }); } else { method.Statements.Add(new AsmStatement { Instruction = "mov ecx," + innerLoc }); } method.Statements.Add(new AsmStatement { Instruction = "pop eax" }); int elementSize = innerType.InnerType.Size; if(elementSize > 1) { int shiftSize = 0; switch(elementSize) { case 2: shiftSize = 1; break; case 4: shiftSize = 2; break; case 8: shiftSize = 3; break; case 16: shiftSize = 4; break; case 32: shiftSize = 5; break; case 64: shiftSize = 6; break; default: method.Statements.Add(new AsmStatement { Instruction = string.Format("imul eax,{0}", elementSize) }); break; } if (shiftSize != 0) { method.Statements.Add(new AsmStatement { Instruction = string.Format("shl eax,{0}", shiftSize) }); } } method.Statements.Add(new AsmStatement { Instruction = "add ecx,eax" }); location = "[ecx]"; storageType = innerType.InnerType; return true; } DereferenceExpression derefExpr = referenceExpression as DereferenceExpression; if (derefExpr != null) { string innerLoc = null; TypeDefinition innerType = null; MethodInfo innerCall = null; if (!this.TryEmitReference( derefExpr.Inner, context, scope, method, out innerLoc, out innerType, out innerCall)) { location = null; storageType = null; return false; } if (!innerType.IsPointer) { log.Write(new Message( derefExpr.Start.Path, derefExpr.Start.Line, derefExpr.Start.Column, Severity.Error, Properties.Resources.CodeGenerator_CannotDerefNonPointer)); location = null; storageType = null; return false; } method.Statements.Add(new AsmStatement { Instruction = "mov ecx," + innerLoc }); location = "[ecx]"; storageType = innerType.InnerType; return true; } InheritedReferenceExpression inhRefExpr = referenceExpression as InheritedReferenceExpression; if (inhRefExpr != null) { storageType = method.Method.Type.BaseClass; if (storageType == null) { string message = string.Format( System.Globalization.CultureInfo.CurrentCulture, Properties.Resources.CodeGenerator_NoBaseTypeForInherited, method.Method.Type.FullName); this.log.Write(new Message( inhRefExpr.Start.Path, inhRefExpr.Start.Line, inhRefExpr.Start.Column, Severity.Error, message)); location = null; return false; } SymbolEntry thisSymbol = null; if (!scope.TryLookup("this", out thisSymbol)) { // reference a static on the base class. location = null; } else { location = "_this$[ebp]"; } return true; } location = null; storageType = null; return false; }
public bool TryFindMethodAndType( string methodNameRef, IList<TypeDefinition> parameterTypes, out TypeDefinition type, out MethodInfo methodInfo) { type = null; methodInfo = null; int methodStart = methodNameRef.LastIndexOf('.'); if (methodStart < 0) { return false; } string methodName = methodNameRef.Substring(methodStart + 1); string typeName = methodNameRef.Substring(0, methodStart); if (!TryFindTypeByName(typeName, out type)) { return false; } foreach (var test in type.Methods) { if (string.CompareOrdinal(test.Name, methodName) == 0) { bool match = true; if (test.Parameters.Count != parameterTypes.Count) { continue; } for (int i = 0; i < test.Parameters.Count; i++) { if (string.CompareOrdinal(test.Parameters[i].Type.FullName, parameterTypes[i].FullName) != 0) { match = false; break; } } if (!match) { continue; } methodInfo = test; return true; } } return false; }
public bool TryFindConstructor( TypeDefinition objectType, IList<TypeDefinition> parameterTypes, out MethodInfo methodInfo) { methodInfo = null; foreach (MethodInfo constructor in objectType.Methods.Where(e => string.CompareOrdinal("constructor", e.Name) == 0)) { if (constructor.Parameters.Count != parameterTypes.Count) { continue; } bool match = true; for (int i = 0; i < parameterTypes.Count; i++) { if (string.CompareOrdinal(constructor.Parameters[i].Type.FullName, parameterTypes[i].FullName) != 0) { match = false; break; } } if (match) { methodInfo = constructor; return true; } } return false; }
public Scope BeginScope(MethodInfo method) { Scope scope = new Scope(); if (method.ReturnType != null) { LocalVariable returnVar = scope.DefineLocalVariable(method.Name, method.ReturnType); scope.ReturnVariable = returnVar; if (method.ReturnType.Size > 8 && !method.ReturnType.IsFloatingPoint || method.ReturnType.IsClass) { scope.LargeReturnVariable = scope.DefineParameter( "$result", this.GetPointerType(method.ReturnType)); } } if (!method.IsStatic) { scope.DefineParameter("this", this.GetPointerType(method.Type)); } foreach (ParameterInfo parameterInfo in method.Parameters) { scope.DefineParameter(parameterInfo.Name, parameterInfo.Type); } return scope; }