tiferet-ly 1.0.0__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.
- tiferet_ly-1.0.0/LICENSE +21 -0
- tiferet_ly-1.0.0/PKG-INFO +47 -0
- tiferet_ly-1.0.0/README.md +28 -0
- tiferet_ly-1.0.0/pyproject.toml +39 -0
- tiferet_ly-1.0.0/setup.cfg +4 -0
- tiferet_ly-1.0.0/tiferet_ly/__init__.py +6 -0
- tiferet_ly-1.0.0/tiferet_ly/assets/__init__.py +9 -0
- tiferet_ly-1.0.0/tiferet_ly/assets/error.py +12 -0
- tiferet_ly-1.0.0/tiferet_ly/assets/grammar.py +21 -0
- tiferet_ly-1.0.0/tiferet_ly/assets/reader.py +12 -0
- tiferet_ly-1.0.0/tiferet_ly/assets/translation.py +9 -0
- tiferet_ly-1.0.0/tiferet_ly/domain/__init__.py +30 -0
- tiferet_ly-1.0.0/tiferet_ly/domain/ast.py +53 -0
- tiferet_ly-1.0.0/tiferet_ly/domain/grammar.py +42 -0
- tiferet_ly-1.0.0/tiferet_ly/domain/lexeme.py +44 -0
- tiferet_ly-1.0.0/tiferet_ly/domain/production.py +68 -0
- tiferet_ly-1.0.0/tiferet_ly/domain/token.py +68 -0
- tiferet_ly-1.0.0/tiferet_ly/events/__init__.py +1 -0
- tiferet_ly-1.0.0/tiferet_ly/events/grammar.py +469 -0
- tiferet_ly-1.0.0/tiferet_ly/events/production.py +729 -0
- tiferet_ly-1.0.0/tiferet_ly/events/reader.py +165 -0
- tiferet_ly-1.0.0/tiferet_ly/events/render.py +48 -0
- tiferet_ly-1.0.0/tiferet_ly/events/token.py +416 -0
- tiferet_ly-1.0.0/tiferet_ly/interfaces/__init__.py +5 -0
- tiferet_ly-1.0.0/tiferet_ly/interfaces/grammar.py +87 -0
- tiferet_ly-1.0.0/tiferet_ly/interfaces/lexer.py +52 -0
- tiferet_ly-1.0.0/tiferet_ly/interfaces/parser.py +52 -0
- tiferet_ly-1.0.0/tiferet_ly/interfaces/production.py +155 -0
- tiferet_ly-1.0.0/tiferet_ly/interfaces/token.py +91 -0
- tiferet_ly-1.0.0/tiferet_ly/mappers/__init__.py +1 -0
- tiferet_ly-1.0.0/tiferet_ly/mappers/ast.py +168 -0
- tiferet_ly-1.0.0/tiferet_ly/mappers/core.py +98 -0
- tiferet_ly-1.0.0/tiferet_ly/mappers/grammar.py +101 -0
- tiferet_ly-1.0.0/tiferet_ly/mappers/lexeme.py +49 -0
- tiferet_ly-1.0.0/tiferet_ly/mappers/production.py +221 -0
- tiferet_ly-1.0.0/tiferet_ly/mappers/token.py +221 -0
- tiferet_ly-1.0.0/tiferet_ly/repos/__init__.py +5 -0
- tiferet_ly-1.0.0/tiferet_ly/repos/grammar.py +187 -0
- tiferet_ly-1.0.0/tiferet_ly/repos/production.py +410 -0
- tiferet_ly-1.0.0/tiferet_ly/repos/token.py +289 -0
- tiferet_ly-1.0.0/tiferet_ly/utils/__init__.py +1 -0
- tiferet_ly-1.0.0/tiferet_ly/utils/core.py +214 -0
- tiferet_ly-1.0.0/tiferet_ly/utils/grammar.py +216 -0
- tiferet_ly-1.0.0/tiferet_ly/utils/lex.py +143 -0
- tiferet_ly-1.0.0/tiferet_ly/utils/parse.py +275 -0
- tiferet_ly-1.0.0/tiferet_ly/utils/render.py +43 -0
- tiferet_ly-1.0.0/tiferet_ly/utils/translation.py +284 -0
- tiferet_ly-1.0.0/tiferet_ly.egg-info/PKG-INFO +47 -0
- tiferet_ly-1.0.0/tiferet_ly.egg-info/SOURCES.txt +50 -0
- tiferet_ly-1.0.0/tiferet_ly.egg-info/dependency_links.txt +1 -0
- tiferet_ly-1.0.0/tiferet_ly.egg-info/requires.txt +7 -0
- tiferet_ly-1.0.0/tiferet_ly.egg-info/top_level.txt +1 -0
tiferet_ly-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Great Strength Systems
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tiferet-ly
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: A Lex/Yacc wrapper built with Tiferet.
|
|
5
|
+
Author-email: "Andrew Shatz, Great Strength Systems" <andrew@greatstrength.me>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/greatstrength/tiferet-ly
|
|
8
|
+
Project-URL: Repository, https://github.com/greatstrength/tiferet-ly
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Requires-Dist: tiferet
|
|
13
|
+
Requires-Dist: pydantic>=2.6
|
|
14
|
+
Requires-Dist: ply>=3.11
|
|
15
|
+
Provides-Extra: test
|
|
16
|
+
Requires-Dist: pytest; extra == "test"
|
|
17
|
+
Requires-Dist: PyYAML; extra == "test"
|
|
18
|
+
Dynamic: license-file
|
|
19
|
+
|
|
20
|
+
# tiferet-ly
|
|
21
|
+
A Lex/Yacc Wrapper built with Tiferet
|
|
22
|
+
|
|
23
|
+
## Overview
|
|
24
|
+
tiferet-ly lets you describe a small language — its words and the sentence
|
|
25
|
+
patterns it accepts — as a declared list instead of hand-written code. Hand
|
|
26
|
+
tiferet-ly that declaration and get back a working reader for text written in
|
|
27
|
+
that language, built on Python's well-established Lex/Yacc engine
|
|
28
|
+
([PLY](https://github.com/dabeaz/ply)). Adding a new keyword or sentence
|
|
29
|
+
pattern becomes an edit to the declaration rather than a new function buried
|
|
30
|
+
in a growing file, and the pieces around it can be tested without invoking
|
|
31
|
+
the real parsing engine at all.
|
|
32
|
+
|
|
33
|
+
## Documentation
|
|
34
|
+
Declare a language's words and sentence patterns as data. Translate that
|
|
35
|
+
declaration into the form the Lex/Yacc engine expects. Assemble those
|
|
36
|
+
translated rules into a reader. Read text written in the declared language
|
|
37
|
+
and hand back the result.
|
|
38
|
+
|
|
39
|
+
- [Quick-Start](docs/quick-start.md) — run the checked-in calculator from
|
|
40
|
+
the repository root.
|
|
41
|
+
- [Domain Vision Statement](docs/domain-vision.md) — what tiferet-ly is for
|
|
42
|
+
and the value it aims to provide.
|
|
43
|
+
- [Core Domain Distillation](docs/core-domain-distillation.md) — the
|
|
44
|
+
technical breakdown of its intended vocabulary, behaviors, and design
|
|
45
|
+
commitments.
|
|
46
|
+
- [AGENTS.md](AGENTS.md) — orientation for contributors and AI agents
|
|
47
|
+
working in this repository.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# tiferet-ly
|
|
2
|
+
A Lex/Yacc Wrapper built with Tiferet
|
|
3
|
+
|
|
4
|
+
## Overview
|
|
5
|
+
tiferet-ly lets you describe a small language — its words and the sentence
|
|
6
|
+
patterns it accepts — as a declared list instead of hand-written code. Hand
|
|
7
|
+
tiferet-ly that declaration and get back a working reader for text written in
|
|
8
|
+
that language, built on Python's well-established Lex/Yacc engine
|
|
9
|
+
([PLY](https://github.com/dabeaz/ply)). Adding a new keyword or sentence
|
|
10
|
+
pattern becomes an edit to the declaration rather than a new function buried
|
|
11
|
+
in a growing file, and the pieces around it can be tested without invoking
|
|
12
|
+
the real parsing engine at all.
|
|
13
|
+
|
|
14
|
+
## Documentation
|
|
15
|
+
Declare a language's words and sentence patterns as data. Translate that
|
|
16
|
+
declaration into the form the Lex/Yacc engine expects. Assemble those
|
|
17
|
+
translated rules into a reader. Read text written in the declared language
|
|
18
|
+
and hand back the result.
|
|
19
|
+
|
|
20
|
+
- [Quick-Start](docs/quick-start.md) — run the checked-in calculator from
|
|
21
|
+
the repository root.
|
|
22
|
+
- [Domain Vision Statement](docs/domain-vision.md) — what tiferet-ly is for
|
|
23
|
+
and the value it aims to provide.
|
|
24
|
+
- [Core Domain Distillation](docs/core-domain-distillation.md) — the
|
|
25
|
+
technical breakdown of its intended vocabulary, behaviors, and design
|
|
26
|
+
commitments.
|
|
27
|
+
- [AGENTS.md](AGENTS.md) — orientation for contributors and AI agents
|
|
28
|
+
working in this repository.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "tiferet-ly"
|
|
3
|
+
dynamic = ["version"]
|
|
4
|
+
description = "A Lex/Yacc wrapper built with Tiferet."
|
|
5
|
+
authors = [
|
|
6
|
+
{ name = "Andrew Shatz, Great Strength Systems", email = "andrew@greatstrength.me" }
|
|
7
|
+
]
|
|
8
|
+
license = { text = "MIT" }
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
dependencies = [
|
|
12
|
+
"tiferet",
|
|
13
|
+
"pydantic>=2.6",
|
|
14
|
+
"ply>=3.11",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
[project.urls]
|
|
18
|
+
Homepage = "https://github.com/greatstrength/tiferet-ly"
|
|
19
|
+
Repository = "https://github.com/greatstrength/tiferet-ly"
|
|
20
|
+
|
|
21
|
+
[project.optional-dependencies]
|
|
22
|
+
test = [
|
|
23
|
+
"pytest",
|
|
24
|
+
"PyYAML",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[build-system]
|
|
28
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
29
|
+
build-backend = "setuptools.build_meta"
|
|
30
|
+
|
|
31
|
+
[tool.setuptools.packages.find]
|
|
32
|
+
where = ["."]
|
|
33
|
+
include = ["tiferet_ly*"]
|
|
34
|
+
|
|
35
|
+
[tool.setuptools.dynamic]
|
|
36
|
+
version = { attr = "tiferet_ly.__version__" }
|
|
37
|
+
|
|
38
|
+
[tool.pytest.ini_options]
|
|
39
|
+
addopts = "--import-mode=importlib"
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""Tiferet Ly Error Assets"""
|
|
2
|
+
|
|
3
|
+
# *** constants (ids)
|
|
4
|
+
|
|
5
|
+
# ** constant: token_already_exists_id
|
|
6
|
+
TOKEN_ALREADY_EXISTS_ID = 'TOKEN_ALREADY_EXISTS'
|
|
7
|
+
|
|
8
|
+
# ** constant: token_not_found_id
|
|
9
|
+
TOKEN_NOT_FOUND_ID = 'TOKEN_NOT_FOUND'
|
|
10
|
+
|
|
11
|
+
# ** constant: token_action_not_supported_id
|
|
12
|
+
TOKEN_ACTION_NOT_SUPPORTED_ID = 'TOKEN_ACTION_NOT_SUPPORTED'
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Tiferet Ly Grammar Assets"""
|
|
2
|
+
|
|
3
|
+
# *** constants (ids)
|
|
4
|
+
|
|
5
|
+
# ** constant: grammar_already_exists_id
|
|
6
|
+
GRAMMAR_ALREADY_EXISTS_ID = 'GRAMMAR_ALREADY_EXISTS'
|
|
7
|
+
|
|
8
|
+
# ** constant: grammar_not_found_id
|
|
9
|
+
GRAMMAR_NOT_FOUND_ID = 'GRAMMAR_NOT_FOUND'
|
|
10
|
+
|
|
11
|
+
# ** constant: grammar_cycle_detected_id
|
|
12
|
+
GRAMMAR_CYCLE_DETECTED_ID = 'GRAMMAR_CYCLE_DETECTED'
|
|
13
|
+
|
|
14
|
+
# ** constant: grammar_start_not_found_id
|
|
15
|
+
GRAMMAR_START_NOT_FOUND_ID = 'GRAMMAR_START_NOT_FOUND'
|
|
16
|
+
|
|
17
|
+
# ** constant: grammar_parent_not_found_id
|
|
18
|
+
GRAMMAR_PARENT_NOT_FOUND_ID = 'GRAMMAR_PARENT_NOT_FOUND'
|
|
19
|
+
|
|
20
|
+
# ** constant: grammar_still_referenced_id
|
|
21
|
+
GRAMMAR_STILL_REFERENCED_ID = 'GRAMMAR_STILL_REFERENCED'
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""Tiferet Ly Reader Assets"""
|
|
2
|
+
|
|
3
|
+
# *** constants (ids)
|
|
4
|
+
|
|
5
|
+
# ** constant: lex_error_id
|
|
6
|
+
LEX_ERROR_ID = 'LEX_ERROR'
|
|
7
|
+
|
|
8
|
+
# ** constant: parse_error_id
|
|
9
|
+
PARSE_ERROR_ID = 'PARSE_ERROR'
|
|
10
|
+
|
|
11
|
+
# ** constant: reader_build_failed_id
|
|
12
|
+
READER_BUILD_FAILED_ID = 'READER_BUILD_FAILED'
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"""Tiferet Ly Translation Error Assets"""
|
|
2
|
+
|
|
3
|
+
# *** constants (ids)
|
|
4
|
+
|
|
5
|
+
# ** constant: action_compilation_failed_id
|
|
6
|
+
ACTION_COMPILATION_FAILED_ID = 'ACTION_COMPILATION_FAILED'
|
|
7
|
+
|
|
8
|
+
# ** constant: rule_pattern_invalid_id
|
|
9
|
+
RULE_PATTERN_INVALID_ID = 'RULE_PATTERN_INVALID'
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Tiferet Ly Domain"""
|
|
2
|
+
|
|
3
|
+
# *** imports
|
|
4
|
+
|
|
5
|
+
# ** app
|
|
6
|
+
from .token import (
|
|
7
|
+
TokenRule,
|
|
8
|
+
SimpleTokenRule,
|
|
9
|
+
ComplexTokenRule,
|
|
10
|
+
)
|
|
11
|
+
from .production import (
|
|
12
|
+
ProductionRule,
|
|
13
|
+
SimpleProductionRule,
|
|
14
|
+
ComplexProductionRule,
|
|
15
|
+
)
|
|
16
|
+
from .grammar import Grammar
|
|
17
|
+
from .ast import AstNode
|
|
18
|
+
|
|
19
|
+
# *** exports
|
|
20
|
+
|
|
21
|
+
__all__ = [
|
|
22
|
+
'TokenRule',
|
|
23
|
+
'SimpleTokenRule',
|
|
24
|
+
'ComplexTokenRule',
|
|
25
|
+
'ProductionRule',
|
|
26
|
+
'SimpleProductionRule',
|
|
27
|
+
'ComplexProductionRule',
|
|
28
|
+
'Grammar',
|
|
29
|
+
'AstNode',
|
|
30
|
+
]
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""Tiferet Ly AST Domain Models"""
|
|
2
|
+
|
|
3
|
+
# *** imports
|
|
4
|
+
|
|
5
|
+
# ** core
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
# ** infra
|
|
9
|
+
from pydantic import Field
|
|
10
|
+
|
|
11
|
+
# ** app
|
|
12
|
+
from tiferet.domain.core import DomainObject
|
|
13
|
+
|
|
14
|
+
# *** models
|
|
15
|
+
|
|
16
|
+
# ** model: ast_node
|
|
17
|
+
class AstNode(DomainObject):
|
|
18
|
+
'''
|
|
19
|
+
An optional generic node for a parse that chooses to keep structure.
|
|
20
|
+
|
|
21
|
+
The node stores a kind, children, a value, and a source span. It is
|
|
22
|
+
not a required parse result.
|
|
23
|
+
'''
|
|
24
|
+
|
|
25
|
+
# * attribute: kind
|
|
26
|
+
kind: str = Field(
|
|
27
|
+
...,
|
|
28
|
+
description='The kind of generic node.',
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# * attribute: children
|
|
32
|
+
children: list = Field(
|
|
33
|
+
default_factory=list,
|
|
34
|
+
description='The child nodes stored under this node.',
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
# * attribute: value
|
|
38
|
+
value: Any | None = Field(
|
|
39
|
+
default=None,
|
|
40
|
+
description='The optional value carried by this node.',
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
# * attribute: lineno
|
|
44
|
+
lineno: int | None = Field(
|
|
45
|
+
default=None,
|
|
46
|
+
description='The optional source line of this node.',
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# * attribute: lexpos
|
|
50
|
+
lexpos: int | None = Field(
|
|
51
|
+
default=None,
|
|
52
|
+
description='The optional source character offset of this node.',
|
|
53
|
+
)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Tiferet Ly Grammar Domain Models"""
|
|
2
|
+
|
|
3
|
+
# *** imports
|
|
4
|
+
|
|
5
|
+
# ** core
|
|
6
|
+
from typing import List
|
|
7
|
+
|
|
8
|
+
# ** infra
|
|
9
|
+
from pydantic import Field
|
|
10
|
+
|
|
11
|
+
# ** app
|
|
12
|
+
from tiferet.domain.core import DomainObject
|
|
13
|
+
|
|
14
|
+
# *** models
|
|
15
|
+
|
|
16
|
+
# ** model: grammar
|
|
17
|
+
class Grammar(DomainObject):
|
|
18
|
+
'''
|
|
19
|
+
The identity and composition of one declared grammar.
|
|
20
|
+
|
|
21
|
+
A grammar names itself, the grammars it composes, and the production
|
|
22
|
+
it starts from. It does not own a rule catalogue or check those facts
|
|
23
|
+
against any other aggregate.
|
|
24
|
+
'''
|
|
25
|
+
|
|
26
|
+
# * attribute: id
|
|
27
|
+
id: str = Field(
|
|
28
|
+
...,
|
|
29
|
+
description='The grammar identifier.',
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
# * attribute: parent_ids
|
|
33
|
+
parent_ids: List[str] = Field(
|
|
34
|
+
default_factory=list,
|
|
35
|
+
description='The ordered identifiers of the grammars this grammar composes.',
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
# * attribute: start
|
|
39
|
+
start: str = Field(
|
|
40
|
+
...,
|
|
41
|
+
description='The declared start-production name.',
|
|
42
|
+
)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""Tiferet Ly Lexeme Domain Models"""
|
|
2
|
+
|
|
3
|
+
# *** imports
|
|
4
|
+
|
|
5
|
+
# ** infra
|
|
6
|
+
from pydantic import Field
|
|
7
|
+
|
|
8
|
+
# ** app
|
|
9
|
+
from tiferet.domain.core import DomainObject
|
|
10
|
+
|
|
11
|
+
# *** models
|
|
12
|
+
|
|
13
|
+
# ** model: lexeme
|
|
14
|
+
class Lexeme(DomainObject):
|
|
15
|
+
'''
|
|
16
|
+
A recognized word and the source span where it was read.
|
|
17
|
+
|
|
18
|
+
The value is structural. Later AST work can reuse the same type,
|
|
19
|
+
text, line, and position without depending on a reader token.
|
|
20
|
+
'''
|
|
21
|
+
|
|
22
|
+
# * attribute: type
|
|
23
|
+
type: str = Field(
|
|
24
|
+
...,
|
|
25
|
+
description='The token type name of the recognized word.',
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
# * attribute: value
|
|
29
|
+
value: str = Field(
|
|
30
|
+
...,
|
|
31
|
+
description='The matched text of the recognized word.',
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
# * attribute: lineno
|
|
35
|
+
lineno: int = Field(
|
|
36
|
+
...,
|
|
37
|
+
description='The source line of the match.',
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
# * attribute: lexpos
|
|
41
|
+
lexpos: int = Field(
|
|
42
|
+
...,
|
|
43
|
+
description='The source character offset of the match.',
|
|
44
|
+
)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Tiferet Ly Production Domain Models"""
|
|
2
|
+
|
|
3
|
+
# *** imports
|
|
4
|
+
|
|
5
|
+
# ** infra
|
|
6
|
+
from pydantic import Field
|
|
7
|
+
|
|
8
|
+
# ** app
|
|
9
|
+
from tiferet.domain.core import DomainObject
|
|
10
|
+
|
|
11
|
+
# *** models
|
|
12
|
+
|
|
13
|
+
# ** model: production_rule
|
|
14
|
+
class ProductionRule(DomainObject):
|
|
15
|
+
'''
|
|
16
|
+
A declared sentence rule, owned by exactly one grammar.
|
|
17
|
+
|
|
18
|
+
A repeated name is a legal alternative, not a duplicate declaration.
|
|
19
|
+
Specification and action source belong to the Simple and Complex variants.
|
|
20
|
+
'''
|
|
21
|
+
|
|
22
|
+
# * attribute: name
|
|
23
|
+
name: str = Field(
|
|
24
|
+
...,
|
|
25
|
+
description='The declared production name.',
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
# * attribute: grammar_id
|
|
29
|
+
grammar_id: str = Field(
|
|
30
|
+
...,
|
|
31
|
+
description='The identifier of the one grammar that owns the production.',
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
# ** model: simple_production_rule
|
|
35
|
+
class SimpleProductionRule(ProductionRule):
|
|
36
|
+
'''
|
|
37
|
+
A production whose declaration is a grammar specification only.
|
|
38
|
+
|
|
39
|
+
Simple productions store no action source and do not themselves
|
|
40
|
+
implement a translation-time pass-through.
|
|
41
|
+
'''
|
|
42
|
+
|
|
43
|
+
# * attribute: spec
|
|
44
|
+
spec: str = Field(
|
|
45
|
+
...,
|
|
46
|
+
description='The declared grammar specification for the production.',
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# ** model: complex_production_rule
|
|
50
|
+
class ComplexProductionRule(ProductionRule):
|
|
51
|
+
'''
|
|
52
|
+
A production that declares both a specification and action source.
|
|
53
|
+
|
|
54
|
+
The action is stored as source text. Compiling or executing it is
|
|
55
|
+
outside the domain model.
|
|
56
|
+
'''
|
|
57
|
+
|
|
58
|
+
# * attribute: spec
|
|
59
|
+
spec: str = Field(
|
|
60
|
+
...,
|
|
61
|
+
description='The declared grammar specification for the production.',
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
# * attribute: action
|
|
65
|
+
action: str = Field(
|
|
66
|
+
...,
|
|
67
|
+
description='The declared action source for the production.',
|
|
68
|
+
)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Tiferet Ly Token Domain Models"""
|
|
2
|
+
|
|
3
|
+
# *** imports
|
|
4
|
+
|
|
5
|
+
# ** infra
|
|
6
|
+
from pydantic import Field
|
|
7
|
+
|
|
8
|
+
# ** app
|
|
9
|
+
from tiferet.domain.core import DomainObject
|
|
10
|
+
|
|
11
|
+
# *** models
|
|
12
|
+
|
|
13
|
+
# ** model: token_rule
|
|
14
|
+
class TokenRule(DomainObject):
|
|
15
|
+
'''
|
|
16
|
+
A declared word in a language, owned by exactly one grammar.
|
|
17
|
+
|
|
18
|
+
The rule stores its name and grammar membership only. Pattern and
|
|
19
|
+
action source belong to the Simple and Complex variants.
|
|
20
|
+
'''
|
|
21
|
+
|
|
22
|
+
# * attribute: name
|
|
23
|
+
name: str = Field(
|
|
24
|
+
...,
|
|
25
|
+
description='The bare declared token name.',
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
# * attribute: grammar_id
|
|
29
|
+
grammar_id: str = Field(
|
|
30
|
+
...,
|
|
31
|
+
description='The identifier of the one grammar that owns the rule.',
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
# ** model: simple_token_rule
|
|
35
|
+
class SimpleTokenRule(TokenRule):
|
|
36
|
+
'''
|
|
37
|
+
A token rule whose declaration is a pattern and nothing else.
|
|
38
|
+
|
|
39
|
+
Simple rules carry no action source. Matching behavior is the
|
|
40
|
+
pattern itself.
|
|
41
|
+
'''
|
|
42
|
+
|
|
43
|
+
# * attribute: pattern
|
|
44
|
+
pattern: str = Field(
|
|
45
|
+
...,
|
|
46
|
+
description='The declared match pattern for the token.',
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# ** model: complex_token_rule
|
|
50
|
+
class ComplexTokenRule(TokenRule):
|
|
51
|
+
'''
|
|
52
|
+
A token rule that declares both a pattern and action source.
|
|
53
|
+
|
|
54
|
+
The action is stored as source text. Compiling or executing it is
|
|
55
|
+
outside the domain model.
|
|
56
|
+
'''
|
|
57
|
+
|
|
58
|
+
# * attribute: pattern
|
|
59
|
+
pattern: str = Field(
|
|
60
|
+
...,
|
|
61
|
+
description='The declared match pattern for the token.',
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
# * attribute: action
|
|
65
|
+
action: str = Field(
|
|
66
|
+
...,
|
|
67
|
+
description='The declared action source for the token.',
|
|
68
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Tiferet Ly Events"""
|