/// <summary> /// Add a method to the type /// </summary> /// <param name="type">Type node</param> /// <param name="method">Method node</param> public void AddMethod(TypeNode type, MethodNode method) { if (type.Methods.Contains(method.Name)) type.Methods[method.Name].Add(method); else type.Methods.Add(method.Name, new List<MethodNode> { method }); }
/// <summary> /// Create an automatic ToString() method /// </summary> /// <param name="type">Type node</param> private void GenerateToString(TypeNode type) { var node = new MethodNode("ToString", new SignatureNode("string"), false); node.Virtual = true; node.Body.Statements.Add(Expr.Return(Expr.String(type.Name))); node.Owner = type; AddMethod(type, node); }
/// <summary> /// Create a default constructor without parameters /// </summary> /// <param name="type">Type node</param> private void GenerateDefaultCtor(TypeNode type) { var node = new MethodNode(".ctor", new SignatureNode("void"), false); node.Body.Statements.Add(Expr.Return()); node.SetParameters(); node.Owner = type; AddMethod(type, node); }
/// <summary> /// Create an automatic constructor to set all fields /// </summary> /// <param name="type">Type node</param> private void GenerateAutoCtor(TypeNode type) { var node = new MethodNode(".ctor", new SignatureNode("void"), false); var parameters = new HashList<ParameterNode>(); int idx = 0; foreach(var curr in type.Fields) { var param = new ParameterNode("_" + curr, type.Fields[curr].Type, idx); parameters.Add("_" + curr, param); idx++; var assignNode = new IdentifierSetNode(curr, true); assignNode.Expression = new IdentifierGetNode("_" + curr); node.Body.Statements.Add(assignNode); } node.SetParameters(parameters); node.Owner = type; AddMethod(type, node); }
/// <summary> /// Create an automatic .Equal() method /// </summary> /// <param name="type">Type node</param> private void GenerateAutoComparator(TypeNode type) { var node = new MethodNode("equal", new SignatureNode("bool"), false); // define parameter var parameters = new HashList<ParameterNode>(); var param = new ParameterNode("_obj", new SignatureNode(type.Name), 0); parameters.Add(param.Name, param); // generate series of comparisons foreach(var curr in type.Fields) { // // if(@<name> != _obj.<name>) return false; // node.Body.Statements.Add( Expr.If( Expr.Compare( Expr.IdentifierGet(curr, true), Lexer.LexemType.NotEqual, Expr.IdentifierGet(curr, Expr.IdentifierGet("_obj")) ), Expr.Return( Expr.Bool(true) ) ) ); } // return true node.Body.Statements.Add( Expr.Return( Expr.Bool(true) ) ); node.SetParameters(parameters); node.Owner = type; AddMethod(type, node); }
/// <summary> /// Create underlying MethodReference in assembly /// </summary> /// <param name="method">Method to prepare</param> public void PrepareMethod(MethodNode method) { // check if method should be virtual and set it's parent to virtual too if (method.Name != ".ctor") { var shadowedMethod = FindShadowedMethod(method); if (shadowedMethod != null) { method.Virtual = shadowedMethod.Virtual = true; if (shadowedMethod.Method != null && !shadowedMethod.BuiltIn) (shadowedMethod.Method as MethodDefinition).IsVirtual = true; } } // calculate required attributes var attribs = MethodAttributes.HideBySig; if (method.Static) attribs |= MethodAttributes.Static; if (method.Virtual) attribs |= MethodAttributes.Virtual; if (method.Name == ".ctor" || method.Name == ".cctor") attribs |= MethodAttributes.SpecialName | MethodAttributes.RTSpecialName; if (method.Name == ".cctor") attribs |= MethodAttributes.Private; else attribs |= MethodAttributes.Public; // create method in assembly method.Type.CompiledType = ResolveType(method.Type); var nativeMethod = new MethodDefinition(method.Name, attribs, ResolveType(method.Type)); method.Method = nativeMethod; method.Scope = new Utils.Scope(nativeMethod); ((TypeDefinition)method.Owner.Type).Methods.Add(nativeMethod); // add parameter info in assembly if(method.Parameters != null) foreach (var curr in method.Parameters) method.Method.Parameters.Add(new ParameterDefinition(curr, ParameterAttributes.None, ResolveType(method.Parameters[curr].Type))); }
/// <summary> /// Explicitly mark method as virtual /// </summary> /// <param name="method">Method to work on</param> public void MakeMethodVirtual(MethodNode method) { var nativeMethod = method.Method as MethodDefinition; if(nativeMethod != null) nativeMethod.Attributes |= MethodAttributes.Virtual; method.Virtual = true; }
/// <summary> /// Find out if there's a method that the current method overloads /// </summary> /// <param name="node">Method node</param> /// <returns></returns> public MethodNode FindShadowedMethod(MethodNode node) { var parentType = FindType(node.Owner.Parent); while(parentType != null) { if(parentType.Methods.Contains(node.Name)) { var overloads = parentType.Methods[node.Name]; var found = overloads.Find(curr => curr.Signature == node.Signature); if(found != null) return found; } parentType = FindType(parentType.Parent); } return null; }
/// <summary> /// Create a method in a type /// </summary> /// <param name="owner">Owner type node</param> /// <param name="name">Method name</param> /// <param name="type">Method return value type signature</param> /// <param name="parameters">Method parameters list</param> /// <param name="isStatic">Static flag</param> /// <returns></returns> public MethodNode CreateMethod(TypeNode owner, string name, SignatureNode type, HashList<ParameterNode> parameters = null, bool isStatic = false, bool prepare = false) { // cannot add methods to built-in types if (owner.BuiltIn) throw new CompilerException(String.Format(Resources.errExtendBuiltInType, owner.Name)); // create method in assembly and in Mirelle Registry var method = new MethodNode(name, type, isStatic); method.SetParameters(parameters); // check if an identical method hasn't already been declared if (owner.Methods.Contains(method.Name)) { if(owner.Methods[method.Name].Exists(curr => curr.Signature == method.Signature)) throw new CompilerException(String.Format(Resources.errMethodRedefinition, method.Name, owner.Name)); } // register method in the parent type AddMethod(owner, method); method.Owner = owner; if (prepare) PrepareMethod(method); return method; }
/// <summary> /// Import a method from any assembly into Mirelle registry /// </summary> /// <param name="baseType">Actual type</param> /// <param name="baseName">Method name within actual type</param> /// <param name="owner">Owner type name within Mirelle</param> /// <param name="name">Method name within mirelle</param> /// <param name="type">Type</param> /// <param name="isStatic">Static flag</param> /// <param name="parameters">Parameter list</param> /// <returns></returns> public MethodNode ImportMethod(Type baseType, string baseName, string owner, string name, string type, bool isStatic = false, params string[] parameters) { var ownerType = FindType(owner); if (ownerType == null) throw new CompilerException(String.Format(Resources.errTypeNotFound, owner)); // find method in the base type and import it var types = new Type[parameters.Length]; var idx = 0; foreach (var curr in parameters) { types[idx] = ResolveBasicType(curr); idx++; } MethodReference importedMethod; if(baseName == ".ctor") importedMethod = AssemblyImport(baseType.GetConstructor(types)); else importedMethod = AssemblyImport(baseType.GetMethod(baseName, types)); var typeNode = new SignatureNode(type); ResolveType(typeNode); var method = new MethodNode(name, typeNode, isStatic, true, importedMethod); // parameters var sb = new StringBuilder(name); idx = 0; foreach (var curr in parameters) { // declared as extension method ? // first parameter is the invoker itself, remove it from parameters list if (!importedMethod.HasThis && !isStatic && idx == 0) { idx++; continue; } var signNode = new SignatureNode(curr); sb.Append(" "); sb.Append(curr); var param = new ParameterNode("p" + idx.ToString(), signNode, idx); method.Parameters.Add(param.Name, param); idx++; } method.Signature = sb.ToString(); // check if an identical method hasn't already been declared if (ownerType.Methods.Contains(method.Signature)) throw new CompilerException(String.Format(Resources.errMethodRedefinition, method.Name, owner)); // register method in the owner type AddMethod(ownerType, method); method.Owner = ownerType; return method; }
/// <summary> /// Call a method /// </summary> /// <param name="node"></param> /// <param name="method"></param> public void EmitCall(MethodNode node) { GetMethodProcessor().Emit((node.Virtual ? OpCodes.Callvirt : OpCodes.Call), node.Method); }
/// <summary> /// Create a new object using the constructor /// </summary> /// <param name="ctor">Constructor method node</param> /// <param name="method"></param> public void EmitNewObj(MethodNode ctor) { GetMethodProcessor().Emit(OpCodes.Newobj, ctor.Method); }
/// <summary> /// Call a virtual method /// </summary> /// <param name="node"></param> /// <param name="method"></param> public void EmitCallVirtual(MethodNode node) { GetMethodProcessor().Emit(OpCodes.Callvirt, node.Method); }