From f9ab91511d42fe817bd409f928e9158ec65f84b9 Mon Sep 17 00:00:00 2001 From: Chloe Kudryavtsev Date: Sun, 11 Jun 2023 10:44:39 +0200 Subject: [PATCH] peg: add support for "true" and "false" primitives to always/never match 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. --- src/core/peg.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/core/peg.c b/src/core/peg.c index a814e65f..a087ddfa 100644 --- a/src/core/peg.c +++ b/src/core/peg.c @@ -735,6 +735,12 @@ static const uint8_t *peg_getrange(Builder *b, Janet x) { return str; } +static int32_t peg_getboolean(Builder *b, Janet x) { + if (!janet_checktype(x, JANET_BOOLEAN)) + peg_panicf(b, "expected boolean, got %v", x); + return janet_unwrap_boolean(x); +} + static int32_t peg_getinteger(Builder *b, Janet x) { if (!janet_checkint(x)) peg_panicf(b, "expected integer, got %v", x); @@ -1261,6 +1267,13 @@ static uint32_t peg_compile1(Builder *b, Janet peg) { default: peg_panic(b, "unexpected peg source"); return 0; + + case JANET_BOOLEAN: { + int n = peg_getboolean(b, peg); + Reserve r = reserve(b, 2); + emit_1(r, n ? RULE_NCHAR : RULE_NOTNCHAR, 0); + break; + } case JANET_NUMBER: { int32_t n = peg_getinteger(b, peg); Reserve r = reserve(b, 2);