-
Notifications
You must be signed in to change notification settings - Fork 228
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
peg: add support for "true" and "false" primitives to always/never match #1187
Conversation
The use cases involve user-expandable grammars. For example, consider the IRC nickname specification. > They SHOULD NOT contain any dot character ('.', 0x2E). > Servers MAY have additional implementation-specific nickname restrictions. To implement this, we can do something along these lines: ```janet (def nickname @{:main '(some :allowed) :allowed (! (+ :forbidden/dot :forbidden/user)) # for lax mode, (put nickname :forbidden/dot false) :forbidden/dot "." # to add your own requirements # (put nickname :forbidden/user 'something) :forbidden/user false}) ``` Additionally, it's common in parsing theory to allow matches of the empty string (epsilon). `true` essentially allows for this. Note that this does not strictly add new functionality, you could emulate this previously using `0` and `(! 0)` respectively, but this should be faster and more intuitive. The speed improvement primarily comes from `(! 0)` which is now a single step.
As a comparison, I suppose Here, it's perhaps not as puzzling (though perhaps it's less puzzling once you've learned what it means compared to As a minor point, please consider using astyle to format via |
TYVM! |
Somewhat related...I had failed to notice that one of the website doc examples here uses (def my-grammar
'{:a (* "a" :b "a")
:b (* "b" (+ :a 0) "b")
:main (* "(" :b ")")}) |
Would another possible approach be to add a couple of key-value pairs to I guess that:
|
For pegs there is actually no perf penalty for indirection like that - but perhaps names like :always and :never might make more sense. I don't mind the short notation but I do see that many people prefer more verbose and descriptive style with pegs |
I do think true/false makes sense to use here, because it is fairly intuitive, and it's nicer to have built-in types have meaning rather than be a compiler error (i.e PEG grammars are a bit closer to being total, which is a nice-to-have). On the other hand, |
To follow up a bit on this, was working on wrapping my head around related details and found that possibly the original example grammar could use a bit of tweaking. This is what I ended up with (including some example invocations): (def nickname
~@{:main (capture (sequence (some :allowed) -1))
:allowed (if-not (choice :forbidden/dot :forbidden/user) 1)
# for lax mode, (put nickname :forbidden/dot false)
:forbidden/dot "."
# to add your own requirements
# (put nickname :forbidden/user 'something)
:forbidden/user false})
(peg/match nickname "alice")
# =>
@["alice"]
(peg/match nickname "good.alice")
# =>
nil
# operating on a clone of the table might be better sometimes?
(put nickname :forbidden/dot false)
(peg/match nickname "alice")
# =>
@["alice"]
(peg/match nickname "good.alice")
# =>
@["good.alice"] |
i thought having compiler error is a good thing! overall, I don't think this feature is needed. |
I think On a side note, I attempted an implementaion of them in margaret. |
This lacks nuance. First, let's establish that, as a blanket statement, it's simply incorrect. This purpose is typically to prevent what would have been a runtime error, but without requiring that the user actually hit that code path. Runtime errors are good when the behavior is either blatantly incorrect, or virtually guaranteed not to be the intended one. Generally speaking, within reason, it's good when language built-ins are total. To drive the point home, consider: what if existing functions were less total?
As for whether the feature is needed, a better time to discuss that would have been before it was merged, half a year ago. |
I appreciate the detailed explanation wrt compiler errors and overall I agree with the most recent comment -- including that a better time to discuss necessity would have been way earlier. However, I don't agree about closing further comments outright. This is the most natural place to follow-up on the example content and in this case, the original grammar was not functional as-is: (def nickname @{:main '(some :allowed)
:allowed (! (+ :forbidden/dot :forbidden/user))
# for lax mode, (put nickname :forbidden/dot false)
:forbidden/dot "."
# to add your own requirements
# (put nickname :forbidden/user 'something)
:forbidden/user false}) I've definitely found it helpful to be able to add comments to PRs and issues later when further details have surfaced. It has sometimes helped with later investigation as things tend to be more consolidated. Searching on this forge is not very good to put it mildly. |
The use cases involve user-expandable grammars.
For example, consider the IRC nickname specification.
To implement this, we can do something along these lines:
Additionally, it's common in parsing theory to allow matches of the empty string (epsilon).
true
essentially allows for this.Note that this does not strictly add new functionality, you could emulate this previously using
0
and(! 0)
respectively, but this should be faster and more intuitive.The speed improvement primarily comes from
(! 0)
which is now a single step.