/* * We are positioned in the pattern at a list variable and match it with * the current subject starting at the current position. * On success, the cursors are advanced. * On failure, switch to backtracking (forward = false) mode. */ private void matchBindingListVar(IMatchingResult child) { assert isListVar[patternCursor]; int start = listVarStart[patternCursor]; int length = listVarLength[patternCursor]; // int reducedLength = (length == 0) ? 0 : ((length < delta) ? 1 : Math.max(length - delta + 1, // 0)); // round to nearest unskipped element int reducedLength = (length <= 1) ? length : (length - (length - 1) % delta); if (debug) { System.err.println("length=" + length); System.err.println("reducedLength=" + reducedLength); } IList sublist = makeSubList(start, reducedLength); if (debug) System.err.println( "matchBindingListVar: init child #" + patternCursor + " (" + child + ") with " + sublist); // TODO : check if we can use a static type here!? child.initMatch(ResultFactory.makeResult(sublist.getType(), sublist, ctx)); if (child.next()) { subjectCursor = start + length; if (debug) System.err.println("child matches, subjectCursor=" + subjectCursor); patternCursor += delta; } else { forward = false; listVarLength[patternCursor] = 0; patternCursor -= delta; if (debug) System.err.println("child fails, subjectCursor=" + subjectCursor); } }
@Override public void initMatch(Result<IValue> subject) { if (debug) { System.err.println("List: initMatch: subject=" + subject); } // This is an experiment to add abstract list matching for concrete subjects // if (subject.getType().isSubtypeOf(Factory.Tree)) { // IConstructor tree = (IConstructor) subject.getValue(); // if (TreeAdapter.isList(tree)) { // subject = ResultFactory.makeResult(Factory.Args, TreeAdapter.getArgs(tree), ctx); // IConstructor rhs = TreeAdapter.getType(tree); // // if (SymbolAdapter.isIterPlusSeps(rhs) || SymbolAdapter.isIterStarSeps(rhs)) { // this.delta = SymbolAdapter.getSeparators(rhs).length() + 1; // } // } // else { // hasNext = false; // return; // } // } super.initMatch(subject); if (!subject.getValue().getType().isList()) { hasNext = false; return; } listSubject = (IList) subject.getValue(); listSubjectType = listSubject.getType(); staticListSubjectType = subject.getType(); staticListSubjectElementType = staticListSubjectType.isList() ? subject.getType().getElementType() : tf.valueType(); subjectCursor = 0; patternCursor = 0; subjectSize = ((IList) subject.getValue()).length(); reducedSubjectSize = (subjectSize + delta - 1) / delta; if (debug) { System.err.println("reducedPatternSize=" + reducedPatternSize); System.err.println("reducedSubjectSize=" + reducedSubjectSize); } isListVar = new boolean[patternSize]; isBindingVar = new boolean[patternSize]; varName = new String[patternSize]; allVars = new HashSet<String>(); listVarStart = new int[patternSize]; listVarLength = new int[patternSize]; listVarMinLength = new int[patternSize]; listVarMaxLength = new int[patternSize]; listVarOccurrences = new int[patternSize]; int nListVar = 0; /* * Pass #1: determine the list variables */ for (int i = 0; i < patternSize; i += delta) { IMatchingResult child = patternChildren.get(i); isListVar[i] = false; isBindingVar[i] = false; Environment env = ctx.getCurrentEnvt(); if (child instanceof TypedMultiVariablePattern) { TypedMultiVariablePattern tmvVar = (TypedMultiVariablePattern) child; Type tmvType = tmvVar.getType(env, null); String name = tmvVar.getName(); varName[i] = name; isListVar[i] = true; listVarOccurrences[i] = 1; ++nListVar; if (!tmvVar.isAnonymous() && allVars.contains(name)) { throw new RedeclaredVariable(name, getAST()); } else if (tmvType.comparable(listSubject.getType().getElementType()) || (tmvVar.bindingInstance() && tmvType.comparable(listSubject.getType()))) { tmvVar.convertToListType(); if (!tmvVar.isAnonymous()) { allVars.add(name); } isBindingVar[i] = true; } else { hasNext = false; return; } } else if (child instanceof MultiVariablePattern) { MultiVariablePattern multiVar = (MultiVariablePattern) child; String name = multiVar.getName(); varName[i] = name; isListVar[i] = true; nListVar++; if (!multiVar.isAnonymous() && allVars.contains(name)) { isBindingVar[i] = false; } else if (multiVar.isAnonymous()) { isBindingVar[i] = true; } else { allVars.add(name); Result<IValue> varRes = env.getVariable(name); if (varRes == null || multiVar.bindingInstance()) { isBindingVar[i] = true; } else { isBindingVar[i] = false; Type varType = varRes.getType(); if (isAnyListType(varType)) { if (!varType.comparable(listSubjectType)) { hasNext = false; return; } } else { if (!(varType instanceof NonTerminalType) && !(varType.comparable(staticListSubjectElementType))) { hasNext = false; return; } } } } } else if (child instanceof ConcreteListVariablePattern) { ConcreteListVariablePattern listVar = (ConcreteListVariablePattern) child; String name = listVar.getName(); varName[i] = name; isListVar[i] = true; if (!listVar.isAnonymous()) allVars.add(name); isBindingVar[i] = true; listVarOccurrences[i] = 1; nListVar++; } else if (child instanceof QualifiedNamePattern) { QualifiedNamePattern qualName = (QualifiedNamePattern) child; String name = qualName.getName(); varName[i] = name; if (!qualName.isAnonymous() && allVars.contains(name)) { /* * A variable that was declared earlier in the pattern */ isListVar[i] = true; nListVar++; listVarOccurrences[i]++; } else if (qualName.isAnonymous()) { /* * Nothing to do */ } else { Result<IValue> varRes = env.getVariable(name); if (varRes == null || qualName.bindingInstance()) { // A completely new non-list variable, nothing to do } else { Type varType = varRes.getType(); if (isAnyListType(varType)) { /* * A variable declared in the current scope. */ if (varType.comparable(listSubjectType)) { isListVar[i] = true; isBindingVar[i] = varRes.getValue() == null; nListVar++; } else { hasNext = false; return; } } else { if (varType instanceof NonTerminalType) { // suppress comparable test for Nonterminal types // TODO: this should be done better } else if (!varType.comparable(staticListSubjectElementType)) { hasNext = false; return; } } } } } else if (child instanceof VariableBecomesPattern) { // Nothing to do } else { if (debug) { System.err.println("List: child " + child); System.err.println("List: child is a" + child.getClass()); } Type childType = child.getType(env, null); // TODO: pattern matching should be specialized such that matching appl(prod...)'s does not // need to use list matching on the fixed arity children of the application of a production if (!(childType instanceof NonTerminalType) && !childType.comparable(staticListSubjectElementType)) { hasNext = false; return; } java.util.List<IVarPattern> childVars = child.getVariables(); if (!childVars.isEmpty()) { for (IVarPattern vp : childVars) { // TODO: This does not profit from extra information allVars.add(vp.name()); } isListVar[i] = false; nListVar++; } } } /* * Pass #2: assign minimum and maximum length to each list variable */ for (int i = 0; i < patternSize; i += delta) { if (isListVar[i]) { // TODO: reduce max length according to number of occurrences listVarMaxLength[i] = delta * Math.max(reducedSubjectSize - (reducedPatternSize - nListVar), 0); listVarLength[i] = 0; listVarMinLength[i] = delta * ((nListVar == 1) ? Math.max(reducedSubjectSize - reducedPatternSize - 1, 0) : 0); if (debug) { System.err.println( "listvar " + i + " min= " + listVarMinLength[i] + " max=" + listVarMaxLength[i]); } } } firstMatch = true; hasNext = subject.getValue().getType().isList() && reducedSubjectSize >= reducedPatternSize - nListVar; if (debug) { System.err.println("List: hasNext=" + hasNext); } }