borschscript 0.1.1__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.
@@ -0,0 +1,28 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2026, Oleksandr Volkohon
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,87 @@
1
+ Metadata-Version: 2.4
2
+ Name: borschscript
3
+ Version: 0.1.1
4
+ Summary: An esoteric XMLlike joke programming language in Ukrainian.
5
+ Requires-Python: >=3.8
6
+ Description-Content-Type: text/markdown
7
+ License-File: LICENSE
8
+ Dynamic: license-file
9
+
10
+ <p align="center">
11
+ <img src="img/icon.png" alt="BorschScript Logo" width="150" /><br />
12
+ <sub
13
+ ><a
14
+ href="https://www.flaticon.com/free-icons/russian-food"
15
+ title="russian food icons"
16
+ >Russian food icons created by Muhammad_Usman - Flaticon</a
17
+ ></sub
18
+ >
19
+ </p>
20
+ <h1 align="center">BorschScript</h1>
21
+
22
+ <p align="center">
23
+ <b>BorschScript</b>, an esoteric, XML-like programming language written in Ukrainian.
24
+ </p>
25
+
26
+ ---
27
+
28
+ ## Installation
29
+
30
+ ### From Source
31
+ Clone the repository and install it locally using `pip`:
32
+
33
+ ```bash
34
+ git clone [https://github.com/your-username/borshscript.git](https://github.com/your-username/borshscript.git)
35
+ cd borshscript
36
+ pip install -e .
37
+ ```
38
+
39
+ ## Quick Start
40
+
41
+ Create a script file named `recipe.brsh`:
42
+
43
+ ```xml
44
+ <змінна назва="порції">3</змінна>
45
+
46
+ <функція назва="зварити_борщ" аргументи="кількість">
47
+ <друк>f"Варимо борщ на {кількість} порції!"</друк>
48
+ </функція>
49
+
50
+ <якщо умова="порції >= 3">
51
+ <викликати назва="зварити_борщ" аргументи="порції" />
52
+ </якщо>
53
+ <інакше>
54
+ <друк>"Занадто мало інгредієнтів..."</друк>
55
+ </інакше>
56
+ ```
57
+
58
+ Run your script from the terminal:
59
+
60
+ ```bash
61
+ borsch recipe.brsh
62
+ ```
63
+
64
+ ### Debug Mode
65
+
66
+ To inspect the transpiled Python code before execution, pass the --debug flag:
67
+
68
+ ```bash
69
+ borsch recipe.brsh --debug
70
+ ```
71
+
72
+ ## Language Syntax Overview
73
+
74
+ |BorschScript|Description|Python Equivalent|
75
+ |-|-|-|
76
+ |`<змінна назва="X">значення</змінна>`|Declare variable|`X = значення`|
77
+ |`<друк>значення</друк>`|Print output|`print(значення)`|
78
+ |`<якщо умова="X">`|Conditional statement|if X:|
79
+ |`<інакше>`|Else block|`else:`|
80
+ |`<поки умова="X">`|While loop|`while X:`|
81
+ |`<функція назва="X" аргументи="A, B">`|Define function|`def X(A,B)`|
82
+ |`<повернути>значення</повернути>`|Return statement|`return значення`|
83
+ |`<викликати назва="X" аргументи="A" />`|Call function|`X(A)`|
84
+
85
+ ## License
86
+
87
+ Distributed under **BSD-3** License. See [LICENSE](LICENSE) for more info.
@@ -0,0 +1,78 @@
1
+ <p align="center">
2
+ <img src="img/icon.png" alt="BorschScript Logo" width="150" /><br />
3
+ <sub
4
+ ><a
5
+ href="https://www.flaticon.com/free-icons/russian-food"
6
+ title="russian food icons"
7
+ >Russian food icons created by Muhammad_Usman - Flaticon</a
8
+ ></sub
9
+ >
10
+ </p>
11
+ <h1 align="center">BorschScript</h1>
12
+
13
+ <p align="center">
14
+ <b>BorschScript</b>, an esoteric, XML-like programming language written in Ukrainian.
15
+ </p>
16
+
17
+ ---
18
+
19
+ ## Installation
20
+
21
+ ### From Source
22
+ Clone the repository and install it locally using `pip`:
23
+
24
+ ```bash
25
+ git clone [https://github.com/your-username/borshscript.git](https://github.com/your-username/borshscript.git)
26
+ cd borshscript
27
+ pip install -e .
28
+ ```
29
+
30
+ ## Quick Start
31
+
32
+ Create a script file named `recipe.brsh`:
33
+
34
+ ```xml
35
+ <змінна назва="порції">3</змінна>
36
+
37
+ <функція назва="зварити_борщ" аргументи="кількість">
38
+ <друк>f"Варимо борщ на {кількість} порції!"</друк>
39
+ </функція>
40
+
41
+ <якщо умова="порції >= 3">
42
+ <викликати назва="зварити_борщ" аргументи="порції" />
43
+ </якщо>
44
+ <інакше>
45
+ <друк>"Занадто мало інгредієнтів..."</друк>
46
+ </інакше>
47
+ ```
48
+
49
+ Run your script from the terminal:
50
+
51
+ ```bash
52
+ borsch recipe.brsh
53
+ ```
54
+
55
+ ### Debug Mode
56
+
57
+ To inspect the transpiled Python code before execution, pass the --debug flag:
58
+
59
+ ```bash
60
+ borsch recipe.brsh --debug
61
+ ```
62
+
63
+ ## Language Syntax Overview
64
+
65
+ |BorschScript|Description|Python Equivalent|
66
+ |-|-|-|
67
+ |`<змінна назва="X">значення</змінна>`|Declare variable|`X = значення`|
68
+ |`<друк>значення</друк>`|Print output|`print(значення)`|
69
+ |`<якщо умова="X">`|Conditional statement|if X:|
70
+ |`<інакше>`|Else block|`else:`|
71
+ |`<поки умова="X">`|While loop|`while X:`|
72
+ |`<функція назва="X" аргументи="A, B">`|Define function|`def X(A,B)`|
73
+ |`<повернути>значення</повернути>`|Return statement|`return значення`|
74
+ |`<викликати назва="X" аргументи="A" />`|Call function|`X(A)`|
75
+
76
+ ## License
77
+
78
+ Distributed under **BSD-3** License. See [LICENSE](LICENSE) for more info.
File without changes
@@ -0,0 +1,15 @@
1
+ import sys
2
+ from borsch.runner import run_file
3
+
4
+ def main():
5
+ if len(sys.argv) < 2:
6
+ print("Використання: borsch <файл.brsh> [--debug]")
7
+ sys.exit(1)
8
+
9
+ filename = sys.argv[1]
10
+ debug_mode = "--debug" in sys.argv
11
+
12
+ run_file(filename, show_generated_python=debug_mode)
13
+
14
+ if __name__ == "__main__":
15
+ main()
@@ -0,0 +1,11 @@
1
+ class BorschSyntaxError(Exception):
2
+ """Raised when the .brsh markup is malformed."""
3
+ pass
4
+
5
+ class BorschRuntimeError(Exception):
6
+ """Raised when the code fails during execution."""
7
+ pass
8
+
9
+ def print_borsch_error(error_type, message):
10
+ print(f"\nBORSCH ERROR: {error_type}")
11
+ print(f"> {message}\n")
@@ -0,0 +1,138 @@
1
+ import re
2
+ from .errors import BorschSyntaxError
3
+
4
+ class Token:
5
+ def __init__(self, kind, value, line):
6
+ self.kind = kind # 'OPEN_TAG', 'CLOSE_TAG', 'SELF_CLOSE_TAG'
7
+ self.value = value # Tag name (e.g. 'змінна', 'якщо')
8
+ self.line = line
9
+ self.attrs = {} # Dictionary of attributes
10
+ self.content = "" # Inner text content
11
+
12
+ class BorschTranspiler:
13
+ def __init__(self):
14
+ # Map BorschScript tags to Python code generation rules
15
+ self.tag_handlers = {
16
+ "змінна": self._handle_variable,
17
+ "друк": self._handle_print,
18
+ "якщо": self._handle_if,
19
+ "інакше": self._handle_else,
20
+ "поки": self._handle_while,
21
+ "функція": self._handle_function,
22
+ "повернути": self._handle_return,
23
+ "викликати": self._handle_call
24
+ }
25
+
26
+ def transpile(self, brsh_code: str) -> str:
27
+ tokens = self._tokenize(brsh_code)
28
+ python_code = self._generate_python(tokens)
29
+ return python_code
30
+
31
+ def _tokenize(self, code: str):
32
+ tokens = []
33
+ # Matches tags like: <tag attr="val">Content</tag> OR <tag attr="val" />
34
+ tag_pattern = re.compile(
35
+ r'<\s*(?P<close>/)?\s*(?P<tag>[\w\'-]+)(?P<attrs>[^/>]*)(?P<self_close>/)?\s*>'
36
+ )
37
+
38
+ pos = 0
39
+ line_num = 1
40
+
41
+ for match in tag_pattern.finditer(code):
42
+ start, end = match.span()
43
+ line_num += code[pos:start].count('\n')
44
+
45
+ is_close = bool(match.group('close'))
46
+ is_self_close = bool(match.group('self_close'))
47
+ tag_name = match.group('tag').lower()
48
+ raw_attrs = match.group('attrs')
49
+
50
+ # Parse attributes (handles both "val" and 'val', plus ім'я/назва)
51
+ attrs = {}
52
+ attr_pattern = re.compile(r'([\w\'-]+)\s*=\s*(?:"([^"]*)"|\'([^\']*)\')')
53
+ for attr_match in attr_pattern.finditer(raw_attrs):
54
+ key = attr_match.group(1).replace("ім'я", "назва").replace("імʼя", "назва")
55
+ val = attr_match.group(2) if attr_match.group(2) is not None else attr_match.group(3)
56
+ attrs[key] = val
57
+
58
+ token = Token(
59
+ kind='CLOSE' if is_close else ('SELF_CLOSE' if is_self_close else 'OPEN'),
60
+ value=tag_name,
61
+ line=line_num
62
+ )
63
+ token.attrs = attrs
64
+
65
+ # Capture text content between the previous position and this tag
66
+ if not is_close:
67
+ pos_next = match.end()
68
+ # Find matching closing tag or next tag to extract text content
69
+ next_tag = tag_pattern.search(code, pos_next)
70
+ if next_tag:
71
+ raw_content = code[pos_next:next_tag.start()]
72
+ token.content = raw_content.strip()
73
+
74
+ tokens.append(token)
75
+ pos = end
76
+
77
+ return tokens
78
+
79
+ def _generate_python(self, tokens) -> str:
80
+ python_lines = []
81
+ indent_level = 0
82
+
83
+ for token in tokens:
84
+ prefix = " " * indent_level
85
+
86
+ if token.kind == 'CLOSE':
87
+ # Dedent when closing a block tag
88
+ if token.value in ["якщо", "інакше", "поки", "функція"]:
89
+ indent_level = max(0, indent_level - 1)
90
+ continue
91
+
92
+ if token.value not in self.tag_handlers:
93
+ raise BorschSyntaxError(f"Рядок {token.line}: Невідомий тег <{token.value}>")
94
+
95
+ handler = self.tag_handlers[token.value]
96
+ line_code, increases_indent = handler(token, prefix)
97
+
98
+ python_lines.append(line_code)
99
+ if increases_indent:
100
+ indent_level += 1
101
+
102
+ return "\n".join(python_lines) + "\n"
103
+
104
+ # --- TAG HANDLERS ---
105
+
106
+ def _handle_variable(self, token, prefix):
107
+ name = token.attrs.get("назва") or token.attrs.get("назва")
108
+ val = token.content if token.content else "None"
109
+ return f"{prefix}{name} = {val}", False
110
+
111
+ def _handle_print(self, token, prefix):
112
+ return f"{prefix}print({token.content})", False
113
+
114
+ def _handle_if(self, token, prefix):
115
+ cond = token.attrs.get("умова", "True")
116
+ return f"{prefix}if {cond}:", True
117
+
118
+ def _handle_else(self, token, prefix):
119
+ # Dedicated handler for <інакше>
120
+ return f"{prefix}else:", True
121
+
122
+ def _handle_while(self, token, prefix):
123
+ cond = token.attrs.get("умова", "True")
124
+ return f"{prefix}while {cond}:", True
125
+
126
+ def _handle_function(self, token, prefix):
127
+ name = token.attrs.get("назва")
128
+ args = token.attrs.get("аргументи", "")
129
+ return f"{prefix}def {name}({args}):", True
130
+
131
+ def _handle_return(self, token, prefix):
132
+ val = token.content if token.content else "None"
133
+ return f"{prefix}return {val}", False
134
+
135
+ def _handle_call(self, token, prefix):
136
+ name = token.attrs.get("назва")
137
+ args = token.attrs.get("аргументи", "")
138
+ return f"{prefix}{name}({args})", False
@@ -0,0 +1,27 @@
1
+ from .parser import BorschTranspiler
2
+ from .errors import BorschSyntaxError, print_borsch_error
3
+
4
+ def run_file(file_path: str, show_generated_python: bool = False):
5
+ if not file_path.endswith(".brsh"):
6
+ print_borsch_error("Файл", "BorschScript файли повинні мати розширення .brsh!")
7
+ return
8
+
9
+ try:
10
+ with open(file_path, "r", encoding="utf-8") as f:
11
+ code = f.read()
12
+
13
+ transpiler = BorschTranspiler()
14
+ py_code = transpiler.transpile(code)
15
+
16
+ if show_generated_python:
17
+ print("--- Transpiled Python Code ---")
18
+ print(py_code)
19
+ print("------------------------------")
20
+
21
+ exec_globals = {"__name__": "__main__"}
22
+ exec(py_code, exec_globals)
23
+
24
+ except BorschSyntaxError as e:
25
+ print_borsch_error("Помилка Синтаксису", str(e))
26
+ except Exception as e:
27
+ print_borsch_error("Помилка Виконання", str(e))
@@ -0,0 +1,87 @@
1
+ Metadata-Version: 2.4
2
+ Name: borschscript
3
+ Version: 0.1.1
4
+ Summary: An esoteric XMLlike joke programming language in Ukrainian.
5
+ Requires-Python: >=3.8
6
+ Description-Content-Type: text/markdown
7
+ License-File: LICENSE
8
+ Dynamic: license-file
9
+
10
+ <p align="center">
11
+ <img src="img/icon.png" alt="BorschScript Logo" width="150" /><br />
12
+ <sub
13
+ ><a
14
+ href="https://www.flaticon.com/free-icons/russian-food"
15
+ title="russian food icons"
16
+ >Russian food icons created by Muhammad_Usman - Flaticon</a
17
+ ></sub
18
+ >
19
+ </p>
20
+ <h1 align="center">BorschScript</h1>
21
+
22
+ <p align="center">
23
+ <b>BorschScript</b>, an esoteric, XML-like programming language written in Ukrainian.
24
+ </p>
25
+
26
+ ---
27
+
28
+ ## Installation
29
+
30
+ ### From Source
31
+ Clone the repository and install it locally using `pip`:
32
+
33
+ ```bash
34
+ git clone [https://github.com/your-username/borshscript.git](https://github.com/your-username/borshscript.git)
35
+ cd borshscript
36
+ pip install -e .
37
+ ```
38
+
39
+ ## Quick Start
40
+
41
+ Create a script file named `recipe.brsh`:
42
+
43
+ ```xml
44
+ <змінна назва="порції">3</змінна>
45
+
46
+ <функція назва="зварити_борщ" аргументи="кількість">
47
+ <друк>f"Варимо борщ на {кількість} порції!"</друк>
48
+ </функція>
49
+
50
+ <якщо умова="порції >= 3">
51
+ <викликати назва="зварити_борщ" аргументи="порції" />
52
+ </якщо>
53
+ <інакше>
54
+ <друк>"Занадто мало інгредієнтів..."</друк>
55
+ </інакше>
56
+ ```
57
+
58
+ Run your script from the terminal:
59
+
60
+ ```bash
61
+ borsch recipe.brsh
62
+ ```
63
+
64
+ ### Debug Mode
65
+
66
+ To inspect the transpiled Python code before execution, pass the --debug flag:
67
+
68
+ ```bash
69
+ borsch recipe.brsh --debug
70
+ ```
71
+
72
+ ## Language Syntax Overview
73
+
74
+ |BorschScript|Description|Python Equivalent|
75
+ |-|-|-|
76
+ |`<змінна назва="X">значення</змінна>`|Declare variable|`X = значення`|
77
+ |`<друк>значення</друк>`|Print output|`print(значення)`|
78
+ |`<якщо умова="X">`|Conditional statement|if X:|
79
+ |`<інакше>`|Else block|`else:`|
80
+ |`<поки умова="X">`|While loop|`while X:`|
81
+ |`<функція назва="X" аргументи="A, B">`|Define function|`def X(A,B)`|
82
+ |`<повернути>значення</повернути>`|Return statement|`return значення`|
83
+ |`<викликати назва="X" аргументи="A" />`|Call function|`X(A)`|
84
+
85
+ ## License
86
+
87
+ Distributed under **BSD-3** License. See [LICENSE](LICENSE) for more info.
@@ -0,0 +1,14 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ setup.py
5
+ borsch/__init__.py
6
+ borsch/cli.py
7
+ borsch/errors.py
8
+ borsch/parser.py
9
+ borsch/runner.py
10
+ borschscript.egg-info/PKG-INFO
11
+ borschscript.egg-info/SOURCES.txt
12
+ borschscript.egg-info/dependency_links.txt
13
+ borschscript.egg-info/entry_points.txt
14
+ borschscript.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ borsch = borsch.cli:main
@@ -0,0 +1,17 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "borschscript"
7
+ version = "0.1.1"
8
+ description = "An esoteric XMLlike joke programming language in Ukrainian."
9
+ readme = "README.md"
10
+ requires-python = ">=3.8"
11
+
12
+ [project.scripts]
13
+ borsch = "borsch.cli:main"
14
+
15
+ [tool.setuptools.packages.find]
16
+ where = ["."]
17
+ include = ["borsch*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,12 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ setup(
4
+ name="borschscript",
5
+ version="0.1.0",
6
+ packages=find_packages(),
7
+ entry_points={
8
+ "console_scripts": [
9
+ "borsch=borsch.cli:main", # Creates the 'borsch' CLI command
10
+ ],
11
+ },
12
+ )