/// <summary>Creates a new index fragment.</summary> /// <param name="brackets">The brackets which contain the indices.</param> /// <param name="variable">The variable being indexed. This will most commonly be an array.</param> public IndexFragment(CodeFragment brackets,CodeFragment variable){ Brackets=brackets; Variable=variable; // Add them as children such that code tree iterators can visit them: AddChild(Variable); AddChild(Brackets); }
/// <summary>Creates a new method call.</summary> /// <param name="brackets">The brackets containing the arguments for the method.</param> /// <param name="methodName">The name of the method being called.</param> public MethodFragment(BracketFragment brackets,CodeFragment methodName){ Brackets=brackets; MethodName=methodName; // Add them as children such that code tree iterators can visit them: AddChild(Brackets); }
public override AddResult AddTo(CodeFragment to,CodeLexer sr){ if(to.LastChild==null){ Error("A property (."+Value+") was found in an unexpected place."); } // Replace the last child with *THIS*: of=to.LastChild; of.Remove(); to.AddChild(this); return AddResult.Ok; }
public override AddResult AddTo(CodeFragment to,CodeLexer sr){ if(MethodName.GetType()==typeof(VariableFragment)){ VariableFragment vfrag=(VariableFragment)MethodName; if(vfrag.Value=="new"){ CodeFragment p=to.LastChild; if(p==null||p.GetType()!=typeof(VariableFragment)||((VariableFragment)p).Value!="function"){ // Constructor call. vfrag.Remove(); return new ConstructorFragment(vfrag.GivenType,Brackets).AddTo(to,sr); } } } return base.AddTo(to,sr); }
/// <summary>Finds methods within the given fragment by looking for 'function'.</summary> /// <param name="fragment">The fragment to search.</param> public void FindMethods(CodeFragment fragment){ CodeFragment child=fragment.FirstChild; while(child!=null){ CodeFragment next=child.NextChild; if(child.IsParent){ FindMethods(child); } try{ if(child.GetType()==typeof(VariableFragment)){ VariableFragment vfrag=((VariableFragment)child); CodeFragment toRemove=null; string Value=vfrag.Value; if(Value=="function"){ // Found a function. bool isPublic; Modifiers.Handle(vfrag,out isPublic); // The return type could be on the function word (function:String{return "hey!";}) TypeFragment returnType=child.GivenType; toRemove=child; child=child.NextChild; if(child==null){ fragment.Error("Keyword 'function' can't be used on its own."); } toRemove.Remove(); string name=""; bool anonymous=false; BracketFragment parameters=null; if(child.GetType()==typeof(MethodFragment)){ MethodFragment method=(MethodFragment)child; name=((VariableFragment)(method.MethodName)).Value; parameters=method.Brackets; toRemove=child; child=child.NextChild; toRemove.Remove(); returnType=method.GivenType; }else if(child.GetType()==typeof(VariableFragment)){ // Found the name vfrag=(VariableFragment)child; if(vfrag.IsKeyword()){ vfrag.Error("Keywords cannot be used as function names ("+vfrag.Value+")."); } name=vfrag.Value; if(returnType==null){ returnType=child.GivenType; } toRemove=child; child=child.NextChild; toRemove.Remove(); if(child==null){ fragment.Error("Invalid function definition ("+name+"). All brackets are missing or arent valid."); } }else{ anonymous=true; } next=AddFoundMethod(fragment,child,name,anonymous,parameters,returnType,isPublic); } }else if(child.GetType()==typeof(MethodFragment)){ // Looking for anonymous methods ( defined as function() ) MethodFragment method=(MethodFragment)child; if(method.MethodName.GetType()==typeof(VariableFragment)){ VariableFragment methodName=((VariableFragment)(method.MethodName)); string name=methodName.Value; if(name=="function"){ // Found an anonymous function, function():RETURN_TYPE{}. // Note that function{}; is also possible and is handled above. CodeFragment toRemove=child; child=child.NextChild; toRemove.Remove(); next=AddFoundMethod(fragment,child,null,true,method.Brackets,method.GivenType,true); }else if(method.Brackets!=null){ FindMethods(method.Brackets); } }else if(method.Brackets!=null){ FindMethods(method.Brackets); } } }catch(CompilationException e){ if(e.LineNumber==-1 && child!=null){ // Setup line number: e.LineNumber=child.GetLineNumber(); } // Rethrow: throw e; } child=next; } }
/// <summary>Finds properties in the given fragment.</summary> /// <param name="fragment">The fragment to search.</param> public void FindProperties(CodeFragment fragment){ CodeFragment child=fragment.FirstChild; CodeFragment next=null; while(child!=null){ next=child.NextChild; if(child.IsParent){ if(child.GetType()==typeof(OperationFragment)){ try{ // Is it private? Note that if it is, "private" is removed. bool isPublic=!Modifiers.Check(child.FirstChild,"private"); // Grab the property name: CodeFragment propName=child.FirstChild; if(propName==null){ child.Error("This value must be followed by something."); } if(propName.GetType()!=typeof(VariableFragment)){ child.Error("Didn't recognise this as a property. Please note that all code you'd like to run immediately should be inside a function called Start, or in the constructor of a class."); } VariableFragment vfrag=((VariableFragment)child.FirstChild); // These are never local: vfrag.AfterVar=false; string Name=vfrag.Value; if(vfrag.IsKeyword()){ child.Error("Can't use "+Name+" as a property because it's a keyword."); } if(Fields.ContainsKey(Name)){ child.Error(Name+" has been defined twice."); } CodeFragment defaultValue=null; if(vfrag.NextChild==null){ }else if(vfrag.NextChild!=null&&!Types.IsTypeOf(vfrag.NextChild,typeof(OperatorFragment))){ // No type OR default, or the block straight after isn't : or = child.Error(Name+" is missing a type or default value."); }else{ OperatorFragment opFrag=(OperatorFragment)vfrag.NextChild; // It must be a set otherwise it's invalid. if(opFrag.Value==null||opFrag.Value.GetType()!=typeof(OperatorSet)){ child.Error("Invalid default value provided for '"+Name+"'."); } defaultValue=opFrag.NextChild; } DefineField(Name,vfrag,isPublic,defaultValue); child.Remove(); if(defaultValue!=null){ GetInit().CodeBlock.AddChild(child); } }catch(CompilationException e){ if(e.LineNumber==-1 && child!=null){ // Setup line number: e.LineNumber=child.GetLineNumber(); } // Rethrow: throw e; } }else{ FindProperties(child); } } child=next; } }
/// <summary>Checks if the given code fragment is a CompiledFragment.</summary> /// <param name="obj">The fragment to check.</param> /// <returns>True if it is a CompiledFragment; false otherwise.</returns> public static bool IsCompiled(CodeFragment obj){ return IsTypeOf(obj,typeof(CompiledFragment)); }
/// <summary>Retrieves a section of the reference from the given fragment. /// This is required as a reference is likely to be a chain of property fragments which must /// be followed to retrieve the full reference.</summary> /// <param name="usingName">The current fragment to handle.</param> /// <returns>The reference as a string, e.g. 'System.Generics'</returns> private string ParseReference(CodeFragment usingName){ if(usingName==null){ return ""; } Type type=usingName.GetType(); if(type==typeof(VariableFragment)){ // e.g. using System; return ((VariableFragment)usingName).Value; }else if(type==typeof(PropertyFragment)){ // e.g. using System.Generic; // Follow the stack of 'of' until you hit null. PropertyFragment property=((PropertyFragment)usingName); string text=property.Value; string propertyOf=ParseReference(property.of); if(propertyOf!=""){ return propertyOf+"."+text; }else{ return text; } } return ""; }
/// <summary>Reads a new operation from the given lexer.</summary> /// <param name="sr">The lexer to read the operation from.</param> /// <param name="parent">The fragment to parent the operation to.</param> public OperationFragment(CodeLexer sr,CodeFragment parent){ ParentFragment=parent; LineNumber=sr.LineNumber; bool localMode=false; while(true){ char peek=sr.Peek(); if(peek==StringReader.NULL){ return; } if(peek==';'||peek==','){ // Read it off: sr.Read(); return; } Handler handler=Handlers.Find(peek); if(handler==Handler.Stop){ return; } // Handle the fragment: CodeFragment fragment; try{ // Try to get the code fragment: fragment=Handlers.Handle(handler,sr); }catch(CompilationException e){ if(e.LineNumber==-1){ // Setup line number: e.LineNumber=LineNumber; } // Rethrow: throw e; } if(localMode){ // Should always be a VariableFragment: if(fragment.GetType()==typeof(VariableFragment)){ VariableFragment local=(VariableFragment)fragment; local.AfterVar=true; } localMode=false; } // Try adding the fragment to the operation: AddResult status=fragment.AddTo(this,sr); // What was the outcome? switch(status){ case AddResult.Stop: // Halt. return; case AddResult.Local: // Local next: localMode=true; break; // Ok otherwise. } } }
/// <summary>Compiles a set of parameters into an array of compiled fragments.</summary> /// <param name="brackets">The parent block which contains each parameter as a child.</param> /// <param name="parentBlock">The method the parameters are for.</param> /// <returns>A set of compiled fragments.</returns> public static CompiledFragment[] CompileParameters(CodeFragment brackets,CompiledMethod parentBlock){ if(!brackets.IsParent){ return null; } int count=0; brackets.Compile(parentBlock); CodeFragment child=brackets.FirstChild; CompiledFragment[] output=new CompiledFragment[brackets.ChildCount()]; while(child!=null){ CompiledFragment frag=(CompiledFragment)child; if(frag==null){ return null; } output[count]=frag; count++; child=child.NextChild; } return output; }
public override AddResult AddTo(CodeFragment to,CodeLexer sr){ if(Value==""){ return AddResult.Ok; }else if(Value=="var"){ // We're reading a local: return AddResult.Local; }else if(Value=="for" || Value=="while"){ return new ForFragment(sr,Value).AddTo(to,sr); }else if(Value=="switch"){ return new SwitchFragment(sr).AddTo(to,sr); }else if(Value=="if"){ return new IfFragment(sr).AddTo(to,sr); }else if(Value=="else"){ CodeFragment previous=to.ParentFragment; // Parent->prev operation->last object. Should be an IF. if(previous==null||((previous=previous.LastChild)==null)||((previous=previous.LastChild)==null)||previous.GetType()!=typeof(IfFragment)){ Error("Else can only be applied to an if. E.g. if(){}else{}."); } IfFragment ifFrag=(IfFragment)previous; ifFrag.ApplyElseTo.SetIfFalse(new BracketFragment(sr)); return AddResult.Stop; }else if(Value=="elseif"){ CodeFragment previous=to.ParentFragment; // Parent->prev operation->last object. Should be an IF. if(previous==null||((previous=previous.LastChild)==null)||((previous=previous.LastChild)==null)||previous.GetType()!=typeof(IfFragment)){ Error("Else if can only be applied to an if. E.g. if(){}else if{}.."); } IfFragment ifFrag=(IfFragment)previous; IfFragment newfrag=new IfFragment(sr); BracketFragment bf=new BracketFragment(); OperationFragment op=new OperationFragment(); op.AddChild(newfrag); bf.AddChild(op); ifFrag.ApplyElseTo.SetIfFalse(bf); ifFrag.ApplyElseTo=newfrag; return AddResult.Stop; }else{ return base.AddTo(to,sr); } }
public CompiledClass(CodeFragment classFragment, NitroCode script, string name, Type baseType, bool isPublic) { IsPublic = isPublic; StartType(name, script, baseType); ClassFragment = classFragment; }
/// <summary>Finds methods within the given fragment by looking for 'function'.</summary> /// <param name="fragment">The fragment to search.</param> public void FindMethods(CodeFragment fragment) { CodeFragment child = fragment.FirstChild; while (child != null) { CodeFragment next = child.NextChild; if (child.IsParent) { FindMethods(child); } try{ if (child.GetType() == typeof(VariableFragment)) { VariableFragment vfrag = ((VariableFragment)child); CodeFragment toRemove = null; string Value = vfrag.Value; if (Value == "function") { // Found a function. bool isPublic; Modifiers.Handle(vfrag, out isPublic); // The return type could be on the function word (function:String{return "hey!";}) TypeFragment returnType = child.GivenType; toRemove = child; child = child.NextChild; if (child == null) { fragment.Error("Keyword 'function' can't be used on its own."); } toRemove.Remove(); string name = ""; bool anonymous = false; BracketFragment parameters = null; if (child.GetType() == typeof(MethodFragment)) { MethodFragment method = (MethodFragment)child; name = ((VariableFragment)(method.MethodName)).Value; parameters = method.Brackets; toRemove = child; child = child.NextChild; toRemove.Remove(); returnType = method.GivenType; } else if (child.GetType() == typeof(VariableFragment)) { // Found the name vfrag = (VariableFragment)child; if (vfrag.IsKeyword()) { vfrag.Error("Keywords cannot be used as function names (" + vfrag.Value + ")."); } name = vfrag.Value; if (returnType == null) { returnType = child.GivenType; } toRemove = child; child = child.NextChild; toRemove.Remove(); if (child == null) { fragment.Error("Invalid function definition (" + name + "). All brackets are missing or arent valid."); } } else { anonymous = true; } next = AddFoundMethod(fragment, child, name, anonymous, parameters, returnType, isPublic); } } else if (child.GetType() == typeof(MethodFragment)) { // Looking for anonymous methods ( defined as function() ) MethodFragment method = (MethodFragment)child; if (method.MethodName.GetType() == typeof(VariableFragment)) { VariableFragment methodName = ((VariableFragment)(method.MethodName)); string name = methodName.Value; if (name == "function") { // Found an anonymous function, function():RETURN_TYPE{}. // Note that function{}; is also possible and is handled above. CodeFragment toRemove = child; child = child.NextChild; toRemove.Remove(); next = AddFoundMethod(fragment, child, null, true, method.Brackets, method.GivenType, true); } else if (method.Brackets != null) { FindMethods(method.Brackets); } } else if (method.Brackets != null) { FindMethods(method.Brackets); } } }catch (CompilationException e) { if (e.LineNumber == -1 && child != null) { // Setup line number: e.LineNumber = child.GetLineNumber(); } // Rethrow: throw e; } child = next; } }
/// <summary>Checks if the given code fragment is a CompiledFragment.</summary> /// <param name="obj">The fragment to check.</param> /// <returns>True if it is a CompiledFragment; false otherwise.</returns> public static bool IsCompiled(CodeFragment obj) { return(IsTypeOf(obj, typeof(CompiledFragment))); }
/// <summary>Adds a method that was found into this classes set of methods to compile.</summary> /// <param name="fragment">The first fragment of the method, used for generating errors. This gives a valid line number.</param> /// <param name="body">The block of code for this method.</param> /// <param name="name">The name of the method. Null if anonymous is true.</param> /// <param name="anonymous">True if this method is an anonymous one and requires a name.</param> /// <param name="parameters">The set of parameters for this method.</param> /// <param name="returnType">The type that this method returns.</param> /// <param name="isPublic">True if this is a public method; false for private.</param> /// <returns>The first fragment following the method, if there is one.</returns> protected virtual CodeFragment AddFoundMethod(CodeFragment fragment,CodeFragment body,string name,bool anonymous,BracketFragment parameters,TypeFragment returnType,bool isPublic){ if(body==null){ fragment.Error("Invalid function definition ("+name+"). The content block {} is missing or isnt valid."); } if(anonymous){ name="Compiler-Generated-$"+AnonymousCount; AnonymousCount++; } // The following is the explicit code block for this function: BracketFragment codeBlock=(BracketFragment)body; CompiledMethod cMethod=new CompiledMethod(this,name,parameters,codeBlock,returnType,isPublic); MethodOverloads set=MakeOrFind(name,cMethod.Builder.ReturnType); CodeFragment next=body.NextChild; if(anonymous){ CodeFragment newChild=DynamicMethodCompiler.Compile(cMethod,name,set.ReturnType,new ThisOperation(cMethod)); newChild.AddAfter(body); } body.Remove(); set.AddMethod(cMethod); FindMethods(codeBlock); return next; }
public override AddResult AddTo(CodeFragment to, CodeLexer sr) { if (Value == "") { return(AddResult.Ok); } else if (Value == "var") { // We're reading a local: return(AddResult.Local); } else if (Value == "for" || Value == "while") { return(new ForFragment(sr, Value).AddTo(to, sr)); } else if (Value == "switch") { return(new SwitchFragment(sr).AddTo(to, sr)); } else if (Value == "if") { return(new IfFragment(sr).AddTo(to, sr)); } else if (Value == "else") { CodeFragment previous = to.ParentFragment; // Parent->prev operation->last object. Should be an IF. if (previous == null || ((previous = previous.LastChild) == null) || ((previous = previous.LastChild) == null) || previous.GetType() != typeof(IfFragment)) { Error("Else can only be applied to an if. E.g. if(){}else{}."); } IfFragment ifFrag = (IfFragment)previous; ifFrag.ApplyElseTo.SetIfFalse(new BracketFragment(sr)); return(AddResult.Stop); } else if (Value == "elseif") { CodeFragment previous = to.ParentFragment; // Parent->prev operation->last object. Should be an IF. if (previous == null || ((previous = previous.LastChild) == null) || ((previous = previous.LastChild) == null) || previous.GetType() != typeof(IfFragment)) { Error("Else if can only be applied to an if. E.g. if(){}else if{}.."); } IfFragment ifFrag = (IfFragment)previous; IfFragment newfrag = new IfFragment(sr); BracketFragment bf = new BracketFragment(); OperationFragment op = new OperationFragment(); op.AddChild(newfrag); bf.AddChild(op); ifFrag.ApplyElseTo.SetIfFalse(bf); ifFrag.ApplyElseTo = newfrag; return(AddResult.Stop); } else { return(base.AddTo(to, sr)); } }
/// <summary>Adds this code fragment as a child before the given one.</summary> /// <param name="frag">The fragment to add this before.</param> public void AddBefore(CodeFragment frag){ AddAfter(frag); frag.Remove(); frag.AddAfter(this); }
/// <summary>Adds this code fragment as a child after the given one.</summary> /// <param name="frag">The fragment to add this one after.</param> public void AddAfter(CodeFragment frag){ if(frag==null||frag.ParentFragment==null){ // It's not added to anything anyway. return; } ParentFragment=frag.ParentFragment; NextChild=frag.NextChild; if(NextChild!=null){ NextChild.PreviousChild=this; } frag.NextChild=this; PreviousChild=frag; }
/// <summary>Removes this fragment from its parent.</summary> public void Remove(){ if(ParentFragment==null){ return; } if(ParentFragment.FirstChild==this){ ParentFragment.FirstChild=NextChild; } if(ParentFragment.LastChild==this){ ParentFragment.LastChild=PreviousChild; } if(NextChild!=null){ NextChild.PreviousChild=PreviousChild; } if(PreviousChild!=null){ PreviousChild.NextChild=NextChild; } PreviousChild=NextChild=null; }
/// <summary>Adds a reference which is named in the given fragment. Using name; is handled here.</summary> /// <param name="usingName">The fragment containing the reference.</param> public void AddReference(CodeFragment usingName){ string fullName=ParseReference(usingName); if(References==null){ References=new List<CodeReference>(); } // The fullName value is now e.g. 'System.Generics' References.Add(new CodeReference(fullName)); }
/// <summary>Adds the given fragment as a child of this one.</summary> /// <param name="child">The fragment to add as a child.</param> public void AddChild(CodeFragment child){ if(child.GetType()==typeof(OperationFragment) && !child.IsParent){ // Don't add empty operations return; } child.ParentFragment=this; if(FirstChild==null){ FirstChild=LastChild=child; }else{ child.PreviousChild=LastChild; LastChild=LastChild.NextChild=child; } }
/// <summary>Finds all classes within the given code fragment, identified with 'class'.</summary> /// <param name="frag">The fragment to search.</param> private void FindClasses(CodeFragment frag){ CodeFragment child=frag.FirstChild; while(child!=null){ CodeFragment next=child.NextChild; if(child.IsParent){ FindClasses(child); }else if(child.GetType()==typeof(VariableFragment)){ VariableFragment vfrag=(VariableFragment)child; if(vfrag.Value=="class"){ bool isPublic; Modifiers.Handle(vfrag,out isPublic); Type baseType=null; CodeFragment nameBlock=vfrag.NextChild; if(nameBlock==null||nameBlock.GetType()!=typeof(VariableFragment)){ vfrag.Error("Class keyword used but no class name given."); } vfrag.Remove(); vfrag=(VariableFragment)nameBlock; if(vfrag.IsKeyword()){ vfrag.Error("Can't use keywords for class names."); } string name=vfrag.Value; if(Types.ContainsKey(name)){ vfrag.Error("Cannot redefine class "+name+" - it already exists in this scope."); } if(vfrag.GivenType!=null){ baseType=vfrag.GivenType.FindType(this); } if(baseType==null){ baseType=typeof(object); } CodeFragment cblock=vfrag.NextChild; if(cblock==null||cblock.GetType()!=typeof(BracketFragment)){ vfrag.Error("Class "+name+" is missing it's code body. Correct syntax: class "+name+"{ .. }."); } next=cblock.NextChild; vfrag.Remove(); cblock.Remove(); Types.Add(name,new CompiledClass(cblock,this,name,baseType,isPublic)); } } child=next; } }
/// <summary>Adds this fragment as a child to the given fragment. /// It may be overriden by some types of fragment as they may wish to handle it differently.</summary> /// <param name="to">The parent to add this fragment to.</param> /// <param name="sr">The lexer containing the original text code.</param> public virtual AddResult AddTo(CodeFragment to,CodeLexer sr){ to.AddChild(this); return AddResult.Ok; }
public override AddResult AddTo(CodeFragment to,CodeLexer sr){ if(Bracket=='['){ if(to.LastChild==null){ Error("Unexpected indexing. must be something[index]."); }else{ CodeFragment var=to.LastChild; var.Remove(); return new IndexFragment(this,var).AddTo(to,sr); } }else if(Bracket=='{'&&to.LastChild!=null){ // new TYPE[]{default,default..}; if(to.LastChild.GetType()==typeof(VariableFragment)&&((VariableFragment)(to.LastChild)).Value=="new"){ VariableFragment var=(VariableFragment)(to.LastChild); if(var.GivenType==null){ Error("new must always be followed by a type name."); }else if(!var.GivenType.IsArray){ Error("new Type{} only works when Type is an array and curley brackets define it's default values e.g. new int[]{1,2}"); }else{ var.Remove(); return new ArrayFragment(var.GivenType,this).AddTo(to,sr); } } }else if(Bracket=='('&&to.LastChild!=null){ Type type=to.LastChild.GetType(); if(type==typeof(IndexFragment)||type==typeof(PropertyFragment)||(type==typeof(VariableFragment)&&!((VariableFragment)(to.LastChild)).IsKeyword())){ // Method call! CodeFragment meth=to.LastChild; meth.Remove(); return new MethodFragment(this,meth).AddTo(to,sr); } } return base.AddTo(to,sr); }
/// <summary>Adds this code fragment to the beginning of the given parents child set.</summary> /// <param name="parent">The parent to parent this fragment to.</param> public void AddToStart(CodeFragment parent){ if(parent==null){ return; } ParentFragment=parent; if(parent.FirstChild==null){ parent.FirstChild=parent.LastChild=this; }else{ NextChild=parent.FirstChild; parent.FirstChild=NextChild.PreviousChild=this; } }
/// <summary>Looks for base.new in the given fragment.</summary> /// <param name="fragment">The code fragment to look in.</param> /// <returns>True if base.new is in this fragment.</returns> private bool NewBaseCall(CodeFragment fragment){ CodeFragment child=fragment.FirstChild; while(child!=null){ if(child.GetType()==typeof(MethodFragment)){ CodeFragment name=((MethodFragment)child).MethodName; if(name.GetType()==typeof(PropertyFragment) && (((PropertyFragment)name).Value)=="new"){ return true; } }else if(child.IsParent){ if(NewBaseCall(child)){ return true; } } child=child.NextChild; } return false; }
/// <summary>Compiles all operations in a given fragment into executable IL.</summary> /// <param name="fragment">The parent fragment. Most likely represents a pair of brackets.</param> /// <param name="block">The method that the operations represent.</param> /// <returns>True if the block returns something.</returns> public static bool CompileOperations(CodeFragment fragment, CompiledMethod block) { CodeFragment child = fragment.FirstChild; bool returns = false; while (child != null) { if (Types.IsTypeOf(child, typeof(Operation))) { Operation operation = (Operation)child; Type t = operation.GetType(); try{ /* * if(operation.RequiresStoring){ * child.Error("Unexpected operation or value - you must give somewhere to hold the result of this."); * } */ // Add the above operation to the block's IL: operation.OutputIL(block.ILStream); }catch (CompilationException e) { // Setup line number: if (e.LineNumber == -1) { e.LineNumber = operation.LineNumber; } // Rethrow: throw e; } if (t == typeof(MethodOperation)) { Type returnType = (((MethodOperation)operation).MethodToCall).ReturnType; if (returnType != null && returnType != typeof(void)) { // Note this doesn't include (nitro) Void because it's an object as far as .net is concerned! block.ILStream.Emit(OpCodes.Pop); } } returns = (t == typeof(ReturnOperation) || (t == typeof(IfOperation) && ((IfOperation)operation).AllRoutesReturn)); if (returns) { if (child.NextChild != null) { Dom.Log.Add("Warning: Unreachable code detected at line " + child.NextChild.GetLineNumber()); child.NextChild = null; } break; } } child = child.NextChild; } return(returns); }
/// <summary>Defines a new field on this class.</summary> /// <param name="name">The name of the field.</param> /// <param name="type">The type of the value held by this field.</param> /// <returns>A new FieldBuilder.</returns> protected virtual void DefineField(string name,VariableFragment nameFragment,bool isPublic,CodeFragment defaultValue){ Type type=null; if(nameFragment.GivenType!=null){ type=nameFragment.GivenType.FindType(Script); nameFragment.GivenType=null; if(type==null){ nameFragment.Error(name+" has a type that was not recognised."); } }else if(defaultValue!=null){ // Try and compile it: CompiledFragment frag=defaultValue.Compile(GetInit()); // Get the output type: type=frag.OutputType(out frag); } if(type==null){ nameFragment.Error(name+"'s type isn't given. Should be e.g. "+name+":String if it has no default value."); } FieldBuilder field=Builder.DefineField(name,type,isPublic?FieldAttributes.Public:FieldAttributes.Private); Fields[name]=field; }
/// <summary>Compiles an operation fragment into an executable operation. The fragment may contain multiple /// operators and some may even be the same so the furthest right takes priority; 1+2+3 becomes 1+(2+3). /// The compiled fragments are placed back into the same operation fragment. When it's complete, the operation /// will only contain one compiled fragment.</summary> /// <param name="fragment">The operation fragment to compile.</param> /// <param name="parentBlock">The method the operations are compiling into.</param> public static void CompileOperators(OperationFragment fragment, CompiledMethod parentBlock) { CodeFragment child = fragment.FirstChild; OperatorFragment highestPriority = null; while (child != null) { if (child.GetType() == typeof(OperatorFragment)) { OperatorFragment thisOperator = (OperatorFragment)child; // <= below enforces furthest right: if (highestPriority == null || highestPriority.Value.Priority <= thisOperator.Value.Priority) { highestPriority = thisOperator; } } child = child.NextChild; } if (highestPriority == null) { return; } CodeFragment left = highestPriority.PreviousChild; CodeFragment right = highestPriority.NextChild; CodeFragment leftUsed = left; CodeFragment rightUsed = right; if (left == null || left.GetType() == typeof(OperatorFragment)) { leftUsed = null; } else if (!Types.IsCompiled(left)) { leftUsed = left.Compile(parentBlock); } if (right == null || right.GetType() == typeof(OperatorFragment)) { rightUsed = null; } else if (!Types.IsCompiled(right)) { rightUsed = right.Compile(parentBlock); } Operation newFragment = highestPriority.Value.ToOperation((CompiledFragment)leftUsed, (CompiledFragment)rightUsed, parentBlock); if (newFragment == null) { highestPriority.Error("Error: An operator has been used but with nothing to use it on! (It was a '" + highestPriority.Value.Pattern + "')"); } // Replace out Left, Right and the operator itself with the new fragment: highestPriority.Remove(); if (left == null) { newFragment.AddBefore(right); } else { newFragment.AddAfter(left); } if (rightUsed != null) { right.Remove(); } if (leftUsed != null) { left.Remove(); } // And call again to collect the rest: CompileOperators(fragment, parentBlock); }
public CompiledClass(CodeFragment classFragment,NitroCode script,string name,Type baseType,bool isPublic){ IsPublic=isPublic; StartType(name,script,baseType); ClassFragment=classFragment; }
/// <summary>Compiles all operations in a given fragment into executable IL.</summary> /// <param name="fragment">The parent fragment. Most likely represents a pair of brackets.</param> /// <param name="block">The method that the operations represent.</param> /// <returns>True if the block returns something.</returns> public static bool CompileOperations(CodeFragment fragment,CompiledMethod block){ CodeFragment child=fragment.FirstChild; bool returns=false; while(child!=null){ if(Types.IsTypeOf(child,typeof(Operation))){ Operation operation=(Operation)child; Type t=operation.GetType(); try{ if(operation.RequiresStoring){ child.Error("Unexpected operation or value - you must give somewhere to hold the result of this."); } // Add the above operation to the block's IL: operation.OutputIL(block.ILStream); }catch(CompilationException e){ // Setup line number: if(e.LineNumber==-1){ e.LineNumber=operation.LineNumber; } // Rethrow: throw e; } if(t==typeof(MethodOperation)){ Type returnType=(((MethodOperation)operation).MethodToCall).ReturnType; if(returnType!=null && returnType!=typeof(void)){ // Note this doesn't include (nitro) Void because it's an object as far as .net is concerned! block.ILStream.Emit(OpCodes.Pop); } } returns=(t==typeof(ReturnOperation)||(t==typeof(IfOperation)&&((IfOperation)operation).AllRoutesReturn)); if(returns){ if(child.NextChild!=null){ Wrench.Log.Add("Warning: Unreachable code detected at line "+child.NextChild.GetLineNumber()); child.NextChild=null; } break; } } child=child.NextChild; } return returns; }
public override AddResult AddTo(CodeFragment to,CodeLexer sr){ base.AddTo(to,sr); return AddResult.Stop; }
public override AddResult AddTo(CodeFragment to,CodeLexer sr){ if(to.LastChild==null||!to.LastChild.Typeable()){ Error("A type ("+ToString()+") was found in an unexpected place."); } to.LastChild.GivenType=this; return AddResult.Ok; }