Giter VIP home page Giter VIP logo

Comments (13)

StrayAlien avatar StrayAlien commented on July 21, 2024

Further to this I guess it goes without saying that the same holds for passing a lambda like this to a BKM. If the function definition body requires context to disambiguate then that context is only known when the BKM invokes the lambda ... which is after you need to parse it ...

Again, all comments welcome.

Greg.

from tck.

etirelli avatar etirelli commented on July 21, 2024

Greg, there are a few syntax problems with your example, but I will answer on what I think is the spirit of your question: the anonymous function syntax (lambdas) can't always be fully resolved at compile time, because of the problems you raised. In fact, a number of the problems you raised here and in other tickets will only be fully solved when the spec moves to a context free grammar.

For DMN 1.2, there was a suggestion to use quoted names for variables with spaces or special characters in it, but there wasn't time in the end to fully resolve all the concerns, as well as there is a concern to maintain backward compatibility in DMN 1.x.

For now, the guideline that the members of the TCK have been using is to ensure compatibility between tools as much as possible and for the most common cases. For edge cases like your example, we will probably only have a complete guarantee of compatibility when DMN 2.0 is released, hopefully with a context free grammar.

from tck.

StrayAlien avatar StrayAlien commented on July 21, 2024

@etirelli Thanks Edson. Appreciated. Referring to one of the things I alluded to in the 'thoughts' threads is that the spec may actually cover for it already. I am not a FEEL nor language grammar expert but here is my take on it. Comments welcome.

Bear with me here in my explanations. I can think of two possible solutions that keep a context free grammar as long as we accept small agree-upon limitations.

Possible solution 1:

Despite the sort() example in the spec, the grammar seems to indicate that a function definition cannot be contained in a textual expression. They can be in 'boxed' expressions, not 'textual'. Grammar rules 1, 2, 55.

1. expression = a.boxed expression | b.textual expression ;

2. textual expression = a.for expression | if expression | quantified expression | b.disjunction | c.conjunction | d. comparison | e. arithmetic expression | f. instance of | g. path expression | filter expression | function invocation | h. literal | simple positive unary test | name | "(" , textual expression , ")" ;

55. boxed expression = list | function definition | context ;

Note 'textual expression has 'function invocation', but not 'function definition'. If this is the case, then I think we're good and do not need a context free grammar. Like I said, not an expert.

A function definition that is not embedded inside in a literal expression, but resides as a stand-alone expression, say, as a context value, can be 'lazy compiled' at execution time. At that point all the context will be available in scope to parse and execute it. The return type may not be known, but that is a lesser evil.

Then the sort function, for example, does not actually have the lambda inline, but references a context value in scope as a param. That context value has he function definition but it is not yet compiled. It is compiled on invocation.

I hope that makes sense.

Possible solution 2

The other possible solution gives embedded lambdas but imposes another small restriction.

Grammar rules 57/58:

57. function definition = "function" , "(" , [ formal parameter { "," , formal parameter } ] , ")" , [ "external" ] , expression ;

58. formal parameter = parameter name [":" type ] ;

A function definition parameters can be typed. So we could have

sort(precedes: function(a:tFoo, b:tBar) etc ...)

If we know the types, we can parse before execution time.

Hopefully, that makes sense also.

Personally, I'd go for 'define a function as a context entry' and stick with that as it is easy to communicate and places less emphasis for users to know types etc etc.

Comments welcome.

Greg.

PS. As an aside, I thought the above 'sort()' example was valid syntax. Very (very) weird .. but valid.

from tck.

etirelli avatar etirelli commented on July 21, 2024

@StrayAlien your overall reasoning makes sense, but from a TCK perspective, we need to take the spec as is, validate/implement/test/critique, and go back to the OMG RTF group with problems that we eventually find.

In particular, in the case of the sort() function and lambda function support, it works if we set constraints according to some rules in the spec.

For instance, I took your example and tested on Drools, and it parses it fine (after fixing the syntax error). Here is the quick parser test I created:

    @Test
    public void testSortExpression() {
        String inputExpression = "sort(precedes: function(a, b) b.tax + total + a.a + a > max(list: for i in ]a.another + total ..5[, j in (2..10[ return i*2 + j*a + total), list: foo)";
        BaseNode pathBase = parse( inputExpression );

        assertThat( pathBase, is( instanceOf( FunctionInvocationNode.class ) ) );
        FunctionInvocationNode sort = (FunctionInvocationNode) pathBase;
        assertThat( sort.getName().getText(), is( "sort" ) );
        assertThat( sort.getParams().getElements().size(), is( 2 ) );

        NamedParameterNode precedes = (NamedParameterNode) sort.getParams().getElements().get(0);
        assertThat( precedes.getName().getText(), is( "precedes" ) );
        assertThat( precedes.getExpression().getText(), is( "function(a, b) b.tax + total + a.a + a > max(list: for i in ]a.another + total ..5[, j in (2..10[ return i*2 + j*a + total)" ) );

        NamedParameterNode list = (NamedParameterNode) sort.getParams().getElements().get(1);
        assertThat( list.getName().getText(), is( "list" ) );
        assertThat( list.getExpression().getText(), is( "foo" ) );
    }

This will probably fail at runtime, because things like 'a.another + total' is probably(?) an expression, but is being parsed as a path variable name (according with the default parsing rules of the grammar). But again, that is how the spec works today. If the user wants to disambiguate that, he has to provide type information as you mention in your "possible solution 2", or use parenthesis as suggested in the spec: (a.another) + total.

PS: the syntax error I referred to in my previous post is that the exclusive range character is the flipped square bracket, not parenthesis. So the correct expression would be:

sort(precedes: function(a, b) b.tax + total + a.a + a > max(list: for i in ]a.another + total ..5[, j in (2..10[ return i*2 + j*a + total), list: foo)

Just a final note, don't pay too much attention to the grammar rule names. The fact that some of the constructions are named "boxed expressions" in the grammar have no effect on their use in the language. They do refer to the fact that those expression have boxed expressions equivalents in DMN, but in no way they prevent their use in textual literal expressions.

from tck.

StrayAlien avatar StrayAlien commented on July 21, 2024

@etirelli . Thank you Edson. Appreciated. I'll digest that in the coming days (just working on some other DMN tests atm). You have an eagle eye. Well done. - yes, the left range delimiter is not correct. My reading of the spec had it differently. Thank you again. Something (else) to add to the test suite!

As another note on func ambiguity .. I'll raise another issue. Just writing 'instance of' tests ...

from tck.

etirelli avatar etirelli commented on July 21, 2024

@StrayAlien can we close this ticket?

As discussed, the grammar is ambiguous, but it is possible to parse expressions like you presented and there are some guide rules on how to decide when there are ambiguities. That is the best we can aim for from a testing perspective at the moment.

from tck.

StrayAlien avatar StrayAlien commented on July 21, 2024

Hi @etirelli, thanks for replying - appreciated. What are the guide rules? If we all stick to them then great. Dare I ask if they are documented somewhere handy?

from tck.

etirelli avatar etirelli commented on July 21, 2024

@StrayAlien there are some references spread on chapter 10 of the spec, but I was referring specifically to chapter "10.3.1.6 Ambiguity". In particular to:

Ambiguity is resolved using the scope. Name tokens are matched from left to right against the names in-scope, and the longest match is preferred. In the case where the longest match is not desired, parenthesis or other punctuation (that is not allowed in a name) can be used to disambiguate a FEEL expression. For example, to subtract b from a if a-b is the name of an in-scope context entry, one could write (a)-(b). Notice that it does not help to write a - b, using space to separate the tokens, because the space is not part of the token sequence and thus not part of the name.

As I mentioned previously, such guidelines are not fool proof. For instance, the guideline defines how to parse "a + b" if "a", "b" and/or "a + b" are previously declared as variables, but it doesn't define what to do when none of them are declared. It also is not clear about fields of variables without type. But, it does allow users to use ( ) to disambiguate expressions, in case type information is not fully available at parsing time.

from tck.

opatrascoiu avatar opatrascoiu commented on July 21, 2024

I believe that an issues was raised https://issues.omg.org/issues/DMN13-121

from tck.

opatrascoiu avatar opatrascoiu commented on July 21, 2024

There is a proposal that is part of Ballot 6. Should be voted by 13th of March.

from tck.

StrayAlien avatar StrayAlien commented on July 21, 2024

Hi @opatrascoiu, anywhere we can see that proposal?

from tck.

opatrascoiu avatar opatrascoiu commented on July 21, 2024

The proposal has been voted this week.

The normal procedure is to attach documents when submitted a proposal. The attached documents are available in the public UI. In this case, becuase the change was small, it was specified in the jira ticket, hence is not visible in the public UI.

The change is

Change grammar rule 2.h. on pg 111 of formal-19-01-05 to
literal | simple positive unary test | name | "(" , expression , ")" ;

from tck.

agilepro avatar agilepro commented on July 21, 2024

I think this is all done. Closing. REopen if there are any more questions.

from tck.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.