/// <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>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>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; } }
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>Globally scopes the given fragment. /// This is like stripping the word 'var' from any discovered properties.</summary> private void GloballyScope(CodeFragment fragment) { CodeFragment child = fragment.FirstChild; while (child != null) { if (child.GetType() == typeof(VariableFragment)) { // It was a variable fragment. VariableFragment variableFragment = child as VariableFragment; // Clear "after var": variableFragment.AfterVar = false; } else if (child.IsParent) { // E.g. this was an OperationFragment. Go into kids: GloballyScope(child); } child = child.NextChild; } }
/// <summary>Loads the parameter block into a set of types.</summary> private void ParseParameters() { if (DefaultParameterValues != null) { DefaultParameterValues = null; Builder.SetParameters(null); } if (ParameterBlock == null || !ParameterBlock.IsParent) { // No inputs anyway, e.g. test(){..} ParametersOk(); return; } // Each of blocks children is an operation segment. ParameterTypes = new Type[ParameterBlock.ChildCount()]; DefaultParameterValues = new CompiledFragment[ParameterTypes.Length]; int index = 0; // For each parameter.. CodeFragment current = ParameterBlock.FirstChild; while (current != null) { if (!current.IsParent) { Error("Invalid function definition input variable found."); } // Default value of this variable (if any). E.g. var1=true,var2.. CompiledFragment DefaultValue = null; CodeFragment inputName = current.FirstChild; if (inputName.GetType() != typeof(VariableFragment)) { Error("Invalid function definition inputs for " + Name + ". Must be (var1:type,var2:type[=a default value],var3:type..). [=..] is optional and can be used for any of the variables."); } string paramName = ((VariableFragment)inputName).Value; if (inputName.NextChild == null) { } else if (inputName.NextChild != null && !Types.IsTypeOf(inputName.NextChild, typeof(OperatorFragment))) { // No type OR default, or the block straight after isn't : or = Error("Invalid function parameters for " + Name + ". '" + paramName + "' is missing a type or default value."); } else { OperatorFragment opFrag = (OperatorFragment)inputName.NextChild; //it must be a set otherwise it's invalid. if (opFrag.Value == null || opFrag.Value.GetType() != typeof(OperatorSet)) { Error("Invalid default function parameter value provided for " + Name + ". '" + paramName + "'."); } current.FirstChild = inputName.NextChild.NextChild; if (!current.IsParent) { Error("Invalid default function definition. Must be (name:type=expr,..)"); } DefaultValue = current.Compile(this); } if (inputName.GivenType != null) { ParameterTypes[index] = inputName.GivenType.FindType(Script); } else if (DefaultValue != null) { ParameterTypes[index] = DefaultValue.OutputType(out DefaultValue); } else { Error("Parameter " + paramName + "'s type isn't given. Should be e.g. (" + paramName + ":String,..)."); } DefaultParameterValues[index] = DefaultValue; if (ParameterSet.ContainsKey(paramName)) { Error("Cant use the same parameter name twice. " + paramName + " in function " + Name + "."); } else if (ParameterTypes[index] == null) { Error("Type not given or invalid for parameter " + paramName + " in function " + Name + "."); } else { ParameterSet.Add(paramName, new ParameterVariable(paramName, ParameterTypes[index])); } current = current.NextChild; index++; } ApplyParameters(); }
/// <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>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 ""; }
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>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>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); }
/// <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; } }