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.
Files changed (24) hide show
  1. {turing_py-2.0.0 → turing_py-2.2.0}/PKG-INFO +1 -1
  2. {turing_py-2.0.0 → turing_py-2.2.0}/pyproject.toml +1 -1
  3. {turing_py-2.0.0 → turing_py-2.2.0}/src/tmpy/__init__.py +16 -0
  4. turing_py-2.2.0/src/tmpy/dsl/__init__.py +15 -0
  5. turing_py-2.2.0/src/tmpy/dsl/ast.py +28 -0
  6. turing_py-2.2.0/src/tmpy/dsl/lexer.py +56 -0
  7. turing_py-2.2.0/src/tmpy/dsl/loader.py +55 -0
  8. turing_py-2.2.0/src/tmpy/dsl/parser.py +103 -0
  9. turing_py-2.2.0/src/tmpy/dsl/token.py +34 -0
  10. {turing_py-2.0.0 → turing_py-2.2.0}/src/tmpy/machine/machine.py +1 -0
  11. {turing_py-2.0.0 → turing_py-2.2.0}/src/tmpy/transition/transition_function.py +10 -12
  12. {turing_py-2.0.0 → turing_py-2.2.0}/LICENSE +0 -0
  13. {turing_py-2.0.0 → turing_py-2.2.0}/README.md +0 -0
  14. {turing_py-2.0.0 → turing_py-2.2.0}/src/tmpy/alphabet/__init__.py +0 -0
  15. {turing_py-2.0.0 → turing_py-2.2.0}/src/tmpy/alphabet/input_alphabet.py +0 -0
  16. {turing_py-2.0.0 → turing_py-2.2.0}/src/tmpy/alphabet/symbol.py +0 -0
  17. {turing_py-2.0.0 → turing_py-2.2.0}/src/tmpy/alphabet/tape_alphabet.py +0 -0
  18. {turing_py-2.0.0 → turing_py-2.2.0}/src/tmpy/exception.py +0 -0
  19. {turing_py-2.0.0 → turing_py-2.2.0}/src/tmpy/machine/__init__.py +0 -0
  20. {turing_py-2.0.0 → turing_py-2.2.0}/src/tmpy/machine/states.py +0 -0
  21. {turing_py-2.0.0 → turing_py-2.2.0}/src/tmpy/machine/tape.py +0 -0
  22. {turing_py-2.0.0 → turing_py-2.2.0}/src/tmpy/transition/__init__.py +0 -0
  23. {turing_py-2.0.0 → turing_py-2.2.0}/src/tmpy/transition/direction.py +0 -0
  24. {turing_py-2.0.0 → turing_py-2.2.0}/src/tmpy/transition/transition.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: turing-py
3
- Version: 2.0.0
3
+ Version: 2.2.0
4
4
  Summary: Education Turing Machine simulator in Python
5
5
  License-File: LICENSE
6
6
  Author: Eric Santos
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "turing-py"
3
- version = "2.0.0"
3
+ version = "2.2.0"
4
4
  description = "Education Turing Machine simulator in Python"
5
5
  authors = [
6
6
  {name = "Eric Santos",email = "ericshantos13@gmail.com"}
@@ -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})"
@@ -1,3 +1,4 @@
1
+ # -*- coding: utf-8 -*-
1
2
  """
2
3
  @author: Eric Santos <ericshantos13@gmail.com>
3
4
 
@@ -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
- def add(self, *transitions: Transition) -> None:
18
+ self._tr: dict[tuple[str, Symbol], Transition] = {}
20
19
 
21
- for t in transitions:
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._transitions[(tr.state, tr.symbol)] = tr
24
+ self._tr[(tr.state, tr.symbol)] = tr
26
25
  else:
27
- self._transitions[(t.state, t.symbol)] = t
26
+ self._tr[(t.state, t.symbol)] = t
28
27
 
29
28
  def __call__(self, state: str, symbol: Symbol) -> Transition | None:
30
- return self._transitions.get((state, symbol))
29
+ return self._tr.get((state, symbol))
31
30
 
32
- def __str__(self) -> str:
33
- return "\n".join(str(t) for t in self._transitions.values())
31
+ def __contains__(self, item) -> bool:
32
+ return item in self._tr
34
33
 
35
- @property
36
- def conjugates(self) -> dict[tuple[str, Symbol], Transition]:
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