/// <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 to_a static method for the enum. /// </summary> /// <param name="owner">Owner type</param> private void GenerateEnumToArray(TypeNode owner) { // exclude .ctor, to_s, to_a and ToString var count = owner.Methods.Count - 4; var to_a = FindMethod(owner.Name, "to_a"); // return arr to_a.Body = Expr.CodeBlock( // var arr = new [null as <enum>] * count Expr.Var( "names", Expr.Multiply( Expr.Array( Expr.String() ), Expr.Int(count) ) ), // previous content to_a.Body, Expr.Var( "arr", Expr.Multiply( Expr.Array( Expr.As( Expr.Null(), owner.Name ) ), Expr.Int(count) ) ), // for idx in 0..(count-1) do Expr.For( "idx", Expr.Range( Expr.Int(0), Expr.Int(count-1) ), // arr[idx] = new <enum> idx, names[idx] Expr.ArraySet( Expr.IdentifierGet("arr"), Expr.IdentifierGet("idx"), Expr.New( owner.Name, Expr.IdentifierGet("idx"), Expr.ArrayGet( Expr.IdentifierGet("names"), Expr.IdentifierGet("idx") ) ) ) ), // return arr Expr.Return( Expr.IdentifierGet("arr") ) ); }
/// <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 type instance constructor /// </summary> /// <param name="owner">Owner type node</param> /// <param name="parameters">List of parameters</param> /// <returns></returns> public MethodNode CreateCtor(TypeNode owner, HashList<ParameterNode> parameters = null, bool prepare = false) { return CreateMethod(owner, ".ctor", new SignatureNode("void"), parameters, false, prepare); }
/// <summary> /// Create a type node /// </summary> /// <param name="name">Type name</param> /// <param name="parent">Parent name</param> /// <returns></returns> public TypeNode CreateType(string name, string parent) { // check if type already exists if (RootNode.Types.Contains(name)) throw new CompilerException(String.Format(Resources.errTypeRedefinition, name)); // check if type's parent does not exist if (!RootNode.Types.Contains(parent)) throw new CompilerException(String.Format(Resources.errTypeParentNotFound, name, parent)); // check if the parent type has a default constructor try { FindMethod(parent, ".ctor"); throw new CompilerException(String.Format(Resources.errTypeParentDefaultCtor, parent)); } catch { } // add type to the assembly and Mirelle registry var attribs = TypeAttributes.AnsiClass | TypeAttributes.Public | TypeAttributes.AutoClass; var nativeType = new TypeDefinition("MirelleCompiled", name, attribs, RootNode.Types[parent].Type); Assembly.MainModule.Types.Add(nativeType); var type = new TypeNode(name, parent, false, nativeType); RootNode.Types.Add(name, type); return type; }
/// <summary> /// Create a type node /// </summary> /// <param name="name">Type name</param> /// <returns></returns> public TypeNode CreateType(string name) { // check if type already exists if (RootNode.Types.Contains(name)) throw new CompilerException(String.Format(Resources.errTypeRedefinition, name)); // add type to the assembly var attribs = TypeAttributes.AnsiClass | TypeAttributes.Public | TypeAttributes.AutoClass; var nativeType = new TypeDefinition("MirelleCompiled", name, attribs, Assembly.MainModule.TypeSystem.Object); nativeType.Interfaces.Add(MirelleTypeInterface); Assembly.MainModule.Types.Add(nativeType); var type = new TypeNode(name, "", false, nativeType); RootNode.Types.Add(name, type); return type; }
/// <summary> /// Create type static constructor /// </summary> /// <param name="owner">Owner type node</param> /// <returns></returns> public MethodNode CreateStaticCtor(TypeNode owner, bool prepare = false) { return CreateMethod(owner, ".cctor", new SignatureNode("void"), null, true, prepare); }
/// <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> /// Create field initializer /// </summary> /// <param name="parent">Owner type node</param> /// <returns></returns> public MethodNode CreateInitializer(TypeNode owner, bool prepare = false) { return CreateMethod(owner, ".init", new SignatureNode("void"), null, false, prepare); }
/// <summary> /// Create a field in a type /// </summary> /// <param name="owner">Owner type node</param> /// <param name="name">Field name</param> /// <param name="type">Field type signature</param> /// <param name="isStatic">Static flag</param> /// <returns></returns> public FieldNode CreateField(TypeNode owner, string name, SignatureNode type, bool isStatic = false) { // cut the atmark if(name[0] == '@') name = name.SafeSubstring(1, name.Length - 1); // cannot add fields to built-in types if (owner.BuiltIn) throw new CompilerException(String.Format(Resources.errExtendBuiltInType, owner.Name)); // check if such a field has already been registered if (owner.Fields.Contains(name)) throw new CompilerException(String.Format(Resources.errFieldRedefinition, name, owner.Name)); // create field in Mirelle registry var field = new FieldNode(name, type, isStatic); owner.Fields.Add(name, field); field.Owner = owner; return field; }
/// <summary> /// Create a new value in the enumerable type /// </summary> /// <param name="owner">Owner type</param> /// <param name="name">Value name</param> public void CreateEnumValue(TypeNode owner, string name) { // get the identifier // .ctor and to_s are not counted // while to_a will be added later var value = owner.Methods.Count - 3; // check for redefinition if(owner.Methods.Contains(name)) throw new CompilerException(String.Format(Resources.errEnumRedefinition, name, owner.Name)); // create the method var method = CreateMethod(owner, name, new SignatureNode(owner.Name), null, true); // create a new instance with a separate identifier method.Body = Expr.CodeBlock( Expr.Return( Expr.New( owner.Name, Expr.Int(value), Expr.String(name) ) ) ); // save corresponding info to to_a var to_a = FindMethod(owner.Name, "to_a"); to_a.Body.Statements.Add( Expr.ArraySet( Expr.IdentifierGet("names"), Expr.Int(value), Expr.String(name) ) ); }
/// <summary> /// Import a type from any assembly into Mirelle Registry /// </summary> /// <param name="name">Type name</param> /// <param name="actualType">Type reference</param> /// <param name="parent">Parent type name (must be already imported)</param> /// <returns></returns> public TypeNode ImportType(Type actualType, string name, string parent = "") { // type has already been defined? if (RootNode.Types.Contains(name)) throw new CompilerException(String.Format(Resources.errTypeRedefinition, name)); FindType(parent); // add type to the assembly and Mirelle registry var importedType = AssemblyImport(actualType); var type = new TypeNode(name, parent, true, importedType); RootNode.Types.Add(name, type); return type; }