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

Automatic return values #302

Open
hildjj opened this issue Jun 19, 2022 · 9 comments
Open

Automatic return values #302

hildjj opened this issue Jun 19, 2022 · 9 comments
Labels
enhancement New feature or request

Comments

@hildjj
Copy link
Contributor

hildjj commented Jun 19, 2022

If you want to return a single piece of your rule definition, or you want to return an array, plucking works really well. If you would like to return an object, you have to write a rule action that includes JS.

Examples:

foo = @"1"  // returns "1"
bar = @"2" @"3" // [ '2', '3' ]
baz = four:"4" five:"5" { return { four, five } } // { four: '4', five: '5' }

It would be cool if rules without an action could generate an object without the JS action. Proposal:

baz = @four:"4" five:"5" @six:"6" // { four: '4', six: '6' }

This is a slight break in backward-compat (today, this generates ['4', '6']), but this syntax is currently allowed and really only useful for predicates at the moment, so it shouldn't break too many things. An alternate approach:

baz = four:"4" five:"5" six:"6" // { four: '4', five:'5', six: '6' }

has similar compatibility issues (today, that generates ['4', '5', '6']), but doesn't have as much flexibility.

If we're worried about back-compat, we can add a flag to the compiler to turn on this behavior.

@hildjj hildjj added the enhancement New feature or request label Jun 19, 2022
@hildjj
Copy link
Contributor Author

hildjj commented Jun 19, 2022

See https://github.com/arcanis/arpege#automatic-return-values for the original idea.

@reverofevil
Copy link

reverofevil commented Jun 19, 2022

Luckily we're programming in JS, where you can have an array that is also an object.

// rule = a:number b:number
const a = [1, 2];
Object.assign(a, {a: 1, b: 2});

We can also define a getter/setter on the array, so that the first time someone accesses its elements (with a number), there is a console.error telling that in the next major version of Peggy it will be just an object. The opt-in flag can switch codegen from this behavior to proper objects. The question is, how bad the performance of such array-objects is compared to bare arrays or objects.

Also TypeScript supports named fields in tuples, and using arrays instead of objects is semi-common performance optimization nowadays. Probably in future there should be a flag to not generate objects instead of arrays there.

My proposal for semantics:

  • pick all the @ and :, or pick everything otherwise;
    • if there are @ and ;, error;
    • if picked @ or everything;
      • if the number of picked terms is 1;
        • return the value without boxing it into a [];
        • otherwise, return a [];
    • if picked :;
      • always box into an {};
      • if sequence is a direct descendant of a rule (i.e. not r = a:a b:b | c), add type: field with the name of the rule.

(Also, IMO, @a:b syntax is utter garbage, and I'm surprised the grammar even allows it. It literally plucks same value in two different ways!)

@hildjj
Copy link
Contributor Author

hildjj commented Jun 19, 2022

  • if there are @ and ;, error;

That won't work quite as-is, because that's currently legal and useful for predicates:

foo = @n:$[0-9]+ ! { return n[0] === '0' } // Currently returns "19" but not "019".

(this is just a quick example, not a good grammar.)

add type: field with the name of the rule

That's interesting. I'd like to use a word that isn't a valid rule name, or even better, a Symbol, instead of "type"

@hildjj
Copy link
Contributor Author

hildjj commented Jun 19, 2022

I'm not sure about the arrays with extra properties on them yet, I'll need to think about that a little. However it is a very elegant solution.

@Mingun
Copy link
Member

Mingun commented Jun 19, 2022

IIRC, proposed solution with

rule = @label:expression

was considered when plucking implementing, but then came to the conclusion that this may not be quite obvious (pegjs/pegjs#235)

@hildjj
Copy link
Contributor Author

hildjj commented Jun 19, 2022

I see Qix as the only one who said it was too magical, in this comment. I think now that we've lived with @ for a while, @label: doing something useful doesn't feel that magical to me.

@reverofevil
Copy link

reverofevil commented Jun 19, 2022

That won't work quite as-is, because that's currently legal and useful for predicates:

Oh god forbid.

That's interesting. I'd like to use a word that isn't a valid rule name, or even better, a Symbol, instead of "type"

It's quite standard for disjoint unions to have a type field. Only if someone is implementing typed programming languages where they might want to use type for types there was a kind once, and probably I've also seen a tag.

For something that is not often used, I'd suggest $. It's valid JS property name with a.$ access, you don't have to a[symbol] for it. Also, unlike with symbols, you can serialize it to JSON. Even current /online wouldn't show such fields. (Then I'd ban in a major version of Peggy all $ from identifier names both to avoid conflict here, and to save users of defining things that clash with peg$....)

@reverofevil
Copy link

Now that I thought about serializing AST to JSON, I'm not sure if array-object should be serialized as an array, or if it should have a custom toJSON. Either option seems to cause someone pain.

@hildjj
Copy link
Contributor Author

hildjj commented Jun 19, 2022

For something that is not often used, I'd suggest $.

That works for me.

custom toJSON

Yeah, this is one of several issues we'd need to figure out. I'll note that the other way we could go is to return a plain object with properties for each of the array indexes as well as each label. However, the compatibility of that approach may not be good enough to be worth the extra complexity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants