/// <summary> /// Create the appropriate element and the appropriate quantifier /// </summary> /// <param name="Item">The elemen to compile</param> /// <param name="Parent">The parent parsed block</param> /// <param name="Compiled">The parent compiled block</param> private void CompileElement(Parse.Element Item, Parse.Block Parent, Block Compiled) { //Just create a NOP for a null item if (Item == null) { Compiled.AddItem(new NOP()); return; } //Anotate Item's commands if (Output != null) Item.Annotation.CompiledPosition.Begin = Output.Length; _OutIdent++; OutComment(Item.GetType().Name + Item.Quantifier); //Check for quantifier QuantifierBefore qb = null; if (!Item.Quantifier.IsDefault()) { if (Item.Quantifier.IsIfAny()) { //Nothing, just add NOP after } else if (Item.Quantifier.IsAsMany() && !Item.Quantifier.Additive) { //Nothing, just add a ConditionalJump after } else if (Item.Quantifier.IsNever()) { //Nothing, add a Fail and a NOP after } else { qb = new QuantifierBefore(Item.Quantifier); Compiled.AddItem(qb); } } int first_runnable_execution_index = Compiled.Count; //Find item's type if (Item is Parse.Block) { Parse.Block pabl = (Parse.Block)Item; Block bl; //New block if it is unnamed, or get the stub if (pabl.Name == null) bl = new Block(this); else bl = _BlocksByName[pabl.Name]; //Compile it CompileBlock(pabl, bl); //Create a call to the block Compiled.AddItem(new CallBlock(bl.ExecuteBlock)); //Update it's index bl.ExecuteIndex = Compiled.Items[first_runnable_execution_index]; } else if (Item is Parse.TextSearch) CETextSearch((Parse.TextSearch) Item, Parent, Compiled); else if (Item is Parse.Literal) CELiterall((Parse.Literal) Item, Compiled); else if (Item is Parse.Variable) CEVariable((Parse.Variable) Item, Parent, Compiled); else if (Item is Parse.ControlFlow) CEControlFlow((Parse.ControlFlow) Item, Parent, Compiled); else if (Item is Parse.FunctionCall) CEFunctionCall((Parse.FunctionCall) Item, Parent, Compiled); else if (Item is Parse.BinaryOperator) CEBinaryOperator((Parse.BinaryOperator) Item, Parent, Compiled); else { Compiled.AddItem(new NOP()); ThrowParseError("Unkown type " + Item.GetType().Name, Item.Annotation.SourcePosition); } int last_runnable_execute_index = Compiled.Count - 1; //Check for quantifier if (!Item.Quantifier.IsDefault()) { if (Item.Quantifier.IsIfAny()) { //On failure jump here var nop = new NOP(); Compiled.AddItem(nop); //Update Runnables CESetOnJumpFailTo(Compiled, first_runnable_execution_index, last_runnable_execute_index, nop); } else if (Item.Quantifier.IsAsMany() && !Item.Quantifier.Additive) { //On failure jump here var cj = new ConditionalJump(Compiled.Items[first_runnable_execution_index]); Compiled.AddItem(cj); //Update Runnables CESetOnJumpFailTo(Compiled, first_runnable_execution_index, last_runnable_execute_index, cj); } else if (Item.Quantifier.IsNever()) { //Fail if the item succeeds Compiled.AddItem(new ReturnBlock(0, false)); //On failure jump here var nop = new NOP(); Compiled.AddItem(nop); //Update Runnables CESetOnJumpFailTo(Compiled, first_runnable_execution_index, last_runnable_execute_index, nop); } else { //On failure jump here var qa = new QuantifierAfter(qb); Compiled.AddItem(qa); //Update Runnables CESetOnJumpFailTo(Compiled, first_runnable_execution_index, last_runnable_execute_index, qa); } } //Anotate Item's commands if (Output != null) Item.Annotation.CompiledPosition.End = Output.Length; _OutIdent--; Item.Annotation.FirstRunnable = Compiled.Items[first_runnable_execution_index]; Item.Annotation.RunnablesCount = Compiled.Count - first_runnable_execution_index; Item.Annotation.RunnableParentBlock = Compiled.ExecuteBlock; for (int i = first_runnable_execution_index ; i < Compiled.Count ; i++) { var rn = Compiled.Items[i]; if (rn.Annotation.Element == null) { rn.Annotation.Element = Item; rn.Annotation.SourcePosition = Item.Annotation.SourcePosition; rn.Annotation.TreeViewNode = Item.Annotation.TreeViewNode; } } IDE.CompiledAnnotations.Add(Item.Annotation.CompiledPosition, Item.Annotation); }
private void CEVariable(Parse.Variable Item, Parse.Block Parent, Block Compiled) { switch (Item.Type) { case Parse.Variable.eType.Variable: var var_index = Parent.Function.Variables[Item.Name]; var nfv = new NodeFromVariable(var_index); nfv.Name = Item.Name; //Get the inital node Compiled.AddItem(nfv); break; case Parse.Variable.eType.RetVal: //Get the inital node Compiled.AddItem(new NodeFromRetVal()); break; case Parse.Variable.eType.Tree: //Get the inital node Compiled.AddItem(new NodeFromTree()); break; case Parse.Variable.eType.Skipped: //Put Skipped at LastResult Compiled.AddItem(new SkippedToResult()); break; case Parse.Variable.eType.Source: //Put Source at LastResult Compiled.AddItem(new SourceToResult()); break; case Parse.Variable.eType.New: //Create a new TreeRoot Compiled.AddItem(new NodeFromNew()); break; case Parse.Variable.eType.Setting: ThrowParseError("Settings not supported", Item.Annotation.SourcePosition); break; default: ThrowParseError("Unknown type", Item.Annotation.SourcePosition); break; } //Get the nodes if (Item.Nodes.Count > 0) { //Clear any temps that are left var ptc = new PushTemporariesCount(); Compiled.AddItem(ptc); //Check to see if actualy a temp guard is needed bool temp_guard_is_needed = false; foreach (var tn in Item.Nodes) { switch (tn.Type) { case Parse.TreeNode.eType.Normal: if (!(tn.Key is Parse.Literal)) temp_guard_is_needed = true; //Push Result to Temp Compiled.AddItem(new ResultToTemp()); //Get the key CompileElement(tn.Key, Parent, Compiled); //Get the node Compiled.AddItem(new NodeByName(tn.Index, false, tn.Index != -1)); //Search by Value if (tn.Value != null) { if (!(tn.Value is Parse.Literal)) temp_guard_is_needed = true; //Push Result to Temp Compiled.AddItem(new ResultToTemp()); //Get the value CompileElement(tn.Value, Parent, Compiled); //Get the node Compiled.AddItem(new NodeSiblingByValue(tn.ByValueNext, tn.ByValueIgnoreCase)); } break; case Parse.TreeNode.eType.Indexed: //Search by Value if (tn.Value != null) { if (!(tn.Value is Parse.Literal)) temp_guard_is_needed = true; //Push Result to Temp Compiled.AddItem(new ResultToTemp()); //Get the value CompileElement(tn.Value, Parent, Compiled); //Get the node Compiled.AddItem(new NodeSiblingByValue(tn.ByValueNext, tn.ByValueIgnoreCase)); } else //Get by index //Get the node Compiled.AddItem(new NodeSiblingByIndex(tn.Index)); break; case Parse.TreeNode.eType.New: if (tn.Key == null) //Get a new node Compiled.AddItem(new NodeSiblingNew()); else { if (!(tn.Key is Parse.Literal)) temp_guard_is_needed = true; //Push Result to Temp Compiled.AddItem(new ResultToTemp()); //Get the key CompileElement(tn.Key, Parent, Compiled); //Get the node Compiled.AddItem(new NodeByName(tn.Index, true, false)); } break; case Parse.TreeNode.eType.NotNew: if (!(tn.Key is Parse.Literal)) temp_guard_is_needed = true; //Push Result to Temp Compiled.AddItem(new ResultToTemp()); //Get the key CompileElement(tn.Key, Parent, Compiled); //Get the node Compiled.AddItem(new NodeByName(tn.Index, false, true)); break; case Parse.TreeNode.eType.Parent: //Get the node Compiled.AddItem(new NodeParent()); break; case Parse.TreeNode.eType.Next: //Get the node Compiled.AddItem(new NodeSiblingByNeighbour(true)); break; case Parse.TreeNode.eType.Previous: //Get the node Compiled.AddItem(new NodeSiblingByNeighbour(false)); break; case Parse.TreeNode.eType.Value: //Get the text Compiled.AddItem(new NodeValue()); break; case Parse.TreeNode.eType.Name: //Get the name Compiled.AddItem(new NodeName()); break; default: ThrowParseError("Unknown tree type", Item.Annotation.SourcePosition); break; } } if (temp_guard_is_needed) //Clear any temps that are left Compiled.AddItem(new PopClearTemporaries()); else Compiled.RemoveItem(ptc); } }
private void CompileBlock(Parse.Block Item, Block Compiled) { //Don't try to compile it twice if (Compiled.Compiled) return; _BlocksByParse.Add(Item, Compiled); Compiled.Compiled = true; Compiled.ExecuteBlock.Name = Item.Name; //Assembly output _OutIdent++; if (Item.Name != null) OutComment("#" + Item.Name + "#"); else OutComment("(unnamed)"); //Compile elements if (Item.Type == Parse.Block.eType.For) { //Just before the loop increment Runnable forContinue = new NOP(); Compiled.ForContinue = forContinue; //When the initializer or loop increment fail succeed Runnable onInitIncrFail = new ReturnBlock(1, true); //First item of loop's body Runnable loopFirst; //Keep track the first and last runnables of current element int this_exec_begin, this_exec_end; this_exec_begin = Compiled.Count; //Compile the initializer CompileElement(Item.Elements[0], Item, Compiled); this_exec_end = Compiled.Count; //Set the on fail for (int i = this_exec_begin; i < this_exec_end; i++) { var it = Compiled.Items[i]; if (it.OnFailJumpTo == null) it.OnFailJumpTo = onInitIncrFail; } this_exec_begin = Compiled.Count; //Compile the loop body CompileElement(Item.Elements[2], Item, Compiled); loopFirst = Compiled.Items[this_exec_begin]; this_exec_begin = Compiled.Count; //Compile the loop increment Compiled.AddItem(forContinue); CompileElement(Item.Elements[1], Item, Compiled); this_exec_end = Compiled.Count; //Set the on fail for (int i = this_exec_begin; i < this_exec_end; i++) { var it = Compiled.Items[i]; if (it.OnFailJumpTo == null) it.OnFailJumpTo = onInitIncrFail; } //Put the continue command var cont = new GoToBlock(0, 1, new[]{loopFirst}); Compiled.AddItem(cont); //Put the on fail Compiled.AddItem(onInitIncrFail); } else { //Keep track the first and last runnables of current and previous element int this_exec_begin, this_exec_end; int prev_exec_begin = 0, prev_exec_end = 0; Runnable this_exec_first; for (int i = 0; i < Item.Elements.Count; i++) { this_exec_begin = Compiled.Count; //Compile the element CompileElement(Item.Elements[i], Item, Compiled); this_exec_end = Compiled.Count; //Put jumps if it is multi (except on the last part) if ((Item.Type == Parse.Block.eType.Multi)) { //Succeed if (i != (Item.Elements.Count - 1)) Compiled.AddItem(new ReturnBlock(1, true)); this_exec_first = Compiled.Items[this_exec_begin]; //Update elements to jump to next on fail if (i != 0) for (int j = prev_exec_begin; j < prev_exec_end; j++) if (Compiled.Items[j].OnFailJumpTo == null) Compiled.Items[j].OnFailJumpTo = this_exec_first; } prev_exec_begin = this_exec_begin; prev_exec_end = this_exec_end; } } //Move elements to Execute.Block Compiled.Done(); _OutIdent--; }
private void CESetOnJumpFailTo(Block Compiled, int indexFrom, int indexTo, Runnable JumpTarget) { for (var i = indexFrom; i <= indexTo; i++) if (Compiled.Items[i].OnFailJumpTo == null) Compiled.Items[i].OnFailJumpTo = JumpTarget; }
private void CETextSearch(Parse.TextSearch Item, Parse.Block Parent, Block Compiled) { switch (Item.Type) { case Parse.TextSearch.eType.Normal: //Put pattern at LastResult CompileElement(Item.Pattern, Parent, Compiled); //Compiled.AddItem(new TextLiteral(Item.Pattern)); //Match Compiled.AddItem(new TextMatch()); break; case Parse.TextSearch.eType.Find: //Put pattern at LastResult CompileElement(Item.Pattern, Parent, Compiled); //Compiled.AddItem(new TextLiteral(Item.Pattern)); //Match Compiled.AddItem(new TextFind()); break; case Parse.TextSearch.eType.FindReverse: //Put pattern at LastResult CompileElement(Item.Pattern, Parent, Compiled); //Compiled.AddItem(new TextLiteral(Item.Pattern)); //Match Compiled.AddItem(new TextFindReverse()); break; case Parse.TextSearch.eType.RegularExpression: //Match Compiled.AddItem(new TextRegEx(((Parse.Literal) Item.Pattern).Text)); //Check for getting a capture if (Item.Tree.Count > 0) Compiled.AddItem(new TextRegExGetItem(Item.Tree[0].Index)); break; default: ThrowParseError("Unknown type", Item.Annotation.SourcePosition); break; } }
private void CELiterall(Parse.Literal Item, Block Compiled) { switch (Item.Type) { case Parse.Literal.eType.Number: Compiled.AddItem(new NOP()); ThrowParseError("Number literalls are not allowed", Item.Annotation.SourcePosition); break; case Parse.Literal.eType.Text: Compiled.AddItem(new TextLiteral(Item.Text, Item.AssemblyDisplayText)); break; default: Compiled.AddItem(new NOP()); ThrowParseError("Unknown type", Item.Annotation.SourcePosition); break; } }
private void CEFunctionCall(Parse.FunctionCall Item, Parse.Block Parent, Block Compiled) { int first_runnable_execution_index = Compiled.Count; //Clear any temps that are left if (Item.Arguments.Count > 0) Compiled.AddItem(new PushTemporariesCount()); //Get the arguments foreach (var el in Item.Arguments) { //Get the argument CompileElement(el, Parent, Compiled); //Push in temprary Compiled.AddItem(new ResultToTemp()); } //Get the arguments and call the function var tar = Item.Target; if (!Functions.ContainsKey(tar)) { var fun = new Function(tar.ArgumentsCount, tar.Variables.Count, Item.Name); Functions.Add(tar, fun); //Create a unique function name (functions from imports may define same named functions if (IDE.ExecutionTree.Functions.ContainsKey(tar.Name)) { var i = 1; string new_name; do { new_name = string.Format("{0}_{1}", tar.Name, i); i++; } while (IDE.ExecutionTree.Functions.ContainsKey(new_name)); IDE.ExecutionTree.Functions.Add(new_name, fun); } else IDE.ExecutionTree.Functions.Add(tar.Name, fun); //Compile the function ComplileFunction(tar); IDE.CompiledAnnotations.Add(tar.Annotation.CompiledPosition, tar.Annotation); } Compiled.AddItem(new CallFunction(Functions[tar])); int last_runnable_execution_index = Compiled.Count - 1; //Clear any temps that are left if (Item.Arguments.Count > 0) { var ct = new PopClearTemporaries(); Compiled.AddItem(ct); CESetOnJumpFailTo(Compiled, first_runnable_execution_index, last_runnable_execution_index, ct); } }
private void CEControlFlow(Parse.ControlFlow Item, Parse.Block Parent, Block Compiled) { switch (Item.Type) { case Parse.ControlFlow.eType.Call: //A call to a block CompileElement(Item.Target, Parent, Compiled); break; case Parse.ControlFlow.eType.Fail: //Return a number of blocks Compiled.AddItem(new ReturnBlock(Parent.Depth - Item.Target.Depth + (Item.Target.Type == Parse.Block.eType.Multi ? 0 : 1), false)); break; case Parse.ControlFlow.eType.Succeed: //Return a number of blocks Compiled.AddItem(new ReturnBlock(Parent.Depth - Item.Target.Depth + 1, true)); break; case Parse.ControlFlow.eType.GoTo: //GoTo block - if the common parent is the target then return it and run it again var gtb = new GoToBlock(0, 0, null); gtb.TargetName = Item.Target.Name; //We will add the elements index after the compilation - we might not know a block's index (it is not compiled yet) _GoToBackPatches.Add(new GoToBackPatchInfo(Item.Target, Parent, gtb, this)); Compiled.AddItem(gtb); break; case Parse.ControlFlow.eType.Continue: //GoTo block var cont = new GoToBlock(Parent.Depth - Item.Target.Depth, 1, new []{_BlocksByParse[Item.Target].ForContinue}); cont.TargetName = Item.Target.Name; Compiled.AddItem(cont); break; default: ThrowParseError("Unknown type", Item.Annotation.SourcePosition); break; } }
private void CEBinaryOperator(Parse.BinaryOperator Item, Parse.Block Parent, Block Compiled) { //Get left element CompileElement(Item.lhs, Parent, Compiled); //If not pipe then push left and get right element if (Item.Type != Parse.BinaryOperator.eType.Pipe) { //Clear any temps that are left Compiled.AddItem(new PushTemporariesCount()); //Push it to temp Compiled.AddItem(new ResultToTemp()); var first_runnable_execute_index = Compiled.Count; //Get right element CompileElement(Item.rhs, Parent, Compiled); var last_runnable_execute_index = Compiled.Count - 1; //Clear any temps that are left var ct = new PopClearTemporaries(); Compiled.AddItem(ct); CESetOnJumpFailTo(Compiled, first_runnable_execute_index, last_runnable_execute_index, ct); } //Apply operator switch (Item.Type) { case Parse.BinaryOperator.eType.Equal: Compiled.AddItem(new ResultTextEqualTempText(true, Item.IgnoreCase)); break; case Parse.BinaryOperator.eType.NotEqual: Compiled.AddItem(new ResultTextEqualTempText(false, Item.IgnoreCase)); break; case Parse.BinaryOperator.eType.ReferenceEqual: Compiled.AddItem(new ResultNodeEqualTempNode(true)); break; case Parse.BinaryOperator.eType.ReferenceNotEqual: Compiled.AddItem(new ResultNodeEqualTempNode(false)); break; case Parse.BinaryOperator.eType.ReferenceCopy: Compiled.AddItem(new ResultNodeToTempVariable()); break; case Parse.BinaryOperator.eType.TextAppend: Compiled.AddItem(new ResultTextAppendToTempText()); break; case Parse.BinaryOperator.eType.TreeAppend: Compiled.AddItem(new ResultNodeAppendToTempNode()); break; case Parse.BinaryOperator.eType.TildeAppend: Compiled.AddItem(new TempTextAppendToResultNode()); break; case Parse.BinaryOperator.eType.Tilde: Compiled.AddItem(new TempTextToResultNode()); break; case Parse.BinaryOperator.eType.Pipe: //Save Source Compiled.AddItem(new SourceAndSkippedToTemp()); //Change Source Compiled.AddItem(new ResultToSource()); var first_runnable_execute_index = Compiled.Count; //Get right element CompileElement(Item.rhs, Parent, Compiled); var last_runnable_execute_index = Compiled.Count - 1; //Get Source back var tts = new TempToSourceAndSkipped(); Compiled.AddItem(tts); //Get Source back if anything fails CESetOnJumpFailTo(Compiled, first_runnable_execute_index, last_runnable_execute_index, tts); ////Save Source //Compiled.AddItem(new NextToSource()); ////Change source //Compiled.AddItem(new ResultToNext()); ////Get right element //CompileElement(Item.rhs, Parent, Compiled); ////Get source back //Compiled.AddItem(new SourceToNext()); break; default: ThrowParseError("Unknown type", Item.Annotation.SourcePosition); break; } }
/// <summary> /// Append a runnable's info to the assembly output /// </summary> /// <param name="Item"></param> /// <param name="Compiled"></param> internal void OutItem(Runnable Item, Block Compiled) { Item.Annotation.CompiledPosition.Begin = Output.Length; var d = Item.GetDescription(); AppendSyntax(new string(' ', (_OutIdent + 1) * 4) + d.Name, Parse.SyntaxType.eType.Name); if (d.Parameters != null) for (int i = 0 ; i < d.Parameters.Length ; i++) { var it = d.Parameters[i]; if (i == 0) Output.Append(" "); else Output.Append(", "); if (it.Name != null) AppendSyntax(it.Name + ":", Parse.SyntaxType.eType.ArgName); if (it.Value != null) AppendSyntax(it.Value, Parse.SyntaxType.eType.ArgValue); } Output.Append("\r"); Item.Annotation.CompiledPosition.End = Output.Length; Item.Annotation.FirstRunnable = Item; Item.Annotation.RunnablesCount = 1; Item.Annotation.RunnableParentBlock = Compiled.ExecuteBlock; IDE.CompiledAnnotations.Add(Item.Annotation.CompiledPosition, Item.Annotation); }