jaclang 0.5.11__py3-none-any.whl → 0.5.15__py3-none-any.whl

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.

Potentially problematic release.


This version of jaclang might be problematic. Click here for more details.

Files changed (43) hide show
  1. jaclang/cli/cli.py +20 -0
  2. jaclang/compiler/__init__.py +35 -19
  3. jaclang/compiler/absyntree.py +103 -95
  4. jaclang/compiler/generated/jac_parser.py +4069 -0
  5. jaclang/compiler/jac.lark +655 -0
  6. jaclang/compiler/parser.py +44 -31
  7. jaclang/compiler/passes/main/fuse_typeinfo_pass.py +92 -37
  8. jaclang/compiler/passes/main/import_pass.py +8 -5
  9. jaclang/compiler/passes/main/pyast_gen_pass.py +512 -352
  10. jaclang/compiler/passes/main/pyast_load_pass.py +271 -64
  11. jaclang/compiler/passes/main/registry_pass.py +3 -7
  12. jaclang/compiler/passes/main/tests/test_pyast_gen_pass.py +2 -0
  13. jaclang/compiler/passes/main/type_check_pass.py +4 -1
  14. jaclang/compiler/passes/tool/jac_formatter_pass.py +7 -0
  15. jaclang/compiler/passes/tool/tests/test_unparse_validate.py +16 -0
  16. jaclang/compiler/passes/utils/mypy_ast_build.py +93 -0
  17. jaclang/compiler/tests/test_importer.py +15 -0
  18. jaclang/core/aott.py +4 -3
  19. jaclang/core/construct.py +1 -1
  20. jaclang/core/importer.py +109 -51
  21. jaclang/core/llms.py +29 -0
  22. jaclang/core/registry.py +22 -0
  23. jaclang/core/utils.py +72 -0
  24. jaclang/plugin/default.py +118 -6
  25. jaclang/plugin/feature.py +29 -2
  26. jaclang/plugin/spec.py +25 -2
  27. jaclang/utils/helpers.py +7 -9
  28. jaclang/utils/lang_tools.py +37 -13
  29. jaclang/utils/test.py +1 -3
  30. jaclang/utils/tests/test_lang_tools.py +6 -0
  31. jaclang/vendor/lark/grammars/common.lark +59 -0
  32. jaclang/vendor/lark/grammars/lark.lark +62 -0
  33. jaclang/vendor/lark/grammars/python.lark +302 -0
  34. jaclang/vendor/lark/grammars/unicode.lark +7 -0
  35. {jaclang-0.5.11.dist-info → jaclang-0.5.15.dist-info}/METADATA +1 -1
  36. {jaclang-0.5.11.dist-info → jaclang-0.5.15.dist-info}/RECORD +40 -36
  37. jaclang/compiler/__jac_gen__/jac_parser.py +0 -4069
  38. jaclang/compiler/tests/fixtures/__jac_gen__/__init__.py +0 -0
  39. jaclang/compiler/tests/fixtures/__jac_gen__/hello_world.py +0 -5
  40. /jaclang/compiler/{__jac_gen__ → generated}/__init__.py +0 -0
  41. {jaclang-0.5.11.dist-info → jaclang-0.5.15.dist-info}/WHEEL +0 -0
  42. {jaclang-0.5.11.dist-info → jaclang-0.5.15.dist-info}/entry_points.txt +0 -0
  43. {jaclang-0.5.11.dist-info → jaclang-0.5.15.dist-info}/top_level.txt +0 -0
jaclang/plugin/default.py CHANGED
@@ -8,7 +8,7 @@ import pickle
8
8
  import types
9
9
  from dataclasses import field
10
10
  from functools import wraps
11
- from typing import Any, Callable, Optional, Type
11
+ from typing import Any, Callable, Optional, Type, Union
12
12
 
13
13
  from jaclang.compiler.absyntree import Module
14
14
  from jaclang.compiler.constant import EdgeDir, colors
@@ -37,7 +37,7 @@ from jaclang.core.construct import (
37
37
  root,
38
38
  )
39
39
  from jaclang.core.importer import jac_importer
40
- from jaclang.core.registry import SemScope
40
+ from jaclang.core.registry import SemInfo, SemRegistry, SemScope
41
41
  from jaclang.core.utils import traverse_graph
42
42
  from jaclang.plugin.feature import JacFeature as Jac
43
43
  from jaclang.plugin.spec import T
@@ -167,17 +167,25 @@ class JacFeatureDefaults:
167
167
  def jac_import(
168
168
  target: str,
169
169
  base_path: str,
170
+ absorb: bool,
170
171
  cachable: bool,
172
+ mdl_alias: Optional[str],
171
173
  override_name: Optional[str],
172
174
  mod_bundle: Optional[Module],
175
+ lng: Optional[str],
176
+ items: Optional[dict[str, Union[str, bool]]],
173
177
  ) -> Optional[types.ModuleType]:
174
178
  """Core Import Process."""
175
179
  result = jac_importer(
176
180
  target=target,
177
181
  base_path=base_path,
182
+ absorb=absorb,
178
183
  cachable=cachable,
184
+ mdl_alias=mdl_alias,
179
185
  override_name=override_name,
180
186
  mod_bundle=mod_bundle,
187
+ lng=lng,
188
+ items=items,
181
189
  )
182
190
  return result
183
191
 
@@ -435,6 +443,110 @@ class JacFeatureDefaults:
435
443
 
436
444
  return builder
437
445
 
446
+ @staticmethod
447
+ @hookimpl
448
+ def get_semstr_type(
449
+ file_loc: str, scope: str, attr: str, return_semstr: bool
450
+ ) -> Optional[str]:
451
+ """Jac's get_semstr_type feature."""
452
+ _scope = SemScope.get_scope_from_str(scope)
453
+ with open(
454
+ os.path.join(
455
+ os.path.dirname(file_loc),
456
+ "__jac_gen__",
457
+ os.path.basename(file_loc).replace(".jac", ".registry.pkl"),
458
+ ),
459
+ "rb",
460
+ ) as f:
461
+ mod_registry: SemRegistry = pickle.load(f)
462
+ _, attr_seminfo = mod_registry.lookup(_scope, attr)
463
+ if attr_seminfo and isinstance(attr_seminfo, SemInfo):
464
+ return attr_seminfo.semstr if return_semstr else attr_seminfo.type
465
+ return None
466
+
467
+ @staticmethod
468
+ @hookimpl
469
+ def obj_scope(file_loc: str, attr: str) -> str:
470
+ """Jac's gather_scope feature."""
471
+ with open(
472
+ os.path.join(
473
+ os.path.dirname(file_loc),
474
+ "__jac_gen__",
475
+ os.path.basename(file_loc).replace(".jac", ".registry.pkl"),
476
+ ),
477
+ "rb",
478
+ ) as f:
479
+ mod_registry: SemRegistry = pickle.load(f)
480
+
481
+ attr_scope = None
482
+ for x in attr.split("."):
483
+ attr_scope, attr_sem_info = mod_registry.lookup(attr_scope, x)
484
+ if isinstance(attr_sem_info, SemInfo) and attr_sem_info.type not in [
485
+ "class",
486
+ "obj",
487
+ "node",
488
+ "edge",
489
+ ]:
490
+ attr_scope, attr_sem_info = mod_registry.lookup(
491
+ None, attr_sem_info.type
492
+ )
493
+ if isinstance(attr_sem_info, SemInfo) and isinstance(
494
+ attr_sem_info.type, str
495
+ ):
496
+ attr_scope = SemScope(
497
+ attr_sem_info.name, attr_sem_info.type, attr_scope
498
+ )
499
+ else:
500
+ if isinstance(attr_sem_info, SemInfo) and isinstance(
501
+ attr_sem_info.type, str
502
+ ):
503
+ attr_scope = SemScope(
504
+ attr_sem_info.name, attr_sem_info.type, attr_scope
505
+ )
506
+ return str(attr_scope)
507
+
508
+ @staticmethod
509
+ @hookimpl
510
+ def get_sem_type(file_loc: str, attr: str) -> tuple[str | None, str | None]:
511
+ with open(
512
+ os.path.join(
513
+ os.path.dirname(file_loc),
514
+ "__jac_gen__",
515
+ os.path.basename(file_loc).replace(".jac", ".registry.pkl"),
516
+ ),
517
+ "rb",
518
+ ) as f:
519
+ mod_registry: SemRegistry = pickle.load(f)
520
+
521
+ attr_scope = None
522
+ for x in attr.split("."):
523
+ attr_scope, attr_sem_info = mod_registry.lookup(attr_scope, x)
524
+ if isinstance(attr_sem_info, SemInfo) and attr_sem_info.type not in [
525
+ "class",
526
+ "obj",
527
+ "node",
528
+ "edge",
529
+ ]:
530
+ attr_scope, attr_sem_info = mod_registry.lookup(
531
+ None, attr_sem_info.type
532
+ )
533
+ if isinstance(attr_sem_info, SemInfo) and isinstance(
534
+ attr_sem_info.type, str
535
+ ):
536
+ attr_scope = SemScope(
537
+ attr_sem_info.name, attr_sem_info.type, attr_scope
538
+ )
539
+ else:
540
+ if isinstance(attr_sem_info, SemInfo) and isinstance(
541
+ attr_sem_info.type, str
542
+ ):
543
+ attr_scope = SemScope(
544
+ attr_sem_info.name, attr_sem_info.type, attr_scope
545
+ )
546
+ if isinstance(attr_sem_info, SemInfo) and isinstance(attr_scope, SemScope):
547
+ return attr_sem_info.semstr, attr_scope.as_type_str
548
+ return "", "" #
549
+
438
550
  @staticmethod
439
551
  @hookimpl
440
552
  def with_llm(
@@ -444,7 +556,7 @@ class JacFeatureDefaults:
444
556
  scope: str,
445
557
  incl_info: list[tuple[str, str]],
446
558
  excl_info: list[tuple[str, str]],
447
- inputs: tuple,
559
+ inputs: list[tuple[str, str, str, Any]],
448
560
  outputs: tuple,
449
561
  action: str,
450
562
  ) -> Any: # noqa: ANN401
@@ -459,6 +571,7 @@ class JacFeatureDefaults:
459
571
  ) as f:
460
572
  mod_registry = pickle.load(f)
461
573
 
574
+ outputs = outputs[0] if isinstance(outputs, list) else outputs
462
575
  _scope = SemScope.get_scope_from_str(scope)
463
576
  assert _scope is not None
464
577
 
@@ -469,7 +582,6 @@ class JacFeatureDefaults:
469
582
  type_collector: list = []
470
583
  information, collected_types = get_info_types(_scope, mod_registry, incl_info)
471
584
  type_collector.extend(collected_types)
472
-
473
585
  inputs_information_list = []
474
586
  for i in inputs:
475
587
  typ_anno = get_type_annotation(i[3])
@@ -479,8 +591,8 @@ class JacFeatureDefaults:
479
591
  )
480
592
  inputs_information = "\n".join(inputs_information_list)
481
593
 
482
- output_information = f"{outputs[0]} ({outputs[2]})"
483
- type_collector.extend(extract_non_primary_type(outputs[2]))
594
+ output_information = f"{outputs[0]} ({outputs[1]})"
595
+ type_collector.extend(extract_non_primary_type(outputs[1]))
484
596
 
485
597
  type_explanations_list = list(
486
598
  get_all_type_explanations(type_collector, mod_registry).values()
jaclang/plugin/feature.py CHANGED
@@ -3,7 +3,7 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import types
6
- from typing import Any, Callable, Optional, Type, TypeAlias
6
+ from typing import Any, Callable, Optional, Type, TypeAlias, Union
7
7
 
8
8
  from jaclang.compiler.absyntree import Module
9
9
  from jaclang.core.construct import (
@@ -77,17 +77,25 @@ class JacFeature:
77
77
  def jac_import(
78
78
  target: str,
79
79
  base_path: str,
80
+ absorb: bool = False,
80
81
  cachable: bool = True,
82
+ mdl_alias: Optional[str] = None,
81
83
  override_name: Optional[str] = None,
82
84
  mod_bundle: Optional[Module] = None,
85
+ lng: Optional[str] = None,
86
+ items: Optional[dict[str, Union[str, bool]]] = None,
83
87
  ) -> Optional[types.ModuleType]:
84
88
  """Core Import Process."""
85
89
  return pm.hook.jac_import(
86
90
  target=target,
87
91
  base_path=base_path,
92
+ absorb=absorb,
88
93
  cachable=cachable,
94
+ mdl_alias=mdl_alias,
89
95
  override_name=override_name,
90
96
  mod_bundle=mod_bundle,
97
+ lng=lng,
98
+ items=items,
91
99
  )
92
100
 
93
101
  @staticmethod
@@ -225,6 +233,25 @@ class JacFeature:
225
233
  is_undirected=is_undirected, conn_type=conn_type, conn_assign=conn_assign
226
234
  )
227
235
 
236
+ @staticmethod
237
+ def get_semstr_type(
238
+ file_loc: str, scope: str, attr: str, return_semstr: bool
239
+ ) -> Optional[str]:
240
+ """Jac's get_semstr_type feature."""
241
+ return pm.hook.get_semstr_type(
242
+ file_loc=file_loc, scope=scope, attr=attr, return_semstr=return_semstr
243
+ )
244
+
245
+ @staticmethod
246
+ def obj_scope(file_loc: str, attr: str) -> str:
247
+ """Jac's get_semstr_type feature."""
248
+ return pm.hook.obj_scope(file_loc=file_loc, attr=attr)
249
+
250
+ @staticmethod
251
+ def get_sem_type(file_loc: str, attr: str) -> tuple[str | None, str | None]:
252
+ """Jac's get_semstr_type feature."""
253
+ return pm.hook.get_sem_type(file_loc=file_loc, attr=attr)
254
+
228
255
  @staticmethod
229
256
  def with_llm(
230
257
  file_loc: str,
@@ -233,7 +260,7 @@ class JacFeature:
233
260
  scope: str,
234
261
  incl_info: list[tuple[str, str]],
235
262
  excl_info: list[tuple[str, str]],
236
- inputs: tuple,
263
+ inputs: list[tuple[str, str, str, Any]],
237
264
  outputs: tuple,
238
265
  action: str,
239
266
  ) -> Any: # noqa: ANN401
jaclang/plugin/spec.py CHANGED
@@ -3,7 +3,7 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import types
6
- from typing import Any, Callable, Optional, Type, TypeVar
6
+ from typing import Any, Callable, Optional, Type, TypeVar, Union
7
7
 
8
8
  from jaclang.compiler.absyntree import Module
9
9
  from jaclang.plugin.default import (
@@ -73,9 +73,13 @@ class JacFeatureSpec:
73
73
  def jac_import(
74
74
  target: str,
75
75
  base_path: str,
76
+ absorb: bool,
76
77
  cachable: bool,
78
+ mdl_alias: Optional[str],
77
79
  override_name: Optional[str],
78
80
  mod_bundle: Optional[Module],
81
+ lng: Optional[str],
82
+ items: Optional[dict[str, Union[str, bool]]],
79
83
  ) -> Optional[types.ModuleType]:
80
84
  """Core Import Process."""
81
85
  raise NotImplementedError
@@ -208,6 +212,25 @@ class JacFeatureSpec:
208
212
  """Jac's root getter."""
209
213
  raise NotImplementedError
210
214
 
215
+ @staticmethod
216
+ @hookspec(firstresult=True)
217
+ def get_semstr_type(
218
+ file_loc: str, scope: str, attr: str, return_semstr: bool
219
+ ) -> Optional[str]:
220
+ """Jac's get_semstr_type stmt feature."""
221
+ raise NotImplementedError
222
+
223
+ @staticmethod
224
+ @hookspec(firstresult=True)
225
+ def obj_scope(file_loc: str, attr: str) -> str:
226
+ """Jac's get_semstr_type feature."""
227
+ raise NotImplementedError
228
+
229
+ @staticmethod
230
+ def get_sem_type(file_loc: str, attr: str) -> tuple[str | None, str | None]:
231
+ """Jac's get_semstr_type feature."""
232
+ raise NotImplementedError
233
+
211
234
  @staticmethod
212
235
  @hookspec(firstresult=True)
213
236
  def with_llm(
@@ -217,7 +240,7 @@ class JacFeatureSpec:
217
240
  scope: str,
218
241
  incl_info: list[tuple[str, str]],
219
242
  excl_info: list[tuple[str, str]],
220
- inputs: tuple,
243
+ inputs: list[tuple[str, str, str, Any]],
221
244
  outputs: tuple,
222
245
  action: str,
223
246
  ) -> Any: # noqa: ANN401
jaclang/utils/helpers.py CHANGED
@@ -5,6 +5,7 @@ import marshal
5
5
  import os
6
6
  import pdb
7
7
  import re
8
+ from typing import Optional
8
9
 
9
10
 
10
11
  def pascal_to_snake(pascal_string: str) -> str:
@@ -127,19 +128,16 @@ def auto_generate_refs() -> None:
127
128
 
128
129
 
129
130
  def import_target_to_relative_path(
130
- import_target: str, base_path: str | None = None, file_extension: str = ".jac"
131
+ import_level: int,
132
+ import_target: str,
133
+ base_path: Optional[str] = None,
134
+ file_extension: str = ".jac",
131
135
  ) -> str:
132
136
  """Convert an import target string into a relative file path."""
133
- if base_path is None:
137
+ if not base_path:
134
138
  base_path = os.getcwd()
135
139
  parts = import_target.split(".")
136
- traversal_levels = 0
137
- for part in parts:
138
- if part == "":
139
- traversal_levels += 1
140
- else:
141
- break # Stop at the first non-empty part
142
- traversal_levels = traversal_levels - 1 if traversal_levels > 0 else 0
140
+ traversal_levels = import_level - 1 if import_level > 0 else 0
143
141
  actual_parts = parts[traversal_levels:]
144
142
  for _ in range(traversal_levels):
145
143
  base_path = os.path.dirname(base_path)
@@ -8,6 +8,7 @@ from typing import List, Optional, Type
8
8
 
9
9
  import jaclang.compiler.absyntree as ast
10
10
  from jaclang.compiler.compile import jac_file_to_pass
11
+ from jaclang.compiler.passes.main.pyast_load_pass import PyastBuildPass
11
12
  from jaclang.compiler.passes.main.schedules import py_code_gen_typed
12
13
  from jaclang.compiler.symtable import SymbolTable
13
14
  from jaclang.utils.helpers import auto_generate_refs, pascal_to_snake
@@ -198,20 +199,43 @@ class AstTool:
198
199
 
199
200
  def ir(self, args: List[str]) -> str:
200
201
  """Generate a AST, SymbolTable tree for .jac file, or Python AST for .py file."""
202
+ error = "Usage: ir <choose one of (sym / sym. / ast / ast. / pyast / py / unparse)> <.py or .jac file_path>"
201
203
  if len(args) != 2:
202
- return "Usage: ir <choose one of (sym / sym. / ast / ast. / pyast / py)> <file_path>"
204
+ return error
203
205
 
204
206
  output, file_name = args
205
207
 
206
208
  if not os.path.isfile(file_name):
207
209
  return f"Error: {file_name} not found"
208
210
 
209
- if file_name.endswith(".jac"):
211
+ if file_name.endswith((".jac", ".py")):
210
212
  [base, mod] = os.path.split(file_name)
211
213
  base = base if base else "./"
212
- ir = jac_file_to_pass(
213
- file_name, schedule=py_code_gen_typed
214
- ).ir # Assuming jac_file_to_pass is defined elsewhere
214
+
215
+ if file_name.endswith(".py"):
216
+ with open(file_name, "r") as f:
217
+ parsed_ast = py_ast.parse(f.read())
218
+ if output == "pyast":
219
+ return f"\n{py_ast.dump(parsed_ast, indent=2)}"
220
+ try:
221
+ rep = PyastBuildPass(
222
+ input_ir=ast.PythonModuleAst(parsed_ast, mod_path=file_name),
223
+ ).ir
224
+
225
+ schedule = py_code_gen_typed
226
+ target = schedule[-1]
227
+ for i in schedule:
228
+ if i == target:
229
+ break
230
+ ast_ret = i(input_ir=rep, prior=None)
231
+ ast_ret = target(input_ir=rep, prior=None)
232
+ ir = ast_ret.ir
233
+ except Exception as e:
234
+ return f"Error While Jac to Py AST conversion: {e}"
235
+ else:
236
+ ir = jac_file_to_pass(
237
+ file_name, schedule=py_code_gen_typed
238
+ ).ir # Assuming jac_file_to_pass is defined elsewhere
215
239
 
216
240
  match output:
217
241
  case "sym":
@@ -245,14 +269,7 @@ class AstTool:
245
269
  else "Compile failed."
246
270
  )
247
271
  case _:
248
- return "Invalid key: Use one of (sym / sym. / ast / ast. / pyast) followed by file_path."
249
- elif file_name.endswith(".py") and output == "pyast":
250
- [base, mod] = os.path.split(file_name)
251
- base = base if base else "./"
252
- with open(file_name, "r") as file:
253
- code = file.read()
254
- parsed_ast = py_ast.parse(code)
255
- return f"\n{py_ast.dump(parsed_ast, indent=2)}"
272
+ return f"Invalid key: {error}"
256
273
  else:
257
274
  return "Not a .jac or .py file, or invalid command for file type."
258
275
 
@@ -260,3 +277,10 @@ class AstTool:
260
277
  """Automate the reference guide generation."""
261
278
  auto_generate_refs()
262
279
  return "References generated."
280
+
281
+ def gen_parser(self) -> str:
282
+ """Generate static parser."""
283
+ from jaclang.compiler import generate_static_parser
284
+
285
+ generate_static_parser(force=True)
286
+ return "Parser generated."
jaclang/utils/test.py CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  import inspect
4
4
  import os
5
- from abc import ABC, abstractmethod
6
5
  from typing import Callable, Optional
7
6
  from unittest import TestCase as _TestCase
8
7
 
@@ -54,7 +53,7 @@ class TestCase(_TestCase):
54
53
  return os.path.abspath(file_path)
55
54
 
56
55
 
57
- class TestCaseMicroSuite(ABC, TestCase):
56
+ class TestCaseMicroSuite(TestCase):
58
57
  """Base test case for Jaseci."""
59
58
 
60
59
  test_micro_jac_files_fully_tested: Optional[Callable[[TestCase], None]] = None
@@ -86,7 +85,6 @@ class TestCaseMicroSuite(ABC, TestCase):
86
85
 
87
86
  cls.test_micro_jac_files_fully_tested = test_micro_jac_files_fully_tested
88
87
 
89
- @abstractmethod
90
88
  def micro_suite_test(self, filename: str) -> None:
91
89
  """Test micro jac file."""
92
90
  pass
@@ -98,3 +98,9 @@ class JacFormatPassTests(TestCase):
98
98
  if file not in created_files
99
99
  ]
100
100
  self.assertEqual(len(other_reference_files), 0)
101
+
102
+ def test_py_jac_mode(self) -> None:
103
+ """Testing for py_jac_mode support."""
104
+ file = self.fixture_abs_path("../../../tests/fixtures/pyfunc.py")
105
+ out = AstTool().ir(["unparse", file])
106
+ self.assertIn("can my_print(x: object) -> None", out)
@@ -0,0 +1,59 @@
1
+ // Basic terminals for common use
2
+
3
+
4
+ //
5
+ // Numbers
6
+ //
7
+
8
+ DIGIT: "0".."9"
9
+ HEXDIGIT: "a".."f"|"A".."F"|DIGIT
10
+
11
+ INT: DIGIT+
12
+ SIGNED_INT: ["+"|"-"] INT
13
+ DECIMAL: INT "." INT? | "." INT
14
+
15
+ // float = /-?\d+(\.\d+)?([eE][+-]?\d+)?/
16
+ _EXP: ("e"|"E") SIGNED_INT
17
+ FLOAT: INT _EXP | DECIMAL _EXP?
18
+ SIGNED_FLOAT: ["+"|"-"] FLOAT
19
+
20
+ NUMBER: FLOAT | INT
21
+ SIGNED_NUMBER: ["+"|"-"] NUMBER
22
+
23
+ //
24
+ // Strings
25
+ //
26
+ _STRING_INNER: /.*?/
27
+ _STRING_ESC_INNER: _STRING_INNER /(?<!\\)(\\\\)*?/
28
+
29
+ ESCAPED_STRING : "\"" _STRING_ESC_INNER "\""
30
+
31
+
32
+ //
33
+ // Names (Variables)
34
+ //
35
+ LCASE_LETTER: "a".."z"
36
+ UCASE_LETTER: "A".."Z"
37
+
38
+ LETTER: UCASE_LETTER | LCASE_LETTER
39
+ WORD: LETTER+
40
+
41
+ CNAME: ("_"|LETTER) ("_"|LETTER|DIGIT)*
42
+
43
+
44
+ //
45
+ // Whitespace
46
+ //
47
+ WS_INLINE: (" "|/\t/)+
48
+ WS: /[ \t\f\r\n]/+
49
+
50
+ CR : /\r/
51
+ LF : /\n/
52
+ NEWLINE: (CR? LF)+
53
+
54
+
55
+ // Comments
56
+ SH_COMMENT: /#[^\n]*/
57
+ CPP_COMMENT: /\/\/[^\n]*/
58
+ C_COMMENT: "/*" /(.|\n)*?/ "*/"
59
+ SQL_COMMENT: /--[^\n]*/
@@ -0,0 +1,62 @@
1
+ # Lark grammar of Lark's syntax
2
+ # Note: Lark is not bootstrapped, its parser is implemented in load_grammar.py
3
+
4
+ start: (_item? _NL)* _item?
5
+
6
+ _item: rule
7
+ | token
8
+ | statement
9
+
10
+ rule: RULE rule_params priority? ":" expansions
11
+ token: TOKEN token_params priority? ":" expansions
12
+
13
+ rule_params: ["{" RULE ("," RULE)* "}"]
14
+ token_params: ["{" TOKEN ("," TOKEN)* "}"]
15
+
16
+ priority: "." NUMBER
17
+
18
+ statement: "%ignore" expansions -> ignore
19
+ | "%import" import_path ["->" name] -> import
20
+ | "%import" import_path name_list -> multi_import
21
+ | "%override" rule -> override_rule
22
+ | "%declare" name+ -> declare
23
+
24
+ !import_path: "."? name ("." name)*
25
+ name_list: "(" name ("," name)* ")"
26
+
27
+ ?expansions: alias (_VBAR alias)*
28
+
29
+ ?alias: expansion ["->" RULE]
30
+
31
+ ?expansion: expr*
32
+
33
+ ?expr: atom [OP | "~" NUMBER [".." NUMBER]]
34
+
35
+ ?atom: "(" expansions ")"
36
+ | "[" expansions "]" -> maybe
37
+ | value
38
+
39
+ ?value: STRING ".." STRING -> literal_range
40
+ | name
41
+ | (REGEXP | STRING) -> literal
42
+ | name "{" value ("," value)* "}" -> template_usage
43
+
44
+ name: RULE
45
+ | TOKEN
46
+
47
+ _VBAR: _NL? "|"
48
+ OP: /[+*]|[?](?![a-z])/
49
+ RULE: /!?[_?]?[a-z][_a-z0-9]*/
50
+ TOKEN: /_?[A-Z][_A-Z0-9]*/
51
+ STRING: _STRING "i"?
52
+ REGEXP: /\/(?!\/)(\\\/|\\\\|[^\/])*?\/[imslux]*/
53
+ _NL: /(\r?\n)+\s*/
54
+
55
+ %import common.ESCAPED_STRING -> _STRING
56
+ %import common.SIGNED_INT -> NUMBER
57
+ %import common.WS_INLINE
58
+
59
+ COMMENT: /\s*/ "//" /[^\n]/* | /\s*/ "#" /[^\n]/*
60
+
61
+ %ignore WS_INLINE
62
+ %ignore COMMENT