llparse 0.3.0__tar.gz → 0.3.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {llparse-0.3.0 → llparse-0.3.2}/PKG-INFO +1 -1
- {llparse-0.3.0 → llparse-0.3.2}/llparse/__init__.py +1 -1
- {llparse-0.3.0 → llparse-0.3.2}/llparse/capi_builder.py +113 -10
- {llparse-0.3.0 → llparse-0.3.2}/llparse/llparse.py +21 -21
- {llparse-0.3.0 → llparse-0.3.2}/llparse.egg-info/PKG-INFO +1 -1
- {llparse-0.3.0 → llparse-0.3.2}/llparse.egg-info/SOURCES.txt +1 -0
- llparse-0.3.2/tests/test_capi.py +121 -0
- {llparse-0.3.0 → llparse-0.3.2}/LICENSE +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/README.md +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/llparse/C_compiler.py +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/llparse/_tempita/__init__.py +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/llparse/_tempita/__init__.pyi +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/llparse/_tempita/__main__.py +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/llparse/_tempita/_looper.py +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/llparse/_tempita/_looper.pyi +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/llparse/_tempita/compat3.py +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/llparse/compilator.py +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/llparse/constants.py +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/llparse/debug.py +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/llparse/dot.py +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/llparse/enumerator.py +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/llparse/errors.py +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/llparse/frontend.py +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/llparse/header.py +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/llparse/pybuilder/__init__.py +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/llparse/pybuilder/builder.py +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/llparse/pybuilder/loopchecker.py +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/llparse/pybuilder/main_code.py +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/llparse/pybuilder/parsemap.py +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/llparse/pyfront/__init__.py +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/llparse/pyfront/code.py +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/llparse/pyfront/implementation.py +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/llparse/pyfront/namespace.py +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/llparse/pyfront/nodes.py +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/llparse/pyfront/peephole.py +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/llparse/pyfront/transform.py +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/llparse/spanalloc.py +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/llparse/trie.py +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/llparse.egg-info/dependency_links.txt +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/llparse.egg-info/requires.txt +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/llparse.egg-info/top_level.txt +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/pyproject.toml +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/setup.cfg +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/tests/test_compilator.py +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/tests/test_frontend.py +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/tests/test_loop_checker.py +0 -0
- {llparse-0.3.0 → llparse-0.3.2}/tests/test_span_allocator.py +0 -0
|
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
|
|
6
6
|
import re # inspired by rust's bindgen clang compiler
|
|
7
7
|
import sys
|
|
8
|
+
from pathlib import Path
|
|
8
9
|
from contextlib import contextmanager
|
|
9
10
|
from dataclasses import dataclass, field
|
|
10
11
|
from enum import IntEnum
|
|
@@ -50,7 +51,7 @@ API_C_CODE = Template("""
|
|
|
50
51
|
|
|
51
52
|
#include "{{header}}"
|
|
52
53
|
|
|
53
|
-
/* Prevent Interfearing with other parsers (example:
|
|
54
|
+
/* Prevent Interfearing with other parsers (example: {{prefix}}) */
|
|
54
55
|
#define {{upper}}_CALLBACK_MAYBE(PARSER, NAME) \\
|
|
55
56
|
do { \\
|
|
56
57
|
{{prefix}}_settings_t* settings; \\
|
|
@@ -73,7 +74,7 @@ API_C_CODE = Template("""
|
|
|
73
74
|
err = settings->NAME((PARSER), (START), (LEN)); \\
|
|
74
75
|
} while (0)
|
|
75
76
|
|
|
76
|
-
/* Custom Underrived from
|
|
77
|
+
/* Custom Underrived from {{prefix}} */
|
|
77
78
|
#define {{upper}}_VALUE_CALLBACK_MAYBE(PARSER, NAME, VALUE) \\
|
|
78
79
|
do { \\
|
|
79
80
|
{{prefix}}_settings_t* settings; \\
|
|
@@ -123,6 +124,15 @@ void {{prefix}}_settings_init({{prefix}}_settings_t* settings) {
|
|
|
123
124
|
memset(settings, 0, sizeof(*settings));
|
|
124
125
|
}
|
|
125
126
|
|
|
127
|
+
int {{prefix}}_execute({{prefix}}_t* parser, const char* data, size_t len) {
|
|
128
|
+
return {{prev_prefix}}_execute(parser, data, data + len);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
{{if extra_code}}
|
|
132
|
+
/* EXTRAS */
|
|
133
|
+
{{extra_code}}
|
|
134
|
+
{{endif}}
|
|
135
|
+
|
|
126
136
|
""")
|
|
127
137
|
|
|
128
138
|
|
|
@@ -134,6 +144,7 @@ API_C_HEADER = Template(
|
|
|
134
144
|
extern "C" {
|
|
135
145
|
#endif
|
|
136
146
|
#include <stddef.h>
|
|
147
|
+
#include <stdint.h>
|
|
137
148
|
|
|
138
149
|
#if defined(__wasm__)
|
|
139
150
|
#define {{export}} __attribute__((visibility("default")))
|
|
@@ -161,20 +172,36 @@ typedef int (*{{prefix}}_value_cb)({{prefix}}_t*, int value);
|
|
|
161
172
|
struct {{prefix}}_settings_s {
|
|
162
173
|
{{if spans}}
|
|
163
174
|
/* Spans */
|
|
164
|
-
{{for _, name in spans}}
|
|
175
|
+
{{for _, name in spans}}
|
|
176
|
+
{{prefix}}_data_cb {{name}};
|
|
177
|
+
{{endfor}}
|
|
165
178
|
|
|
166
179
|
{{endif}}
|
|
167
180
|
{{if values}}
|
|
168
181
|
/* Value Callbacks */
|
|
169
|
-
{{for _, name in values}}
|
|
182
|
+
{{for _, name in values}}
|
|
183
|
+
{{prefix}}_value_cb {{name}};
|
|
184
|
+
{{endfor}}
|
|
170
185
|
|
|
171
186
|
{{endif}}
|
|
172
187
|
{{if matches}}
|
|
173
188
|
/* Callbacks */
|
|
174
|
-
{{for _, name in matches}}
|
|
189
|
+
{{for _, name in matches}}
|
|
190
|
+
{{prefix}}_cb {{name}};
|
|
191
|
+
{{endfor}}
|
|
175
192
|
{{endif}}
|
|
176
193
|
};
|
|
177
194
|
|
|
195
|
+
{{export}}
|
|
196
|
+
void {{prefix}}_settings_init({{prefix}}_settings_t* settings);
|
|
197
|
+
|
|
198
|
+
{{export}}
|
|
199
|
+
int {{prefix}}_execute({{prefix}}_t* parser, const char* data, size_t len);
|
|
200
|
+
|
|
201
|
+
{{if extra_code}}
|
|
202
|
+
{{extra_code}}
|
|
203
|
+
{{endif}}
|
|
204
|
+
|
|
178
205
|
#ifdef __cplusplus
|
|
179
206
|
} /* extern "C" */
|
|
180
207
|
#endif
|
|
@@ -268,7 +295,7 @@ class CythonWriter(CodeWriter):
|
|
|
268
295
|
|
|
269
296
|
class Filter:
|
|
270
297
|
"""A Filter to go off for match, value, and spans
|
|
271
|
-
to help organize the output for an
|
|
298
|
+
to help organize the output for an {{prefix}}-like C
|
|
272
299
|
Library"""
|
|
273
300
|
|
|
274
301
|
__slots__ = ("_pattern", "_is_re", "_use")
|
|
@@ -302,10 +329,10 @@ class Filter:
|
|
|
302
329
|
def is_match(self, name: str) -> bool:
|
|
303
330
|
"""Determines if the source matches up"""
|
|
304
331
|
if self._is_re:
|
|
305
|
-
return re.search(self._pattern) is not None
|
|
332
|
+
return re.search(self._pattern, name) is not None
|
|
306
333
|
else:
|
|
307
334
|
# it's most likely a prefix of ignorable callbacks...
|
|
308
|
-
return name.startswith(self._pattern)
|
|
335
|
+
return name.startswith(self._pattern) or self._pattern == name
|
|
309
336
|
|
|
310
337
|
def edit_name(self, name: str) -> str:
|
|
311
338
|
"""Ran when use is enabled"""
|
|
@@ -374,7 +401,7 @@ class UsedResults:
|
|
|
374
401
|
raise TypeError(f"unknown type for name:{name} type:{ty}")
|
|
375
402
|
|
|
376
403
|
|
|
377
|
-
@dataclass
|
|
404
|
+
@dataclass(slots=True)
|
|
378
405
|
class Results:
|
|
379
406
|
ignore: IgnoredResults = field(default_factory=IgnoredResults)
|
|
380
407
|
"""Seperates into a non-api file under a .c suffix these
|
|
@@ -395,6 +422,73 @@ class CAPIResult:
|
|
|
395
422
|
c: str
|
|
396
423
|
header: str
|
|
397
424
|
|
|
425
|
+
def write(self, c: Path | str, header:Path | str) -> None:
|
|
426
|
+
"""
|
|
427
|
+
Writes the output to the chosen file locations
|
|
428
|
+
|
|
429
|
+
:param c: Output for where to write the C File
|
|
430
|
+
:type c: Path | str
|
|
431
|
+
:param header: Output for where to write the Header File
|
|
432
|
+
:type header: Path | str
|
|
433
|
+
"""
|
|
434
|
+
Path(c).write_text(self.c)
|
|
435
|
+
Path(header).write_text(self.header)
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
# Undecided on implementing yet...
|
|
439
|
+
# class Getter:
|
|
440
|
+
# """A property that can be defined and obtained with a C wrapper"""
|
|
441
|
+
|
|
442
|
+
# def __init__(
|
|
443
|
+
# self,
|
|
444
|
+
# name: str,
|
|
445
|
+
# reset: bool = False,
|
|
446
|
+
# init: bool = False,
|
|
447
|
+
# recast_type:str | None = None
|
|
448
|
+
# ) -> None:
|
|
449
|
+
# self.name = name
|
|
450
|
+
# self.reset = reset
|
|
451
|
+
# self.init = init
|
|
452
|
+
# self.recast_type = recast_type
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
# class ErrnoGetter(Getter):
|
|
456
|
+
# """
|
|
457
|
+
# Creates a list of errors that your parser can raise
|
|
458
|
+
# if you provided enums originally.
|
|
459
|
+
# """
|
|
460
|
+
|
|
461
|
+
# def __init__(
|
|
462
|
+
# self,
|
|
463
|
+
# ty: type[IntEnum],
|
|
464
|
+
# recast_type: str | None = None,
|
|
465
|
+
# pause:IntEnum | None= None,
|
|
466
|
+
# ) -> None:
|
|
467
|
+
# self.pause = pause
|
|
468
|
+
# self.emap = {k:v.value for k, v in ty._member_map_.items()}
|
|
469
|
+
|
|
470
|
+
# super().__init__(name="error", reset=False, init=False, recast_type=recast_type)
|
|
471
|
+
|
|
472
|
+
# def write_enum(self, prefix:str) -> str:
|
|
473
|
+
# code = f"enum {prefix}_errno" + "{"
|
|
474
|
+
# code += ",\n".join([f" {k} = {v}" for k, v in self.emap.items()])
|
|
475
|
+
# code += "\n};"
|
|
476
|
+
# code += f"typedef enum {prefix}_errno {prefix}_errno_t;\n"
|
|
477
|
+
# return code
|
|
478
|
+
|
|
479
|
+
# def write_map(self, prefix:str):
|
|
480
|
+
# code = "#define " + prefix.upper() + "_ERRNO_MAP(XX) \\\n"
|
|
481
|
+
# for v, k in self.emap.items():
|
|
482
|
+
# code += f"XX({v}, {k}, {k}) \\\n"
|
|
483
|
+
# code += "\n\n"
|
|
484
|
+
# return code
|
|
485
|
+
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
|
|
398
492
|
|
|
399
493
|
class LibraryCompiler:
|
|
400
494
|
"""Used for writing in what callbacks to mark as wrappable or don't use
|
|
@@ -403,7 +497,7 @@ class LibraryCompiler:
|
|
|
403
497
|
|
|
404
498
|
__slots__ = ("_filters", "_dummy_ignore", "_prefix", "_previous_prefix")
|
|
405
499
|
|
|
406
|
-
def __init__(self, prefix: str, llparse: LLParse):
|
|
500
|
+
def __init__(self, prefix: str, llparse: LLParse) -> None:
|
|
407
501
|
self._filters: set[Filter] = set()
|
|
408
502
|
# Put all ignored spans, matches and values here...
|
|
409
503
|
self._dummy_ignore = Filter("dummy", False)
|
|
@@ -491,6 +585,8 @@ class LibraryCompiler:
|
|
|
491
585
|
root: builder.Node,
|
|
492
586
|
header: str | None = None,
|
|
493
587
|
headerguard: str | None = None,
|
|
588
|
+
extra_header_code:str | None = None,
|
|
589
|
+
extra_c_code:str | None = None
|
|
494
590
|
) -> CAPIResult:
|
|
495
591
|
"""
|
|
496
592
|
Compile library's data and create a header file and other external for the library's c-api
|
|
@@ -501,6 +597,10 @@ class LibraryCompiler:
|
|
|
501
597
|
:type header: str | None
|
|
502
598
|
:param headerguard: The Macro's name for the Header guard
|
|
503
599
|
:type headerguard: str | None
|
|
600
|
+
:param extra_header_code: Applies extra code to the header file if extra functions or things were required
|
|
601
|
+
:type extra_header_code:str | None
|
|
602
|
+
:param extra_c_code: Applies extra code to the c file if extra functions or things were required
|
|
603
|
+
:type extra_c_code:str | None
|
|
504
604
|
:return: The CAPI Result containing extra files for the c-wrapper
|
|
505
605
|
:rtype: CAPIResult
|
|
506
606
|
|
|
@@ -515,6 +615,8 @@ class LibraryCompiler:
|
|
|
515
615
|
spans=used.spans,
|
|
516
616
|
upper=self._prefix.upper(),
|
|
517
617
|
header=header or (self._prefix + ".h"),
|
|
618
|
+
prev_prefix=self._previous_prefix,
|
|
619
|
+
extra_code=extra_c_code
|
|
518
620
|
)
|
|
519
621
|
header_code = API_C_HEADER.substitute(
|
|
520
622
|
prefix=self._prefix,
|
|
@@ -525,5 +627,6 @@ class LibraryCompiler:
|
|
|
525
627
|
export=self._prefix.upper() + "_EXPORT",
|
|
526
628
|
headerguard=headerguard or f"{self._prefix.upper()}_CAPI_INCLUDE",
|
|
527
629
|
prev_prefix=self._previous_prefix,
|
|
630
|
+
extra_code=extra_header_code
|
|
528
631
|
)
|
|
529
632
|
return CAPIResult(api_code, header_code)
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
""""""
|
|
2
|
-
|
|
3
1
|
from dataclasses import dataclass
|
|
2
|
+
from pathlib import Path
|
|
4
3
|
|
|
5
4
|
from .C_compiler import CCompiler
|
|
6
5
|
from .frontend import (
|
|
@@ -14,34 +13,35 @@ from .header import HeaderBuilder
|
|
|
14
13
|
from .capi_builder import LibraryCompiler
|
|
15
14
|
|
|
16
15
|
|
|
17
|
-
@dataclass
|
|
16
|
+
@dataclass(slots=True)
|
|
18
17
|
class CompilerResult:
|
|
19
18
|
c: str
|
|
20
19
|
"""Textual C code"""
|
|
21
20
|
header: str
|
|
22
21
|
"""Textual C header file"""
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
def write(self, c: Path | str, header:Path | str) -> None:
|
|
24
|
+
"""
|
|
25
|
+
Writes the output to the chosen file locations
|
|
27
26
|
|
|
27
|
+
:param c: Output for where to write the C File
|
|
28
|
+
:type c: Path | str
|
|
29
|
+
:param header: Output for where to write the Header File
|
|
30
|
+
:type header: Path | str
|
|
31
|
+
"""
|
|
32
|
+
Path(c).write_text(self.c)
|
|
33
|
+
Path(header).write_text(self.header)
|
|
34
|
+
|
|
28
35
|
|
|
36
|
+
# It's just small enough to write the compile as a dataclass
|
|
37
|
+
@dataclass(slots=True)
|
|
29
38
|
class Compiler:
|
|
30
39
|
"""Used to Compile C code together"""
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
debug: str | None = None,
|
|
37
|
-
maxTableElemWidth: int | None = None,
|
|
38
|
-
minTableSize: int | None = None,
|
|
39
|
-
):
|
|
40
|
-
self.prefix = prefix
|
|
41
|
-
self.headerGuard = headerGuard
|
|
42
|
-
self.debug = debug
|
|
43
|
-
self.maxTableElemWidth = maxTableElemWidth
|
|
44
|
-
self.minTableSize = minTableSize
|
|
40
|
+
prefix: str
|
|
41
|
+
headerGuard: str | None = None
|
|
42
|
+
debug: str | None = None
|
|
43
|
+
maxTableElemWidth: int | None = None
|
|
44
|
+
minTableSize: int | None = None
|
|
45
45
|
|
|
46
46
|
def to_frontend(
|
|
47
47
|
self,
|
|
@@ -167,6 +167,6 @@ class LLParse(source.Builder):
|
|
|
167
167
|
minTableSize if minTableSize else DEFAULT_MIN_TABLE_SIZE,
|
|
168
168
|
).to_frontend(root, self.properties)
|
|
169
169
|
|
|
170
|
-
def capi(self, prefix: str):
|
|
170
|
+
def capi(self, prefix: str) -> LibraryCompiler:
|
|
171
171
|
"""Using a new prefix this tool enables helping build c-api wrapper that is simillar to llhttp"""
|
|
172
172
|
return LibraryCompiler(prefix, self)
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tests tools for writing C-API Wrappers
|
|
3
|
+
"""
|
|
4
|
+
from llparse import LLParse
|
|
5
|
+
import re
|
|
6
|
+
|
|
7
|
+
import pytest
|
|
8
|
+
|
|
9
|
+
DUMMY_HEADER = """#ifndef LLPARSE_CAPI_INCLUDE
|
|
10
|
+
#define LLPARSE_CAPI_INCLUDE
|
|
11
|
+
#ifdef __cplusplus
|
|
12
|
+
extern "C" {
|
|
13
|
+
#endif
|
|
14
|
+
#include <stddef.h>
|
|
15
|
+
#include <stdint.h>
|
|
16
|
+
|
|
17
|
+
#if defined(__wasm__)
|
|
18
|
+
#define LLPARSE_EXPORT __attribute__((visibility("default")))
|
|
19
|
+
#elif defined(_WIN32)
|
|
20
|
+
#define LLPARSE_EXPORT __declspec(dllexport)
|
|
21
|
+
#else
|
|
22
|
+
#define LLPARSE_EXPORT
|
|
23
|
+
#endif
|
|
24
|
+
|
|
25
|
+
typedef llparse_internal_t llparse_t;
|
|
26
|
+
typedef struct llparse_settings_s llparse_settings_t;
|
|
27
|
+
typedef int (*llparse_data_cb)(llparse_t*, const char* at, size_t length);
|
|
28
|
+
typedef int (*llparse_cb)(llparse_t*);
|
|
29
|
+
|
|
30
|
+
struct llparse_settings_s {
|
|
31
|
+
/* Spans */
|
|
32
|
+
llparse_data_cb llparse_on_span;
|
|
33
|
+
/* Callbacks */
|
|
34
|
+
llparse_cb llparse_on_test;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
LLPARSE_EXPORT
|
|
38
|
+
void llparse_settings_init(llparse_settings_t* settings);
|
|
39
|
+
|
|
40
|
+
LLPARSE_EXPORT
|
|
41
|
+
int llparse_execute(llparse_t* parser, const char* data, size_t len);
|
|
42
|
+
|
|
43
|
+
#ifdef __cplusplus
|
|
44
|
+
} /* extern "C" */
|
|
45
|
+
#endif
|
|
46
|
+
|
|
47
|
+
#endif /* LLPARSE_CAPI_INCLUDE */
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
@pytest.fixture()
|
|
53
|
+
def llparse() -> LLParse:
|
|
54
|
+
return LLParse("llparse_internal")
|
|
55
|
+
|
|
56
|
+
def test_collecting_spans(llparse:LLParse):
|
|
57
|
+
lc = llparse.capi("llparse")
|
|
58
|
+
span = llparse.span(llparse.code.span("span"))
|
|
59
|
+
start = llparse.node("start")
|
|
60
|
+
body = llparse.node("body")
|
|
61
|
+
|
|
62
|
+
start.otherwise(span.start(body))
|
|
63
|
+
|
|
64
|
+
body.skipTo(span.end(start))
|
|
65
|
+
|
|
66
|
+
lc.use("span")
|
|
67
|
+
result = lc.filter(start)
|
|
68
|
+
assert result.use.spans, "No spans found"
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def test_collecting_matches(llparse:LLParse):
|
|
72
|
+
lc = llparse.capi("lc")
|
|
73
|
+
span = llparse.span(llparse.code.span("llparse_on_span"))
|
|
74
|
+
on_test = llparse.code.match("llparse_on_test")
|
|
75
|
+
|
|
76
|
+
start = llparse.node("start")
|
|
77
|
+
body = llparse.node("body")
|
|
78
|
+
|
|
79
|
+
start.otherwise(
|
|
80
|
+
span.start(body)
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
body.skipTo(
|
|
84
|
+
span.end(
|
|
85
|
+
llparse.invoke(on_test, {0:start}, llparse.error(-1, "error"))
|
|
86
|
+
)
|
|
87
|
+
)
|
|
88
|
+
lc.use("llparse_")
|
|
89
|
+
result = lc.filter(start)
|
|
90
|
+
assert result.use.spans, "No spans found"
|
|
91
|
+
assert result.use.matches, "No matches found"
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def test_write_capi(llparse:LLParse):
|
|
95
|
+
lc = llparse.capi("llparse")
|
|
96
|
+
span = llparse.span(llparse.code.span("llparse_on_span"))
|
|
97
|
+
on_test = llparse.code.match("llparse_on_test")
|
|
98
|
+
|
|
99
|
+
start = llparse.node("start")
|
|
100
|
+
body = llparse.node("body")
|
|
101
|
+
|
|
102
|
+
start.otherwise(
|
|
103
|
+
span.start(body)
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
body.skipTo(
|
|
107
|
+
span.end(
|
|
108
|
+
llparse.invoke(on_test, {0:start}, llparse.error(-1, "error"))
|
|
109
|
+
)
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
lc.use("span")
|
|
113
|
+
lc.use_regex(r"llparse_([^\s]+)")
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
result = lc.build(start)
|
|
117
|
+
assert result.header.strip() == DUMMY_HEADER.strip()
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|