// Accepts pattersn: // , @method @prose , // , @method , public override PNode evaluate(PNode evaluateMe, PatternMatcher successfulMatch) { PatternMatcher match = successfulMatch; // Extract the "arguments" from the PatternMatcher. List<PNode> M = match.Matching; // The pattern -> prose index from the match MethodNameWord methodWord = (MethodNameWord) M[1].value; List<ProseObject> args; ProseObject terminalPunctuation; // Depending on whether or not our method has arguments. if (successfulMatch.NumObjectsMatched > 3) { args = successfulMatch.getArgumentAsProseAtIndex(2); terminalPunctuation = M[3].value; } else { args = new List<ProseObject>(); terminalPunctuation = M[2].value; } ProseAction action = new MethodDelegateAction(methodWord, args); value = new ProseObject[3]; value[0] = M[0].value; value[1] = action; value[2] = terminalPunctuation; PNode ret = replaceWithValueAt(evaluateMe, successfulMatch); value = null; return ret; }
// Expects the pattern: // // , word[parent] : word[child] , // // Replaces a "parent : child" expression with an action that effects the // word creation/inheritance assertion. //override public override PNode evaluate(PNode evaluateMe, PatternMatcher successfulMatch) { // Extract the "arguments" from the PatternMatcher. List<PNode> M = successfulMatch.Matching; // The pattern -> prose index from the match ProseObject parentObject = M[1].value; ProseObject childObject = M[3].value; // The childObject must be either a word or raw-word. Either way we just use the raw word // data because it will result in looking up the correct word in the end anyway. RawWord[] childObjectRawWords; if (childObject is RawWordObject) { childObjectRawWords = ((RawWordObject) childObject).RawWords; } else if (childObject is Word) { childObjectRawWords = ((Word) childObject).RawWords; } else { throw new RuntimeFailure("WordBindingPhrase passed something other than a word or raw word to bind."); } // Create an action that has the desired effect WordBindingAction action = new WordBindingAction(childObjectRawWords, (Word) parentObject); // Wrap the action in whatever punctuation was present and write the list of objects // we want to substitute into our "value" field. value = new ProseObject[3]; value[0] = M[0].value; // Initial punctuation value[1] = action; // Word binding action value[2] = M[4].value; // Terminal punctuation // Call the super-class to do the substitution. PNode ret = replaceWithValueAt(evaluateMe, successfulMatch); value = null; return ret; }
// // Meant to match: // // @break // public override PNode evaluate(PNode evaluateMe, PatternMatcher successfulMatch) { PatternMatcher match = successfulMatch; // Extract the "arguments" from the PatternMatcher. List<PNode> M = match.Matching; // The pattern -> prose index from the match value = new ProseObject[1]; //value[0] = new BreakPointObject(""); value[0] = new BreakPointObject("# Breakpoint script - \n"); PNode ret = replaceWithValueAt(evaluateMe, successfulMatch); value = null; return ret; }
public override PNode evaluate(PNode evaluateMe, PatternMatcher successfulMatch) { PatternMatcher match = successfulMatch; // Extract the "arguments" from the PatternMatcher. List<PNode> M = match.Matching; // The pattern -> prose index from the match string sourceString = ((StringLiteralObject) M[2].value).literal; ProseAction action = new ReadAction(sourceString); value = new ProseObject[3]; value[0] = M[0].value; value[1] = action; value[2] = M[3].value; PNode ret = replaceWithValueAt(evaluateMe, successfulMatch); value = null; return ret; }
// Expects pattern: contents of text file @string[file_name] public override PNode evaluate(PNode evaluateMe, PatternMatcher successfulMatch) { // Extract the "arguments" from the PatternMatcher. List<PNode> M = successfulMatch.Matching; // The pattern -> prose index from the match string fileName = ((StringLiteralObject) M[4].value).literal; string source = System.IO.File.ReadAllText(fileName); // Wrap the action in whatever punctuation was present and write the list of objects // we want to substitute into our "value" field. value = new ProseObject[1]; value[0] = new StringLiteralObject(source); // Call the super-class to do the substitution. PNode ret = replaceWithValueAt(evaluateMe, successfulMatch); value = null; return ret; }
// Clone the pattern matcher and reconfigure it in a new state based on a word. private PatternMatcher makeCopyWithStateFromAtWord(ProseObject atWord) { PatternMatcher newMatcher = new PatternMatcher(runtime); newMatcher.patternComponentNodes.AddRange(patternComponentNodes); newMatcher.numObjectsMatched = numObjectsMatched; if (currPatternObject != null) { newMatcher.currPatternObject = currPatternObject.clone(); } if (atWord == runtime.@prose) { newMatcher.switchToState_MATCHING_PROSE(); if (parentheticalStack != null) { //newMatcher.parentheticalStack = new Stack<ProseObject>(parentheticalStack); newMatcher.parentheticalStack = new Stack <ProseObject>(); ProseObject[] objs = parentheticalStack.ToArray(); for (int i = objs.Length - 1; i >= 0; i--) { newMatcher.parentheticalStack.Push(objs[i]); } } newMatcher.inText = inText; } else if (atWord == runtime.@text) { newMatcher.switchToState_MATCHING_TEXT(); newMatcher.textMatchingQQcount = textMatchingQQcount; } else if (atWord == runtime.@pattern) { newMatcher.switchToState_MATCHING_PATTERN(); } else { newMatcher.switchToState_MATCHING_OBJECT(); } return(newMatcher); }
public override PNode evaluate(PNode evaluateMe, PatternMatcher successfulMatch) { PatternMatcher match = successfulMatch; // Extract the "arguments" from the PatternMatcher. List<PNode> M = match.Matching; // The pattern -> prose index from the match string dllFileName = ((StringLiteralObject) M[4].value).literal; ProseObject newAssemblyWord = M[6].value; LoadAssemblyAction action = new LoadAssemblyAction(dllFileName, newAssemblyWord); value = new ProseObject[3]; value[0] = M[0].value; value[1] = action; value[2] = M[7].value; PNode ret = replaceWithValueAt(evaluateMe, successfulMatch); value = null; return ret; }
public override PNode evaluate(PNode evaluateMe, PatternMatcher successfulMatch) { PatternMatcher match = successfulMatch; // Extract the "arguments" from the PatternMatcher. List <PNode> M = match.Matching; // The pattern -> prose index from the match string sourceString = ((StringLiteralObject)M[2].value).literal; ProseAction action = new ReadAction(sourceString); value = new ProseObject[3]; value[0] = M[0].value; value[1] = action; value[2] = M[3].value; PNode ret = replaceWithValueAt(evaluateMe, successfulMatch); value = null; return(ret); }
// Expects pattern: contents of text file @string[file_name] public override PNode evaluate(PNode evaluateMe, PatternMatcher successfulMatch) { // Extract the "arguments" from the PatternMatcher. List <PNode> M = successfulMatch.Matching; // The pattern -> prose index from the match string fileName = ((StringLiteralObject)M[4].value).literal; string source = System.IO.File.ReadAllText(fileName); // Wrap the action in whatever punctuation was present and write the list of objects // we want to substitute into our "value" field. value = new ProseObject[1]; value[0] = new StringLiteralObject(source); // Call the super-class to do the substitution. PNode ret = replaceWithValueAt(evaluateMe, successfulMatch); value = null; return(ret); }
public override PNode evaluate(PNode evaluateMe, PatternMatcher successfulMatch) { PatternMatcher match = successfulMatch; // Extract the "arguments" from the PatternMatcher. List <PNode> M = match.Matching; // The pattern -> prose index from the match string dllFileName = ((StringLiteralObject)M[4].value).literal; ProseObject newAssemblyWord = M[6].value; LoadAssemblyAction action = new LoadAssemblyAction(dllFileName, newAssemblyWord); value = new ProseObject[3]; value[0] = M[0].value; value[1] = action; value[2] = M[7].value; PNode ret = replaceWithValueAt(evaluateMe, successfulMatch); value = null; return(ret); }
// Expects pattern: , -> @prose -> , public override PNode evaluate(PNode evaluateMe, PatternMatcher successfulMatch) { // Extract the "arguments" from the PatternMatcher. List<PNode> M = successfulMatch.Matching; // The pattern -> prose index from the match // Create an action that has the desired effect DebugOutputAction action = new DebugOutputAction("dbg", message); // Wrap the action in whatever punctuation was present and write the list of objects // we want to substitute into our "value" field. value = new ProseObject[5]; value[0] = M[0].value; // Initial punctuation value[1] = action; // Word binding action value[2] = M[4].value; // Terminal punctuation value[3] = action; // Word binding action value[4] = M[4].value; // Terminal punctuation // Call the super-class to do the substitution. PNode ret = replaceWithValueAt(evaluateMe, successfulMatch); value = null; return ret; }
public override PNode evaluate(PNode evaluateMe, PatternMatcher successfulMatch) { PatternMatcher match = successfulMatch; // Extract the "arguments" from the PatternMatcher. List<PNode> M = match.Matching; // The pattern -> prose index from the match TypeNameWord typeNameWord = ((TypeNameWord) M[1].value); string methodName = ((StringLiteralObject) M[4].value).literal; RawWord[] newMethodWord; if (M[6].value is RawWordObject) newMethodWord = ((RawWordObject) M[6].value).RawWords; else newMethodWord = ((Word) M[6].value).RawWords; BindMethodAction action = new BindMethodAction(typeNameWord, methodName, newMethodWord); value = new ProseObject[3]; value[0] = M[0].value; value[1] = action; value[2] = M[7].value; PNode ret = replaceWithValueAt(evaluateMe, successfulMatch); value = null; return ret; }
// Expects the pattern: // // , word[parent] : word[child] , // // Replaces a "parent : child" expression with an action that effects the // word creation/inheritance assertion. //override public override PNode evaluate(PNode evaluateMe, PatternMatcher successfulMatch) { // Extract the "arguments" from the PatternMatcher. List <PNode> M = successfulMatch.Matching; // The pattern -> prose index from the match ProseObject parentObject = M[1].value; ProseObject childObject = M[3].value; // The childObject must be either a word or raw-word. Either way we just use the raw word // data because it will result in looking up the correct word in the end anyway. RawWord[] childObjectRawWords; if (childObject is RawWordObject) { childObjectRawWords = ((RawWordObject)childObject).RawWords; } else if (childObject is Word) { childObjectRawWords = ((Word)childObject).RawWords; } else { throw new RuntimeFailure("WordBindingPhrase passed something other than a word or raw word to bind."); } // Create an action that has the desired effect WordBindingAction action = new WordBindingAction(childObjectRawWords, (Word)parentObject); // Wrap the action in whatever punctuation was present and write the list of objects // we want to substitute into our "value" field. value = new ProseObject[3]; value[0] = M[0].value; // Initial punctuation value[1] = action; // Word binding action value[2] = M[4].value; // Terminal punctuation // Call the super-class to do the substitution. PNode ret = replaceWithValueAt(evaluateMe, successfulMatch); value = null; return(ret); }
// Compare matches against each other and throw out matchers which are "dominated" // according to the inheritence system. private List <PatternMatcher> getStrongestMatchesUsingInheritence(List <PatternMatcher> matches) { List <PatternMatcher> betterMatches = new List <PatternMatcher>(); int idx = 0; do { PatternMatcher m = matches[idx]; betterMatches = filterMatchesUsingInheritenceAgainstOneMatcher(matches, m); // If we didn't manage to shorten the list then we got back the exact same list. // So, we have to look at the next spot in that list. if (betterMatches.Count == matches.Count) { idx++; } matches = betterMatches; }while (matches.Count > 1 && matches.Count > idx); return(matches); }
// Expects pattern: , -> @prose -> , public override PNode evaluate(PNode evaluateMe, PatternMatcher successfulMatch) { // Extract the "arguments" from the PatternMatcher. List <PNode> M = successfulMatch.Matching; // The pattern -> prose index from the match // Create an action that has the desired effect DebugOutputAction action = new DebugOutputAction("dbg", message); // Wrap the action in whatever punctuation was present and write the list of objects // we want to substitute into our "value" field. value = new ProseObject[5]; value[0] = M[0].value; // Initial punctuation value[1] = action; // Word binding action value[2] = M[4].value; // Terminal punctuation value[3] = action; // Word binding action value[4] = M[4].value; // Terminal punctuation // Call the super-class to do the substitution. PNode ret = replaceWithValueAt(evaluateMe, successfulMatch); value = null; return(ret); }
// Clone the pattern matcher and reconfigure it in a new state based on a word. private PatternMatcher makeCopyWithStateFromAtWord(ProseObject atWord) { PatternMatcher newMatcher = new PatternMatcher(runtime); newMatcher.patternComponentNodes.AddRange(patternComponentNodes); newMatcher.numObjectsMatched = numObjectsMatched; if (currPatternObject != null) newMatcher.currPatternObject = currPatternObject.clone(); if (atWord == runtime.@prose) { newMatcher.switchToState_MATCHING_PROSE(); if (parentheticalStack != null) { //newMatcher.parentheticalStack = new Stack<ProseObject>(parentheticalStack); newMatcher.parentheticalStack = new Stack<ProseObject>(); ProseObject[] objs = parentheticalStack.ToArray(); for (int i=objs.Length - 1; i >= 0; i--) newMatcher.parentheticalStack.Push(objs[i]); } newMatcher.inText = inText; } else if (atWord == runtime.@text) { newMatcher.switchToState_MATCHING_TEXT(); newMatcher.textMatchingQQcount = textMatchingQQcount; } else if (atWord == runtime.@pattern) { newMatcher.switchToState_MATCHING_PATTERN(); } else { newMatcher.switchToState_MATCHING_OBJECT(); } return newMatcher; }
public PatternMatcherException(string msg, PatternMatcher matcher) : base(msg) { patternMatcher = matcher; }
public static void onMatcherFailure(ProseRuntime runtime, PatternMatcher match) { restoreConsoleColor(); StringBuilder str = new StringBuilder(); ProseObject[] partialPattern = match.AssociatedPattern; foreach(ProseObject po in partialPattern) { str.Append(po.getReadableString()); str.Append(" "); } if (str.Length != 0) str.Remove(str.Length-1, 1); Console.WriteLine("match fail> " + str.ToString()); }
public static void onMatch(ProseRuntime runtime, PatternMatcher match) { restoreConsoleColor(); foreach (Phrase phrase in match.MatchedPhrases) Console.WriteLine("match> " + phrase.getReadableString()); }
private List<PatternMatcher> getSuccessfulMatchesStartingAtPNode(PNode source) { PatternMatcher seedMatcher = new PatternMatcher(this); List<PatternMatcher> activeMatchers = new List<PatternMatcher>(64); activeMatchers.Add(seedMatcher); List<PatternMatcher> successfullMatches = new List<PatternMatcher>(); // Start out looking at the first node in the source. PNode sourceNode = source; // As long as there are still active matchers... while(activeMatchers.Count != 0 && sourceNode != null) { sourceNode = debugFilterIncomingPNode(sourceNode); if (sourceNode == null) break; // If we run into left parenthesis, reduce and eliminate before continuing. while (sourceNode.value == LeftParenthesis) { PNode leftParen = sourceNode; // Reduce the parenthetical bool didReduce; sourceNode = reduceParentheticalExpression(sourceNode, out didReduce, LeftParenthesis, RightParenthesis); // Some matchers may have retained a reference to the leftParen, so swap it for whatever is there now. foreach (PatternMatcher matcher in activeMatchers) { if (matcher.terminatorNode == leftParen) matcher.terminatorNode = sourceNode; } // Refilter the source node sourceNode = debugFilterIncomingPNode(sourceNode); if (sourceNode == null) break; } // Try to extend all of the active matchers. List<PatternMatcher> babyMatchers = new List<PatternMatcher>(256); foreach(PatternMatcher matcher in activeMatchers) { // Try to extend the given matcher and get all the resulting babies. List<PatternMatcher> thisMatchersBabies = matcher.matchNextPNode(sourceNode); int failCount = 0; // Count the baby matchers that arrive dead. foreach (PatternMatcher babyMatcher in thisMatchersBabies) { // if the matcher has found a match, remember it. if (babyMatcher.IsMatched) { // Callback for successful match if (OnMatch != null) OnMatch(this, babyMatcher); successfullMatches.Add(babyMatcher); babyMatchers.Add(babyMatcher); // // Rest the matcher so it can be can be continued // babyMatcher.IsMatched = false; } else if (babyMatcher.IsntFailed) { // Regardless, throw it back in the pot to see if it can be extended //if (babyMatcher.IsntFailed) babyMatchers.Add(babyMatcher); } else { // This baby matcher was stillborn failCount++; } } // If the matcher produced no good children then that branch is "dead" // Only count it as a "fail" if it isn't a success itself. if ( thisMatchersBabies.Count - failCount == 0 && !matcher.IsMatched) { if (OnMatcherFailure != null) OnMatcherFailure(this, matcher); } } // After one generation, the baby matchers become the new active matchers. activeMatchers = babyMatchers; // And now we're looking at the next object in the sequence sourceNode = sourceNode.next; } return successfullMatches; }
bool firstMatcherDominatesSecond(PatternMatcher a, PatternMatcher b) { // Compare their class word first // Compare the associated patterns. // Extract the patterns from a, b. ProseObject[] pa = a.AssociatedPattern; ProseObject[] pb = b.AssociatedPattern; for (int i=0; i < pa.Length; i++) { // Most often they'll be the same and then if (pa[i] == pb[i]) continue; // @prose is weaker than everything else if (pa[i] == @prose && pb[i] != @prose) return false; else if (pa[i] != @prose && pb[i] == @prose) continue; else if (pa[i] == @raw && pb[i] is Word) return false; else if (pa[i] is Word && pb[i] == @raw) continue; Word aword = (Word) pa[i]; List<ProseObject> descendents = aword.getAllDescendents(this); // If there even one piece of b's pattern doesn't descend from a's // then a doesn't dominate. if (!descendents.Contains(pb[i])) return false; } return true; }
// Evaluate a list of prose objects into a new list of prose objects. public PNode replaceWithValueAt(PNode evaluateMe, PatternMatcher match) { // If the phrase only serves to delete the pattern... if (value.Length == 0) { // PNode firstNodeAfterPattern = evaluateMe.forwardSeek(match.NumObjectsMatched); PNode firstNodeAfterPattern = match.terminatorNode; if (evaluateMe.prev != null) evaluateMe.prev.next = firstNodeAfterPattern; firstNodeAfterPattern.prev = evaluateMe.prev; return firstNodeAfterPattern; } // Make a node to write and hook it up the previous part of the list. PNode prevWriteHead = evaluateMe.prev; PNode firstNodeInNewList = new PNode(); PNode writeHead = firstNodeInNewList; prevWriteHead.next = writeHead; foreach (ProseObject obj in value) { // Write a value into it // Argrefs get special treatment. if (obj is ArgRefObject) { // Look up the appropriate argument in "evaluate me" and substitute it. int idx = ((ArgRefObject) obj).reffedArgIndex; //ProseObject evaluated = evaluateMe.forwardSeek(index).value; PNode subStart, subEnd; subStart = match.getArgumentBounds(idx, out subEnd); //TODO This needs to support @prose, @text, and @string. //writeHead.value = evaluated; PNode readHead = subStart; //writeHead.initWithPNode(subStart); while (readHead != subEnd) { // Hook p into the output if (prevWriteHead != null) { prevWriteHead.next = writeHead; } writeHead.prev = prevWriteHead; writeHead.initWithPNode(readHead); // Update prevWriteHead = writeHead; readHead = readHead.next; // Get a new node for the next cycle writeHead = new PNode(); } } else { // Hook this node into the list writeHead.prev = prevWriteHead; if (prevWriteHead != null) prevWriteHead.next = writeHead; writeHead.value = obj; // Grab a new node prevWriteHead = writeHead; writeHead = new PNode(); } } // When we're done, tie the end of the output list back into the input list. // Note: prevWriteHead is actually the last PNode we wrote. if (prevWriteHead != null) { prevWriteHead.next = match.terminatorNode; //prevWriteHead.next = evaluateMe.forwardSeek(match.NumObjectsMatched); if (match.terminatorNode != null) match.terminatorNode.prev = prevWriteHead; } return firstNodeInNewList; }
// Returns 1 if a > b, -1 if a < b, 0 otherwise int compareMatchers(PatternMatcher a, PatternMatcher b) { // These matches represent exactly the same thing. if (a.PhraseTrieNode == b.PhraseTrieNode) { return 0; } if (firstMatcherDominatesSecond(a,b)) { if (firstMatcherDominatesSecond(b, a)) return 0; else return 1; } else { if (firstMatcherDominatesSecond(b,a)) return -1; else return 0; } }
List <PatternMatcher> while_MATCHING_PROSE_matchNextObject(PNode node) { ProseObject obj = node.value; // Return this list of spawned matchers. List <PatternMatcher> babyMatchers = new List <PatternMatcher>(); // Possibly we can make this prose block longer (in addition to other options where we may leave it) bool canExtendThisProseBlock = false; // If we want extend our prose block by adding a right parenthetical, remember to pop the left off the stack. bool shouldPopParentheticalStack = false; // If we stay in this prose block, record if we are entering text or leaving text bool shouldToggleInText = false; // Should we exit to a different mode? bool shouldLeaveMatchingProse = false; MatcherState switchToThisState; // Check for parentheticals // No need to check for () because it's eliminated before we're ever called. if (obj == runtime.LeftCurlyBracket) { canExtendThisProseBlock = true; // Do this in extend //parentheticalStack.Push(runtime.LeftCurlyBracket); } else if (obj == runtime.LeftSquareBracket) { canExtendThisProseBlock = true; // Do this in extend //parentheticalStack.Push(runtime.LeftSquareBracket); } else if (obj == runtime.RightCurlyBracket) { ProseObject matchingParenthetical = tryPeekParenthetical(); if (matchingParenthetical == null || matchingParenthetical != runtime.LeftCurlyBracket) { throw new PatternMatcherException("Right curly bracket wihtout matching left curly bracket inside @prose block.", this); } // At this point, we agree the curly bracket makes sense, so we pop it's counterpart off the stack. shouldPopParentheticalStack = true; canExtendThisProseBlock = true; } else if (obj == runtime.RightSquareBracket) { ProseObject matchingParenthetical = tryPeekParenthetical(); if (matchingParenthetical == null || matchingParenthetical != runtime.LeftSquareBracket) { throw new PatternMatcherException("Right square bracket without matching left square bracket inside @prose block.", this); } // At this point, we agree the square bracket makes sense, so we pop it's counterpart off the stack. shouldPopParentheticalStack = true; canExtendThisProseBlock = true; } else if (obj == runtime.Quadquote) { // In this case, we count that we are in a text block, but we don't "read it as text". Instead, we just // bundle the symbols in with our prose object and pass it along to be interpreted later. if (inText) { ProseObject matchingParenthetical = tryPeekParenthetical(); if (matchingParenthetical == null || matchingParenthetical != runtime.Quadquote) { // The "" didn't match up with a previous one! throw new PatternMatcherException("Quadquote entagled with other parenthetical.", this); } else { canExtendThisProseBlock = true; shouldToggleInText = true; // inText = false; shouldPopParentheticalStack = true; // Pop off the left "" } } else { // In this case, we treat this as an opening quadquote. canExtendThisProseBlock = true; parentheticalStack.Push(runtime.Quadquote); // Remember the left "" shouldToggleInText = true; // inText = true; } } // When the parenthetical stack is empty, we are allowed to exit the prose block if // we can match the next piece of the pattern. else if (parentheticalStack.Count == 0) { // if (obj == runtime.Period) { // // A period ends a "prose" block unless it is protected by {} or [] or "" "" // // The period does not appear in the block. It is interpreted as ending the sentence. // // So exit reading prose // shouldLeaveMatchingProse = true; // //switchToThisState = MatcherState.MATCHING_OBJECT; // //CURSOR // } else { // Use inheritance to look for an exit! // Look up words which would match if they were in a pattern. List <ProseObject> matchingPatternWords = getMatchingPatternWords(obj); // Look these words up to see if actual patterns exist. canExtendThisProseBlock = (matchingPatternWords.Count != 0); foreach (ProseObject match in matchingPatternWords) { // If it's not a period and the attempt to extend @prose immediately failed, // then we continue matching @prose. If the attempt didn't immediately fail then // the rules say we must leave @prose. if (obj == runtime.Period) // && !babyMatcher.IsntFailed) { canExtendThisProseBlock = false; } if (match == runtime.@prose) { continue; // back to back @prose outlawed. } // Look up the match Trie <ProseObject, List <Phrase> > .Node matchNode = currNode.getChildNode(match); if (matchNode == null) { continue; } // If this pattern can be extended by leaving prose, then do it // Spawn a baby matcher to pursue this pattern PatternMatcher babyMatcher = makeCopyWithStateFromAtWord(match); // Clone ourselves babyMatcher.switchToState_MATCHING_OBJECT(); // Move babyMatcher into the generic state (can accept anything) babyMatcher.while_MATCHING_OBJECT_extendWith(node, matchNode); // Append the new node babyMatchers.Add(babyMatcher); // Eventually return this baby matcher // If it's possible to exit an @prose block, the matcher MUST canExtendThisProseBlock = false; } } // In this case the parenthetical stack is not empty and we have some symbol that // isn't parenthetical (or ""). else { // Add it to this prose block canExtendThisProseBlock = true; } // // Perform updates according to flags // if (shouldToggleInText) { inText = !inText; } if (shouldPopParentheticalStack) { parentheticalStack.Pop(); } if (canExtendThisProseBlock) { // Extend ourselves! // NOTE: We don't change the node we're using! PatternMatcher babyMatcher = makeCopyWithStateFromAtWord(runtime.@prose); // Clone ourselves babyMatcher.objectsInCurrentProseblock = objectsInCurrentProseblock; babyMatcher.while_MATCHING_PROSE_extendWith(node, currNode); babyMatchers.Add(babyMatcher); } else if (shouldLeaveMatchingProse) { throw new Exception("Failboat."); // PatternMatcher babyMatcher = makeCopyWithStateFromAtWord(obj); // Clone ourselves // //babyMatcher.switchToState_MATCHING_OBJECT(); // babyMatcher.while_MATCHING_OBJECT_extendWith(node, ); // babyMatchers.Add(babyMatcher); } return(babyMatchers); }
// Read a new object and maybe switch to reading prose, text, or pattern if necessary. List <PatternMatcher> while_MATCHING_OBJECT_matchNextObject(PNode node) { ProseObject obj = node.value; // Some symbols get special treatment at the beginning or end of if (obj == runtime.Period || obj == runtime.Semicolon && currNode == patternTrie.Root) { } // Get a list of words which, if they appeared in a pattern, would match with this one. List <ProseObject> matchingPatternWords = getMatchingPatternWords(obj); // // For each matchingPatternWord, query the pattern tree to see if // our pattern can be extended any further. // List <PatternMatcher> babyMatchers = new List <PatternMatcher>(16); bool foundAMatch = false; //ProseObject myExtensionObject = null; Trie <ProseObject, List <Phrase> > .Node myExtensionNode = null; foreach (ProseObject objMatch in matchingPatternWords) { ProseObject match = objMatch; //Word match = (Word) objMatch; // Look up the node that would correspond to the pattern word that would match. Trie <ProseObject, List <Phrase> > .Node matchNode = currNode.getChildNode(match); // If we can't find it, then there are no patterns with that matching word, so skip it if (matchNode == null) { continue; } // If we can find it, then we might need to make a new matcher // Since ONE match has to be reserved for THIS, and the other matches spawn new matchers, // we use "foundAMatch" to decide which to do. // if (foundAMatch) // { // Spawn off a baby matcher and transform its state to represent the new possibility. PatternMatcher babyMatcher = this.makeCopyWithStateFromAtWord(match); babyMatcher.while_MATCHING_OBJECT_extendWith(node, matchNode); babyMatchers.Add(babyMatcher); // List this baby matcher foundAMatch = true; // } // else { // // Cache these two so we can use them later. // myExtensionObject = match; // myExtensionNode = matchNode; // foundAMatch = true; // } } // If we found at least one, then we need to tweak ourselves and add ourselves to the babies. // if (foundAMatch) { // this.while_MATCHING_OBJECT_extendWith(node, myExtensionNode); // babyMatchers.Add(this); // } // else { // state = MatcherState.FAILED; // } if (!foundAMatch) { state = MatcherState.FAILED; } return(babyMatchers); }
List <PatternMatcher> while_MATCHING_PATTERN_matchNextObject(PNode node) { List <PatternMatcher> babyMatchers = new List <PatternMatcher>(); ProseObject obj = node.value; // @Pattern won't match periods if (obj == runtime.Period) { return(babyMatchers); } // switch (bracketReaderCount) { case 0: // Check to see if obj is -> :+ or :- if (obj == runtime.RightArrow || obj == runtime.ColonPlus || obj == runtime.ColonMinus) { // If so, then we have to leave matching. See if anything is checking for this symbol Trie <ProseObject, List <Phrase> > .Node childNode = currNode.getChildNode(obj); if (childNode != null) { PatternMatcher babyMatcher = makeCopyWithStateFromAtWord(obj); // Clone ourselves babyMatcher.while_MATCHING_OBJECT_extendWith(node, childNode); babyMatchers.Add(babyMatcher); } } else if (obj == runtime.Period || !(obj is Word)) { return(babyMatchers); } else { PatternMatcher babyMatcher = makeCopyWithStateFromAtWord(runtime.@pattern); babyMatcher.while_MATCHING_PATTERN_extendWith(node, currNode); // Use same node if (babyMatcher.IsntFailed) { babyMatchers.Add(babyMatcher); } } break; case 1: { // In this case, just trust while_..._extendWith to do the right thing. PatternMatcher babyMatcher = makeCopyWithStateFromAtWord(runtime.@pattern); babyMatcher.bracketReaderCount = bracketReaderCount; babyMatcher.while_MATCHING_PATTERN_extendWith(node, currNode); // Use same node if (babyMatcher.IsntFailed) { babyMatchers.Add(babyMatcher); } break; } } return(babyMatchers); }
private List <PatternMatcher> getSuccessfulMatchesStartingAtPNode(PNode source) { PatternMatcher seedMatcher = new PatternMatcher(this); List <PatternMatcher> activeMatchers = new List <PatternMatcher>(64); activeMatchers.Add(seedMatcher); List <PatternMatcher> successfullMatches = new List <PatternMatcher>(); // Start out looking at the first node in the source. PNode sourceNode = source; // As long as there are still active matchers... while (activeMatchers.Count != 0 && sourceNode != null) { sourceNode = debugFilterIncomingPNode(sourceNode); if (sourceNode == null) { break; } // If we run into left parenthesis, reduce and eliminate before continuing. while (sourceNode.value == LeftParenthesis) { PNode leftParen = sourceNode; // Reduce the parenthetical bool didReduce; sourceNode = reduceParentheticalExpression(sourceNode, out didReduce, LeftParenthesis, RightParenthesis); // Some matchers may have retained a reference to the leftParen, so swap it for whatever is there now. foreach (PatternMatcher matcher in activeMatchers) { if (matcher.terminatorNode == leftParen) { matcher.terminatorNode = sourceNode; } } // Refilter the source node sourceNode = debugFilterIncomingPNode(sourceNode); if (sourceNode == null) { break; } } // Try to extend all of the active matchers. List <PatternMatcher> babyMatchers = new List <PatternMatcher>(256); foreach (PatternMatcher matcher in activeMatchers) { // Try to extend the given matcher and get all the resulting babies. List <PatternMatcher> thisMatchersBabies = matcher.matchNextPNode(sourceNode); int failCount = 0; // Count the baby matchers that arrive dead. foreach (PatternMatcher babyMatcher in thisMatchersBabies) { // if the matcher has found a match, remember it. if (babyMatcher.IsMatched) { // Callback for successful match if (OnMatch != null) { OnMatch(this, babyMatcher); } successfullMatches.Add(babyMatcher); babyMatchers.Add(babyMatcher); // // Rest the matcher so it can be can be continued // babyMatcher.IsMatched = false; } else if (babyMatcher.IsntFailed) { // Regardless, throw it back in the pot to see if it can be extended //if (babyMatcher.IsntFailed) babyMatchers.Add(babyMatcher); } else { // This baby matcher was stillborn failCount++; } } // If the matcher produced no good children then that branch is "dead" // Only count it as a "fail" if it isn't a success itself. if (thisMatchersBabies.Count - failCount == 0 && !matcher.IsMatched) { if (OnMatcherFailure != null) { OnMatcherFailure(this, matcher); } } } // After one generation, the baby matchers become the new active matchers. activeMatchers = babyMatchers; // And now we're looking at the next object in the sequence sourceNode = sourceNode.next; } return(successfullMatches); }
// Take a pass through the list and throw out everything that loses against m. private List <PatternMatcher> filterMatchesUsingInheritenceAgainstOneMatcher(List <PatternMatcher> matches, PatternMatcher m) { List <PatternMatcher> winners = new List <PatternMatcher>(); foreach (PatternMatcher match in matches) { int res = compareMatchers(m, match); // As long as it isn't a clear victory for m we keep match if (res != 1) { winners.Add(match); } } return(winners); }
public override PNode evaluate(PNode evaluateMe, PatternMatcher successfulMatch) { PatternMatcher match = successfulMatch; // Create the phrase represented by the user's code // Extract the pattern from the match ProseObject[] pattern = match.CurrPatternObject.Pattern; ProseObject[] argNames = match.CurrPatternObject.elementNames.ToArray(); // Create a value[] array for the new phrase ProseObject[] pvalue = match.getArgumentAsProseAtIndex(5).ToArray(); // Go through and make substitutions for the arguments PatternObject po = match.CurrPatternObject; for (int i = 0; i < po.Length; i++) { ProseObject argName = po.elementNames[i]; if (argName == null) { continue; } // If we actually have an argument name, then scan through // the value array and replace instances of that variable name // with ArgRefObjects. for (int j = 0; j < pvalue.Length; j++) { if (pvalue[j] == argName) { // Replace this object with a reference to the pattern. pvalue[j] = new ArgRefObject(i); } } } // Follow rules regarding , ; . // 1. When matching these on the beginning or end of a pattern, they automatically // generate ArgRefObjects on the beginning/end of the corresponding value. This // means punctuation never gets downgraded. // 2. Shouldn't allow stronger punctuation on the inside than on the outside, but // this is a little tougher to check. ProseRuntime runtime = successfulMatch.Runtime; if (pattern[0] == runtime.Comma || pattern[0] == runtime.Semicolon) { // Add a ref to the beginning ProseObject[] newValue = new ProseObject[pvalue.Length + 1]; Array.Copy(pvalue, 0, newValue, 1, pvalue.Length); newValue[0] = new ArgRefObject(0); pvalue = newValue; } int patternEnd = pattern.Length - 1; if (pattern[patternEnd] == runtime.Comma || pattern[patternEnd] == runtime.Semicolon) { // Add a ref to the beginning ProseObject[] newValue = new ProseObject[pvalue.Length + 1]; Array.Copy(pvalue, 0, newValue, 0, pvalue.Length); newValue[pvalue.Length] = new ArgRefObject(patternEnd); pvalue = newValue; } // Create a simple phrase from these ingredients SimplePhrase newPhrase = new SimplePhrase(match.Matching[1].value, pattern, argNames, pvalue); // Extract the "arguments" from the PatternMatcher. List <PNode> M = successfulMatch.Matching; // The pattern -> prose index from the match value = new ProseObject[3]; value[0] = M[0].value; value[1] = new ExclusivePhraseBindingAction(newPhrase); value[2] = M[6].value; PNode ret = replaceWithValueAt(evaluateMe, successfulMatch); value = null; return(ret); }
// Take a pass through the list and throw out everything that loses against m. private List<PatternMatcher> filterMatchesUsingInheritenceAgainstOneMatcher(List<PatternMatcher> matches, PatternMatcher m) { List<PatternMatcher> winners = new List<PatternMatcher>(); foreach (PatternMatcher match in matches) { int res = compareMatchers(m, match); // As long as it isn't a clear victory for m we keep match if (res != 1) { winners.Add(match); } } return winners; }
public virtual PNode evaluate(PNode evaluateMe, PatternMatcher match) { return(replaceWithValueAt(evaluateMe, match)); }
public virtual PNode evaluate(PNode evaluateMe, PatternMatcher match) { return replaceWithValueAt(evaluateMe, match); }
// Match must start at the beginning private PNode reduceSentenceFragmentStartingAtBeginning(PNode source, out bool didReduce) { // Create a matcher // While there are still "matchers in progress" // Feed each PNode in the source to each matcher in progress. // If the matcher indicats it is done then // Ask for it's list of best matches. // Add that list to the complete list of best matches. // Remove the completed matcher from the list of matchers in progress. // Otherwise, // Add the list of child matchers it returns to the list of matchers in progress List <PatternMatcher> matches = getSuccessfulMatchesStartingAtPNode(source); // Get the matches List <PatternMatcher> bestMatches = getStrongestMatchesFromMatchList(matches); // Select the winners // Deal with ambiguity (too many matches) if (bestMatches.Count > 1 || bestMatches.Count == 1 && bestMatches[0].MatchedPhrases.Count > 1) { didReduce = false; // Make an ambiguity callback and throw an exception to bail out of this mess. if (OnAmbiguity != null) { OnAmbiguity(this, source, bestMatches); throw new RuntimeProseLanguageException("Sentence is ambiguous.", source); } else { throw new RuntimeProseLanguageException("Sentence is ambiguous.", source); } } else if (bestMatches.Count == 0) { // We couldn't reduce anything didReduce = false; return(source); } // Apply the phrase PatternMatcher bestMatcher = bestMatches[0]; Phrase bestPhrase = bestMatcher.MatchedPhrases[0]; didReduce = true; // Do any automatic casting necessary to make the arguments match the pattern. bestMatcher.autoCastArguments(); if (BeforeReduction != null) { BeforeReduction(this, source); } // REDUCE! PNode reducedSource = bestPhrase.evaluate(source, bestMatcher); if (AfterReduction != null) { AfterReduction(this, reducedSource); } return(reducedSource); }
// Evaluate a list of prose objects into a new list of prose objects. public PNode replaceWithValueAt(PNode evaluateMe, PatternMatcher match) { // If the phrase only serves to delete the pattern... if (value.Length == 0) { // PNode firstNodeAfterPattern = evaluateMe.forwardSeek(match.NumObjectsMatched); PNode firstNodeAfterPattern = match.terminatorNode; if (evaluateMe.prev != null) { evaluateMe.prev.next = firstNodeAfterPattern; } firstNodeAfterPattern.prev = evaluateMe.prev; return(firstNodeAfterPattern); } // Make a node to write and hook it up the previous part of the list. PNode prevWriteHead = evaluateMe.prev; PNode firstNodeInNewList = new PNode(); PNode writeHead = firstNodeInNewList; prevWriteHead.next = writeHead; foreach (ProseObject obj in value) { // Write a value into it // Argrefs get special treatment. if (obj is ArgRefObject) { // Look up the appropriate argument in "evaluate me" and substitute it. int idx = ((ArgRefObject)obj).reffedArgIndex; //ProseObject evaluated = evaluateMe.forwardSeek(index).value; PNode subStart, subEnd; subStart = match.getArgumentBounds(idx, out subEnd); //TODO This needs to support @prose, @text, and @string. //writeHead.value = evaluated; PNode readHead = subStart; //writeHead.initWithPNode(subStart); while (readHead != subEnd) { // Hook p into the output if (prevWriteHead != null) { prevWriteHead.next = writeHead; } writeHead.prev = prevWriteHead; writeHead.initWithPNode(readHead); // Update prevWriteHead = writeHead; readHead = readHead.next; // Get a new node for the next cycle writeHead = new PNode(); } } else { // Hook this node into the list writeHead.prev = prevWriteHead; if (prevWriteHead != null) { prevWriteHead.next = writeHead; } writeHead.value = obj; // Grab a new node prevWriteHead = writeHead; writeHead = new PNode(); } } // When we're done, tie the end of the output list back into the input list. // Note: prevWriteHead is actually the last PNode we wrote. if (prevWriteHead != null) { prevWriteHead.next = match.terminatorNode; //prevWriteHead.next = evaluateMe.forwardSeek(match.NumObjectsMatched); if (match.terminatorNode != null) { match.terminatorNode.prev = prevWriteHead; } } return(firstNodeInNewList); }
public override PNode evaluate(PNode evaluateMe, PatternMatcher successfulMatch) { PatternMatcher match = successfulMatch; // Create the phrase represented by the user's code // Extract the pattern from the match ProseObject[] pattern = match.CurrPatternObject.Pattern; ProseObject[] argNames = match.CurrPatternObject.elementNames.ToArray(); // Create a value[] array for the new phrase ProseObject[] pvalue = match.getArgumentAsProseAtIndex(5).ToArray(); // Go through and make substitutions for the arguments PatternObject po = match.CurrPatternObject; for(int i=0; i < po.Length; i++) { ProseObject argName = po.elementNames[i]; if (argName == null) continue; // If we actually have an argument name, then scan through // the value array and replace instances of that variable name // with ArgRefObjects. for(int j=0; j < pvalue.Length; j++) { if (pvalue[j] == argName) { // Replace this object with a reference to the pattern. pvalue[j] = new ArgRefObject(i); } } } // Follow rules regarding , ; . // 1. When matching these on the beginning or end of a pattern, they automatically // generate ArgRefObjects on the beginning/end of the corresponding value. This // means punctuation never gets downgraded. // 2. Shouldn't allow stronger punctuation on the inside than on the outside, but // this is a little tougher to check. ProseRuntime runtime = successfulMatch.Runtime; if (pattern[0] == runtime.Comma || pattern[0] == runtime.Semicolon) { // Add a ref to the beginning ProseObject[] newValue = new ProseObject[pvalue.Length + 1]; Array.Copy(pvalue, 0, newValue, 1, pvalue.Length); newValue[0] = new ArgRefObject(0); pvalue = newValue; } int patternEnd = pattern.Length - 1; if (pattern[patternEnd] == runtime.Comma || pattern[patternEnd] == runtime.Semicolon) { // Add a ref to the beginning ProseObject[] newValue = new ProseObject[pvalue.Length + 1]; Array.Copy(pvalue, 0, newValue, 0, pvalue.Length); newValue[pvalue.Length] = new ArgRefObject(patternEnd); pvalue = newValue; } // Create a simple phrase from these ingredients SimplePhrase newPhrase = new SimplePhrase(match.Matching[1].value, pattern, argNames, pvalue); // Extract the "arguments" from the PatternMatcher. List<PNode> M = successfulMatch.Matching; // The pattern -> prose index from the match value = new ProseObject[3]; value[0] = M[0].value; value[1] = new ExclusivePhraseBindingAction(newPhrase); value[2] = M[6].value; PNode ret = replaceWithValueAt(evaluateMe, successfulMatch); value = null; return ret; }