Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow lazy evaluation of some expressions #663

Open
Rangi42 opened this issue Dec 24, 2020 · 4 comments
Open

Allow lazy evaluation of some expressions #663

Rangi42 opened this issue Dec 24, 2020 · 4 comments
Labels
enhancement Typically new features; lesser priority than bugs rgbasm This affects RGBASM

Comments

@Rangi42
Copy link
Contributor

Rangi42 commented Dec 24, 2020

This is an internal requirement for features including:

@Rangi42
Copy link
Contributor Author

Rangi42 commented Dec 24, 2020

I don't know if constructing a whole RPN tree would be necessary for these, at least not for short-circuiting logic operators. Instead, consider an isEvaluating flag for the parser. When given false && X, as soon as it reaches the && is sets isEvaluating = false for the duration of parsing X; likewise for true || X, and for both cases of ?:. This flag would disable symbol lookup and actual math and just keep evaluating a trivial 0 value, so syntax errors would still occur but not evaluation errors.

User-defined functions are more complicated but might also be doable without RPN trees. Their body would be captured like a macro body when they're defined. Then when they're called, the parser would expand the function body similar to a macro body, but instead of substituting the parameters \1, \2, etc at lex time, it would evaluate the parameters like any other symbols at parse time. This would mean keeping a context of which function it's in so that the parameter names map to the right argument values (symbol "layering" as mentioned in #662).

@ISSOtm ISSOtm added enhancement Typically new features; lesser priority than bugs rgbasm This affects RGBASM labels Jan 21, 2021
@ISSOtm
Copy link
Member

ISSOtm commented Jan 21, 2021

The proposed solution for user-defined functions would imply re-parsing them, which is slow, and can be avoided since the expression tree won't change. This is why I'm pushing so hard to decouple expression evaluation from parsing.

Evaluation can still be eager for purely numeric expressions (1 + 1 will never change), and yield a "bad" RPN expression (say, pointing to NULL, so it doesn't require allocating a 1-byte buffer) for e.g. 1 / 0; that expression could be discarded due to short-circuiting, or turned into an error when trying to get a number out of it.

I believe this is necessary for a proper user-defined function implementation, notably to avoid technical debt, and since I think it also encompasses the other usages, I think we shouldn't use "partial" impls. This is why I've been reluctant to merge #665.

@ISSOtm
Copy link
Member

ISSOtm commented Apr 19, 2021

Here are my thoughts on implementing this:

  • Change the RPN IDs to have $80+ be errors; so the current immediates ($80 and $81) would become e.g. $70 and $71.
  • When encountering a hard error, such as a division by 0, emit a RPN "error" byte, say $80 for RPN_DIV_BY_ZERO.
  • RPN errors get turned into hard errors when:
    • The expression's value is extracted (either by RGBASM in the const productions, or by RGBLINK)
    • Attempting to emit a RPN expression solely containing an error (to catch db 1 / 0 early)

This way, db 1 || 2 / 0 would first generate the RPN buffer RPN_CONST 1 RPN_CONST 2 RPN_CONST 0 DIV, which RGBASM would collapse to RPN_CONST 1 RPN_DIV_BY_0, and seeing the ||, RGBASM would see the first constant, and ignore the RHS.
(Note that RGBASM would actually internally store the expressions differently due to their "const" status, but the principle stays the same.)
Assuming 1 is an unknown (wNonZeroLabel), RGBLINK would basically perform the same, though instead having to skip the RHS in the buffer, but that should be doable by keeping track of pushes and pops in the RPN stack, without actually evaluating anything.

Am I missing anything there?

@Rangi42
Copy link
Contributor Author

Rangi42 commented Apr 19, 2021

To avoid reserving half of the IDs for errors, the defined error values could count down from $FF, and check for a minimum threshold value instead of the high bit.

@Rangi42 Rangi42 modified the milestones: v0.5.1, v0.6.0 Apr 25, 2021
@ISSOtm ISSOtm mentioned this issue Jul 27, 2021
@Rangi42 Rangi42 removed this from the v0.10.0 milestone Aug 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Typically new features; lesser priority than bugs rgbasm This affects RGBASM
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants