turing-py 2.0.0__tar.gz → 2.2.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.
- {turing_py-2.0.0 → turing_py-2.2.0}/PKG-INFO +1 -1
- {turing_py-2.0.0 → turing_py-2.2.0}/pyproject.toml +1 -1
- {turing_py-2.0.0 → turing_py-2.2.0}/src/tmpy/__init__.py +16 -0
- turing_py-2.2.0/src/tmpy/dsl/__init__.py +15 -0
- turing_py-2.2.0/src/tmpy/dsl/ast.py +28 -0
- turing_py-2.2.0/src/tmpy/dsl/lexer.py +56 -0
- turing_py-2.2.0/src/tmpy/dsl/loader.py +55 -0
- turing_py-2.2.0/src/tmpy/dsl/parser.py +103 -0
- turing_py-2.2.0/src/tmpy/dsl/token.py +34 -0
- {turing_py-2.0.0 → turing_py-2.2.0}/src/tmpy/machine/machine.py +1 -0
- {turing_py-2.0.0 → turing_py-2.2.0}/src/tmpy/transition/transition_function.py +10 -12
- {turing_py-2.0.0 → turing_py-2.2.0}/LICENSE +0 -0
- {turing_py-2.0.0 → turing_py-2.2.0}/README.md +0 -0
- {turing_py-2.0.0 → turing_py-2.2.0}/src/tmpy/alphabet/__init__.py +0 -0
- {turing_py-2.0.0 → turing_py-2.2.0}/src/tmpy/alphabet/input_alphabet.py +0 -0
- {turing_py-2.0.0 → turing_py-2.2.0}/src/tmpy/alphabet/symbol.py +0 -0
- {turing_py-2.0.0 → turing_py-2.2.0}/src/tmpy/alphabet/tape_alphabet.py +0 -0
- {turing_py-2.0.0 → turing_py-2.2.0}/src/tmpy/exception.py +0 -0
- {turing_py-2.0.0 → turing_py-2.2.0}/src/tmpy/machine/__init__.py +0 -0
- {turing_py-2.0.0 → turing_py-2.2.0}/src/tmpy/machine/states.py +0 -0
- {turing_py-2.0.0 → turing_py-2.2.0}/src/tmpy/machine/tape.py +0 -0
- {turing_py-2.0.0 → turing_py-2.2.0}/src/tmpy/transition/__init__.py +0 -0
- {turing_py-2.0.0 → turing_py-2.2.0}/src/tmpy/transition/direction.py +0 -0
- {turing_py-2.0.0 → turing_py-2.2.0}/src/tmpy/transition/transition.py +0 -0
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
from .alphabet import Alphabet, Symbol, TapeAlphabet
|
|
2
|
+
from .dsl import (
|
|
3
|
+
Lexer,
|
|
4
|
+
MachineLoader,
|
|
5
|
+
MachineNode,
|
|
6
|
+
Parser,
|
|
7
|
+
Token,
|
|
8
|
+
TokenType,
|
|
9
|
+
TransitionNode,
|
|
10
|
+
)
|
|
2
11
|
from .exception import (
|
|
3
12
|
AlphabetError,
|
|
4
13
|
BlankSymbolError,
|
|
@@ -28,6 +37,13 @@ __all__ = [
|
|
|
28
37
|
"States",
|
|
29
38
|
"Tape",
|
|
30
39
|
"Direction",
|
|
40
|
+
"MachineNode",
|
|
41
|
+
"TransitionNode",
|
|
42
|
+
"Lexer",
|
|
43
|
+
"MachineLoader",
|
|
44
|
+
"Parser",
|
|
45
|
+
"Token",
|
|
46
|
+
"TokenType",
|
|
31
47
|
"BlankSymbolError",
|
|
32
48
|
"TuringMachineError",
|
|
33
49
|
"AlphabetError",
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from .ast import MachineNode, TransitionNode
|
|
2
|
+
from .lexer import Lexer
|
|
3
|
+
from .loader import MachineLoader
|
|
4
|
+
from .parser import Parser
|
|
5
|
+
from .token import Token, TokenType
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"MachineNode",
|
|
9
|
+
"TransitionNode",
|
|
10
|
+
"Lexer",
|
|
11
|
+
"MachineLoader",
|
|
12
|
+
"Parser",
|
|
13
|
+
"Token",
|
|
14
|
+
"TokenType",
|
|
15
|
+
]
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
@author: Eric Santos <ericshantos13@gmai.com>
|
|
4
|
+
|
|
5
|
+
AST node definitions for the Turing machine description language.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Optional
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class MachineNode:
|
|
12
|
+
|
|
13
|
+
def __init__(self, name: str):
|
|
14
|
+
self.name = name
|
|
15
|
+
self.start: Optional[str] = None
|
|
16
|
+
self.accept: Optional[str] = None
|
|
17
|
+
self.blank: Optional[str] = None
|
|
18
|
+
self.transitions: list[TransitionNode] = []
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class TransitionNode:
|
|
22
|
+
|
|
23
|
+
def __init__(self, state, read, next_state, write, move):
|
|
24
|
+
self.state = state
|
|
25
|
+
self.read = read
|
|
26
|
+
self.next_state = next_state
|
|
27
|
+
self.write = write
|
|
28
|
+
self.move = move
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
@author: Eric Santos <ericshantos13@gmail.com>
|
|
4
|
+
|
|
5
|
+
Lexer for the Turing machine description language.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from .token import Token, TokenType
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Lexer:
|
|
12
|
+
|
|
13
|
+
def __init__(self, input_text: str) -> None:
|
|
14
|
+
|
|
15
|
+
self.lines = input_text.splitlines()
|
|
16
|
+
self.current_line: int = 0
|
|
17
|
+
|
|
18
|
+
def tokenize(self) -> list[Token]:
|
|
19
|
+
|
|
20
|
+
tokens = []
|
|
21
|
+
|
|
22
|
+
for line in self.lines:
|
|
23
|
+
|
|
24
|
+
line = line.strip()
|
|
25
|
+
|
|
26
|
+
if not line or line.startswith("#"):
|
|
27
|
+
continue
|
|
28
|
+
|
|
29
|
+
parts = line.split()
|
|
30
|
+
|
|
31
|
+
for part in parts:
|
|
32
|
+
|
|
33
|
+
if part == "machine":
|
|
34
|
+
tokens.append(Token(TokenType.MACHINE, part))
|
|
35
|
+
|
|
36
|
+
elif part == "start":
|
|
37
|
+
tokens.append(Token(TokenType.START, part))
|
|
38
|
+
|
|
39
|
+
elif part == "accept":
|
|
40
|
+
tokens.append(Token(TokenType.ACCEPT, part))
|
|
41
|
+
|
|
42
|
+
elif part == "blank":
|
|
43
|
+
tokens.append(Token(TokenType.BLANK, part))
|
|
44
|
+
|
|
45
|
+
elif part == "->":
|
|
46
|
+
tokens.append(Token(TokenType.ARROW, part))
|
|
47
|
+
|
|
48
|
+
elif part in ("L", "R", "S"):
|
|
49
|
+
tokens.append(Token(TokenType.MOVE, part))
|
|
50
|
+
|
|
51
|
+
else:
|
|
52
|
+
tokens.append(Token(TokenType.IDENTIFIER, part))
|
|
53
|
+
|
|
54
|
+
tokens.append(Token(TokenType.EOF, None))
|
|
55
|
+
|
|
56
|
+
return tokens
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
@author: Eric Santos <ericshantos13@gmail.com>
|
|
4
|
+
|
|
5
|
+
Loader for the Turing machine DSL.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from ..transition import Transition
|
|
9
|
+
from .lexer import Lexer
|
|
10
|
+
from .parser import MachineNode, Parser
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class MachineLoader:
|
|
14
|
+
|
|
15
|
+
def load(self, path: str):
|
|
16
|
+
text = self._read_file(path)
|
|
17
|
+
|
|
18
|
+
tokens = self._lex(text)
|
|
19
|
+
|
|
20
|
+
ast = self._parse(tokens)
|
|
21
|
+
|
|
22
|
+
transitions = self._build_transitions(ast)
|
|
23
|
+
|
|
24
|
+
return transitions
|
|
25
|
+
|
|
26
|
+
def _read_file(self, path: str) -> str:
|
|
27
|
+
|
|
28
|
+
with open(path, "r") as f:
|
|
29
|
+
return f.read()
|
|
30
|
+
|
|
31
|
+
from tmpy.dsl.lexer import Lexer
|
|
32
|
+
|
|
33
|
+
def _lex(self, text: str):
|
|
34
|
+
|
|
35
|
+
lexer = Lexer(text)
|
|
36
|
+
|
|
37
|
+
return lexer.tokenize()
|
|
38
|
+
|
|
39
|
+
def _parse(self, tokens):
|
|
40
|
+
|
|
41
|
+
parser = Parser(tokens)
|
|
42
|
+
|
|
43
|
+
return parser.parse()
|
|
44
|
+
|
|
45
|
+
def _build_transitions(self, machine_ast: MachineNode) -> list[Transition]:
|
|
46
|
+
|
|
47
|
+
transitions = []
|
|
48
|
+
|
|
49
|
+
for node in machine_ast.transitions:
|
|
50
|
+
|
|
51
|
+
t = Transition(node.state, node.read, node.next_state, node.write, node.move)
|
|
52
|
+
|
|
53
|
+
transitions.append(t)
|
|
54
|
+
|
|
55
|
+
return transitions
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
@author: Eric Santos <ericshantos13@gmail.com>
|
|
4
|
+
|
|
5
|
+
Parser for the Turing machine DSL.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from .ast import MachineNode, TransitionNode
|
|
9
|
+
from .token import Token, TokenType
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Parser:
|
|
13
|
+
|
|
14
|
+
def __init__(self, tokens: list[Token]) -> None:
|
|
15
|
+
self.tokens = tokens
|
|
16
|
+
self.pos: int = 0
|
|
17
|
+
|
|
18
|
+
def current(self) -> Token:
|
|
19
|
+
return self.tokens[self.pos]
|
|
20
|
+
|
|
21
|
+
def advance(self) -> None:
|
|
22
|
+
self.pos += 1
|
|
23
|
+
|
|
24
|
+
def parse(self) -> MachineNode:
|
|
25
|
+
|
|
26
|
+
machine: MachineNode | None = None
|
|
27
|
+
|
|
28
|
+
while self.current().type != TokenType.EOF:
|
|
29
|
+
|
|
30
|
+
token = self.current()
|
|
31
|
+
|
|
32
|
+
if token.type == TokenType.MACHINE:
|
|
33
|
+
|
|
34
|
+
self.advance()
|
|
35
|
+
name = self.current().value
|
|
36
|
+
|
|
37
|
+
if name is None:
|
|
38
|
+
raise SyntaxError("Machine name expected")
|
|
39
|
+
|
|
40
|
+
machine = MachineNode(name)
|
|
41
|
+
|
|
42
|
+
self.advance()
|
|
43
|
+
|
|
44
|
+
elif token.type == TokenType.START:
|
|
45
|
+
|
|
46
|
+
if machine is None:
|
|
47
|
+
raise SyntaxError("Machine must be declared first")
|
|
48
|
+
|
|
49
|
+
self.advance()
|
|
50
|
+
machine.start = self.current().value
|
|
51
|
+
self.advance()
|
|
52
|
+
|
|
53
|
+
elif token.type == TokenType.ACCEPT:
|
|
54
|
+
|
|
55
|
+
if machine is None:
|
|
56
|
+
raise SyntaxError("Machine must be declared first")
|
|
57
|
+
|
|
58
|
+
self.advance()
|
|
59
|
+
machine.accept = self.current().value
|
|
60
|
+
self.advance()
|
|
61
|
+
|
|
62
|
+
elif token.type == TokenType.BLANK:
|
|
63
|
+
|
|
64
|
+
if machine is None:
|
|
65
|
+
raise SyntaxError("Machine must be declared first")
|
|
66
|
+
|
|
67
|
+
self.advance()
|
|
68
|
+
machine.blank = self.current().value
|
|
69
|
+
self.advance()
|
|
70
|
+
|
|
71
|
+
else:
|
|
72
|
+
|
|
73
|
+
if machine is None:
|
|
74
|
+
raise SyntaxError("Machine must be declared first")
|
|
75
|
+
|
|
76
|
+
transition = self.parse_transition()
|
|
77
|
+
machine.transitions.append(transition)
|
|
78
|
+
|
|
79
|
+
if machine is None:
|
|
80
|
+
raise SyntaxError("Machine declaration not found")
|
|
81
|
+
|
|
82
|
+
return machine
|
|
83
|
+
|
|
84
|
+
def parse_transition(self) -> TransitionNode:
|
|
85
|
+
|
|
86
|
+
state = self.current().value
|
|
87
|
+
self.advance()
|
|
88
|
+
|
|
89
|
+
read = self.current().value
|
|
90
|
+
self.advance()
|
|
91
|
+
|
|
92
|
+
self.advance()
|
|
93
|
+
|
|
94
|
+
next_state = self.current().value
|
|
95
|
+
self.advance()
|
|
96
|
+
|
|
97
|
+
write = self.current().value
|
|
98
|
+
self.advance()
|
|
99
|
+
|
|
100
|
+
move = self.current().value
|
|
101
|
+
self.advance()
|
|
102
|
+
|
|
103
|
+
return TransitionNode(state, read, next_state, write, move)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
@author: Eric dos Santos <ericshantos13@gmail.com>
|
|
4
|
+
|
|
5
|
+
Token definitions for the Turing machine parser.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from enum import Enum
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TokenType(Enum):
|
|
12
|
+
MACHINE = "MACHINE"
|
|
13
|
+
START = "START"
|
|
14
|
+
ACCEPT = "ACCEPT"
|
|
15
|
+
BLANK = "BLANK"
|
|
16
|
+
|
|
17
|
+
ARROW = "ARROW"
|
|
18
|
+
|
|
19
|
+
IDENTIFIER = "IDENTIFIER"
|
|
20
|
+
MOVE = "MOVE"
|
|
21
|
+
|
|
22
|
+
EOF = "EOF"
|
|
23
|
+
|
|
24
|
+
def __repr__(self):
|
|
25
|
+
return self.name
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class Token:
|
|
29
|
+
def __init__(self, type_: TokenType, value: str | None) -> None:
|
|
30
|
+
self.type = type_
|
|
31
|
+
self.value = value
|
|
32
|
+
|
|
33
|
+
def __repr__(self) -> str:
|
|
34
|
+
return f"Token({self.type.name}, {self.value})"
|
|
@@ -13,25 +13,23 @@ from .transition import Transition
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
class TransitionFunction:
|
|
16
|
-
def __init__(self) -> None:
|
|
17
|
-
self._transitions: dict[tuple[str, Symbol], Transition] = {}
|
|
16
|
+
def __init__(self, *args: Transition) -> None:
|
|
18
17
|
|
|
19
|
-
|
|
18
|
+
self._tr: dict[tuple[str, Symbol], Transition] = {}
|
|
20
19
|
|
|
21
|
-
for t in
|
|
20
|
+
for t in args:
|
|
22
21
|
|
|
23
22
|
if isinstance(t, Iterable) and not isinstance(t, Transition):
|
|
24
23
|
for tr in t:
|
|
25
|
-
self.
|
|
24
|
+
self._tr[(tr.state, tr.symbol)] = tr
|
|
26
25
|
else:
|
|
27
|
-
self.
|
|
26
|
+
self._tr[(t.state, t.symbol)] = t
|
|
28
27
|
|
|
29
28
|
def __call__(self, state: str, symbol: Symbol) -> Transition | None:
|
|
30
|
-
return self.
|
|
29
|
+
return self._tr.get((state, symbol))
|
|
31
30
|
|
|
32
|
-
def
|
|
33
|
-
return
|
|
31
|
+
def __contains__(self, item) -> bool:
|
|
32
|
+
return item in self._tr
|
|
34
33
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
return self._transitions
|
|
34
|
+
def __str__(self) -> str:
|
|
35
|
+
return "\n".join(str(t) for t in self._tr.values())
|
|
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
|