qt4cg / qtspecs

QT4 specifications
https://qt4cg.org/
Other
27 stars 15 forks source link

Ambiguity in XPath EBNF - Lookup with TypeQualifier vs DynamicFunctionCall #1314

Open johnlumley opened 1 week ago

johnlumley commented 1 week ago

Additional to https://github.com/qt4cg/qtspecs/issues/1050 An additional ambiguity occurs in one of the deep lookup examples:

$tree ??$from ??type(record(to, distance))[?to=$to] ?distance

which can be simplified to

$tree ??type(foo)

where there is ambiguity between a LookupExpr with TypeQualifier and a DynamicFunctionCall on a function named type. That is, type should perhaps be one of the restrictions on function name to avoid this ambiguity.

Whether something more fundamental is needed on the productions around [74],[75] and [84]-[88] I'm not sure, but certainly type can appear either as a keyword for TypeQualifier (consuming the bracketed type) or a value of an NCName (with the bracketed section being a higher-level PositionalArgumentList), both being part of aKeySpecifier.

rhdunn commented 6 days ago

As noted in the meeting, the type and record keywords should be added to the reserved function name list.

johnlumley commented 5 days ago

I don't think it's quite as simple as that. Taking the simple example:

$tree ??type(foo)

and a reduced-tree grammar, we get two parses:

<XPath xmlns:ixml="http://invisiblexml.org/NS" ixml:state="ambiguous">
   <ValueExpr>
      <LookupExpr>
         <VarRef>
            <QName local="tree"/>
         </VarRef>
         <Lookup>??<TypeQualifier>
               <SequenceType>
                  <QName local="foo"/>
               </SequenceType>
            </TypeQualifier>
         </Lookup>
      </LookupExpr>
   </ValueExpr>
</XPath>

which is probably the intended meaning, and

<XPath xmlns:ixml="http://invisiblexml.org/NS" ixml:state="ambiguous">
   <ValueExpr>
      <DynamicFunctionCall>
         <LookupExpr>
            <VarRef>
               <QName local="tree"/>
            </VarRef>
            <Lookup>??<QName local="type"/>
            </Lookup>
         </LookupExpr>
         <PositionalArgumentList>
            <ValueExpr>
               <AxisStep>
                  <QName local="foo"/>
                  <PredicateList/>
               </AxisStep>
            </ValueExpr>
         </PositionalArgumentList>
      </DynamicFunctionCall>
   </ValueExpr>
</XPath>

where the bracketed section is taken as arguments to a dynamic function call via a LookupExpr, the lookup key of which happened to be type, and similarly for record. (If we change the expression to $tree ??Type(foo), the ambiguity disappears of course and it parses as a DynamicFunctionCall.)

In this case it isn't a function call that would have to disallow type, but the conjunction of a Lookup with key type within a DynamicFunctionCall. The alternative would be to forbid type or record being used as lookup keys, which I don't think would go down very well.

rhdunn commented 5 days ago

Right, so the actual ambiguity is in LookupExpr parsing a TypeQualifier or NCName:

    $tree??type(foo)
           ^^^^^^^^^ -- KeySpecifier / TypeQualifier
         ^^^^^^^^^^^ -- Lookup
    ^^^^^^^^^^^^^^^^ -- LookupExpr

    $tree??type(foo)
           ^^^^      -- KeySpecifier / NCName
         ^^^^^^      -- Lookup
    ^^^^^^^^^^^      -- PostfixExpr / LookupExpr
    ^^^^^^^^^^^^^^^^ -- DynamicFunctionCall

Does moving TypeQualifier to the start of the KeySpecifier list resolve this? I.e.

[88]        KeySpecifier       ::=      TypeQualifier | NCName | IntegerLiteral | StringLiteral | VarRef | ParenthesizedExpr | LookupWildcard   

And do we need to do the same with PostfixExpr for DynamicFunctionCall (moving it to the end):

[75]        PostfixExpr        ::=      PrimaryExpr | FilterExpr | LookupExpr | FilterExprAM | DynamicFunctionCall
johnlumley commented 5 days ago

Does moving TypeQualifier to the start of the KeySpecifier list resolve this?

I don't think so, as the order of alternatives in EBNF doesn't, I think, constitute a priority order. (Please correct me if I'm wrong, but I can't see anything that suggests that)

rhdunn commented 5 days ago

I'm not sure as I've only hand-written the XPath/XQuery parser, so would handle this case by maximally matching the TypeQualifier i.e. by placing it before testing for an NCName.

johnlumley commented 5 days ago

If maximal matching on TypeQualifier is required, it needs to be stated in the extra-grammatical notes of the spec. (Such is already done for occurrence indicators on function types.) If this is the case then I assume:

($tree??type)(foo)

would be required and allow dynamic lookup and evaluation of a function via a type keyspecifier.

michaelhkay commented 5 days ago

I would have expected the rule "Postfix expressions are evaluated from left-to-right." (in 4.3) to cover this. But actually, that would encourage the ($tree??type)(foo) interpretation. And I agree, while we can make type a reserved function name easily enough, we can't make it a reserved key in a map. So perhaps we do need to find a different syntax.