mbeckerle commented on a change in pull request #259: Incremental progress on schema compilation space/speed issue. URL: https://github.com/apache/incubator-daffodil/pull/259#discussion_r301233918
########## File path: daffodil-core/src/main/scala/org/apache/daffodil/dpath/Expression.scala ########## @@ -1103,64 +1104,123 @@ case class NamedStep(s: String, predArg: Option[PredicateExpression]) res } - lazy val dpathElementCompileInfo = stepElement + lazy val dpathElementCompileInfos = stepElements lazy val downwardStep = { - if (stepElement.isArray && pred.isDefined) { - Assert.invariant(pred.get.targetType == NodeInfo.ArrayIndex) - val indexRecipe = pred.get.compiledDPath - new DownArrayOccurrence(dpathElementCompileInfo, indexRecipe) - } else if (stepElement.isArray && targetType == NodeInfo.Exists) { - new DownArrayExists(dpathElementCompileInfo) - } else if (stepElement.isArray) { - schemaDefinitionUnless(targetType == NodeInfo.Array, "Query-style paths not supported. Must have '[...]' after array-element's name. Offending path step: '%s'.", step) - new DownArray(dpathElementCompileInfo) + if (isArray) { + if (pred.isDefined) { + Assert.invariant(pred.get.targetType == NodeInfo.ArrayIndex) + val indexRecipe = pred.get.compiledDPath + new DownArrayOccurrence(dpathElementCompileInfos.head, indexRecipe) + } else if (targetType == NodeInfo.Exists) { + new DownArrayExists(dpathElementCompileInfos.head) + } else { + schemaDefinitionUnless(targetType == NodeInfo.Array, "Query-style paths not supported. Must have '[...]' after array-element's name. Offending path step: '%s'.", step) + new DownArray(dpathElementCompileInfos.head) + } } else { // // Note: DFDL spec allows a[exp] if a is not an array, but it's a processing // error if exp doesn't evaluate to 1. // TODO: Implement this. if (pred.isDefined) subsetError("Indexing is only allowed on arrays. Offending path step: '%s%s'.", step, pred.get.text) - new DownElement(dpathElementCompileInfo) + new DownElement(dpathElementCompileInfos.head) } } override def text = step - private def die = { - Assert.invariantFailed("should have thrown") - } /* - * The ERD of the element that corresponds to this path step - * (or SDE trying to find it.) + * The ERDs of the elements that corresponds to this path step + * (or SDE trying to find them.) + * + * There are multiple step elements because an upward relative path can be say + * from an element inside a global group, upward to multiple group + * references where the relative path then steps downward to + * different elements having the same name. + * + * E.g., ../../b must type check for all possible b that this path + * can refer to. If that path appears inside a global group definition, + * then every place that group is used must have a corresponding b + * child element that satisfies this path, and which type-checks. + * + * So long as they all type check, the we can generate the + * downward step we need in a way that works universally for all + * uses of the path. */ - override lazy val stepElement: DPathElementCompileInfo = { - val stepElem = if (isFirstStep) { - if (isAbsolutePath) { - // has to be the root element, but we have to make sure the name matches. - rootElement.findRoot(stepQName, this) - rootElement + override lazy val stepElements: Seq[DPathElementCompileInfo] = LV('stepElements) { + val res: Seq[DPathElementCompileInfo] = + if (isFirstStep) { + if (isAbsolutePath) { + // has to be the root element, but we have to make sure the name matches. + val re = rootElement + re.findRoot(stepQName, this) + Seq(re) + } else { + // Since we're first we start from the element, or nearest enclosing + // for this path expression. + + // That can already be multiple such, because this expression could be + // say on the initiator property of an inner sequence inside a global sequence + // group def. That global def could be used inside the complex type of + // 3 different elements. So we would have 3 elementCompileInfos for this + // step. + // + // Also since we're the first step, and this is a named step, this has + // to be downward to a child. Assertion check here is just in case + // somebody refactors this code elsewhere, as it is a very strong + // assumption for this algorithm. + Assert.invariant(this.isInstanceOf[NamedStep]) + // + // All enclosing elements for this path step must be able to + // find a named child that matches. + // + val nc = compileInfo.elementCompileInfos.map { + _.findNamedChild(stepQName, this) // will SDE on not found. + } + nc + } } else { - // since we're first we start from the element, or nearest enclosing - val nc = compileInfo.elementCompileInfo.getOrElse { - // happens for example if you have defaultValue="false" since false looks like a path step, but is really illegal. should be fn:false(). - compileInfo.SDE("The expression path step '%s' has no defined enclosing element.", s) - }.findNamedChild(stepQName, this) - nc + // This is not first step so we are extension of prior step + // + // // First we have to walk up any chain of relative upward path steps. Review comment: Delete commented code. ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org With regards, Apache Git Services