mirror of
https://github.com/janet-lang/janet
synced 2024-12-01 12:29:54 +00:00
Add peg/find and peg/find-all.
These peg functions should make pegs a bit easier to use and more efficient in some common cases.
This commit is contained in:
parent
9a5cfe9f75
commit
17a131ac21
@ -99,7 +99,7 @@
|
|||||||
(defn array? "Check if x is an array." [x] (= (type x) :array))
|
(defn array? "Check if x is an array." [x] (= (type x) :array))
|
||||||
(defn tuple? "Check if x is a tuple." [x] (= (type x) :tuple))
|
(defn tuple? "Check if x is a tuple." [x] (= (type x) :tuple))
|
||||||
(defn boolean? "Check if x is a boolean." [x] (= (type x) :boolean))
|
(defn boolean? "Check if x is a boolean." [x] (= (type x) :boolean))
|
||||||
(defn bytes? "Check if x is a string, symbol, or buffer." [x]
|
(defn bytes? "Check if x is a string, symbol, keyword, or buffer." [x]
|
||||||
(def t (type x))
|
(def t (type x))
|
||||||
(if (= t :string) true (if (= t :symbol) true (if (= t :keyword) true (= t :buffer)))))
|
(if (= t :string) true (if (= t :symbol) true (if (= t :keyword) true (= t :buffer)))))
|
||||||
(defn dictionary? "Check if x a table or struct." [x]
|
(defn dictionary? "Check if x a table or struct." [x]
|
||||||
@ -112,7 +112,7 @@
|
|||||||
(defn true? "Check if x is true." [x] (= x true))
|
(defn true? "Check if x is true." [x] (= x true))
|
||||||
(defn false? "Check if x is false." [x] (= x false))
|
(defn false? "Check if x is false." [x] (= x false))
|
||||||
(defn nil? "Check if x is nil." [x] (= x nil))
|
(defn nil? "Check if x is nil." [x] (= x nil))
|
||||||
(defn empty? "Check if xs is empty." [xs] (= 0 (length xs)))
|
(defn empty? "Check if xs is empty." [xs] (= (length xs) 0))
|
||||||
|
|
||||||
(def idempotent?
|
(def idempotent?
|
||||||
"(idempotent? x)\n\nCheck if x is a value that evaluates to itself when compiled."
|
"(idempotent? x)\n\nCheck if x is a value that evaluates to itself when compiled."
|
||||||
|
110
src/core/peg.c
110
src/core/peg.c
@ -1308,47 +1308,89 @@ static Janet cfun_peg_compile(int32_t argc, Janet *argv) {
|
|||||||
return janet_wrap_abstract(peg);
|
return janet_wrap_abstract(peg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Janet cfun_peg_match(int32_t argc, Janet *argv) {
|
/* Common data for peg cfunctions */
|
||||||
janet_arity(argc, 2, -1);
|
typedef struct {
|
||||||
JanetPeg *peg;
|
JanetPeg *peg;
|
||||||
|
PegState s;
|
||||||
|
JanetByteView bytes;
|
||||||
|
int32_t start;
|
||||||
|
} PegCall;
|
||||||
|
|
||||||
|
/* Initialize state for peg cfunctions */
|
||||||
|
static PegCall peg_cfun_init(int32_t argc, Janet *argv) {
|
||||||
|
PegCall ret;
|
||||||
|
janet_arity(argc, 2, -1);
|
||||||
if (janet_checktype(argv[0], JANET_ABSTRACT) &&
|
if (janet_checktype(argv[0], JANET_ABSTRACT) &&
|
||||||
janet_abstract_type(janet_unwrap_abstract(argv[0])) == &janet_peg_type) {
|
janet_abstract_type(janet_unwrap_abstract(argv[0])) == &janet_peg_type) {
|
||||||
peg = janet_unwrap_abstract(argv[0]);
|
ret.peg = janet_unwrap_abstract(argv[0]);
|
||||||
} else {
|
} else {
|
||||||
peg = compile_peg(argv[0]);
|
ret.peg = compile_peg(argv[0]);
|
||||||
}
|
}
|
||||||
JanetByteView bytes = janet_getbytes(argv, 1);
|
ret.bytes = janet_getbytes(argv, 1);
|
||||||
int32_t start;
|
|
||||||
PegState s;
|
|
||||||
if (argc > 2) {
|
if (argc > 2) {
|
||||||
start = janet_gethalfrange(argv, 2, bytes.len, "offset");
|
ret.start = janet_gethalfrange(argv, 2, ret.bytes.len, "offset");
|
||||||
s.extrac = argc - 3;
|
ret.s.extrac = argc - 3;
|
||||||
s.extrav = janet_tuple_n(argv + 3, argc - 3);
|
ret.s.extrav = janet_tuple_n(argv + 3, argc - 3);
|
||||||
} else {
|
} else {
|
||||||
start = 0;
|
ret.start = 0;
|
||||||
s.extrac = 0;
|
ret.s.extrac = 0;
|
||||||
s.extrav = NULL;
|
ret.s.extrav = NULL;
|
||||||
}
|
}
|
||||||
s.mode = PEG_MODE_NORMAL;
|
ret.s.mode = PEG_MODE_NORMAL;
|
||||||
s.text_start = bytes.bytes;
|
ret.s.text_start = ret.bytes.bytes;
|
||||||
s.text_end = bytes.bytes + bytes.len;
|
ret.s.text_end = ret.bytes.bytes + ret.bytes.len;
|
||||||
s.depth = JANET_RECURSION_GUARD;
|
ret.s.depth = JANET_RECURSION_GUARD;
|
||||||
s.captures = janet_array(0);
|
ret.s.captures = janet_array(0);
|
||||||
s.scratch = janet_buffer(10);
|
ret.s.scratch = janet_buffer(10);
|
||||||
s.tags = janet_buffer(10);
|
ret.s.tags = janet_buffer(10);
|
||||||
s.constants = peg->constants;
|
ret.s.constants = ret.peg->constants;
|
||||||
s.bytecode = peg->bytecode;
|
ret.s.bytecode = ret.peg->bytecode;
|
||||||
const uint8_t *result = peg_rule(&s, s.bytecode, bytes.bytes + start);
|
return ret;
|
||||||
return result ? janet_wrap_array(s.captures) : janet_wrap_nil();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Janet cfun_peg_match(int32_t argc, Janet *argv) {
|
||||||
|
PegCall c = peg_cfun_init(argc, argv);
|
||||||
|
const uint8_t *result = peg_rule(&c.s, c.s.bytecode, c.bytes.bytes + c.start);
|
||||||
|
return result ? janet_wrap_array(c.s.captures) : janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Janet cfun_peg_find(int32_t argc, Janet *argv) {
|
||||||
|
PegCall c = peg_cfun_init(argc, argv);
|
||||||
|
for (int32_t i = c.start; i < c.bytes.len; i++) {
|
||||||
|
c.s.captures->count = 0;
|
||||||
|
c.s.scratch->count = 0;
|
||||||
|
c.s.tags->count = 0;
|
||||||
|
if (peg_rule(&c.s, c.s.bytecode, c.bytes.bytes + i))
|
||||||
|
return janet_wrap_integer(i);
|
||||||
|
}
|
||||||
|
return janet_wrap_nil();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Janet cfun_peg_find_all(int32_t argc, Janet *argv) {
|
||||||
|
PegCall c = peg_cfun_init(argc, argv);
|
||||||
|
JanetArray *ret = janet_array(0);
|
||||||
|
for (int32_t i = c.start; i < c.bytes.len; i++) {
|
||||||
|
c.s.captures->count = 0;
|
||||||
|
c.s.scratch->count = 0;
|
||||||
|
c.s.tags->count = 0;
|
||||||
|
if (peg_rule(&c.s, c.s.bytecode, c.bytes.bytes + i))
|
||||||
|
janet_array_push(ret, janet_wrap_integer(i));
|
||||||
|
}
|
||||||
|
return janet_wrap_array(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static JanetMethod peg_methods[] = {
|
||||||
|
{"match", cfun_peg_match},
|
||||||
|
{"find", cfun_peg_find},
|
||||||
|
{"find-all", cfun_peg_find_all},
|
||||||
|
{NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
static int cfun_peg_getter(JanetAbstract a, Janet key, Janet *out) {
|
static int cfun_peg_getter(JanetAbstract a, Janet key, Janet *out) {
|
||||||
(void) a;
|
(void) a;
|
||||||
if (janet_keyeq(key, "match")) {
|
if (!janet_checktype(key, JANET_KEYWORD))
|
||||||
*out = janet_wrap_cfunction(cfun_peg_match);
|
return 0;
|
||||||
return 1;
|
return janet_getmethod(janet_unwrap_keyword(key), peg_methods, out);
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const JanetReg peg_cfuns[] = {
|
static const JanetReg peg_cfuns[] = {
|
||||||
@ -1364,6 +1406,16 @@ static const JanetReg peg_cfuns[] = {
|
|||||||
"Match a Parsing Expression Grammar to a byte string and return an array of captured values. "
|
"Match a Parsing Expression Grammar to a byte string and return an array of captured values. "
|
||||||
"Returns nil if text does not match the language defined by peg. The syntax of PEGs is documented on the Janet website.")
|
"Returns nil if text does not match the language defined by peg. The syntax of PEGs is documented on the Janet website.")
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"peg/find", cfun_peg_find,
|
||||||
|
JDOC("(peg/find peg text &opt start & args)\n\n"
|
||||||
|
"Find first index where the peg matches in text. Returns an integer, or nil if not found.")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"peg/find-all", cfun_peg_find_all,
|
||||||
|
JDOC("(peg/find-all peg text &opt start & args)\n\n"
|
||||||
|
"Find all indexes where the peg matches in text. Returns an array of integers.")
|
||||||
|
},
|
||||||
{NULL, NULL, NULL}
|
{NULL, NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user