J1A8448169611 has quit [Ping timeout: 252 seconds]
lastrodamo has joined #openscad
J1A84481696114 has quit [Ping timeout: 252 seconds]
J1A8448169611461 is now known as J1A84
snaked has quit [Quit: Leaving]
xxpolitf has quit [Quit: leaving]
teepee_ has joined #openscad
teepee has quit [Ping timeout: 258 seconds]
teepee_ is now known as teepee
epony has joined #openscad
lastrodamo has quit [Quit: Leaving]
qeed has quit [Quit: qeed]
qeed has joined #openscad
castaway has quit [Ping timeout: 268 seconds]
<InPhase>
JordanBrown[m]: I think we should contemplate and discuss a bit about whether or not an object-function solution in lieu of module literals at all is really sufficient.
<InPhase>
JordanBrown[m]: It seems the two issues we thought about so far were the parser challenges of grabbing function literals out of weird evaluations and manifesting them as an instantiated geometry, and the issue of children. But I think we are in agreement that the first is going to be an identical set of problems to that of making module literals work in the same place. So really the only thing I'm
<InPhase>
currently seeing as an issue is the question of children.
<InPhase>
The failure to have children available does not actuall break it, because they can become object parameters under this approach, which is actually MORE flexible. But it would still be nice if we could somehow preserve the standard syntax.
<JordanBrown[m]>
Can’t really talk now, in the middle of lunch. But I am not sure that the module reference parsing problem is as serious as the “add geometry object to model” problem. The set of expressions that are reasonable for module references is much smaller.
<InPhase>
The parser is already setup to pick up children in a module context, so it seems to me like all it requires is somehow providing to the function literals an accessible children element, like in the modules context.
<InPhase>
But there are a lot of potential complications, so I figure it will require some thought.
<InPhase>
And sure, it doesn't need to be now. I'm just pre-feeding some thoughts for later, as they popped into head.
<InPhase>
The object to model problem is a little tricky, but I think that's doable mostly because nothing else looks like it. :)
<InPhase>
But, there is quite possibly a tricky edge case lurking.
teepee_ has joined #openscad
teepee has quit [Ping timeout: 258 seconds]
teepee_ is now known as teepee
<JordanBrown[m]>
Invoking module references in statement context (where the simple case looks like a traditional module invocation) can I think be done by replacing the ID token with a “call” production. That will allow identifier(), list[i](), obj.elem(), func()() and (expr)().
<JordanBrown[m]>
Burying the generality of expressions in (expr) does not bother me in that context because there just aren’t very many expressions that make sense for module references. Other than the ones I listed, the only one that I cam think of is ?:, and that would already need parens because of precedence.
<tcurdt>
I have a STL that OpenSCAD doesn't seem to like. Any advice to fix it?
<tcurdt>
It seems like netfabb got absorbed by autodesk. But the basic version would probably not have been enough anyway.
<JordanBrown[m]>
One thing that might be awkward, but in the long run good, is that we might have to allow expression-context mentions of traditional and built-in modules.
<JordanBrown[m]>
(All of this is primarily for InPhase )
<JordanBrown[m]>
The reason for that is that the syntax would be basically an expression that evaluates to a module reference, followed by module invocation args. That implies that bare names (including traditional and built-in modules) need to evaluate to a module reference.
<JordanBrown[m]>
If we can get that to work it would be good generality. The trick would be the name space collision with variables, that in this context you want the module to “win” but in general expressions you want the variable to “win”.
<JordanBrown[m]>
And as I write that I have a feeling of dread…
<JordanBrown[m]>
tcurdt: sorry, not my area of expertise.
<InPhase>
JordanBrown[m]: I have less dread, but think we just need to plan out a little carefully the divide between "what should evaluate this" and "what should this do". What a thing does, does not need to follow from the parser. It can follow from the type information after lookup.
<InPhase>
Although I think strictly speaking we have unique parsing anyway for all scenarios, where the alternative is "fail". The only arbitrariness from lookup would be things like "call a function that needs to return an object for this to be semantically valid" or "call a module".
ur5us has joined #openscad
castaway has quit [Ping timeout: 268 seconds]
<InPhase>
Foo = function(x) x<10 ? "bar" : { cube(x); }; Foo(12); Foo(5); // This for example is syntactically valid, can be parsed, and can be evaluated. But the second invocation should be a warning.
<JordanBrown[m]>
Agree that there are syntactically valid cases that are semantically invalid.
<JordanBrown[m]>
But I am concerned about syntax conflicts or cases where it would be hard to do the right semantic thing without contorted parsing.
<InPhase>
Likewise with: a = [Foo, 5]; a[0](a[1]); a[1](a[0]);
<JordanBrown[m]>
cube=5; cube(); needs to invoke the cube module. cube=5; (cube)(); probably needs to be an error.
<InPhase>
It looks like: echo(a[0](a[1])); echo(a[1](a[0])); already behaves as desired for function literals, so we're mostly there.
<JordanBrown[m]>
It would be weird if putting an identifier in parentheses caused it to be interpreted using different rules.
<InPhase>
This just needs to be extended to the module call context.
<InPhase>
Well, actually it could be convenient.
<InPhase>
It does change the context after all.
<InPhase>
You'd almost never need that, and wouldn't hit it accidentally, but it could be a convenient workaround in some edge cases.
<JordanBrown[m]>
You mean that the parens change the context? Maybe, but only maybe.
<InPhase>
Many languages have something like that.
<InPhase>
I'd never plan that as a special case, but I can accept it as a natural consequence of existing behavior.
<JordanBrown[m]>
Allowing a[i](); and o.m(); and f()(); at the top level all imply that the real syntax is <expression>(), which in turn implies that in cube(); the “cube” evaluates to a module reference.
<JordanBrown[m]>
If we were starting from zero that would be clearly right, but we are starting with a split namespace…
<joseph_>
teepee: Several items on my schedule this week ended up consuming massively more time than expected. So I am just getting a chance now to resume writing of the final report. I think with time this weekend it's still on track to be ready for Oct 9 submission, depending on whether you look at it beforehand and offer feedback. However my GSoC portal still says Oct 23, and I didn't see another update from you about contacting Sean.
<joseph_>
In the event that the date cannot be moved back in time, I believe it is fine to keep the current Oct 23 deadline (I would just have finished early)
<JordanBrown[m]>
Oops looks like a bunch of punctuation might have been eaten in that. Did it look right?
<InPhase>
JordanBrown[m]: But we don't need a split namespace anymore, because we agreed on a lookup rule.
<InPhase>
JordanBrown[m]: In what we can call the "module lookup context" we look up modules first, then functions.
<JordanBrown[m]>
The question is whether we know at lookup time which lookup to do.
<InPhase>
One, then the other. :)
<JordanBrown[m]>
Normally at parse time we know what context to use, but as we allow more complex structures it gets less obvious.
<teepee>
joseph_: yes, we probably don't want to touch this anymore at this point, my suggestion would be to just check the dashboard and follow that as soon as things open up
<InPhase>
JordanBrown[m]: Well for anything that is obtaining a value to be passed or assigned, we do only the function lookup. For anything that is a bare call, we do the module then function lookup order.
<InPhase>
We simply adhere to the baked in rule that modules will never return values.
<InPhase>
And then lookup order saves us in the other direction.
<joseph_>
teepee: That is fine by me, I think receiving the stipend late is not a significant downside. My only question is whether your most recent message to Sean requested moving the date back in time. I want to make sure that the end date doesn't unexpectedly go back to Oct 9th resulting in a missed deadline. Unfortunately the submission doesn't open until the "last week" starts so I can't officially submit this weekend currently
ur5us has quit [Remote host closed the connection]
ur5us has joined #openscad
<JordanBrown[m]>
I’m not even worrying yet about functions that return geometry. I’m just worrying about variables versus traditional and built-in modules.
<InPhase>
An example of the ambiguity?
<JordanBrown[m]>
It isn't an ambiguity, exactly.
<JordanBrown[m]>
Considering only module references - that is, data items that refer to modules...
<teepee>
joseph_: no, I gave up on trying to move things around. it's too scary this close to the deadline and google usually being very strict on dates
<InPhase>
Here's a way to think about it: Everything is an expression which is passed to something, such as an assignment or a call. At the top level of every expression things are passed to an implicit sort of AddGeometry.
<teepee>
I still don't know how we ended up with that date, but if the dashboard works with that, we should be fine
<InPhase>
JordanBrown[m]: Well maybe not needing modref(), but sure, approximately that.
<JordanBrown[m]>
Yes, maybe functions that return geometry can fill in that gap, totally eliminating the need for module references, module literals, et cetera.
<JordanBrown[m]>
But only maybe; they will still be a bit weird since they probably would not behave like modules.
<JordanBrown[m]>
And I think they have even worse parsing problems.
<JordanBrown[m]>
But going with that list for the moment...
<InPhase>
I think we can solve that, but we'll defer that issue for simplicity.
<JordanBrown[m]>
That suggests that in
<JordanBrown[m]>
x();
<JordanBrown[m]>
x is an expression that evaluates to a module reference.
<InPhase>
Seems okay so far.
<JordanBrown[m]>
*Maybe* that expression can be a totally normal expression, coming in at the top of the definition of "expression". Most variations coming in at the top would not be valid.
<InPhase>
We don't really need to call it a module reference though.
<InPhase>
For simplicity, lets evaluate it to a module_lookup function.
<JordanBrown[m]>
(Hmm. As I think about allowing the top-level "expression" production... I don't think that would work.)
<InPhase>
The parser doesn't need to exactly match the semantics. It just needs to match a processing function that can handle the syntactic context correctly.
<JordanBrown[m]>
So let's assume that we say that a statement-context module invocation is a "call" followed by arguments.
<JordanBrown[m]>
Where today it is an identifier followed by arguments.
<JordanBrown[m]>
A "call", in case you don't have parser.y memorized, is a primitive, an array lookup, an object lookup, or a function invocation. Or something a lot like that. And primitive includes identifiers.
<JordanBrown[m]>
So at first blush that seems to match our needs: identifier, array lookup, et cetera.
<JordanBrown[m]>
But let's look closely at the "identifier" case.
<InPhase>
Sounding okay so far.
<JordanBrown[m]>
Normally in an expression when we see an identifier we look it up as a variable. Natural use of "call" will cause that to happen.
<joseph_>
teepee: I think that was a good judgement. I have set up calendar alerts for Oct 16th (the first day of the final week, presumably the earliest that submission opens). As for the final report I will ping you as soon as I have posted it as a comment on my central pull request
<JordanBrown[m]>
And note that by the time that "call" sees it, it doesn't *know* that it was originally an identifier.
<JordanBrown[m]>
It's just the result of an evaluation.
<JordanBrown[m]>
In a single-namespace environment, that would be fine.
<JordanBrown[m]>
"cube" would evaluate to a module reference to the cube module.
<JordanBrown[m]>
and everybody would be happy.
<JordanBrown[m]>
But we don't have that, and if there's a variable named "cube", the natural evaluation semantics will turn its value.
<JordanBrown[m]>
And then the module-invocation layer will say "why did you ask me to call a five?"
<teepee>
joseph_: sounds good. you may need to share that separately in addition. It's likely the dashboard will open for mentors only after the deadline
<JordanBrown[m]>
But if we had that symbol lookup return a reference to the cube builtin by default, then module invocation would be happy, but ordinary expressions would not.
<InPhase>
So we make an mcall.
<JordanBrown[m]>
Do you mean invoke a module?
<JordanBrown[m]>
or execute/evaluate if you prefer those words.
<InPhase>
The mcall at the top level must prioritize module lookup.
<JordanBrown[m]>
Right... but in the obvious way to structure the syntax, the lookup gets done something like four layers below that, where it doesn't know that it's supposed to be a module lookup.
<InPhase>
Well the mcall layers need to do a different thing.
<JordanBrown[m]>
We could maybe special-case the identifier() case, either by duplicating some parsing with a modification or maybe with precedence directives. (I'm not sure exactly how those work.)
<InPhase>
Like, a separate parse tree with the same behavior?
<JordanBrown[m]>
For a layer or two, yes.
<JordanBrown[m]>
Because it has to have subtly *different* behavior.
<InPhase>
And in nested parts that won't evaluate to the module call, they go to call.
<JordanBrown[m]>
I don't quite understand that, but I think so.
snaked has joined #openscad
<InPhase>
I don't quite understand it either, but it feels doable. ;)
<JordanBrown[m]>
With that special case logic, we would recognize simple-identifier module calls up at the layer that recognizes module calls.
<JordanBrown[m]>
And they would use a lookup that prioritizes traditional and builtin modules over variables.
<JordanBrown[m]>
But that special-ness can't extend all the way down; that way lies madness.
<InPhase>
I think it specifically can't extend all the way down.
<JordanBrown[m]>
and so since one of the constructs that kind of automatically falls out is
<JordanBrown[m]>
(expr)();
<JordanBrown[m]>
if you are down in that expression and you say "cube", you're in an expression that is *not* special, and so "cube" has to prefer the variable.
<JordanBrown[m]>
and that semantic difference from putting parentheses around something that's supposed to be an expression is bothersome.
<JordanBrown[m]>
I should look at how parallel constructs related to function references are handled. I don't know whether the same issue is present there, or how it's handled.
<InPhase>
Looks like 472 of parser.y, where call right above it sub-evaluates to primary, which evaluates to (expr)
<InPhase>
Then expr does the function literal lookup.
<InPhase>
Or, somehow. I don't see that in the expr parse.
<JordanBrown[m]>
The question is how
<JordanBrown[m]>
echo(sin(45));
<JordanBrown[m]>
doesn't yield an error.
<JordanBrown[m]>
sin = 0;
<InPhase>
Well, that ends up on 472.
<JordanBrown[m]>
if the f in f() is an expression that evaluates to a function reference, it should get up to the point of wanting to make the function call, and then say "what is this zero?".
<JordanBrown[m]>
You can look at it some, and I'll look at it later, but as been happening way too often recently I've spent far more time on OpenSCAD during work hours than I should have, and need to get back to the stuff my boss wants me to do.
<InPhase>
Yep, fair. I'm mostly doing these discussions during my home hours, but we are probably in different timezones. :)
<InPhase>
Ah, right. I remember seeing that big headquarters building off of the 101. I suppose that's about where you are hiding out. :)