Skip to content

Commit 0272556

Browse files
committed
Added match() function
1 parent f84b72b commit 0272556

File tree

6 files changed

+149
-31
lines changed

6 files changed

+149
-31
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# v1.7.5
2+
3+
* Added `match()` function for regular expressions, pr #.
4+
15
# v1.7.4
26

37
* Added `bit_count()` function, pr #405.

inc/doc.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@
258258
#define DOC_MPDATA_LEN DOC_SEE("data-types/mpdata/len")
259259
#define DOC_MPDATA_LOAD DOC_SEE("data-types/mpdata/load")
260260
#define DOC_REGEX_TEST DOC_SEE("data-types/regex/test")
261+
#define DOC_REGEX_MATCH DOC_SEE("data-types/regex/match")
261262
#define DOC_ROOM_EMIT DOC_SEE("data-types/room/emit")
262263
#define DOC_ROOM_ID DOC_SEE("data-types/room/id")
263264
#define DOC_ROOM_NAME DOC_SEE("data-types/room/name")

inc/ti/fn/fnmatch.h

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#include <ti/fn/fn.h>
2+
3+
4+
static int do__f_match(ti_query_t * query, cleri_node_t * nd, ex_t * e)
5+
{
6+
const int nargs = fn_get_nargs(nd);
7+
ti_regex_t * regex;
8+
ti_raw_t * vstr;
9+
ti_varr_t * arr;
10+
int rc, i;
11+
PCRE2_SIZE * ovector;
12+
13+
if (!ti_val_is_regex(query->rval))
14+
return fn_call_try("match", query, nd, e);
15+
16+
if (fn_nargs("match", DOC_REGEX_MATCH, 1, nargs, e))
17+
return e->nr;
18+
19+
regex = (ti_regex_t *) query->rval;
20+
query->rval = NULL;
21+
22+
if (ti_do_statement(query, nd->children, e))
23+
goto fail0;
24+
25+
if (!ti_val_is_str(query->rval))
26+
{
27+
ex_set(e, EX_TYPE_ERROR,
28+
"function `match` expects argument 1 to be "
29+
"of type `"TI_VAL_STR_S"` but got type `%s` instead"DOC_REGEX_MATCH,
30+
ti_val_str(query->rval));
31+
goto fail0;
32+
}
33+
34+
vstr = (ti_raw_t *) query->rval;
35+
query->rval = NULL;
36+
37+
/* TODO: we could allow `g` as regular expression flag which in turn could
38+
* change the behavior for match(..) to return all matches similar
39+
* to javascripts match.
40+
*/
41+
rc = pcre2_match(
42+
regex->code,
43+
(PCRE2_SPTR8) vstr->data,
44+
vstr->n,
45+
0, /* start looking at this point */
46+
0, /* OPTIONS */
47+
regex->match_data,
48+
NULL);
49+
50+
if (rc < 0)
51+
{
52+
query->rval = (ti_val_t *) ti_nil_get();
53+
goto fail1; /* success, but no match */
54+
}
55+
ovector = pcre2_get_ovector_pointer(regex->match_data);
56+
57+
arr = ti_varr_create(rc);
58+
if (!arr)
59+
{
60+
ex_set_mem(e);
61+
goto fail1;
62+
}
63+
query->rval = (ti_val_t *) arr;
64+
65+
for (i = 0; i < rc; i++)
66+
{
67+
ti_raw_t * substr;
68+
PCRE2_SPTR pt = vstr->data + ovector[2*i];
69+
PCRE2_SIZE n = ovector[2*i+1] - ovector[2*i];
70+
71+
substr = ti_str_create((const char *) pt, n);
72+
if (!substr)
73+
{
74+
ex_set_mem(e);
75+
goto fail1;
76+
}
77+
78+
VEC_push(arr->vec, substr);
79+
}
80+
81+
fail1:
82+
ti_val_unsafe_drop((ti_val_t *) vstr);
83+
fail0:
84+
ti_val_unsafe_drop((ti_val_t *) regex);
85+
return e->nr;
86+
}

inc/ti/version.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
#define TI_VERSION_MAJOR 1
88
#define TI_VERSION_MINOR 7
9-
#define TI_VERSION_PATCH 4
9+
#define TI_VERSION_PATCH 5
1010

1111
/* The syntax version is used to test compatibility with functions
1212
* using the `ti_nodes_check_syntax()` function */
@@ -25,7 +25,7 @@
2525
* "-rc0"
2626
* ""
2727
*/
28-
#define TI_VERSION_PRE_RELEASE ""
28+
#define TI_VERSION_PRE_RELEASE "-alpha0"
2929

3030
#define TI_MAINTAINER \
3131
"Jeroen van der Heijden <[email protected]>"

itest/test_collection_functions.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4228,6 +4228,31 @@ async def test_test(self, client):
42284228
self.assertFalse(await client.query(r'/hi/.test("Hi");'))
42294229
self.assertFalse(await client.query(r'/hello!.*/.test("hello");'))
42304230

4231+
async def test_match(self, client):
4232+
with self.assertRaisesRegex(
4233+
LookupError,
4234+
'type `int` has no function `match`'):
4235+
await client.query('(42).match();')
4236+
4237+
with self.assertRaisesRegex(
4238+
NumArgumentsError,
4239+
'function `match` takes 1 argument but 0 were given'):
4240+
await client.query('/.*/.match();')
4241+
4242+
with self.assertRaisesRegex(
4243+
TypeError,
4244+
r'function `match` expects argument 1 to be of '
4245+
r'type `str` but got type `regex` instead'):
4246+
await client.query('/.*/.match(/.*/);')
4247+
4248+
self.assertEqual(
4249+
await client.query(r'/.*/.match("");'),
4250+
[""])
4251+
self.assertEqual(
4252+
await client.query(r'/Hi\ (.*)\!/.match("So, Hi Iriske! How");'),
4253+
["Hi Iriske!", "Iriske"])
4254+
self.assertIs(await client.query(r'/hi iris/.match("Hi");'), None)
4255+
42314256
async def test_search(self, client):
42324257
r, x, t, a, w, b = await client.query(r"""//ti
42334258
set_type('A', {

src/ti/qbind.c

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@
150150
#include <ti/fn/fnmapid.h>
151151
#include <ti/fn/fnmaptype.h>
152152
#include <ti/fn/fnmapwrap.h>
153+
#include <ti/fn/fnmatch.h>
153154
#include <ti/fn/fnmodenum.h>
154155
#include <ti/fn/fnmodprocedure.h>
155156
#include <ti/fn/fnmodtype.h>
@@ -300,11 +301,11 @@ static void qbind__statement(ti_qbind_t * qbind, cleri_node_t * nd);
300301
*/
301302
enum
302303
{
303-
TOTAL_KEYWORDS = 275,
304+
TOTAL_KEYWORDS = 276,
304305
MIN_WORD_LENGTH = 2,
305306
MAX_WORD_LENGTH = 17,
306-
MIN_HASH_VALUE = 11,
307-
MAX_HASH_VALUE = 700
307+
MIN_HASH_VALUE = 26,
308+
MAX_HASH_VALUE = 710
308309
};
309310

310311
/*
@@ -316,32 +317,32 @@ static inline unsigned int qbind__hash(
316317
{
317318
static unsigned short asso_values[] =
318319
{
319-
701, 701, 701, 701, 701, 701, 701, 701, 701, 701,
320-
701, 701, 701, 701, 701, 701, 701, 701, 701, 701,
321-
701, 701, 701, 701, 701, 701, 701, 701, 701, 701,
322-
701, 701, 701, 701, 701, 701, 701, 701, 701, 701,
323-
701, 701, 701, 701, 701, 701, 701, 701, 2, 1,
324-
2, 701, 4, 701, 4, 701, 8, 701, 701, 701,
325-
701, 701, 701, 701, 701, 701, 701, 701, 701, 701,
326-
701, 701, 701, 701, 701, 701, 701, 701, 701, 701,
327-
701, 701, 701, 701, 701, 701, 701, 701, 701, 701,
328-
701, 701, 701, 701, 701, 1, 701, 19, 114, 56,
329-
24, 5, 88, 366, 191, 1, 44, 50, 27, 54,
330-
10, 42, 98, 125, 6, 1, 2, 42, 178, 77,
331-
136, 262, 24, 701, 701, 701, 701, 701, 701, 701,
332-
701, 701, 701, 701, 701, 701, 701, 701, 701, 701,
333-
701, 701, 701, 701, 701, 701, 701, 701, 701, 701,
334-
701, 701, 701, 701, 701, 701, 701, 701, 701, 701,
335-
701, 701, 701, 701, 701, 701, 701, 701, 701, 701,
336-
701, 701, 701, 701, 701, 701, 701, 701, 701, 701,
337-
701, 701, 701, 701, 701, 701, 701, 701, 701, 701,
338-
701, 701, 701, 701, 701, 701, 701, 701, 701, 701,
339-
701, 701, 701, 701, 701, 701, 701, 701, 701, 701,
340-
701, 701, 701, 701, 701, 701, 701, 701, 701, 701,
341-
701, 701, 701, 701, 701, 701, 701, 701, 701, 701,
342-
701, 701, 701, 701, 701, 701, 701, 701, 701, 701,
343-
701, 701, 701, 701, 701, 701, 701, 701, 701, 701,
344-
701, 701, 701, 701, 701, 701
320+
711, 711, 711, 711, 711, 711, 711, 711, 711, 711,
321+
711, 711, 711, 711, 711, 711, 711, 711, 711, 711,
322+
711, 711, 711, 711, 711, 711, 711, 711, 711, 711,
323+
711, 711, 711, 711, 711, 711, 711, 711, 711, 711,
324+
711, 711, 711, 711, 711, 711, 711, 711, 10, 10,
325+
10, 711, 10, 711, 9, 711, 12, 711, 711, 711,
326+
711, 711, 711, 711, 711, 711, 711, 711, 711, 711,
327+
711, 711, 711, 711, 711, 711, 711, 711, 711, 711,
328+
711, 711, 711, 711, 711, 711, 711, 711, 711, 711,
329+
711, 711, 711, 711, 711, 9, 711, 14, 27, 102,
330+
17, 11, 128, 328, 77, 9, 24, 53, 11, 50,
331+
14, 43, 151, 45, 10, 9, 10, 60, 135, 248,
332+
156, 150, 30, 711, 711, 711, 711, 711, 711, 711,
333+
711, 711, 711, 711, 711, 711, 711, 711, 711, 711,
334+
711, 711, 711, 711, 711, 711, 711, 711, 711, 711,
335+
711, 711, 711, 711, 711, 711, 711, 711, 711, 711,
336+
711, 711, 711, 711, 711, 711, 711, 711, 711, 711,
337+
711, 711, 711, 711, 711, 711, 711, 711, 711, 711,
338+
711, 711, 711, 711, 711, 711, 711, 711, 711, 711,
339+
711, 711, 711, 711, 711, 711, 711, 711, 711, 711,
340+
711, 711, 711, 711, 711, 711, 711, 711, 711, 711,
341+
711, 711, 711, 711, 711, 711, 711, 711, 711, 711,
342+
711, 711, 711, 711, 711, 711, 711, 711, 711, 711,
343+
711, 711, 711, 711, 711, 711, 711, 711, 711, 711,
344+
711, 711, 711, 711, 711, 711, 711, 711, 711, 711,
345+
711, 711, 711, 711, 711, 711
345346
};
346347

347348
register unsigned int hval = n;
@@ -629,6 +630,7 @@ qbind__fmap_t qbind__fn_mapping[TOTAL_KEYWORDS] = {
629630
{.name="map_id", .fn=do__f_map_id, CHAIN_NE},
630631
{.name="map_type", .fn=do__f_map_type, CHAIN_NE},
631632
{.name="map_wrap", .fn=do__f_map_wrap, CHAIN_NE},
633+
{.name="match", .fn=do__f_match, CHAIN_NE},
632634
{.name="max_quota_err", .fn=do__f_max_quota_err, ROOT_NE},
633635
{.name="mod_enum", .fn=do__f_mod_enum, ROOT_CE},
634636
{.name="mod_procedure", .fn=do__f_mod_procedure, ROOT_BE},

0 commit comments

Comments
 (0)