public override ICodeNode VisitPropertyReferenceExpression(PropertyReferenceExpression node) { MethodReferenceExpression methodRefExpression = node.MethodExpression; if (methodRefExpression.Target != null) { if (methodRefExpression.Target.CodeNodeType == CodeNodeType.VariableReferenceExpression && asyncData.AwaiterVariables.Contains((methodRefExpression.Target as VariableReferenceExpression).Variable)) { VariableReference awaiterVariable = (methodRefExpression.Target as VariableReferenceExpression).Variable; if (currentAwaiterVariable == awaiterVariable) { if (methodRefExpression.Method.Name == "get_IsCompleted") { if (matcherState == MatcherState.FindIsCompletedInvoke) { matcherState = MatcherState.FindInitObj | MatcherState.FindGetResultInvoke; return(null); } } } matcherState = MatcherState.Stopped; return(node); } } return(base.VisitPropertyReferenceExpression(node)); }
private bool Match() { if (this.originalStatements.Count == 0) { return false; } if (!this.methodContext.Method.IsAsync(out this.stateMachineTypeDef)) { if (!this.methodContext.Method.HasAsyncAttributes() || !IsAsyncFirstAssignmentStatement(this.originalStatements[0], out this.stateMachineTypeDef) || !this.methodContext.Method.HasAsyncStateMachineVariable()) { return false; } } if (!GetBuilderField()) { return false; } asyncStatements = GetMoveNextStatements(); if (asyncStatements == null || !TryRemoveOuterTryCatch(asyncStatements)) { return false; } SetParameterMappings(originalStatements); matcherState = MatcherState.FindAwaitExpression; asyncStatements = (StatementCollection)Visit(asyncStatements); bool result = matcherState == MatcherState.FindAwaitExpression; return result; }
// Start a pattern match at the beginning with one object. internal PatternMatcher(ProseRuntime runtime) { this.runtime = runtime; patternTrie = runtime.GlobalScope.PatternTree; state = MatcherState.MATCHING_OBJECT; currNode = patternTrie.Root; }
private void while_MATCHING_TEXT_extendWith(PNode node, Trie <ProseObject, List <Phrase> > .Node patternNode) { this.numObjectsMatched++; this.currNode = patternNode; if (node.value == runtime.Quadquote) { textMatchingQQcount++; // If this is the first time through, record the beginning of the text block if (textMatchingQQcount == 1) { patternComponentNodes.Add(node); } } // We become matched when the text ends. if (currNode.Value != null && currNode.Value.Count != 0 && textMatchingQQcount == 2) { //isMatched = true; becomeMatched(node.next); } else if (textMatchingQQcount > 2) { state = MatcherState.FAILED; } else if (textMatchingQQcount == 2) { switchToState_MATCHING_OBJECT(); } }
// Start a pattern match at the beginning with one object. internal PatternMatcher(ProseRuntime runtime) { this.runtime = runtime; patternTrie = runtime.GlobalScope.PatternTree; state = MatcherState.MATCHING_OBJECT; currNode = patternTrie.Root; }
public override ICodeNode VisitBinaryExpression(BinaryExpression node) { if (node.Operator == BinaryOperator.Assign) { if (node.Left.CodeNodeType == CodeNodeType.VariableReferenceExpression && asyncData.AwaiterVariables.Contains((node.Left as VariableReferenceExpression).Variable)) { VariableReference awaiterVariable = (node.Left as VariableReferenceExpression).Variable; if (node.Right.CodeNodeType == CodeNodeType.MethodInvocationExpression && (node.Right as MethodInvocationExpression).MethodExpression.Method.Name == "GetAwaiter") { Expression expression = null;//(Expression)Visit((node.Right as MethodInvocationExpression).MethodExpression.Target); MethodInvocationExpression methodInvocation = node.Right as MethodInvocationExpression; if (methodInvocation.MethodExpression.Target != null) { if (methodInvocation.Arguments.Count == 0) { expression = (Expression)Visit(methodInvocation.MethodExpression.Target); } } else { if (methodInvocation.Arguments.Count == 1) { expression = (Expression)Visit(methodInvocation.Arguments[0]); } } if (expression != null && matcherState == MatcherState.FindAwaitExpression) { currentAwaiterVariable = awaiterVariable; awaitedExpression = expression; matcherState = MatcherState.FindIsCompletedInvoke; return(null); } } else if ((node.Right.CodeNodeType == CodeNodeType.ObjectCreationExpression) || ((node.Right.CodeNodeType == CodeNodeType.LiteralExpression) && ((node.Right as LiteralExpression).Value == null))) { if ((matcherState & MatcherState.FindInitObj) == MatcherState.FindInitObj && currentAwaiterVariable == awaiterVariable) { matcherState ^= MatcherState.FindInitObj; return(null); } } matcherState = MatcherState.Stopped; return(node); } else if (node.Left.CodeNodeType == CodeNodeType.FieldReferenceExpression && (node.Left as FieldReferenceExpression).Field.Resolve() == asyncData.StateField || node.Right.CodeNodeType == CodeNodeType.ThisReferenceExpression) { return(null); } } return(base.VisitBinaryExpression(node)); }
private void switchToState_MATCHING_PROSE() { state = MatcherState.MATCHING_PROSE; // Create a new block to hold the building Prose. proseBlock = new ProseBlockObject(); parentheticalStack = new Stack <ProseObject>(); objectsInCurrentProseblock = 0; }
private void switchToState_MATCHING_PATTERN() { state = MatcherState.MATCHING_PATTERN; // Counts 1 when hits [, increments for each word. When it gets // to ] it makes sure the count is at 2. More words is illegal, no words is illegal. // Also, checks that the words are words or RawWords. bracketReaderCount = 0; prevBracketReaderCount = 0; if (currPatternObject == null) { currPatternObject = new PatternObject(); } }
public override ICodeNode VisitMethodInvocationExpression(MethodInvocationExpression node) { MethodReferenceExpression methodRefExpression = node.MethodExpression; if (methodRefExpression.Target != null) { if (methodRefExpression.Target.CodeNodeType == CodeNodeType.VariableReferenceExpression && asyncData.AwaiterVariables.Contains((methodRefExpression.Target as VariableReferenceExpression).Variable)) { VariableReference awaiterVariable = (methodRefExpression.Target as VariableReferenceExpression).Variable; if (currentAwaiterVariable == awaiterVariable) { if (methodRefExpression.Method.Name == "get_IsCompleted") { if (matcherState == MatcherState.FindIsCompletedInvoke) { matcherState = MatcherState.FindInitObj | MatcherState.FindGetResultInvoke; return(null); } } else if (methodRefExpression.Method.Name == "GetResult") { if ((matcherState & MatcherState.FindGetResultInvoke) == MatcherState.FindGetResultInvoke) { matcherState ^= MatcherState.FindGetResultInvoke; return(new AwaitExpression((Expression)Visit(awaitedExpression), methodRefExpression.Method.ReturnType, node.UnderlyingSameMethodInstructions)); } } } matcherState = MatcherState.Stopped; return(node); } else if (methodRefExpression.Target.CodeNodeType == CodeNodeType.FieldReferenceExpression && (methodRefExpression.Target as FieldReferenceExpression).Field.Resolve() == builderField) { if (methodRefExpression.Method.Name == "SetResult") { Expression returnValue = node.Arguments.Count > 0 ? node.Arguments[0] : null; return(new ReturnExpression(returnValue, methodRefExpression.UnderlyingSameMethodInstructions)); } } } return(base.VisitMethodInvocationExpression(node)); }
private bool Match() { if (this.originalStatements.Count == 0) { return(false); } if (!this.methodContext.Method.IsAsync(out this.stateMachineTypeDef)) { if (!this.methodContext.Method.HasAsyncAttributes() || !IsAsyncFirstAssignmentStatement(this.originalStatements[0], out this.stateMachineTypeDef) || !this.methodContext.Method.HasAsyncStateMachineVariable()) { return(false); } } if (!GetBuilderField()) { return(false); } asyncStatements = GetMoveNextStatements(); if (asyncStatements == null || !TryRemoveOuterTryCatch(asyncStatements)) { return(false); } SetParameterMappings(originalStatements); matcherState = MatcherState.FindAwaitExpression; asyncStatements = (StatementCollection)Visit(asyncStatements); // The C# compiler that comes with MSBuild 15.0 (VS 2017 and .NET Core) seems to produce different code that the one coming with // MSBuild 14.0 (VS 2015) and the ones before that. In the new one there is one missing object initialization (when matcherState // is MatcherState.FindInitObj this step is searching for it) and this is causing our pattern matching to fail. // "|| matcherState == MatcherState.FindInitObj" is quick and dirty fix, which can be improved but due to the limited time right now, // I'm leaving it that way. bool result = matcherState == MatcherState.FindAwaitExpression || matcherState == MatcherState.FindInitObj; return(result); }
private bool Match() { if (this.originalStatements.Count == 0) { return(false); } if (!this.methodContext.Method.IsAsync(out this.stateMachineTypeDef)) { if (!this.methodContext.Method.HasAsyncAttributes() || !IsAsyncFirstAssignmentStatement(this.originalStatements[0], out this.stateMachineTypeDef) || !this.methodContext.Method.HasAsyncStateMachineVariable()) { return(false); } } if (!GetBuilderField()) { return(false); } asyncStatements = GetMoveNextStatements(); if (asyncStatements == null || !TryRemoveOuterTryCatch(asyncStatements)) { return(false); } SetParameterMappings(originalStatements); matcherState = MatcherState.FindAwaitExpression; asyncStatements = (StatementCollection)Visit(asyncStatements); bool result = matcherState == MatcherState.FindAwaitExpression; return(result); }
private void switchToState_MATCHING_OBJECT() { state = MatcherState.MATCHING_OBJECT; }
private void switchToState_MATCHING_TEXT() { state = MatcherState.MATCHING_TEXT; textMatchingQQcount = 0; }
private void switchToState_MATCHING_PROSE() { state = MatcherState.MATCHING_PROSE; // Create a new block to hold the building Prose. proseBlock = new ProseBlockObject(); parentheticalStack = new Stack<ProseObject>(); objectsInCurrentProseblock = 0; }
// 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; }
private void while_MATCHING_PATTERN_extendWith(PNode node, Trie <ProseObject, List <Phrase> > .Node patternNode) { // If this is the first node we're pushing in as a "pattern", then add it to patternComponentNodes if (currPatternObject.Length == 0) { patternComponentNodes.Add(node); } ProseObject obj = node.value; switch (bracketReaderCount) { case 0: if (obj == runtime.LeftSquareBracket) { // Attempting to name an argument when no argument type preceeds it! if (currPatternObject.Length == 0) { state = MatcherState.FAILED; return; } numObjectsMatched++; setBracketReaderCount(1); } else { if (obj is Word) { currPatternObject.putPatternElement(obj); numObjectsMatched++; } else { state = MatcherState.FAILED; return; } } break; case 1: if (obj == runtime.RightSquareBracket) { justPutArgName = false; setBracketReaderCount(0); numObjectsMatched++; } // If its a word or raw word then it should be an argument name else if (obj is Word || obj is RawWord) { if (!justPutArgName) { currPatternObject.replaceLastPutElementNameWith(obj); justPutArgName = true; numObjectsMatched++; } else { // Can't supply two arg names. state = MatcherState.FAILED; return; } } break; } // VERY IMPORTANT: Keep the matcher moving up the tree. currNode = patternNode; }
private void switchToState_MATCHING_TEXT() { state = MatcherState.MATCHING_TEXT; textMatchingQQcount = 0; }
private void while_MATCHING_PATTERN_extendWith(PNode node, Trie<ProseObject, List<Phrase>>.Node patternNode) { // If this is the first node we're pushing in as a "pattern", then add it to patternComponentNodes if (currPatternObject.Length == 0) { patternComponentNodes.Add(node); } ProseObject obj = node.value; switch (bracketReaderCount) { case 0: if (obj == runtime.LeftSquareBracket) { // Attempting to name an argument when no argument type preceeds it! if (currPatternObject.Length == 0) { state = MatcherState.FAILED; return; } numObjectsMatched++; setBracketReaderCount(1); } else { if (obj is Word) { currPatternObject.putPatternElement(obj); numObjectsMatched++; } else { state = MatcherState.FAILED; return; } } break; case 1: if (obj == runtime.RightSquareBracket) { justPutArgName = false; setBracketReaderCount(0); numObjectsMatched++; } // If its a word or raw word then it should be an argument name else if (obj is Word || obj is RawWord) { if (!justPutArgName) { currPatternObject.replaceLastPutElementNameWith(obj); justPutArgName = true; numObjectsMatched++; } else { // Can't supply two arg names. state = MatcherState.FAILED; return; } } break; } // VERY IMPORTANT: Keep the matcher moving up the tree. currNode = patternNode; }
private void while_MATCHING_TEXT_extendWith(PNode node, Trie<ProseObject, List<Phrase>>.Node patternNode) { this.numObjectsMatched++; this.currNode = patternNode; if (node.value == runtime.Quadquote) { textMatchingQQcount++; // If this is the first time through, record the beginning of the text block if (textMatchingQQcount == 1) { patternComponentNodes.Add(node); } } // We become matched when the text ends. if ( currNode.Value != null && currNode.Value.Count != 0 && textMatchingQQcount == 2) { //isMatched = true; becomeMatched(node.next); } else if (textMatchingQQcount > 2) { state = MatcherState.FAILED; } else if (textMatchingQQcount == 2) { switchToState_MATCHING_OBJECT(); } }
// 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); }
private void switchToState_MATCHING_PATTERN() { state = MatcherState.MATCHING_PATTERN; // Counts 1 when hits [, increments for each word. When it gets // to ] it makes sure the count is at 2. More words is illegal, no words is illegal. // Also, checks that the words are words or RawWords. bracketReaderCount = 0; prevBracketReaderCount = 0; if (currPatternObject == null) currPatternObject = new PatternObject(); }
public override ICodeNode VisitMethodInvocationExpression(MethodInvocationExpression node) { MethodReferenceExpression methodRefExpression = node.MethodExpression; if (methodRefExpression.Target != null) { if (methodRefExpression.Target.CodeNodeType == CodeNodeType.VariableReferenceExpression && asyncData.AwaiterVariables.Contains((methodRefExpression.Target as VariableReferenceExpression).Variable)) { VariableReference awaiterVariable = (methodRefExpression.Target as VariableReferenceExpression).Variable; if (currentAwaiterVariable == awaiterVariable) { if (methodRefExpression.Method.Name == "get_IsCompleted") { if (matcherState == MatcherState.FindIsCompletedInvoke) { matcherState = MatcherState.FindInitObj | MatcherState.FindGetResultInvoke; return null; } } else if (methodRefExpression.Method.Name == "GetResult") { if ((matcherState & MatcherState.FindGetResultInvoke) == MatcherState.FindGetResultInvoke) { matcherState ^= MatcherState.FindGetResultInvoke; return new AwaitExpression((Expression)Visit(awaitedExpression), methodRefExpression.Method.ReturnType, node.UnderlyingSameMethodInstructions); } } } matcherState = MatcherState.Stopped; return node; } else if (methodRefExpression.Target.CodeNodeType == CodeNodeType.FieldReferenceExpression && (methodRefExpression.Target as FieldReferenceExpression).Field.Resolve() == builderField) { if (methodRefExpression.Method.Name == "SetResult") { Expression returnValue = node.Arguments.Count > 0 ? node.Arguments[0] : null; return new ReturnExpression(returnValue, methodRefExpression.UnderlyingSameMethodInstructions); } } } return base.VisitMethodInvocationExpression(node); }
public override ICodeNode VisitPropertyReferenceExpression(PropertyReferenceExpression node) { MethodReferenceExpression methodRefExpression = node.MethodExpression; if (methodRefExpression.Target != null) { if (methodRefExpression.Target.CodeNodeType == CodeNodeType.VariableReferenceExpression && asyncData.AwaiterVariables.Contains((methodRefExpression.Target as VariableReferenceExpression).Variable)) { VariableReference awaiterVariable = (methodRefExpression.Target as VariableReferenceExpression).Variable; if (currentAwaiterVariable == awaiterVariable) { if (methodRefExpression.Method.Name == "get_IsCompleted") { if (matcherState == MatcherState.FindIsCompletedInvoke) { matcherState = MatcherState.FindInitObj | MatcherState.FindGetResultInvoke; return null; } } } matcherState = MatcherState.Stopped; return node; } } return base.VisitPropertyReferenceExpression(node); }
public override ICodeNode VisitBinaryExpression(BinaryExpression node) { if (node.Operator == BinaryOperator.Assign) { if (node.Left.CodeNodeType == CodeNodeType.VariableReferenceExpression && asyncData.AwaiterVariables.Contains((node.Left as VariableReferenceExpression).Variable)) { VariableReference awaiterVariable = (node.Left as VariableReferenceExpression).Variable; if (node.Right.CodeNodeType == CodeNodeType.MethodInvocationExpression && (node.Right as MethodInvocationExpression).MethodExpression.Method.Name == "GetAwaiter") { Expression expression = null;//(Expression)Visit((node.Right as MethodInvocationExpression).MethodExpression.Target); MethodInvocationExpression methodInvocation = node.Right as MethodInvocationExpression; if (methodInvocation.MethodExpression.Target != null) { if(methodInvocation.Arguments.Count == 0) { expression = (Expression)Visit(methodInvocation.MethodExpression.Target); } } else { if (methodInvocation.Arguments.Count == 1) { expression = (Expression)Visit(methodInvocation.Arguments[0]); } } if (expression != null && matcherState == MatcherState.FindAwaitExpression) { currentAwaiterVariable = awaiterVariable; awaitedExpression = expression; matcherState = MatcherState.FindIsCompletedInvoke; return null; } } else if ( (node.Right.CodeNodeType == CodeNodeType.ObjectCreationExpression) || ((node.Right.CodeNodeType == CodeNodeType.LiteralExpression) && ((node.Right as LiteralExpression).Value == null)) ) { if ((matcherState & MatcherState.FindInitObj) == MatcherState.FindInitObj && currentAwaiterVariable == awaiterVariable) { matcherState ^= MatcherState.FindInitObj; return null; } } matcherState = MatcherState.Stopped; return node; } else if (node.Left.CodeNodeType == CodeNodeType.FieldReferenceExpression && (node.Left as FieldReferenceExpression).Field.Resolve() == asyncData.StateField || node.Right.CodeNodeType == CodeNodeType.ThisReferenceExpression) { return null; } } return base.VisitBinaryExpression(node); }
private void switchToState_MATCHING_OBJECT() { state = MatcherState.MATCHING_OBJECT; }