public static bool Match(PassiveExpression expression, Pattern pattern) { bool match = true; Stack rollBackStack = new Stack(); // assume that expression and pattern aren't empty int exIndex = 0, patIndex = 0; while (true) { while (match && patIndex < pattern.Count && exIndex < expression.Count) { object ex = expression[exIndex]; object pat = pattern[patIndex]; bool needRollback = false; // braces can only match itself if (pat is OpeningBrace) { if (ex is OpeningBrace) { exIndex++; patIndex++; continue; } else needRollback = true; } else if (pat is ClosingBrace) { if (ex is ClosingBrace) { exIndex++; patIndex++; continue; } else needRollback = true; } // symbol matches single symbol else if (!(pat is Variable)) { // check for () is redundant because of ex.Equals(pat) if (ex.Equals(pat) && !(ex is StructureBrace)) { exIndex++; patIndex++; continue; } else needRollback = true; } // symbol or term variable matches single symbol else if ((pat is SymbolVariable || pat is TermVariable) && !(ex is StructureBrace)) { Variable var = pat as Variable; if (patIndex == var.FirstOccurance) { var.Value = ex; exIndex++; patIndex++; continue; } else if (ex.Equals(var.Value)) { exIndex++; patIndex++; continue; } else { // symbol don't match the bound variable, // roll back to the last expression variable needRollback = true; } } // term variable matches subexpression in structure braces else if ((pat is TermVariable) && (ex is StructureBrace)) { TermVariable term = pat as TermVariable; // first occurance => copy subexpression if (patIndex == term.FirstOccurance) { if (ex is OpeningBrace) { term.Expression.Add(ex); exIndex++; patIndex++; // extract subexpression within the structure braces int rank = 1; while (exIndex < expression.Count && rank > 0) { ex = expression[exIndex++]; term.Expression.Add(ex); if (ex is OpeningBrace) rank++; else if (ex is ClosingBrace) rank--; } // subexpression with surrounding braces is extracted if (rank == 0) continue; else { // closing structure brace not found => rolling back // in fact, this can only be caused by unmatched braces... needRollback = true; } } else { needRollback = true; } } else // not the first occurance => compare expression { if (CompareExpressions(expression, exIndex, term.Expression)) { exIndex += term.Expression.Count; patIndex++; continue; } else needRollback = true; } } // expression variable can match nothing, symbol(s), // and expression(s) within structure braces else if (pat is ExpressionVariable) { ExpressionVariable var = pat as ExpressionVariable; if (patIndex == var.FirstOccurance) { if (var.Expression == null) { // start with empty expression var.Expression = new PassiveExpression(); RollbackInfo info = new RollbackInfo(); info.exIndex = exIndex; info.patIndex = patIndex; rollBackStack.Push(info); patIndex++; continue; } else { // continue adding terms to expression if (!(ex is StructureBrace)) { var.Expression.Add(ex); RollbackInfo info = new RollbackInfo(); info.exIndex = exIndex + 1; info.patIndex = patIndex; rollBackStack.Push(info); exIndex++; patIndex++; continue; } // handle structure braces, extract subexpression else if (ex is OpeningBrace) { var.Expression.Add(ex); exIndex++; // extract subexpression within the structure braces int rank = 1; while (exIndex < expression.Count && rank > 0) { ex = expression[exIndex++]; var.Expression.Add(ex); if (ex is OpeningBrace) rank++; else if (ex is ClosingBrace) rank--; } // subexpression with surrounding braces is extracted if (rank == 0) continue; else { // closing structure brace not found => rolling back // this can only be caused by unmatched braces => error in compiler needRollback = true; } } else { // extra closing brace ) => roll back needRollback = true; } } } else // not the first occurance, compare expressions { if (CompareExpressions(expression, exIndex, var.Expression)) { exIndex += var.Expression.Count; patIndex++; continue; } else // expression don't match, roll back needRollback = true; } } // if can't find any match, roll back else { needRollback = true; } // roll back to the last expression variable, if needed if (needRollback) { // can't roll back => matching failed if (rollBackStack.Count == 0) { match = false; } else { // restore state up to the last expression variable RollbackInfo info = (RollbackInfo)rollBackStack.Pop(); exIndex = info.exIndex; patIndex = info.patIndex; // clear values of all bound variables starting later than patIndex ClearBoundValues(pattern, patIndex); } } // if (needRollback) } // while() if (match && patIndex >= pattern.Count && exIndex >= expression.Count) return true; // check for special case: expression has ended, but pattern contains a few expression variables // in that case, matching should succeed, with all remaining variables taking empty values if (match && exIndex >= expression.Count && patIndex < pattern.Count) { while (match && patIndex < pattern.Count) { object pat = pattern[patIndex++]; if (!(pat is ExpressionVariable)) { match = false; break; } ExpressionVariable var = (ExpressionVariable)pat; var.Expression = new PassiveExpression(); } if (match && patIndex >= pattern.Count) return true; } // if can roll back, try once more if (rollBackStack.Count == 0) { // nothing to roll back => matching has failed return false; } else { // restore state up to the last expression variable and iterate once more! RollbackInfo info = (RollbackInfo)rollBackStack.Pop(); exIndex = info.exIndex; patIndex = info.patIndex; // clear values of all bound variables starting later than patIndex ClearBoundValues(pattern, patIndex); } } }
public static bool Match(PassiveExpression expression, Pattern pattern) { if (expression == null || expression.IsEmpty) { // empty expression matches empty pattern if (pattern == null || pattern.IsEmpty) { return(true); } // any expression matches the pattern consisting of a // single expression variable (like e.1) if (pattern.Count == 1 && pattern[0] is ExpressionVariable) { // bind free variable to an expression ExpressionVariable var = (ExpressionVariable)pattern[0]; var.Expression = expression; return(true); } // expression is empty, pattern isn't return(false); } // pattern is empty while expression isn't if (pattern == null || pattern.IsEmpty) { return(false); } // handle simple cases if (pattern.Count == 1) { if (pattern[0] is ExpressionVariable) { // bind free variable to an expression ExpressionVariable var = (ExpressionVariable)pattern[0]; var.Expression = expression; return(true); } // check for single symbol or single term if (expression.Count == 1) { // symbol matches symbol if (pattern[0].Equals(expression[0]) && !(pattern[0] is Variable)) { return(true); } // term ::= symbol | (expression) if (expression[0] is PassiveExpression && pattern[0] is TermVariable) { // bind free variable to an expression TermVariable var = (TermVariable)pattern[0]; PassiveExpression expr = (PassiveExpression)expression[0]; var.Expression = expr; return(true); } // either term or symbol if (pattern[0] is Variable && !(expression[0] is PassiveExpression)) { Variable var = (Variable)pattern[0]; var.Value = expression[0]; return(true); } } } // both pattern and expression are not empty, perform non-trivial matching return(PatternMatchHelper.Match(expression, pattern)); }