parser change in 19.12 vs 19.05

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

parser change in 19.12 vs 19.05

adrianv
I have noticed that there is a change in parsing between versions
2019.12.21.ai4163 and 2019.05.   I display it here in a simple form:

It the current version the following code is legal:

a=[2,2,3,4];
x = is_list(a) && let(L=len(a)) L > 3 ? 1 : 2;

In the 2019.12 version, the above code produces an error.  It seems that the
let() statement is not allowed in that location.  

I can move it to the front:

x = let(L=len(a)) is_list(a) && L > 3 ? 1 : 2;

but of course then I get an error if a is not a list, "len() parameter could
not be converted".   Yes, I know in this case it's trivial to work around,
but maybe in more complicated cases, it's more of a nuisance to work around
this.

Is this an intentional change in syntax?  If so, why?  



--
Sent from: http://forum.openscad.org/

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: parser change in 19.12 vs 19.05

Parkinbot
Obviously you always can write:
a = [2,2,3,4];
x = is_list(a) && len(a) > 3 ? 1 : 2;

A backward compatible expression for is_list(a) is
a[0]!=undef

In general you can use any (Boolean) function call to replace len().

However, your special semantics can be simply written as
y = a[3]!=undef ? 1 : 2;






--
Sent from: http://forum.openscad.org/

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: parser change in 19.12 vs 19.05

adrianv
The point is not to find a workaround in this toy example, which is the
simplest example I could come up with to display the behavior.  Maybe other
situations in real code are not so trivial.  Yes, you can always work around
it somehow, perhaps with a bunch of temporary variables or more complex
repeated conditions.  

The point is that the syntax has changed.  Is it intentional?  Why did it
change?    


Parkinbot wrote

> Obviously you always can write:
> a = [2,2,3,4];
> x = is_list(a) && len(a) > 3 ? 1 : 2;
>
> A backward compatible expression for is_list(a) is
> a[0]!=undef
>
> In general you can use any (Boolean) function call to replace len().
>
> However, your special semantics can be simply written as
> y = a[3]!=undef ? 1 : 2;
>
>
>
>
>
>
> --
> Sent from: http://forum.openscad.org/
>
> _______________________________________________
> OpenSCAD mailing list

> Discuss@.openscad

> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org





--
Sent from: http://forum.openscad.org/

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: parser change in 19.12 vs 19.05

Parkinbot
This post was updated on .
I wouldn't ever expect to be able to define a variable within a boolean
expression - last but not least, because this is bad programming style. And
I don't regard it as a workaround to call a predicate function that does
intermediate calculations by use of local variables within its own body.

So what was the real intention that led to your question? Would you opt to
allow such freaky possiblities?
E.g.: While the compiler allows you to write
a=[2,2,let(x=10) 3,4];

without a warning, this syntax is obviously not intended, because the value
of x is not accessible.

b=[2,2,let(x=10) 3,4+x];




--
Sent from: http://forum.openscad.org/

_______________________________________________
OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: parser change in 19.12 vs 19.05

Ronaldo
In reply to this post by adrianv


It the current version the following code is legal:

a=[2,2,3,4];
x = is_list(a) && let(L=len(a)) L > 3 ? 1 : 2;

In the 2019.12 version, the above code produces an error.  It seems that the
let() statement is not allowed in that location. 

That seems really a parser change and I don't know why. However I found a way to get the same semantics with
a minimal change that is easily applicable to more complex cases:

a=[2,2,3,4];
x = is_list(a) && ( let(L=len(a)) L > 3 ? 1 : 2 ) ;  

or

a=[2,2,3,4];
x = is_list(a) && ( let(L=len(a)) L > 3 )? 1 : 2;  


_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: parser change in 19.12 vs 19.05

adrianv
In reply to this post by Parkinbot
To me, nearly all uses of let() in OpenSCAD are unexpected and weird.  I have
gotten used to it.  

I have no objection to your example, which I have modified to add a
dependence on x:

a=[2,2,let(x=10) 3*x,4];

You write

b=[2,2,let(x=10) 3,4+x];
 
and complain that x is not accessible.  Why would it be?  Its scope only
extends to the comma, so it's out of scope at the next list entry where you
try to use it.  Basically the behavior as I observe it is that any
expression

expr

can be replaced by

let(expr1) expr

Hence you can replace "3" by "let(x=4) 3*x" in the list.  

a=[2,2,let(x=10) 3*x,4];

There is no reason to expect the scope of the let() to extend to the end of
the list, say.  If you wanted that you need to put the let() before the list
definition begins, as in

a = let(x=10) [2,3,3*x, 4+x];

This to me is pretty strange syntax---defining variables within definitions
of other variables--but it's how one must do things in OpenSCAD.  I don't
find this any less strang than the previous example where the let() was
inside the list.    

With regards to workarounds, it does appear that adding parentheses works,
so my original example can be rewritten like this:

x = is_list(a) && (let(L=len(a)) L > 3) ? 1 : 2;

But note that it is *not* correct to write it as

x = is_list(a) && (let(L=len(a)) L > 3 ? 1 : 2);

which treats the whole second section just as a boolean and results in a
boolean value of x instead of either 1 or 2.  


Parkinbot wrote

> I wouldn't ever expect to be able to define a variable within a boolean
> expression - last but not least, because this is bad programming style.
> And
> I don't regard it as a workaround to call a predicate function that does
> intermediate calculations by use of local variables within its own body.
>
> So what was the real intention that led to your question? Would you opt to
> allow such freaky possiblities?
> E.g.: While the compiler allows you to write
> a=[2,2,let(x=10) 3,4];
>
> without a warning, this syntax is obviously not intended, because the
> value
> of x is not accessible.
>
> b=[2,2,let(x=10) 3,4+x];
>
>
>
>
> --
> Sent from: http://forum.openscad.org/
>
> _______________________________________________
> OpenSCAD mailing list
> [hidden email]
> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org





--
Sent from: http://forum.openscad.org/

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: parser change in 19.12 vs 19.05

doug.moen
In reply to this post by adrianv
adrianv wrote:
> The point is that the syntax has changed.  Is it intentional?  Why did it
> change?

Based on my experience with parsers and programming language syntax, the new behaviour is what I expect, and the old behaviour is unexpected.

It is a matter of operator precedence. The `&&` operator has higher precedence than the `let` operator, so I would not expect that a `let` expression could be parsed as a legal argument to `&&`. Therefore, I would expect that the `let` expression would need to be parenthesized in your example.

I looked at the code, and the parser (a Bison program called src/parser.y) has been rewritten from the former style, which relied on Bison operator precedence declarations, to a new more explicit style that defines a separate non-terminal for each level of operator precedence in an expression. I endorse the new coding style. Previously, the behaviour was "whatever Bison does", which is hard to infer from the source code. Now, the grammar is explicit, and you can see exactly how the arguments to `&&` will be parsed.

So I don't think that the change in behaviour was intentional. I think it was the result of replacing unspecified, implementation defined parsing behaviour with an explicit grammar where we know how things will be parsed.

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org