public static PNode new_PNodeList(ProseObject[] objs, out PNode lastNode) { // Create a first object. if (objs.Length == 0) { lastNode = null; return null; } PNode firstNode = new PNode(); firstNode.value = objs[0]; firstNode.prev = null; if (objs.Length == 1) { firstNode.next = null; lastNode = firstNode; return firstNode; } PNode prevNode = firstNode; PNode currNode = null; for (int i=2; i < objs.Length; i++) { currNode = new PNode(); prevNode.next = currNode; currNode.prev = prevNode; currNode.value = objs[i]; prevNode = currNode; } currNode.next = null; lastNode = currNode; return firstNode; }
// 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; }
public PNode(ProseObject[] objs) { debugData = null; this.prev = null; if (objs.Length == 0) { this.value = null; this.next = null; return; } if (objs.Length == 1) { this.value = objs[0]; this.next = null; return; } PNode prevNode = this; PNode currNode = null; for (int i=2; i < objs.Length; i++) { currNode = new PNode(); prevNode.next = currNode; currNode.prev = prevNode; currNode.value = objs[i]; prevNode = currNode; } currNode.next = null; return; }
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 AssemblyNameWord asmbly = ((AssemblyNameWord)M[1].value); string typeName = ((StringLiteralObject)M[4].value).literal; RawWord[] newTypeWord; if (M[6].value is RawWordObject) { newTypeWord = ((RawWordObject)M[6].value).RawWords; } else { newTypeWord = ((Word)M[6].value).RawWords; } BindTypeAction action = new BindTypeAction(asmbly, typeName, newTypeWord); 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 void makeTerminal() { if (next != null) { next.prev = null; } next = null; }
public void makePrevEqualTo(PNode newPrev) { prev = newPrev; if (newPrev != null) { newPrev.next = this; } }
public void makeNextEqualTo(PNode newNext) { next = newNext; if (newNext != null) { newNext.prev = this; } }
// Take a single pattern matcher and actually add the next object and node to it // If the pattern object involves @prose, @text, or @pattern then switch to those states. // This is only called while MATCHING_OBJECT. The @prose, @text, @pattern matching algorithms // do their extensions internally. // private void while_MATCHING_OBJECT_extendWith(ProseObject matchedObject, Trie<ProseObject, List<Phrase>>.Node patternNode) private void while_MATCHING_OBJECT_extendWith(PNode node, Trie <ProseObject, List <Phrase> > .Node patternNode) { // Depending on the contents of patternNode we may need to change state. // If // If we do change state, then re-match ProseObject key = patternNode.getKey(); if (key == runtime.@prose) { // Either this node matches directly with a word in the pattern, or it's the first node in // a match of @prose, @text, @pattern. Either way, it goes in the patternComponentNodes. patternComponentNodes.Add(node); // this.currNode = patternNode; //this.numObjectsMatched++; switchToState_MATCHING_PROSE(); while_MATCHING_PROSE_extendWith(node, patternNode); if (currNode.Value != null && currNode.Value.Count != 0) { becomeMatched(node.next); } } else if (key == runtime.@text) { switchToState_MATCHING_TEXT(); } else if (key == runtime.@pattern) { switchToState_MATCHING_PATTERN(); while_MATCHING_PATTERN_extendWith(node, patternNode); } // A text expression masquerading as a string. else if (key == runtime.@string && node.value == runtime.Quadquote) { switchToState_MATCHING_TEXT(); while_MATCHING_TEXT_extendWith(node, patternNode); } else { // Either this node matches directly with a word in the pattern, or it's the first node in // a match of @prose, @text, @pattern. Either way, it goes in the patternComponentNodes. patternComponentNodes.Add(node); this.currNode = patternNode; this.numObjectsMatched++; // If there's something to match at this node, and we're not entering a // fancy matcher state. Then, having a value at this patternNode is the same // thing as saying, there's a phrase out there that matches US. So we're a match. if (state == MatcherState.MATCHING_OBJECT && patternNode.Value != null && patternNode.Value.Count != 0) { //isMatched = true; becomeMatched(node.next); } } }
public void read(PNode source) { // Read the source one sentence at a time. PNode sourcePtr = source.next.next; // Skip the little header PNode and the inserted . while (sourcePtr != null) { sourcePtr = readSentence(sourcePtr); } }
// public PNode parseTokensIntoPNodes2(ProseRuntime runtime, ProseClient who, List<LexerToken> tokens) // { // // Save the parameters // this.who = who; // this.runtime = runtime; // sourceTokenList = tokens; // // setupForParsing(); // // // // This tracks a word if we're trying to build up a word longer than one rawword // // Trie<RawWord, Word>.Node currWordLookupNode, wordLookupRoot, lastGoodNode; // wordLookupRoot = runtime.getWordLookupRoot(); // currWordLookupNode = wordLookupRoot; // lastGoodNode = null; // // for (LexerToken token = getNextToken(); // token != null; // token = getNextToken()) // { // if (token.rawWord == ProseLanguage.Raw.Quadquote) { // // Output a quadquote // writePNode(new PNode(runtime.Quadquote)); // // Toggle our quad-quote-state. // insideQuadquoteExpression = !insideQuadquoteExpression; // continue; // } // // // if (insideQuadquoteExpression) // { // // Test to see if the raw word is already a word. // // If it is, include that word. // // If it isn't, wrap it as a RawWordObject. // } // else { // switch (token.tokenType) // { // case LexerToken.TYPE.UNCLASSIFIED: // // If we've made no progress looking up any word so far... // if (currWordLookupNode == wordLookupRoot) { // // Is it ia word? // Trie<RawWord, Word>.Node nodeForThisRawWord = currWordLookupNode.getChildNode(token.rawWord); // // // If we didn't find anything at all, then this is a bogus word // if (nodeForThisRawWord == null) // throw new RuntimeLexerSourceException("Unrecognized word or symbol.", token); // // Start searching here // currWordLookupNode = nodeForThisRawWord; // // Is this actually a word? Maybe we're done. // if (currWordLookupNode.Value != null) // { // // If no children, then this HAS to be the word // if (!currWordLookupNode.HasChildren) { // writePNode(new PNode(currWordLookupNode.Value)); // // Reset our search // currWordLookupNode = wordLookupRoot; // Start looking at the bottom // lastGoodNode = null; // We haven't found anything yet. // continue; // } // else { // // This is an acceptable word so cache the node // lastGoodNode = currWordLookupNode; // continue; // } // } // continue; // } // // // If we have made some progress looking up the word // else { // Trie<RawWord, Word>.Node nodeForThisRawWord = currWordLookupNode.getChildNode(token.rawWord); // // If there is no appropriate child, this means that we MUST have found the end of our word already. // if (nodeForThisRawWord == null) // { // // Make sure there's really a word here! // if (currWordLookupNode.Value == null) { // // This is an error // } // } // } // // // Is it an action? // break; // // case LexerToken.TYPE.STRING: // break; // } // } // } // // // // finalCheckAfterParsing(); // return outputRoot; // } private void setupForParsing() { sourceTokens = sourceTokenList.ToArray(); // Setup the output outputRoot = new PNode(); output = outputRoot; insideQuadquoteExpression = false; tokenIdx = 0; }
public PNode forwardSeek(int idx) { int i = 0; PNode currNode = this; for (; i < idx && currNode != null; i++) { currNode = currNode.next; } return(currNode); }
// Reads a sentence from the source and returns the new // begining of the source. // didReduce: Whether or not it actually succeeded in reducing anything. private PNode reduceSentence(PNode source, out bool didReduce) { // We back up the read head to read from the previous terminal symbol. try { return(reduceSentenceFragment(source.prev, out didReduce)); } catch (RuntimeProseLanguageFragmentException e) { // Forward this message and fill in the beginning of the sentence. throw new RuntimeProseLanguageException(e.Message, source); } }
// Do the work of reading the sentence (not threadsafe) private PNode doReadSentence(PNode sourcePtr) { // // If the sentence is just a period, skip it. // if (sourcePtr.value == Period) // return sourcePtr.next; if (OnParseSentence != null) { OnParseSentence(this, sourcePtr.prev); } // Reduce the sentence. bool didReduce; PNode reducedSource = reduceSentence(sourcePtr, out didReduce); // If there are actions on the left, do them. and then try to reduce again. while (true) { bool didSomeActions, sentenceHasBeenExecuted; PNode afterActions = doActionsOnLeftOfSentence(reducedSource, out didSomeActions, out sentenceHasBeenExecuted); if (sentenceHasBeenExecuted) { return(afterActions); } if (didSomeActions) { // If we're at a terminal symbol, then finish, otherwise reduce more. if (afterActions.value == Period) { reducedSource = afterActions; break; } } else if (afterActions == reducedSource) { // If we didn't even do any actions and didn't move over any punctuation then... // If we reduced the sentence and didn't end up with any actions on the left, then // reducing again won't do anything and we have nothing to do. We have to crash. throw new RuntimeProseLanguageException("Sentence reduced to non-actionable code.", reducedSource); } // Try again to reduce the source reducedSource = reduceSentence(afterActions, out didReduce); } // Move the source pointer past the terminal symbol. return(reducedSource.next); }
// Read a text expression and reduce it to a string // textStart = opening "", textEnd = object after closing "" public string parseTextExpressionIntoString(PNode textStart, PNode textEnd) { StringBuilder str = new StringBuilder(); int prevObjSpaceRequest = 0; int thisObjSpaceRequest = 0; for (PNode node = textStart.next; node != null && node.next != textEnd; node = node.next) { ProseObject obj = node.value; // WARNING: MUST COME FIRST BECAUSE IT MAY CHANGE THE VALUE OF node // Left square bracket opens an inline prose expression that must be evaluated if (obj == LeftSquareBracket) { bool didReduce; node = reduceParentheticalExpression(node, out didReduce, LeftSquareBracket, RightSquareBracket); obj = node.value; } // String literals substitute their contents directly if (obj is StringLiteralObject) { str.Append(((StringLiteralObject)obj).literal); thisObjSpaceRequest = -1; } else { if (prevObjSpaceRequest != -1) { str.Append(" "); } str.Append(obj.getReadableString()); thisObjSpaceRequest = 1; } // if (prevObjSpaceRequest != -1 && thisObjSpaceRequest != -1) // str.Append(" "); // Update prevObjSpaceRequest = thisObjSpaceRequest; } if (str[str.Length - 1] == ' ') { str.Remove(str.Length - 1, 1); } return(str.ToString()); }
// Just before public void autoCastArguments() { ProseObject[] pattern = AssociatedPattern; for (int i = 0; i < pattern.Length; i++) { PNode componentStart, componentEnd; componentStart = getArgumentBounds(i, out componentEnd); // Check for auto-formatting of text expression into string // Auto-cast a text expression into a string by evaluating it. if (pattern[i] == runtime.@string && Matching[i].value == runtime.Quadquote) { PNode textStart = componentStart; PNode textEnd = componentEnd; // Create a StringLiteralObject to substitute string textAsString = runtime.parseTextExpressionIntoString(textStart, textEnd); PNode literal = new PNode(new StringLiteralObject(textAsString)); // Splice in this literal literal.prev = textStart.prev; if (textStart.prev != null) { textStart.prev.next = literal; } literal.next = textEnd; if (textEnd != null) { textEnd.prev = literal; } // Correct the match list. Matching[i] = literal; continue; } // Auto-cast a prose expression by unwrapping {} if (pattern[i] == runtime.@prose && componentStart.value == runtime.LeftCurlyBracket && componentEnd.prev.value == runtime.RightCurlyBracket) { PNode leftCurly = componentStart; PNode rightCurly = componentEnd.prev; // Correct the match list Matching[i] = leftCurly.next; // Eliminate the curly brackets leftCurly.removeSelf(); rightCurly.removeSelf(); continue; } } }
// Synchronize calls to "doReadSentence(...)" private PNode readSentence(PNode sourcePtr) { lock (sentenceReaderLock) { PNode val; callDepth++; try { val = doReadSentence(sourcePtr); } finally { callDepth--; } return(val); } }
// // 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 void read(string source, ProseClient who) { // Insert a leading period because the parser expects the previous terminal symbol. source = "." + source + "."; // Apply lexical analysis that requires no knowledge of the runtime words/phrases List <LexerToken> statLexSrc = staticLexer.parseStringIntoTokens(source); // Parse LexerTokens into runtime code. PNode parsedSource = parseTokensIntoPNodes(global_client, statLexSrc); // Debug //Console.WriteLine("After runtime lexer: " + parsedSource.getReadableString() ); read(parsedSource); }
List <PatternMatcher> while_MATCHING_TEXT_matchNextObject(PNode node) { ProseObject obj = node.value; List <PatternMatcher> babyMatchers = new List <PatternMatcher>(); // Extend ourselves! // NOTE: We don't change the node we're using! PatternMatcher babyMatcher = makeCopyWithStateFromAtWord(runtime.@text); // Clone ourselves babyMatcher.while_MATCHING_TEXT_extendWith(node, currNode); babyMatchers.Add(babyMatcher); return(babyMatchers); }
// // 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); }
private PNode debugFilterIncomingPNode(PNode node) { node = filterIncomingPNode(node); bool filterAgain = false; // Determines if we repeatedly apply this. do { if (node == null) { break; } // Check for breakpoints if (node.value is BreakPointObject) { BreakPointObject bp = (BreakPointObject)node.value; BreakPointObject.RuntimeData rtdata = new BreakPointObject.RuntimeData(); // Do any action associated with the breakpoint and make the default callback if asked if (bp.doBreakPoint(this, node, rtdata)) { if (OnBreakPoint != null) { OnBreakPoint(this, node, rtdata, bp.BreakScript); } } // Remove the breakpoint if (node.prev != null) { node.prev.next = node.next; } if (node.next != null) { node.next.prev = node.prev; } filterAgain = true; // Skip over the breakpoint node = node.next; } } while (filterAgain); return(node); }
// 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 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; }
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 string getReadableString() { StringBuilder outStr = new StringBuilder(); PNode p = this; do { if (p.value == null) { p = p.next; continue; } outStr.Append(p.value.getReadableString()); outStr.Append(" "); p = p.next; } while (p != null); outStr.Remove(outStr.Length - 1, 1); return(outStr.ToString()); }
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 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 PNode getArgumentBounds(int idx, out PNode terminator) { // Start at the given index PNode start = patternComponentNodes[idx]; // Slightly differen if asked for the last one. PNode end; if (idx == patternComponentNodes.Count - 1) { end = terminatorNode; } else { end = patternComponentNodes[idx + 1]; } terminator = end; return(start); }
// 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; }
// Possibly translate some incoming nodes public PNode filterIncomingPNode(PNode node) { // Raw nodes get free upgrades to words if the word is defined. if (node.value is RawWordObject) { RawWordObject raw = (RawWordObject)node.value; Word word = global_scope.searchWordFromRawWords(raw.RawWords); // If it's a real word, then upgrade it if (word != null) { PNode newNode = new PNode(word); // Hook up the new word node in place if this raw word node node.prev.next = newNode; newNode.prev = node.prev; node.next.prev = newNode; newNode.next = node.next; return(newNode); } } return(node); }
// 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); }
// 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); }
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; }
public List <ProseObject> getArgumentAsProseAtIndex(int idx) { // Start at the given index PNode start = patternComponentNodes[idx]; // Slightly different if asked for the last one. PNode end; if (idx == patternComponentNodes.Count - 1) { end = terminatorNode; } else { end = patternComponentNodes[idx + 1]; } // NO LONGER NECESSARY // We do this in the autoCast method. // // Auto-unwrapping of {} // if ( start.value == runtime.LeftCurlyBracket // && end.prev.value == runtime.RightCurlyBracket) // { // // If the prose block starts with { and ends with } then throw them out. // start = start.next; // end = end.prev; // } List <ProseObject> proseOut = new List <ProseObject>(12); PNode p = start; while (p != end) { proseOut.Add(p.value); p = p.next; } return(proseOut); }
// Take the current pattern matcher, attempt to extend the match by one object. // Return the list of child matchers spawned. //public List<PatternMatcher> matchNextObject(ProseObject nextObject) public List <PatternMatcher> matchNextPNode(PNode nextNode) { ProseObject obj = nextNode.value; // Create a list of ProseObjects that, if they appeared in a pattern, would match with obj. // For each such object, query the pattern tree to see if our pattern can be extended any further. // If it can be extended further // for each such extension (except the first) // Clone this patternMatcher and then advance that matcher to represent the extension. // Add the new matcher to the output children list // for the first such extension: // Modify this matcher toe represent the extension. // If it can't be extended further // isComplete = true; // You're NEVER allowed to match parenthesis if (obj == runtime.LeftParenthesis || obj == runtime.RightParenthesis) { throw new RuntimeFailure("getListOfMatchingPatternObjects received parenthesis."); } switch (state) { case MatcherState.MATCHING_OBJECT: return(while_MATCHING_OBJECT_matchNextObject(nextNode)); case MatcherState.MATCHING_PROSE: return(while_MATCHING_PROSE_matchNextObject(nextNode)); case MatcherState.MATCHING_TEXT: return(while_MATCHING_TEXT_matchNextObject(nextNode)); case MatcherState.MATCHING_PATTERN: return(while_MATCHING_PATTERN_matchNextObject(nextNode)); } return(null); }
public static PNode new_PNodeList(ProseObject[] objs, out PNode lastNode) { // Create a first object. if (objs.Length == 0) { lastNode = null; return(null); } PNode firstNode = new PNode(); firstNode.value = objs[0]; firstNode.prev = null; if (objs.Length == 1) { firstNode.next = null; lastNode = firstNode; return(firstNode); } PNode prevNode = firstNode; PNode currNode = null; for (int i = 2; i < objs.Length; i++) { currNode = new PNode(); prevNode.next = currNode; currNode.prev = prevNode; currNode.value = objs[i]; prevNode = currNode; } currNode.next = null; lastNode = currNode; return(firstNode); }
static void onAmbiguity(ProseRuntime runtime, PNode source, List<PatternMatcher> matches) { Console.BackgroundColor = ConsoleColor.Yellow; Console.ForegroundColor = ConsoleColor.Black; Console.WriteLine("ambiguity> "); foreach (PatternMatcher match in matches) { foreach (Phrase phrase in match.MatchedPhrases) { Console.WriteLine(phrase.getReadableString()); } } }
// Do the work of reading the sentence (not threadsafe) private PNode doReadSentence(PNode sourcePtr) { // // If the sentence is just a period, skip it. // if (sourcePtr.value == Period) // return sourcePtr.next; if (OnParseSentence != null) OnParseSentence(this, sourcePtr.prev); // Reduce the sentence. bool didReduce; PNode reducedSource = reduceSentence(sourcePtr, out didReduce); // If there are actions on the left, do them. and then try to reduce again. while (true) { bool didSomeActions, sentenceHasBeenExecuted; PNode afterActions = doActionsOnLeftOfSentence(reducedSource, out didSomeActions, out sentenceHasBeenExecuted); if (sentenceHasBeenExecuted) { return afterActions; } if (didSomeActions) { // If we're at a terminal symbol, then finish, otherwise reduce more. if (afterActions.value == Period) { reducedSource = afterActions; break; } } else if (afterActions == reducedSource) { // If we didn't even do any actions and didn't move over any punctuation then... // If we reduced the sentence and didn't end up with any actions on the left, then // reducing again won't do anything and we have nothing to do. We have to crash. throw new RuntimeProseLanguageException("Sentence reduced to non-actionable code.", reducedSource); } // Try again to reduce the source reducedSource = reduceSentence(afterActions, out didReduce); } // Move the source pointer past the terminal symbol. return reducedSource.next; }
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; }
public RuntimeProseLanguageException(string msg, PNode reducedSentence) : base(msg) { beginningOfReducedSentence = reducedSentence; }
// Synchronize calls to "doReadSentence(...)" private PNode readSentence(PNode sourcePtr) { lock(sentenceReaderLock) { PNode val; callDepth++; try { val = doReadSentence(sourcePtr); } finally { callDepth--; } return val; } }
// Overriding instructions: // Return true if you want the runtime to make the standard breakpoint callback. // Return false if you prefer to handle the event yourself in the body of onBreak() public bool onBreak(ProseRuntime runtime, PNode source, BreakPointObject.RuntimeData rtdata) { // Handle the breakpoint in a non-standard way if you want // by putting something in the body of this function. return true; }
public bool doBreakPoint(ProseRuntime runtime, PNode source, BreakPointObject.RuntimeData rtdata) { return onBreak (runtime, source, rtdata); }
private PNode reduceParentheticalExpression(PNode source, out bool didReduce, ProseObject leftParentheticalObject, ProseObject rightParentheticalObject) { // Find the ending parenthesis PNode rightParen = source; for (int parenDepthCount = 0; true; rightParen = rightParen.next) { if (rightParen.value == leftParentheticalObject) { parenDepthCount++; continue; } if (rightParen.value == rightParentheticalObject) { parenDepthCount--; if (parenDepthCount == 0) // We've found the closing right parenthesis break; } } while (rightParen.value != rightParentheticalObject) { rightParen= rightParen.next; } // Unhook the ending parenthesis from the expression we want to reduce. rightParen.prev.next = null; // Reduce the expression (starting AFTER the left paren) bool didReduceParenthetical; PNode reducedExpression; callDepth++; try { reducedExpression= reduceSentenceFragment(source.next, out didReduceParenthetical); } finally { callDepth--; } //We splice it in in two ways depending on whether it reduces to anything or not if (reducedExpression == null) { // If we get nothing back, cut out the parenthesis and continue source.prev.next = rightParen.next; if (rightParen.next != null) rightParen.next.prev = source.prev; reducedExpression = rightParen.next; // The first thing after the paren is what we look at next. } else { // If we get something back, splice it in // Cut out the left paren if (source.prev != null) source.prev.next = reducedExpression; reducedExpression.prev = source.prev; // Hook the end of the expression back into the original source (skipping right paren) // First find the new end PNode reducedExprEnd = reducedExpression; while (reducedExprEnd.next != null) reducedExprEnd = reducedExprEnd.next; reducedExprEnd.next = rightParen.next; if (rightParen.next != null) rightParen.next.prev = reducedExprEnd; } didReduce = didReduceParenthetical; return reducedExpression; }
// Pass null to progress mark to eliminate static void writePrettyProseWithProgressMark(ProseRuntime runtime, PNode start, PNode progressMark, int maxNodesToProcess) { writeStackDepthMarker(runtime); //Stack<ProseObject> parenStack = new Stack<ProseObject>(); int parenCount = 0; int bracketCount = 0; int quadQuoteCount = 0; int periodCount = 0; int nodesProcessed = 0; PNode p = start; do { nodesProcessed++; while (p != null && p.value == null) { p = p.next; } if (p.value == null) { p = p.next; continue; } p = runtime.filterIncomingPNode(p); if (p == null) break; // PROGRESS MARK if (p == progressMark) { Console.BackgroundColor = ConsoleColor.Black; Console.Write (" "); Console.BackgroundColor = ConsoleColor.DarkBlue; Console.Write (" "); Console.BackgroundColor = ConsoleColor.Black; Console.Write (" "); } // Write a leading space Console.BackgroundColor = ConsoleColor.Black; Console.Write(" "); // OBJECTS if (p.value is ProseAction) { Console.BackgroundColor = ConsoleColor.Black; Console.ForegroundColor = ConsoleColor.Green; } else if (p.value == runtime.Comma || p.value == runtime.Semicolon || p.value == runtime.Period) { Console.BackgroundColor = ConsoleColor.Black; Console.ForegroundColor = ConsoleColor.Magenta; } else if (p.value is RawWordObject) { Console.BackgroundColor = ConsoleColor.Black; Console.ForegroundColor = ConsoleColor.Red; } // else if ( p.value == runtime.LefetParenthesis // || p.value == runtime.LeftSquareBracket // || p.value == runtime.LeftCurlyBracket // || p.value == runtime.RightParenthesis // || p.value == r else if ( p.value == runtime.Colon || p.value == runtime.LeftArrow || p.value == runtime.PlusColon || p.value == runtime.MinusColon || p.value == runtime.RightArrow || p.value == runtime.ColonPlus || p.value == runtime.ColonMinus || p.value == runtime.Quadquote) { Console.BackgroundColor = ConsoleColor.Black; Console.ForegroundColor = ConsoleColor.Cyan; } else if ( p.value is AssemblyNameWord || p.value is TypeNameWord || p.value is MethodNameWord) { Console.BackgroundColor = ConsoleColor.Black; Console.ForegroundColor = ConsoleColor.Yellow; } else { Console.BackgroundColor = ConsoleColor.Black; Console.ForegroundColor = ConsoleColor.Gray; } // Inside a text block everything is forced to white unless its in brackets // Deal with different highighting inside of text expressions if (quadQuoteCount % 2 == 1) { if (p.value == runtime.LeftSquareBracket) { bracketCount++; } // Neutralize colors of words that behave as text if (bracketCount == 0) { Console.BackgroundColor = ConsoleColor.Black; Console.ForegroundColor = ConsoleColor.Cyan; } if (p.value == runtime.RightSquareBracket) { bracketCount--; } } if ( p.value == runtime.@break || p.value is BreakPointObject) { Console.BackgroundColor = ConsoleColor.White; Console.ForegroundColor = ConsoleColor.Black; } // Prewrite logic // Write the output // Console.Write(p.value.getReadableString()); // Just so nothing too ugly can go wrong Console.BackgroundColor = ConsoleColor.Black; // Postwrite logic if ( p.value == runtime.RightArrow || p.value == runtime.ColonPlus || p.value == runtime.ColonMinus) { if ( Console.CursorLeft > 60 || Console.CursorLeft + 40 > Console.BufferWidth) { restoreConsoleColor(); Console.WriteLine(); Console.Write (" "); writeStackDepthMarker(runtime); restoreConsoleColor(); Console.Write ("\t\t"); } } // // Other exits // if (nodesProcessed == maxNodesToProcess) break; // // Keep track of parentheticals to know if we can quit // if ( p.value == runtime.LeftParenthesis || p.value == runtime.LeftCurlyBracket || p.value == runtime.LeftSquareBracket) { parenCount++; //parenStack.Push(p.value); } else if ( p.value == runtime.RightParenthesis || p.value == runtime.RightCurlyBracket || p.value == runtime.RightSquareBracket) { parenCount--; } else if (p.value == runtime.Quadquote) { quadQuoteCount++; } else if ( p.value == runtime.Period && parenCount == 0 && quadQuoteCount % 2 == 0) { periodCount++; // If parens and quadquotes are done and we have period then bail if (periodCount == 2) break; } // Update p = p.next; } while (p != null); //outStr.Remove(outStr.Length - 1, 1); //return outStr.ToString(); Console.WriteLine(); }
static void onProgressReport(ProseRuntime runtime, PNode beginningOfFragment, PNode progressMark) { //debugOutput("- " + beginningOfFragment.getReadableStringWithProgressMark(progressMark)); Console.BackgroundColor = ConsoleColor.Black; Console.ForegroundColor = ConsoleColor.Blue; Console.Write("progress> "); writePrettyProseWithProgressMark(runtime, beginningOfFragment, progressMark, 0); }
// Reads a sentence from the source and returns the new // begining of the source. // didReduce: Whether or not it actually succeeded in reducing anything. private PNode reduceSentence(PNode source, out bool didReduce) { // We back up the read head to read from the previous terminal symbol. try { return reduceSentenceFragment(source.prev, out didReduce); } catch (RuntimeProseLanguageFragmentException e) { // Forward this message and fill in the beginning of the sentence. throw new RuntimeProseLanguageException(e.Message, source); } }
// throws RuntimeProseLanguageFragmentException private PNode reduceSentenceFragment(PNode source, out bool didReduce) { // Preserve this so we can figure out where the reduced source begins. PNode prevNode = source.prev; // When we can't undestand the beginning of a sentence, we move on. progressMark // stores the location of this new "virtual beginning" we try to analyze. PNode reducedFragment = source; PNode progressMark = source; didReduce = false; // start assuming we didn't do anything. bool atBeginning = true; while(true) { if (progressMark == null) throw new RuntimeProseLanguageFragmentException("Source ended before sentence.", source); // Make a progress report callback. PNode beginningOfFragment = source.prev.next; // If source has been changed, this is the new head if (OnProgressReport != null) OnProgressReport(this, beginningOfFragment, progressMark); // Try to reduce starting at the progressMark bool didReduceAtMark; PNode reducedAtMark; reducedAtMark = reduceSentenceFragmentStartingAtBeginning(progressMark, out didReduceAtMark); didReduce = didReduce || didReduceAtMark; // Record if we managed to reduce anything. // Possibly this changed the beginning of the fragment we're looking at. // If so, record the change. //if (progressMark == reducedFragment) // Check for the beginning, if we're at the beginning then... if (atBeginning) // Check for the beginning, if we're at the beginning then... reducedFragment = reducedAtMark; // ...need to keep track of the moving beginning. if (didReduceAtMark) { // If we reduced something, then start over to see if we can match from the beginning. progressMark = reducedFragment; atBeginning = true; // // First check to see if we're moving it past an action. // if (progressMark.value is ProseAction) { // // If so, return to allow the action to be performed. // return progressMark; // } } else { // We didn't reduce anything, so move the progress mark forward. { progressMark = progressMark.next; atBeginning = false; } // If we run into a sentence ending symbol like this, then we're finished. if (progressMark == null || symbolEndsSentence(progressMark)) { //INCORRECT: // Return the ending punctation (beginning punctuation depending on how you think about it) //return progressMark; // Returning this should give us the beginning of the source fragment whether we // replaced anything or not. return prevNode.next; } } } }
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); }
public static void onBreakPoint(ProseRuntime runtime, PNode source, BreakPointObject.RuntimeData rtdata, string script) { breakPointDepth++; runtime.read(script, runtime.GlobalClient); runtime.read("read file \"Libraries/REPL/onbreak.prose\"", runtime.GlobalClient); ProseREPLLoop(); breakPointDepth--; }
static void beforePerformingAction(ProseRuntime runtime, PNode source) { Console.BackgroundColor = ConsoleColor.Black; Console.ForegroundColor = ConsoleColor.Green; Console.Write("preaction> "); writePrettyProseWithProgressMark(runtime, source, null, 1); }
static void onParseSentence(ProseRuntime runtime, PNode source) { Console.BackgroundColor = ConsoleColor.Black; Console.ForegroundColor = ConsoleColor.Gray; Console.Write("postparse> "); writePrettyProseWithProgressMark(runtime, source, null, 0); }
static void beforeReduction(ProseRuntime runtime, PNode source) { Console.BackgroundColor = ConsoleColor.Black; Console.ForegroundColor = ConsoleColor.Gray; Console.Write("prereduction> "); writePrettyProseWithProgressMark(runtime, source, null, 0); }
private PNode reduceParentheticalExpression(PNode source, out bool didReduce, ProseObject leftParentheticalObject, ProseObject rightParentheticalObject) { // Find the ending parenthesis PNode rightParen = source; for (int parenDepthCount = 0; true; rightParen = rightParen.next) { if (rightParen.value == leftParentheticalObject) { parenDepthCount++; continue; } if (rightParen.value == rightParentheticalObject) { parenDepthCount--; if (parenDepthCount == 0) // We've found the closing right parenthesis { break; } } } while (rightParen.value != rightParentheticalObject) { rightParen = rightParen.next; } // Unhook the ending parenthesis from the expression we want to reduce. rightParen.prev.next = null; // Reduce the expression (starting AFTER the left paren) bool didReduceParenthetical; PNode reducedExpression; callDepth++; try { reducedExpression = reduceSentenceFragment(source.next, out didReduceParenthetical); } finally { callDepth--; } //We splice it in in two ways depending on whether it reduces to anything or not if (reducedExpression == null) { // If we get nothing back, cut out the parenthesis and continue source.prev.next = rightParen.next; if (rightParen.next != null) { rightParen.next.prev = source.prev; } reducedExpression = rightParen.next; // The first thing after the paren is what we look at next. } else { // If we get something back, splice it in // Cut out the left paren if (source.prev != null) { source.prev.next = reducedExpression; } reducedExpression.prev = source.prev; // Hook the end of the expression back into the original source (skipping right paren) // First find the new end PNode reducedExprEnd = reducedExpression; while (reducedExprEnd.next != null) { reducedExprEnd = reducedExprEnd.next; } reducedExprEnd.next = rightParen.next; if (rightParen.next != null) { rightParen.next.prev = reducedExprEnd; } } didReduce = didReduceParenthetical; return(reducedExpression); }
private PNode debugFilterIncomingPNode(PNode node) { node = filterIncomingPNode(node); bool filterAgain = false; // Determines if we repeatedly apply this. do { if (node == null) break; // Check for breakpoints if (node.value is BreakPointObject) { BreakPointObject bp = (BreakPointObject) node.value; BreakPointObject.RuntimeData rtdata = new BreakPointObject.RuntimeData(); // Do any action associated with the breakpoint and make the default callback if asked if (bp.doBreakPoint(this, node, rtdata)) { if (OnBreakPoint != null) OnBreakPoint(this, node, rtdata, bp.BreakScript); } // Remove the breakpoint if (node.prev != null) node.prev.next = node.next; if (node.next != null) node.next.prev = node.prev; filterAgain = true; // Skip over the breakpoint node = node.next; } } while (filterAgain); return node; }
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; }
// Start on the left side of the sentence and perform actions. Eliminate ; along the way if // it's sandwhiched between actions. // NOTE: EXPECTS INITIAL PUNCTUATION private PNode doActionsOnLeftOfSentence(PNode sourcePtr, out bool didSomeActions, out bool sentenceHasBeenExecuted) { didSomeActions = false; sentenceHasBeenExecuted = false; PNode reduced = sourcePtr.next; // Skip initial punctuation while (reduced != null) { if (reduced.value is ProseAction) { // Callback Before if (BeforePerformingAction != null) BeforePerformingAction(this, reduced); // DO THE ACTION! // try { ((ProseAction) reduced.value).performAction(this); // } // catch (Exception e) // { // this.read ("language function exception: \"" + e.Message + "\"", GlobalClient); // } // Callback After if (AfterPerformingAction != null) AfterPerformingAction(this, reduced); didSomeActions = true; reduced.removeSelf(); reduced = reduced.next; } else if (reduced.value == Semicolon || reduced.value == Comma) { // Check to see if we should leave this semicolon in (as punctuation for the remaining // prose to match) or remove it because it's surrounded in actions. if (reduced.next != null) { // Skip over the semicolon and move on to the next action we found reduced = reduced.next; } else { // We've run into a the end, so leave the symbol there. break; } } else if(reduced.value == Period) { // We've run into the end of the whole sentence, so skip the period. sentenceHasBeenExecuted = true; return reduced.next; } else { break; } } if (didSomeActions) return reduced; else return sourcePtr; }