/// <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; }
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)); }
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>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>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>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 known keyword fragment into the given method.</summary> /// <param name="kwd">The known keyword fragment. return, using, break or continue.</param> /// <param name="method">The method to compile the fragment into.</param> /// <returns>A compiled instruction of the given keyword.</returns> public static CompiledFragment Compile(VariableFragment kwd,CompiledMethod method){ OperationFragment parent=(OperationFragment)kwd.ParentFragment; switch(kwd.Value){ case "return": if(kwd.PreviousChild!=null){ kwd.Error("Return cannot follow other operations. You might have a missing ;."); } kwd.Remove(); ReturnOperation returnOperation=new ReturnOperation(method); if(parent.FirstChild!=null){ if((returnOperation.Input0=parent.Compile(method))==null){ return null; } } parent.FirstChild=returnOperation; return returnOperation; case "typeof": if(kwd.PreviousChild!=null){ kwd.Error("Typeof cannot follow other operations. You might have a missing ;."); } kwd.Remove(); TypeofOperation tOperation=new TypeofOperation(method); if(parent.FirstChild==null){ kwd.Error("typeof command is missing the thing to find the type of."); } if((tOperation.Input0=parent.Compile(method))==null){ return null; } parent.FirstChild=tOperation; return tOperation; case "using": if(kwd.PreviousChild!=null){ kwd.Error("Using cannot follow other operations. You might be missing a ;."); } kwd.Remove(); if(parent.FirstChild!=null){ method.Script.AddReference(parent.FirstChild); } return null; case "break": kwd.Remove(); BreakOperation breakOperation=new BreakOperation(method,1); if(parent.FirstChild!=null){ CompiledFragment cf=parent.Compile(method); if(cf.Value!=null&&cf.Value.GetType()==typeof(int)){ breakOperation.Depth=(int)cf.Value; if(breakOperation.Depth<=0){ parent.Error("Break operations must be greater than 0 loops."); } }else{ parent.Error("Break statements can only be followed by a fixed integer constant, e.g. break 2; or just break;"); } } parent.FirstChild=breakOperation; return breakOperation; case "continue": kwd.Remove(); ContinueOperation cOperation=new ContinueOperation(method,1); if(parent.FirstChild!=null){ CompiledFragment cf=parent.Compile(method); if(cf.Value!=null&&cf.Value.GetType()==typeof(int)){ cOperation.Depth=(int)cf.Value; if(cOperation.Depth<=0){ parent.Error("Continue operations must be greater than 0 loops."); } }else{ parent.Error("Continue statements can only be followed by a fixed integer constant, e.g. continue 2; or just continue;"); } } parent.FirstChild=cOperation; return cOperation; default: parent.Error("Unrecognised keyword: "+kwd.Value); return null; } }
/// <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 a known keyword fragment into the given method.</summary> /// <param name="kwd">The known keyword fragment. return, using, break or continue.</param> /// <param name="method">The method to compile the fragment into.</param> /// <returns>A compiled instruction of the given keyword.</returns> public static CompiledFragment Compile(VariableFragment kwd, CompiledMethod method) { OperationFragment parent = (OperationFragment)kwd.ParentFragment; switch (kwd.Value) { case "return": if (kwd.PreviousChild != null) { kwd.Error("Return cannot follow other operations. You might have a missing ;."); } kwd.Remove(); ReturnOperation returnOperation = new ReturnOperation(method); if (parent.FirstChild != null) { if ((returnOperation.Input0 = parent.Compile(method)) == null) { return(null); } } parent.FirstChild = returnOperation; return(returnOperation); case "typeof": if (kwd.PreviousChild != null) { kwd.Error("Typeof cannot follow other operations. You might have a missing ;."); } kwd.Remove(); TypeofOperation tOperation = new TypeofOperation(method); if (parent.FirstChild == null) { kwd.Error("typeof command is missing the thing to find the type of."); } if ((tOperation.Input0 = parent.Compile(method)) == null) { return(null); } parent.FirstChild = tOperation; return(tOperation); case "using": if (kwd.PreviousChild != null) { kwd.Error("Using cannot follow other operations. You might be missing a ;."); } kwd.Remove(); if (parent.FirstChild != null) { method.Script.AddReference(parent.FirstChild); } return(null); case "break": kwd.Remove(); BreakOperation breakOperation = new BreakOperation(method, 1); if (parent.FirstChild != null) { CompiledFragment cf = parent.Compile(method); if (cf.Value != null && cf.Value.GetType() == typeof(int)) { breakOperation.Depth = (int)cf.Value; if (breakOperation.Depth <= 0) { parent.Error("Break operations must be greater than 0 loops."); } } else { parent.Error("Break statements can only be followed by a fixed integer constant, e.g. break 2; or just break;"); } } parent.FirstChild = breakOperation; return(breakOperation); case "continue": kwd.Remove(); ContinueOperation cOperation = new ContinueOperation(method, 1); if (parent.FirstChild != null) { CompiledFragment cf = parent.Compile(method); if (cf.Value != null && cf.Value.GetType() == typeof(int)) { cOperation.Depth = (int)cf.Value; if (cOperation.Depth <= 0) { parent.Error("Continue operations must be greater than 0 loops."); } } else { parent.Error("Continue statements can only be followed by a fixed integer constant, e.g. continue 2; or just continue;"); } } parent.FirstChild = cOperation; return(cOperation); default: parent.Error("Unrecognised keyword: " + kwd.Value); return(null); } }