1
0
mirror of https://github.com/janet-lang/janet synced 2025-10-31 23:53:02 +00:00

Add rules for nth and only-tags. Address #1503

These rules allow selecting from a number of sub-captures
while dropping the rest. `nth` is more succinct in many cases, but `only-tags` is
more general and corresponds to an internal mechanism already present.
This commit is contained in:
Calvin Rose
2024-09-12 17:03:03 -05:00
parent 2697b0e425
commit 9694aee819
4 changed files with 74 additions and 1 deletions

View File

@@ -465,6 +465,16 @@ tail:
return result;
}
case RULE_ONLY_TAGS: {
CapState cs = cap_save(s);
down1(s);
const uint8_t *result = peg_rule(s, s->bytecode + rule[1], text);
up1(s);
if (!result) return NULL;
cap_load_keept(s, cs);
return result;
}
case RULE_GROUP: {
uint32_t tag = rule[2];
int oldmode = s->mode;
@@ -486,6 +496,29 @@ tail:
return result;
}
case RULE_NTH: {
uint32_t nth = rule[1];
uint32_t tag = rule[3];
int oldmode = s->mode;
CapState cs = cap_save(s);
s->mode = PEG_MODE_NORMAL;
down1(s);
const uint8_t *result = peg_rule(s, s->bytecode + rule[2], text);
up1(s);
s->mode = oldmode;
if (!result) return NULL;
int32_t num_sub_captures = s->captures->count - cs.cap;
Janet cap;
if (num_sub_captures > (int32_t) nth) {
cap = s->captures->data[cs.cap + nth];
} else {
return NULL;
}
cap_load_keept(s, cs);
pushcap(s, cap, tag);
return result;
}
case RULE_SUB: {
const uint8_t *text_start = text;
const uint32_t *rule_window = s->bytecode + rule[1];
@@ -1061,6 +1094,9 @@ static void spec_thru(Builder *b, int32_t argc, const Janet *argv) {
static void spec_drop(Builder *b, int32_t argc, const Janet *argv) {
spec_onerule(b, argc, argv, RULE_DROP);
}
static void spec_only_tags(Builder *b, int32_t argc, const Janet *argv) {
spec_onerule(b, argc, argv, RULE_ONLY_TAGS);
}
/* Rule of the form [rule, tag] */
static void spec_cap1(Builder *b, int32_t argc, const Janet *argv, uint32_t op) {
@@ -1084,6 +1120,15 @@ static void spec_unref(Builder *b, int32_t argc, const Janet *argv) {
spec_cap1(b, argc, argv, RULE_UNREF);
}
static void spec_nth(Builder *b, int32_t argc, const Janet *argv) {
peg_arity(b, argc, 2, 3);
Reserve r = reserve(b, 4);
uint32_t nth = peg_getnat(b, argv[0]);
uint32_t rule = peg_compile1(b, argv[1]);
uint32_t tag = (argc == 3) ? emit_tag(b, argv[2]) : 0;
emit_3(r, RULE_NTH, nth, rule, tag);
}
static void spec_capture_number(Builder *b, int32_t argc, const Janet *argv) {
peg_arity(b, argc, 1, 3);
Reserve r = reserve(b, 4);
@@ -1262,7 +1307,9 @@ static const SpecialPair peg_specials[] = {
{"line", spec_line},
{"look", spec_look},
{"not", spec_not},
{"nth", spec_nth},
{"number", spec_capture_number},
{"only-tags", spec_only_tags},
{"opt", spec_opt},
{"position", spec_position},
{"quote", spec_capture},
@@ -1619,6 +1666,7 @@ static void *peg_unmarshal(JanetMarshalContext *ctx) {
break;
case RULE_ERROR:
case RULE_DROP:
case RULE_ONLY_TAGS:
case RULE_NOT:
case RULE_TO:
case RULE_THRU:
@@ -1632,6 +1680,12 @@ static void *peg_unmarshal(JanetMarshalContext *ctx) {
if (rule[1] > JANET_MAX_READINT_WIDTH) goto bad;
i += 3;
break;
case RULE_NTH:
/* [nth, rule, tag] */
if (rule[2] >= blen) goto bad;
op_flags[rule[2]] |= 0x01;
i += 4;
break;
default:
goto bad;
}