diff options
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | pdm.lock | 12 | ||||
| -rw-r--r-- | pyproject.toml | 1 | ||||
| -rw-r--r-- | src/psi/__init__.py | 45 | ||||
| -rw-r--r-- | src/psi/execution.py | 35 | ||||
| -rw-r--r-- | src/psi/interpreter.py | 49 | ||||
| -rw-r--r-- | src/psi/lexer.py | 96 | ||||
| -rw-r--r-- | src/psi/parsers.py | 79 | ||||
| -rw-r--r-- | test.html | 0 |
9 files changed, 314 insertions, 4 deletions
@@ -17,6 +17,7 @@ LangTrans/ docs/site/ # pdm +.pdm-python .pdm-build/ .venv/ 1.1 @@ -6,7 +6,7 @@ groups = ["default"] cross_platform = true static_urls = false lock_version = "4.3" -content_hash = "sha256:b4a772bba741f312f87ccfb7b833351aa83cbf6b23e9cd1f84463059c9b0447d" +content_hash = "sha256:b629d4cd8e8585cf1128e9dd7f1a585746bc3e94bb588794250bf99dd80d00b3" [[package]] name = "anyio" @@ -140,6 +140,16 @@ files = [ ] [[package]] +name = "docutils" +version = "0.20.1" +requires_python = ">=3.7" +summary = "Docutils -- Python Documentation Utilities" +files = [ + {file = "docutils-0.20.1-py3-none-any.whl", hash = "sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6"}, + {file = "docutils-0.20.1.tar.gz", hash = "sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b"}, +] + +[[package]] name = "essentials" version = "1.1.5" summary = "General purpose classes and functions, reusable in any kind of Python application" diff --git a/pyproject.toml b/pyproject.toml index 97a7768..bc5709d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,6 +12,7 @@ dependencies = [ "mkdocs-git-authors-plugin>=0.7.2", "mkdocs-material-extensions>=1.2", "neoteroi-mkdocs>=1.0.4", + "docutils>=0.20.1", ] requires-python = ">=3.8" readme = "README.md" diff --git a/src/psi/__init__.py b/src/psi/__init__.py index 1c274e2..3652c6d 100644 --- a/src/psi/__init__.py +++ b/src/psi/__init__.py @@ -8,19 +8,64 @@ __all__ = ['psi'] from psi.execution import Execution class Psi: + """ + A class representing a Psi object. + + Args: + input: The input value for the Psi object. + + Returns: + None + + Example: + ```python + obj = Psi("example") + ``` + """ + def __init__(self, input): + """ + Initializes a Psi object. + + Args: + input: The input value for the Psi object. + + Returns: + None + """ self.input = input self.execution = Execution(input) self.result = None def execute(self): + """ + Executes the Psi object. + + Returns: + The result of the execution. + """ self.result = self.execution.execute() return self.result def get_result(self): + """ + Retrieves the result of the Psi object. + + Returns: + The result of the execution. + """ return self.result def set_input(self, input): + """ + Sets the input value for the Psi object. + + Args: + input: The new input value. + + Returns: + None + """ self.input = input self.execution = Execution(input) self.result = None diff --git a/src/psi/execution.py b/src/psi/execution.py index 052f7ab..0abdf2c 100644 --- a/src/psi/execution.py +++ b/src/psi/execution.py @@ -4,14 +4,43 @@ from psi.interpreter import Interpreter __all__ = ['Execution'] class Execution: + """ + A class representing the execution of Psi code. + + Args: + input: The input code to be executed. + + Returns: + None + + Example: + ```python + execution = Execution("print('Hello, World!')") + execution.execute() + ``` + """ + def __init__(self, input): + """ + Initializes an Execution object. + + Args: + input: The input code to be executed. + + Returns: + None + """ self.input = input def execute(self): + """ + Executes the input code. + + Returns: + The result of the execution. + """ parser = Parser(self.input) ast = parser.parse() interpreter = Interpreter(ast) - result = interpreter.interpret() - - return result + return interpreter.interpret() diff --git a/src/psi/interpreter.py b/src/psi/interpreter.py index f98a777..8aa8fad 100644 --- a/src/psi/interpreter.py +++ b/src/psi/interpreter.py @@ -4,13 +4,53 @@ from psi.lexer import Token __all__ = ['Interpreter'] class Interpreter: + """ + A class representing an interpreter for Psi code. + + Args: + ast: The abstract syntax tree (AST) of the code to be interpreted. + + Returns: + None + + Example: + ```python + interpreter = Interpreter(ast) + interpreter.interpret() + ``` + """ + def __init__(self, ast): + """ + Initializes an Interpreter object. + + Args: + ast: The abstract syntax tree (AST) of the code to be interpreted. + + Returns: + None + """ self.ast = ast def interpret(self): + """ + Interprets the code represented by the AST. + + Returns: + The result of the interpretation. + """ return self.interpret_expr(self.ast) def interpret_expr(self, node): + """ + Interprets an expression node in the AST. + + Args: + node: The expression node to be interpreted. + + Returns: + The result of the interpretation. + """ if isinstance(node, Token): return node.value elif isinstance(node, list): @@ -20,6 +60,15 @@ class Interpreter: return result def interpret_condition(self, node): + """ + Interprets a condition node in the AST. + + Args: + node: The condition node to be interpreted. + + Returns: + The result of the interpretation. + """ variable = self.interpret_expr(node[0]) value = self.interpret_expr(node[2]) diff --git a/src/psi/lexer.py b/src/psi/lexer.py index 2fce0eb..d2c6f68 100644 --- a/src/psi/lexer.py +++ b/src/psi/lexer.py @@ -56,22 +56,97 @@ print([t['type'] for t in lexer]) __all__ = ['Token', 'Lexer'] class Token(dict): + """ + A class representing a token in the lexer. + + Args: + type: The type of the token. + value: The value of the token. + position: The position of the token. + + Returns: + None + + Example: + ```python + token = Token("identifier", "x", (1, 5)) + ``` + """ + def __init__(self, type, value, position): + """ + Initializes a Token object. + + Args: + type: The type of the token. + value: The value of the token. + position: The position of the token. + + Returns: + None + """ super().__init__(type=type, value=value, position=position) def __getattr__(self, name): + """ + Retrieves the value of an attribute from the Token object. + + Args: + name: The name of the attribute. + + Returns: + The value of the attribute. + + Raises: + AttributeError: Raised when the attribute does not exist. + """ try: return self[name] except KeyError: raise AttributeError(f"'Token' object has no attribute '{name}'") + class Lexer: + """ + A class representing a lexer for Psi code. + + Args: + input: The input code to be lexed. + + Returns: + None + + Example: + ```python + lexer = Lexer("x = 10") + for token in lexer: + print(token) + ``` + """ def __init__(self, input): + """ + Initializes a Lexer object. + + Args: + input: The input code to be lexed. + + Returns: + None + """ self.input = input self.position = 0 self.tokens = [] def get_next_token(self): + """ + Retrieves the next token from the input code. + + Returns: + The next token. + + Raises: + Exception: Raised when an unknown character is encountered. + """ while self.position < len(self.input): current_char = self.input[self.position] @@ -144,10 +219,31 @@ class Lexer: return token def __iter__(self): + """ + Returns an iterator over the tokens. + + Returns: + An iterator over the tokens. + """ return iter(self.tokens) def __getitem__(self, index): + """ + Retrieves the token at the specified index. + + Args: + index: The index of the token. + + Returns: + The token at the specified index. + """ return self.tokens[index] def __len__(self): + """ + Returns the number of tokens. + + Returns: + The number of tokens. + """ return len(self.tokens)
\ No newline at end of file diff --git a/src/psi/parsers.py b/src/psi/parsers.py index db3e52c..f68f95f 100644 --- a/src/psi/parsers.py +++ b/src/psi/parsers.py @@ -4,15 +4,52 @@ from psi.lexer import Lexer, Token __all__ = ['Parser'] class Parser: + """ + A class representing a parser for Psi code. + + Args: + input: The input code to be parsed. + + Returns: + None + + Example: + ```python + parser = Parser(input) + parser.parse() + ``` + """ + def __init__(self, input): + """ + Initializes a Parser object. + + Args: + input: The input code to be parsed. + + Returns: + None + """ self.lexer = Lexer(input) self.tokens = iter(self.lexer) self.current_token = next(self.tokens) def parse(self): + """ + Parses the input code. + + Returns: + The result of the parsing. + """ return self.parse_expr() def parse_expr(self): + """ + Parses an expression in the input code. + + Returns: + The result of the parsing. + """ token = self.current_token if token.value == '?': self.eat('?') @@ -29,6 +66,12 @@ class Parser: return result def parse_condition(self): + """ + Parses a condition in the input code. + + Returns: + The result of the parsing. + """ variable = self.parse_variable() self.eat('==') value = self.parse_value() @@ -36,11 +79,26 @@ class Parser: return variable == value def parse_variable(self): + """ + Parses a variable in the input code. + + Returns: + The result of the parsing. + """ token = self.current_token self.eat('IDENTIFIER') return token.value def parse_value(self): + """ + Parses a value in the input code. + + Returns: + The result of the parsing. + + Raises: + Exception: Raised when an invalid value is encountered. + """ token = self.current_token if token.type == 'INTEGER': self.eat('INTEGER') @@ -49,6 +107,15 @@ class Parser: raise Exception(f'Invalid value: {token.value}') def parse_reply(self): + """ + Parses a reply in the input code. + + Returns: + The result of the parsing. + + Raises: + Exception: Raised when an invalid reply is encountered. + """ self.eat('reply') self.eat(':') @@ -59,6 +126,18 @@ class Parser: return token.value def eat(self, expected_type): + """ + Consumes the current token if it matches the expected type. + + Args: + expected_type: The expected type of the token. + + Returns: + None + + Raises: + Exception: Raised when an unexpected token is encountered. + """ if self.current_token.type == expected_type: self.current_token = next(self.tokens) else: diff --git a/test.html b/test.html new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/test.html |
