jaclang 0.5.11__py3-none-any.whl → 0.5.16__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 (41) hide show
  1. jaclang/cli/cli.py +20 -0
  2. jaclang/compiler/__init__.py +35 -19
  3. jaclang/compiler/absyntree.py +106 -97
  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 +127 -8
  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.16.dist-info}/METADATA +1 -1
  36. {jaclang-0.5.11.dist-info → jaclang-0.5.16.dist-info}/RECORD +40 -34
  37. jaclang/compiler/__jac_gen__/jac_parser.py +0 -4069
  38. /jaclang/compiler/{__jac_gen__ → generated}/__init__.py +0 -0
  39. {jaclang-0.5.11.dist-info → jaclang-0.5.16.dist-info}/WHEEL +0 -0
  40. {jaclang-0.5.11.dist-info → jaclang-0.5.16.dist-info}/entry_points.txt +0 -0
  41. {jaclang-0.5.11.dist-info → jaclang-0.5.16.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
@@ -86,8 +86,15 @@ class JacFeatureDefaults:
86
86
  i.resolve(cls)
87
87
  if not issubclass(cls, arch_base):
88
88
  cls = type(cls.__name__, (cls, arch_base), {})
89
- cls._jac_entry_funcs_ = on_entry # type: ignore
90
- cls._jac_exit_funcs_ = on_exit # type: ignore
89
+ cls._jac_entry_funcs_ = on_entry # type: ignore
90
+ cls._jac_exit_funcs_ = on_exit # type: ignore
91
+ else:
92
+ cls._jac_entry_funcs_ = cls._jac_entry_funcs_ + [
93
+ x for x in on_entry if x not in cls._jac_entry_funcs_
94
+ ]
95
+ cls._jac_exit_funcs_ = cls._jac_exit_funcs_ + [
96
+ x for x in on_exit if x not in cls._jac_exit_funcs_
97
+ ]
91
98
  inner_init = cls.__init__ # type: ignore
92
99
 
93
100
  @wraps(inner_init)
@@ -167,17 +174,25 @@ class JacFeatureDefaults:
167
174
  def jac_import(
168
175
  target: str,
169
176
  base_path: str,
177
+ absorb: bool,
170
178
  cachable: bool,
179
+ mdl_alias: Optional[str],
171
180
  override_name: Optional[str],
172
181
  mod_bundle: Optional[Module],
182
+ lng: Optional[str],
183
+ items: Optional[dict[str, Union[str, bool]]],
173
184
  ) -> Optional[types.ModuleType]:
174
185
  """Core Import Process."""
175
186
  result = jac_importer(
176
187
  target=target,
177
188
  base_path=base_path,
189
+ absorb=absorb,
178
190
  cachable=cachable,
191
+ mdl_alias=mdl_alias,
179
192
  override_name=override_name,
180
193
  mod_bundle=mod_bundle,
194
+ lng=lng,
195
+ items=items,
181
196
  )
182
197
  return result
183
198
 
@@ -435,6 +450,110 @@ class JacFeatureDefaults:
435
450
 
436
451
  return builder
437
452
 
453
+ @staticmethod
454
+ @hookimpl
455
+ def get_semstr_type(
456
+ file_loc: str, scope: str, attr: str, return_semstr: bool
457
+ ) -> Optional[str]:
458
+ """Jac's get_semstr_type feature."""
459
+ _scope = SemScope.get_scope_from_str(scope)
460
+ with open(
461
+ os.path.join(
462
+ os.path.dirname(file_loc),
463
+ "__jac_gen__",
464
+ os.path.basename(file_loc).replace(".jac", ".registry.pkl"),
465
+ ),
466
+ "rb",
467
+ ) as f:
468
+ mod_registry: SemRegistry = pickle.load(f)
469
+ _, attr_seminfo = mod_registry.lookup(_scope, attr)
470
+ if attr_seminfo and isinstance(attr_seminfo, SemInfo):
471
+ return attr_seminfo.semstr if return_semstr else attr_seminfo.type
472
+ return None
473
+
474
+ @staticmethod
475
+ @hookimpl
476
+ def obj_scope(file_loc: str, attr: str) -> str:
477
+ """Jac's gather_scope feature."""
478
+ with open(
479
+ os.path.join(
480
+ os.path.dirname(file_loc),
481
+ "__jac_gen__",
482
+ os.path.basename(file_loc).replace(".jac", ".registry.pkl"),
483
+ ),
484
+ "rb",
485
+ ) as f:
486
+ mod_registry: SemRegistry = pickle.load(f)
487
+
488
+ attr_scope = None
489
+ for x in attr.split("."):
490
+ attr_scope, attr_sem_info = mod_registry.lookup(attr_scope, x)
491
+ if isinstance(attr_sem_info, SemInfo) and attr_sem_info.type not in [
492
+ "class",
493
+ "obj",
494
+ "node",
495
+ "edge",
496
+ ]:
497
+ attr_scope, attr_sem_info = mod_registry.lookup(
498
+ None, attr_sem_info.type
499
+ )
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
+ else:
507
+ if isinstance(attr_sem_info, SemInfo) and isinstance(
508
+ attr_sem_info.type, str
509
+ ):
510
+ attr_scope = SemScope(
511
+ attr_sem_info.name, attr_sem_info.type, attr_scope
512
+ )
513
+ return str(attr_scope)
514
+
515
+ @staticmethod
516
+ @hookimpl
517
+ def get_sem_type(file_loc: str, attr: str) -> tuple[str | None, str | None]:
518
+ with open(
519
+ os.path.join(
520
+ os.path.dirname(file_loc),
521
+ "__jac_gen__",
522
+ os.path.basename(file_loc).replace(".jac", ".registry.pkl"),
523
+ ),
524
+ "rb",
525
+ ) as f:
526
+ mod_registry: SemRegistry = pickle.load(f)
527
+
528
+ attr_scope = None
529
+ for x in attr.split("."):
530
+ attr_scope, attr_sem_info = mod_registry.lookup(attr_scope, x)
531
+ if isinstance(attr_sem_info, SemInfo) and attr_sem_info.type not in [
532
+ "class",
533
+ "obj",
534
+ "node",
535
+ "edge",
536
+ ]:
537
+ attr_scope, attr_sem_info = mod_registry.lookup(
538
+ None, attr_sem_info.type
539
+ )
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
+ else:
547
+ if isinstance(attr_sem_info, SemInfo) and isinstance(
548
+ attr_sem_info.type, str
549
+ ):
550
+ attr_scope = SemScope(
551
+ attr_sem_info.name, attr_sem_info.type, attr_scope
552
+ )
553
+ if isinstance(attr_sem_info, SemInfo) and isinstance(attr_scope, SemScope):
554
+ return attr_sem_info.semstr, attr_scope.as_type_str
555
+ return "", "" #
556
+
438
557
  @staticmethod
439
558
  @hookimpl
440
559
  def with_llm(
@@ -444,7 +563,7 @@ class JacFeatureDefaults:
444
563
  scope: str,
445
564
  incl_info: list[tuple[str, str]],
446
565
  excl_info: list[tuple[str, str]],
447
- inputs: tuple,
566
+ inputs: list[tuple[str, str, str, Any]],
448
567
  outputs: tuple,
449
568
  action: str,
450
569
  ) -> Any: # noqa: ANN401
@@ -459,6 +578,7 @@ class JacFeatureDefaults:
459
578
  ) as f:
460
579
  mod_registry = pickle.load(f)
461
580
 
581
+ outputs = outputs[0] if isinstance(outputs, list) else outputs
462
582
  _scope = SemScope.get_scope_from_str(scope)
463
583
  assert _scope is not None
464
584
 
@@ -469,7 +589,6 @@ class JacFeatureDefaults:
469
589
  type_collector: list = []
470
590
  information, collected_types = get_info_types(_scope, mod_registry, incl_info)
471
591
  type_collector.extend(collected_types)
472
-
473
592
  inputs_information_list = []
474
593
  for i in inputs:
475
594
  typ_anno = get_type_annotation(i[3])
@@ -479,8 +598,8 @@ class JacFeatureDefaults:
479
598
  )
480
599
  inputs_information = "\n".join(inputs_information_list)
481
600
 
482
- output_information = f"{outputs[0]} ({outputs[2]})"
483
- type_collector.extend(extract_non_primary_type(outputs[2]))
601
+ output_information = f"{outputs[0]} ({outputs[1]})"
602
+ type_collector.extend(extract_non_primary_type(outputs[1]))
484
603
 
485
604
  type_explanations_list = list(
486
605
  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