bracket-lang 0.2.0__tar.gz → 0.4.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.
- bracket_lang-0.4.0/MANIFEST.in +2 -0
- bracket_lang-0.4.0/PKG-INFO +156 -0
- {bracket_lang-0.2.0 → bracket_lang-0.4.0}/README.md +10 -3
- bracket_lang-0.4.0/TKGUI_helloworld.jpg +0 -0
- {bracket_lang-0.2.0 → bracket_lang-0.4.0}/bracket/BRANCH.py +13 -3
- {bracket_lang-0.2.0 → bracket_lang-0.4.0}/bracket/CLASS.py +19 -5
- {bracket_lang-0.2.0 → bracket_lang-0.4.0}/bracket/ERROR.py +7 -1
- {bracket_lang-0.2.0 → bracket_lang-0.4.0}/bracket/FUN.py +22 -6
- bracket_lang-0.4.0/bracket/GUI.py +16 -0
- {bracket_lang-0.2.0 → bracket_lang-0.4.0}/bracket/IMPORTLIB.py +2 -2
- {bracket_lang-0.2.0 → bracket_lang-0.4.0}/bracket/IO.py +22 -7
- {bracket_lang-0.2.0 → bracket_lang-0.4.0}/bracket/LOOP.py +22 -6
- {bracket_lang-0.2.0 → bracket_lang-0.4.0}/bracket/VAR.py +23 -7
- {bracket_lang-0.2.0 → bracket_lang-0.4.0}/bracket/WARN.py +7 -1
- {bracket_lang-0.2.0 → bracket_lang-0.4.0}/bracket/__init__.py +1 -0
- {bracket_lang-0.2.0 → bracket_lang-0.4.0}/bracket/cli.py +13 -3
- bracket_lang-0.4.0/bracket_lang.egg-info/PKG-INFO +156 -0
- {bracket_lang-0.2.0 → bracket_lang-0.4.0}/bracket_lang.egg-info/SOURCES.txt +3 -0
- bracket_lang-0.4.0/bracket_lang.egg-info/requires.txt +2 -0
- bracket_lang-0.4.0/setup.py +25 -0
- bracket_lang-0.2.0/PKG-INFO +0 -9
- bracket_lang-0.2.0/bracket_lang.egg-info/PKG-INFO +0 -9
- bracket_lang-0.2.0/bracket_lang.egg-info/requires.txt +0 -1
- bracket_lang-0.2.0/setup.py +0 -15
- {bracket_lang-0.2.0 → bracket_lang-0.4.0}/LICENSE +0 -0
- {bracket_lang-0.2.0 → bracket_lang-0.4.0}/bracket/bkted.py +0 -0
- {bracket_lang-0.2.0 → bracket_lang-0.4.0}/bracket/transpile.py +0 -0
- {bracket_lang-0.2.0 → bracket_lang-0.4.0}/bracket_lang.egg-info/dependency_links.txt +0 -0
- {bracket_lang-0.2.0 → bracket_lang-0.4.0}/bracket_lang.egg-info/entry_points.txt +0 -0
- {bracket_lang-0.2.0 → bracket_lang-0.4.0}/bracket_lang.egg-info/top_level.txt +0 -0
- {bracket_lang-0.2.0 → bracket_lang-0.4.0}/setup.cfg +0 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bracket-lang
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Requires-Python: >=3.8
|
|
5
|
+
Description-Content-Type: text/markdown
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Requires-Dist: rich>=13.0.0
|
|
8
|
+
Requires-Dist: pyinstaller>=6.0.0
|
|
9
|
+
Dynamic: description
|
|
10
|
+
Dynamic: description-content-type
|
|
11
|
+
Dynamic: license-file
|
|
12
|
+
Dynamic: requires-dist
|
|
13
|
+
Dynamic: requires-python
|
|
14
|
+
|
|
15
|
+
# bracket
|
|
16
|
+
python制作的转译型简单编程语言
|
|
17
|
+
|
|
18
|
+
## 1 安装
|
|
19
|
+
```bash
|
|
20
|
+
pip install bracket-lang
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## 2 Hello world
|
|
24
|
+
```bracket
|
|
25
|
+
[INFO] ["Hello world!"]
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## 3 基本语法
|
|
29
|
+
```bracket
|
|
30
|
+
# main.bracket
|
|
31
|
+
|
|
32
|
+
# 打印
|
|
33
|
+
[INFO] ["这是一段文本"]
|
|
34
|
+
[INFO] ["Loading...", end=" "]
|
|
35
|
+
[INFO] ["complete"]
|
|
36
|
+
|
|
37
|
+
# 变量
|
|
38
|
+
[VAR] [integer] [2]
|
|
39
|
+
[VAR] [floating_point] [3.0]
|
|
40
|
+
[VAR] [string] ["abc"]
|
|
41
|
+
[VAR] [lst] [[1, 2, 3, 4, 5]]
|
|
42
|
+
[VAR] [t] [(1, 2, 3)]
|
|
43
|
+
[VAR] [dict] [{1: 1, 2: 4, 3: 9}]
|
|
44
|
+
[INFO] [integer, floating_point, string, lst, t, dict]
|
|
45
|
+
|
|
46
|
+
# 输入
|
|
47
|
+
[VAR] [short] [INPUT] ["单行文本"] [False]
|
|
48
|
+
[VAR] [long] [INPUT] ["多行文本"] [True]
|
|
49
|
+
[INFO] ["您这两次分别输入了: "]
|
|
50
|
+
[INFO] [short]
|
|
51
|
+
[INFO] [long]
|
|
52
|
+
|
|
53
|
+
# 分支语句
|
|
54
|
+
[VAR] [a] [6]
|
|
55
|
+
[IF] [a>0]
|
|
56
|
+
[INFO] ["正数"]
|
|
57
|
+
[ELSEIF] [a==0]
|
|
58
|
+
[INFO] ["零"]
|
|
59
|
+
[ELSE]
|
|
60
|
+
[INFO] ["负数"]
|
|
61
|
+
|
|
62
|
+
# 循环
|
|
63
|
+
[VAR] [total] [0]
|
|
64
|
+
[FOR] [i] [1, 101, 1]
|
|
65
|
+
[VAR] [total] [total+i]
|
|
66
|
+
[INFO] ["1~100的和:", total]
|
|
67
|
+
[VAR] [i] [0]
|
|
68
|
+
[WHILE] [i<10]
|
|
69
|
+
[INFO] [i]
|
|
70
|
+
[VAR] [i] [i+1]
|
|
71
|
+
[LOOP]
|
|
72
|
+
[INFO] [i]
|
|
73
|
+
[IF] [i==100]
|
|
74
|
+
[BREAK]
|
|
75
|
+
[VAR] [i] [i+1]
|
|
76
|
+
|
|
77
|
+
# 函数
|
|
78
|
+
[FUNC] [longest] [x, y]
|
|
79
|
+
[IF] [len(x)>len(y)]
|
|
80
|
+
[RETURN] [x]
|
|
81
|
+
[RETURN] [y]
|
|
82
|
+
[INFO] [longest("hi", "hello")]
|
|
83
|
+
|
|
84
|
+
# 类
|
|
85
|
+
[CLASS] [Calculator] [object]
|
|
86
|
+
[FUNC] [add] [a, b]
|
|
87
|
+
[RETURN] [a+b]
|
|
88
|
+
[FUNC] [subtract] [a, b]
|
|
89
|
+
[RETURN] [a-b]
|
|
90
|
+
[FUNC] [mul] [a, b]
|
|
91
|
+
[RETURN] [a*b]
|
|
92
|
+
[FUNC] [division] [a, b]
|
|
93
|
+
[IF] [b==0]
|
|
94
|
+
[ERROR] ["Cannot devide by zero."]
|
|
95
|
+
[RETURN] [a/b]
|
|
96
|
+
[FUNC] [percent] [a]
|
|
97
|
+
[RETURN] [a/100]
|
|
98
|
+
[INFO] [Calculator.add(1, 1)]
|
|
99
|
+
|
|
100
|
+
# 警告
|
|
101
|
+
[WARN] ["警告信息"]
|
|
102
|
+
|
|
103
|
+
# GUI
|
|
104
|
+
[USE] [GUI]
|
|
105
|
+
[VAR] [root] [Base()]
|
|
106
|
+
root.title("Hello bracket")
|
|
107
|
+
root.geometry("300x200")
|
|
108
|
+
[VAR] [label] [Tag(root, text="Hello, World!")]
|
|
109
|
+
label.pack()
|
|
110
|
+
root.mainloop()
|
|
111
|
+
```
|
|
112
|
+
输出:
|
|
113
|
+
```text
|
|
114
|
+
这是一段文本
|
|
115
|
+
Loading... complete
|
|
116
|
+
2 3.0 abc [1, 2, 3, 4, 5] (1, 2, 3) {1: 1, 2: 4, 3: 9}
|
|
117
|
+
单行文本: 1
|
|
118
|
+
多行文本: 2
|
|
119
|
+
3
|
|
120
|
+
您这两次分别输入了
|
|
121
|
+
1
|
|
122
|
+
2
|
|
123
|
+
3
|
|
124
|
+
正数
|
|
125
|
+
5050
|
|
126
|
+
1
|
|
127
|
+
2
|
|
128
|
+
3
|
|
129
|
+
...
|
|
130
|
+
100
|
|
131
|
+
hello
|
|
132
|
+
2
|
|
133
|
+
警告信息[yellow]
|
|
134
|
+
```
|
|
135
|
+

|
|
136
|
+
打包:
|
|
137
|
+
```bash
|
|
138
|
+
bracket pack main.bracket
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## 4 命令行工具参数
|
|
142
|
+
| 参数 | 用法 |
|
|
143
|
+
| ------ | ------ |
|
|
144
|
+
| `--help` `-h` | 帮助 |
|
|
145
|
+
| `build` | 转译 |
|
|
146
|
+
| `run` | 转译运行 |
|
|
147
|
+
| `pack` | 打包成二进制 |
|
|
148
|
+
|
|
149
|
+
## 6 注意事项
|
|
150
|
+
1. `INFO`的参数与python的`print`基本相同
|
|
151
|
+
2. `[VAR] [lst] [[1, 2, 3, 4, 5]]`是真正的列表, `[VAR] [t] [1, 2, 3, 4, 5]`是元组
|
|
152
|
+
3. `FOR`必须要写三个参数
|
|
153
|
+
4. `[LOOP]`是无限循环, 与`[WHILE] [True]`等效
|
|
154
|
+
5. 变量名不能与bracket关键字和python关键字重名
|
|
155
|
+
6. bracket语言不兼容python的列表推导式, 三元表达式等
|
|
156
|
+
7. bracket内置轻量编辑器bkted
|
|
@@ -13,6 +13,8 @@ pip install bracket-lang
|
|
|
13
13
|
|
|
14
14
|
## 3 基本语法
|
|
15
15
|
```bracket
|
|
16
|
+
# main.bracket
|
|
17
|
+
|
|
16
18
|
# 打印
|
|
17
19
|
[INFO] ["这是一段文本"]
|
|
18
20
|
[INFO] ["Loading...", end=" "]
|
|
@@ -85,11 +87,11 @@ pip install bracket-lang
|
|
|
85
87
|
[WARN] ["警告信息"]
|
|
86
88
|
|
|
87
89
|
# GUI
|
|
88
|
-
[USE] [
|
|
89
|
-
[VAR] [root] [
|
|
90
|
+
[USE] [GUI]
|
|
91
|
+
[VAR] [root] [Base()]
|
|
90
92
|
root.title("Hello bracket")
|
|
91
93
|
root.geometry("300x200")
|
|
92
|
-
[VAR] [label] [
|
|
94
|
+
[VAR] [label] [Tag(root, text="Hello, World!")]
|
|
93
95
|
label.pack()
|
|
94
96
|
root.mainloop()
|
|
95
97
|
```
|
|
@@ -117,6 +119,10 @@ hello
|
|
|
117
119
|
警告信息[yellow]
|
|
118
120
|
```
|
|
119
121
|

|
|
122
|
+
打包:
|
|
123
|
+
```bash
|
|
124
|
+
bracket pack main.bracket
|
|
125
|
+
```
|
|
120
126
|
|
|
121
127
|
## 4 命令行工具参数
|
|
122
128
|
| 参数 | 用法 |
|
|
@@ -124,6 +130,7 @@ hello
|
|
|
124
130
|
| `--help` `-h` | 帮助 |
|
|
125
131
|
| `build` | 转译 |
|
|
126
132
|
| `run` | 转译运行 |
|
|
133
|
+
| `pack` | 打包成二进制 |
|
|
127
134
|
|
|
128
135
|
## 6 注意事项
|
|
129
136
|
1. `INFO`的参数与python的`print`基本相同
|
|
Binary file
|
|
@@ -2,12 +2,18 @@
|
|
|
2
2
|
# bracket/BRANCH.py
|
|
3
3
|
# manage the branch sentences
|
|
4
4
|
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
import rich
|
|
8
|
+
|
|
5
9
|
# [IF] [<cond>] → if <cond>:
|
|
6
10
|
def IF_to_if(code: str):
|
|
7
11
|
code = code.lstrip()
|
|
8
12
|
keyword, cond = code.split(" ", 1)
|
|
9
13
|
if keyword!="[IF]":
|
|
10
|
-
|
|
14
|
+
rich.print(f"[red]{code}[/red]")
|
|
15
|
+
rich.print(f"error:Expect `[IF]` got {keyword}")
|
|
16
|
+
sys.exit(1)
|
|
11
17
|
text = cond.removeprefix("[").removesuffix("]")
|
|
12
18
|
return f"if {text}:"
|
|
13
19
|
|
|
@@ -16,7 +22,9 @@ def ELSEIF_to_elif(code: str):
|
|
|
16
22
|
code = code.lstrip()
|
|
17
23
|
keyword, cond = code.split(" ", 1)
|
|
18
24
|
if keyword!="[ELSEIF]":
|
|
19
|
-
|
|
25
|
+
rich.print(f"[red]{code}[/red]")
|
|
26
|
+
rich.print(f"error:Expect `[ELSEIF]` got {keyword}")
|
|
27
|
+
sys.exit(1)
|
|
20
28
|
text = cond.removeprefix("[").removesuffix("]")
|
|
21
29
|
return f"elif {text}:"
|
|
22
30
|
|
|
@@ -24,7 +32,9 @@ def ELSEIF_to_elif(code: str):
|
|
|
24
32
|
def ELSE_to_else(code: str):
|
|
25
33
|
code = code.lstrip()
|
|
26
34
|
if code!="[ELSE]":
|
|
27
|
-
|
|
35
|
+
rich.print(f"[red]{code}[/red]")
|
|
36
|
+
rich.print(f"error:Expect `[ELSE]` got {keyword}")
|
|
37
|
+
sys.exit(1)
|
|
28
38
|
return "else:"
|
|
29
39
|
|
|
30
40
|
def transpile_line(line: str):
|
|
@@ -2,27 +2,41 @@
|
|
|
2
2
|
# bracket/CLASS.py
|
|
3
3
|
# manage classes defining
|
|
4
4
|
|
|
5
|
+
import sys
|
|
5
6
|
from keyword import kwlist
|
|
6
7
|
|
|
8
|
+
import rich
|
|
9
|
+
|
|
7
10
|
# [CLASS] [<class name>] [<parent class>] → class <class name>(<parent class>):
|
|
8
11
|
def CLASS_to_class(code: str):
|
|
9
12
|
code = code.lstrip()
|
|
10
13
|
keyword, rest = code.split(" ", 1)
|
|
11
14
|
if keyword!="[CLASS]":
|
|
12
|
-
|
|
15
|
+
rich.print(f"[red]{code}[/red]")
|
|
16
|
+
rich.print(f"[red]Expected `CLASS` got `{keyword}`.[/red]")
|
|
17
|
+
sys.exit(1)
|
|
13
18
|
inner = rest.removeprefix("[").removesuffix("]")
|
|
14
19
|
parts = inner.split("] [")
|
|
15
20
|
if len(parts) != 2:
|
|
16
|
-
|
|
21
|
+
rich.print(f"[red]{code}[/red]")
|
|
22
|
+
rich.print("[red]error:Something wrong in your code")
|
|
23
|
+
rich.print("[red]The usage of `[CLASS]` sentences is `[CLASS] [<class name>] [<parent class>]`[/red]")
|
|
24
|
+
sys.exit(1)
|
|
17
25
|
class_name = parts[0].strip()
|
|
18
26
|
parent_class = parts[1].strip()
|
|
19
27
|
if not class_name:
|
|
20
|
-
|
|
28
|
+
rich.print(f"[red]{code}[/red]")
|
|
29
|
+
rich.print("[red]error:Class name cannot be empty.[/red]")
|
|
30
|
+
sys.exit(1)
|
|
21
31
|
dangerous_list = kwlist+["INFO", "VAR", "INPUT", "IF", "ELSEIF", "ELSE", "FOR", "WHILE", "LOOP", "FUNC", "CLASS", "ERROR", "WARN", "USE"]
|
|
22
32
|
if not class_name.isidentifier():
|
|
23
|
-
|
|
33
|
+
rich.print(f"[red]{code}[/red]")
|
|
34
|
+
rich.print(f"[red]error:Invalid class name: {class_name}.[/red]")
|
|
35
|
+
sys.exit(1)
|
|
24
36
|
if class_name in dangerous_list:
|
|
25
|
-
|
|
37
|
+
rich.print(f"[red]{code}[/red]")
|
|
38
|
+
rich.print(f"[red]error:Invalid class name: {class_name}.[/red]")
|
|
39
|
+
sys.exit(1)
|
|
26
40
|
return f"class {class_name}({parent_class}):"
|
|
27
41
|
|
|
28
42
|
def transpile_line(line: str) -> str:
|
|
@@ -2,12 +2,18 @@
|
|
|
2
2
|
# bracket/ERROR.py
|
|
3
3
|
# manage errors generating
|
|
4
4
|
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
import rich
|
|
8
|
+
|
|
5
9
|
# [ERROR] [<info>] → __import__("rich").print([red]<info>[/red]);__import__("sys").exit(1)
|
|
6
10
|
def ERROR_to_rich_print_and_exit_1(code: str):
|
|
7
11
|
code = code.lstrip()
|
|
8
12
|
keyword, info = code.split(" ", 1)
|
|
9
13
|
if keyword!="[ERROR]":
|
|
10
|
-
|
|
14
|
+
rich.print(f"[red]{code}[/red]")
|
|
15
|
+
rich.print(f"[red]Expected `ERROR` got `{keyword}`.[/red]")
|
|
16
|
+
sys.exit(1)
|
|
11
17
|
info = info.removeprefix("[").removesuffix("]")
|
|
12
18
|
return f"__import__('rich').print('[red]{info[1:-1]}[/red]');__import__('sys').exit(1)"
|
|
13
19
|
|
|
@@ -3,26 +3,40 @@
|
|
|
3
3
|
# mamage function defining
|
|
4
4
|
|
|
5
5
|
from keyword import kwlist
|
|
6
|
+
import sys
|
|
7
|
+
|
|
8
|
+
import rich
|
|
6
9
|
|
|
7
10
|
# [FUNC] [<function name>] [<args>] → def <function name>(<args>):
|
|
8
11
|
def FUNC_to_def(code: str):
|
|
9
12
|
code = code.lstrip()
|
|
10
13
|
keyword, rest = code.split(" ", 1)
|
|
11
14
|
if keyword!="[FUNC]":
|
|
12
|
-
|
|
15
|
+
rich.print(f"[red]{code}[/red]")
|
|
16
|
+
rich.print(f"[red]error:Expected `FUNC` got `{keyword}`.[/red]")
|
|
17
|
+
sys.exit(1)
|
|
13
18
|
inner = rest.removeprefix("[").removesuffix("]")
|
|
14
19
|
parts = inner.split("] [")
|
|
15
20
|
if len(parts) != 2:
|
|
16
|
-
|
|
21
|
+
rich.print(f"[red]{code}[red]")
|
|
22
|
+
rich.print("[red]error:Something wrong in your code[/red]")
|
|
23
|
+
rich.print("[red]The usage of `[FUNC]` sentences is `[FUNC] [<function name>] [<args>]`[/red]")
|
|
24
|
+
sys.exit(1)
|
|
17
25
|
function_name = parts[0].strip()
|
|
18
26
|
args = parts[1].strip()
|
|
19
27
|
if not function_name:
|
|
20
|
-
|
|
28
|
+
rich.print(f"[red]{code}[/red]")
|
|
29
|
+
rich.print("[/red]error:Function name cannot be empty.[/red]")
|
|
30
|
+
sys.exit(1)
|
|
21
31
|
dangerous_list = kwlist+["INFO", "VAR", "INPUT", "IF", "ELSEIF", "ELSE", "FOR", "WHILE", "LOOP", "FUNC", "CLASS", "ERROR", "WARN", "USE"]
|
|
22
32
|
if not function_name.isidentifier():
|
|
23
|
-
|
|
33
|
+
rich.print(f"[red]{code}[/red]")
|
|
34
|
+
rich.print(f"[red]error:Invalid function name: {function_name}.[/red]")
|
|
35
|
+
sys.exit(1)
|
|
24
36
|
if function_name in dangerous_list:
|
|
25
|
-
|
|
37
|
+
rich.print(f"[red]{code}[/red]")
|
|
38
|
+
rich.print(f"[red]error:Invalid function name: {function_name}.[/red]")
|
|
39
|
+
sys.exit(1)
|
|
26
40
|
return f"def {function_name}({args}):"
|
|
27
41
|
|
|
28
42
|
# [RETURN] [<val>] → return <val>
|
|
@@ -30,7 +44,9 @@ def RETURN_to_return(code: str):
|
|
|
30
44
|
code = code.lstrip()
|
|
31
45
|
keyword, val = code.split(" ", 1)
|
|
32
46
|
if keyword!="[RETURN]":
|
|
33
|
-
|
|
47
|
+
rich.print(f"[red]{code}[/red]")
|
|
48
|
+
rich.print(f"[red]error:Expected `FUNC` got `{keyword}`.[/red]")
|
|
49
|
+
sys.exit(1)
|
|
34
50
|
val = val.removeprefix("[").removesuffix("]")
|
|
35
51
|
if not val:
|
|
36
52
|
return "return"
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# bracket/GUI.py
|
|
2
|
+
# GUI support for bracket
|
|
3
|
+
|
|
4
|
+
import tkinter as tk
|
|
5
|
+
|
|
6
|
+
Base = tk.Tk
|
|
7
|
+
Tag = tk.Label
|
|
8
|
+
Button = tk.Button
|
|
9
|
+
InputBox = tk.Entry
|
|
10
|
+
Text = tk.Text
|
|
11
|
+
Checkbutton = tk.Checkbutton
|
|
12
|
+
Radiobutton = tk.Radiobutton
|
|
13
|
+
Int = tk.IntVar
|
|
14
|
+
String = tk.StringVar
|
|
15
|
+
Double = tk.DoubleVar
|
|
16
|
+
Bool = tk.BooleanVar
|
|
@@ -9,6 +9,6 @@ def USE_to_import(code: str):
|
|
|
9
9
|
raise SyntaxError(f"Expect `[USE]` got {keyword}")
|
|
10
10
|
key = lib.removeprefix("[").removesuffix("]")
|
|
11
11
|
lib_dict = {
|
|
12
|
-
"
|
|
12
|
+
"GUI": "bracket.GUI",
|
|
13
13
|
}
|
|
14
|
-
return f"
|
|
14
|
+
return f"from {lib_dict[key]} import*"
|
|
@@ -3,37 +3,52 @@
|
|
|
3
3
|
# manage I/O operation
|
|
4
4
|
|
|
5
5
|
from keyword import kwlist
|
|
6
|
+
import sys
|
|
6
7
|
|
|
8
|
+
import rich
|
|
7
9
|
# [INFO] [<text>] → print(<text>)
|
|
8
10
|
def INFO_to_print(code: str):
|
|
9
11
|
code = code.lstrip()
|
|
10
12
|
keyword, text = code.split(" ", 1)
|
|
11
13
|
if keyword!="[INFO]":
|
|
12
|
-
|
|
14
|
+
rich.print(f"[red]{code}[/red]")
|
|
15
|
+
rich.print(f"[red]error:Expected `INFO` got `{keyword}`.[/red]")
|
|
16
|
+
sys.exit(1)
|
|
13
17
|
text = text.removeprefix("[").removesuffix("]")
|
|
14
18
|
return f"print({text})"
|
|
15
19
|
|
|
16
20
|
# [VAR] [<var name>] [INPUT] [<tip word>] [<multilines> (bool)] → var = input(<tip word>)
|
|
17
|
-
def INPUT_to_input(code: str)
|
|
21
|
+
def INPUT_to_input(code: str):
|
|
18
22
|
code = code.lstrip()
|
|
19
23
|
rest = code.split(" ", 1)[1]
|
|
20
24
|
inner = rest.removeprefix("[").removesuffix("]")
|
|
21
25
|
parts = inner.split("] [")
|
|
22
26
|
if len(parts) != 4:
|
|
23
|
-
|
|
27
|
+
rich.print(f"[red]{code}[/red]")
|
|
28
|
+
rich.print("[red]error:Something wrong in your code.[/red]")
|
|
29
|
+
rich.print("[red]The true usage of `[INPUT]` sentences is `[VAR] [<var name>] [INPUT] [<tip word>] [<multilines> (bool)]`[/red]")
|
|
30
|
+
sys.exit(1)
|
|
24
31
|
var_name = parts[0].strip()
|
|
25
32
|
keyword = parts[1]
|
|
26
33
|
tip_word = parts[2].strip()
|
|
27
34
|
multilines = parts[3].lower() in ("true", "1", "yes", "on")
|
|
28
35
|
if not var_name:
|
|
29
|
-
|
|
36
|
+
rich.print(f"[red]{code}[/red]")
|
|
37
|
+
rich.print("[red]error:Var name cannot be empty.[/red]")
|
|
38
|
+
sys.exit(1)
|
|
30
39
|
if not var_name.isidentifier():
|
|
31
|
-
|
|
40
|
+
rich.print(f"[red]{code}[/red]")
|
|
41
|
+
rich.print(f"[red]error:Invalid var name: {var_name}.[/red]")
|
|
42
|
+
sys.exit(1)
|
|
32
43
|
dangerous_list = kwlist+["INFO", "VAR", "INPUT", "IF", "ELSEIF", "ELSE", "FOR", "WHILE", "LOOP", "FUNC", "CLASS", "ERROR", "WARN", "USE"]
|
|
33
44
|
if var_name in dangerous_list:
|
|
34
|
-
|
|
45
|
+
rich.print(f"[red]{code}[/red]")
|
|
46
|
+
rich.print(f"[red]error:Invalid var name: {var_name}.[/red]")
|
|
47
|
+
sys.exit(1)
|
|
35
48
|
if keyword != "INPUT":
|
|
36
|
-
|
|
49
|
+
rich.print(f"[red]{code}[/red]")
|
|
50
|
+
rich.print(f"[red]error:Expected `INPUT` got `{keyword}`.[/red]")
|
|
51
|
+
sys.exit(1)
|
|
37
52
|
if multilines:
|
|
38
53
|
return f'''\
|
|
39
54
|
print({tip_word})
|
|
@@ -2,18 +2,26 @@
|
|
|
2
2
|
# bracket/LOOP.py
|
|
3
3
|
# manage the loop sentences
|
|
4
4
|
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
import rich
|
|
8
|
+
|
|
5
9
|
# [FOR] [<range var>] [<start>, <end>, <step length>] → for <range var> in range(<start>, <end>, <step length>)
|
|
6
10
|
def FOR_to_for(code: str) -> str:
|
|
7
11
|
code = code.lstrip()
|
|
8
12
|
keyword, rest = code.split(" ", 1)
|
|
9
13
|
if keyword != "[FOR]":
|
|
10
|
-
|
|
14
|
+
rich.print(f"[red]{code}[/red]")
|
|
15
|
+
rich.print(f"[red]error:Expected `[FOR]` got `{keyword}`[/red]")
|
|
16
|
+
sys.exit(1)
|
|
11
17
|
var_part, range_part = rest.split(" ", 1)
|
|
12
18
|
var = var_part.removeprefix("[").removesuffix("]")
|
|
13
19
|
range_args = range_part.removeprefix("[").removesuffix("]")
|
|
14
20
|
parts = [p.strip() for p in range_args.split(",")]
|
|
15
21
|
if len(parts)!=3:
|
|
16
|
-
|
|
22
|
+
rich.print(f"[red]{code}[/red]")
|
|
23
|
+
rich.print("[red]error:[FOR] needs 3 range arguments[/red]")
|
|
24
|
+
sys.exit(1)
|
|
17
25
|
start, end, step = parts
|
|
18
26
|
return f"for {var} in range({start}, {end}, {step}):"
|
|
19
27
|
|
|
@@ -22,7 +30,9 @@ def WHILE_to_while(code: str):
|
|
|
22
30
|
code = code.lstrip()
|
|
23
31
|
keyword, cond = code.split(" ", 1)
|
|
24
32
|
if keyword!="[WHILE]":
|
|
25
|
-
|
|
33
|
+
rich.print(f"[red]{code}[/red]")
|
|
34
|
+
rich.print(f"[red]error:Expected `[WHILE]` got `{keyword}`[/red]")
|
|
35
|
+
sys.exit(1)
|
|
26
36
|
text = cond.removeprefix("[").removesuffix("]")
|
|
27
37
|
return f"while {text}:"
|
|
28
38
|
|
|
@@ -30,21 +40,27 @@ def WHILE_to_while(code: str):
|
|
|
30
40
|
def LOOP_to_while_True(code: str):
|
|
31
41
|
code = code.lstrip()
|
|
32
42
|
if code!="[LOOP]":
|
|
33
|
-
|
|
43
|
+
rich.print(f"[red]{code}[/red]")
|
|
44
|
+
rich.print(f"[red]error:Expected `[LOOP]` got `{keyword}`[/red]")
|
|
45
|
+
sys.exit(1)
|
|
34
46
|
return "while True:"
|
|
35
47
|
|
|
36
48
|
# [CONTINUE] → continue
|
|
37
49
|
def CONTINUE_to_continue(code: str):
|
|
38
50
|
code = code.lstrip()
|
|
39
51
|
if code!="[CONTINUE]":
|
|
40
|
-
|
|
52
|
+
rich.print(f"[red]{code}[/red]")
|
|
53
|
+
rich.print(f"[red]error:Expected `[CONTINUE]` got `{keyword}`[/red]")
|
|
54
|
+
sys.exit(1)
|
|
41
55
|
return "continue"
|
|
42
56
|
|
|
43
57
|
# [BREAK] → break
|
|
44
58
|
def BREAK_to_break(code: str):
|
|
45
59
|
code = code.lstrip()
|
|
46
60
|
if code!="[BREAK]":
|
|
47
|
-
|
|
61
|
+
rich.print(f"[red]{code}[/red]")
|
|
62
|
+
rich.print(f"[red]error:Expected `[BREAK]` got `{keyword}`[/red]")
|
|
63
|
+
sys.exit(1)
|
|
48
64
|
return "break"
|
|
49
65
|
|
|
50
66
|
def transpile_line(line: str) -> str:
|
|
@@ -3,31 +3,47 @@
|
|
|
3
3
|
# manage variables
|
|
4
4
|
|
|
5
5
|
from keyword import kwlist
|
|
6
|
+
import sys
|
|
7
|
+
|
|
8
|
+
import rich
|
|
6
9
|
|
|
7
10
|
# [VAR] [<var name>] [<value>] → <var name> = <value>
|
|
8
11
|
def VAR_to_varname_equal(code: str):
|
|
9
12
|
code = code.lstrip()
|
|
10
13
|
keyword, rest = code.split(" ", 1)
|
|
11
14
|
if keyword!="[VAR]":
|
|
12
|
-
|
|
15
|
+
rich.print(f"[red]{code}[/red]")
|
|
16
|
+
rich.print(f"[red]error:Expected `VAR` got `{keyword}`.[/red]")
|
|
17
|
+
sys.exit(1)
|
|
13
18
|
inner = rest.removeprefix("[").removesuffix("]")
|
|
14
19
|
parts = inner.split("] [")
|
|
15
20
|
if len(parts) != 2:
|
|
16
|
-
|
|
21
|
+
rich.print(f"[red]{code}[/red]")
|
|
22
|
+
rich.print("[red]error:Something wrong in your code[/red]")
|
|
23
|
+
rich.print("[red]the true usage of `[VAR]` sentences is `[VAR] [<var name>] [<value>]`[red]")
|
|
24
|
+
sys.exit(1)
|
|
17
25
|
var_name = parts[0].strip()
|
|
18
26
|
value = parts[1].strip()
|
|
19
27
|
if not var_name:
|
|
20
|
-
|
|
28
|
+
rich.print(f"[red]{code}[/red]")
|
|
29
|
+
rich.print("[red]error:Var name cannot be empty.[/red]")
|
|
30
|
+
sys.exit(1)
|
|
21
31
|
dangerous_list = kwlist+["INFO", "VAR", "INPUT", "IF", "ELSEIF", "ELSE", "FOR", "WHILE", "LOOP", "FUNC", "CLASS", "ERROR", "WARN", "USE"]
|
|
22
32
|
if not var_name.isidentifier():
|
|
23
|
-
|
|
33
|
+
rich.print(f"[red]{code}[/red]")
|
|
34
|
+
rich.print(f"[red]error:Invalid var name: {var_name}.[/red]")
|
|
35
|
+
sys.exit(1)
|
|
24
36
|
if var_name in dangerous_list:
|
|
25
|
-
|
|
37
|
+
rich.print(f"[red]{code}[/red]")
|
|
38
|
+
rich.print(f"[red]error:Invalid var name: {var_name}.[/red]")
|
|
39
|
+
sys.exit(1)
|
|
26
40
|
if not value:
|
|
27
|
-
|
|
41
|
+
rich.print(f"[red]{code}[/red]")
|
|
42
|
+
rich.print("[red]error:Value cannot be empty.[/red]")
|
|
43
|
+
sys.exit(1)
|
|
28
44
|
return f"{var_name} = {value}"
|
|
29
45
|
|
|
30
|
-
def transpile_line(line: str)
|
|
46
|
+
def transpile_line(line: str):
|
|
31
47
|
"""transpile one line of bracket code and operate indents"""
|
|
32
48
|
indent = len(line) - len(line.lstrip())
|
|
33
49
|
stripped = line.lstrip()
|
|
@@ -2,12 +2,18 @@
|
|
|
2
2
|
# bracket/WARN.py
|
|
3
3
|
# manage warnings generating
|
|
4
4
|
|
|
5
|
+
import sys
|
|
6
|
+
|
|
7
|
+
import rich
|
|
8
|
+
|
|
5
9
|
# [WARN] [<info>] → __import__("rich").print("[yellow]<info>[/yellow]")
|
|
6
10
|
def WARN_to_rich_print(code: str):
|
|
7
11
|
code = code.lstrip()
|
|
8
12
|
keyword, info = code.split(" ", 1)
|
|
9
13
|
if keyword!="[WARN]":
|
|
10
|
-
|
|
14
|
+
rich.print(f"[red]{code}[/red]")
|
|
15
|
+
rich.print(f"[red]Expected `WARN` got `{keyword}`.[/red]")
|
|
16
|
+
sys.exit(1)
|
|
11
17
|
info = info.removeprefix("[").removesuffix("]")
|
|
12
18
|
return f"__import__('rich').print('[yellow]{info[1:-1]}[/yellow]')"
|
|
13
19
|
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
import sys
|
|
6
6
|
import argparse
|
|
7
|
+
import subprocess
|
|
8
|
+
|
|
7
9
|
from .transpile import transpile
|
|
8
10
|
|
|
9
11
|
def main():
|
|
@@ -20,20 +22,28 @@ def main():
|
|
|
20
22
|
build_parser = subparsers.add_parser("build", help="transpile .bracket file to .py")
|
|
21
23
|
build_parser.add_argument("file", help="the .bracket file you want to transpile")
|
|
22
24
|
build_parser.add_argument("-o", "--output", help="output file name(default same name .py)")
|
|
25
|
+
# pack command
|
|
26
|
+
pack_parser = subparsers.add_parser("pack", help="pack .bracket file to binary")
|
|
27
|
+
pack_parser.add_argument("file", help="the .bracket file you want to pack")
|
|
28
|
+
pack_parser.add_argument("-o", "--output", help="output file name(default same name .bracket)")
|
|
23
29
|
args = parser.parse_args()
|
|
24
|
-
if args.command
|
|
30
|
+
if args.command=="run":
|
|
25
31
|
with open(args.file, "r", encoding="utf-8") as f:
|
|
26
32
|
code = f.read()
|
|
27
33
|
py_code = transpile(code)
|
|
28
34
|
exec(py_code)
|
|
29
|
-
elif args.command
|
|
35
|
+
elif args.command=="build":
|
|
30
36
|
with open(args.file, "r", encoding="utf-8") as f:
|
|
31
37
|
code = f.read()
|
|
32
38
|
py_code = transpile(code)
|
|
33
39
|
output = args.output or args.file.replace(".bracket", ".py")
|
|
34
40
|
with open(output, "w", encoding="utf-8") as f:
|
|
35
41
|
f.write(py_code)
|
|
36
|
-
|
|
42
|
+
elif args.command=="pack":
|
|
43
|
+
print(f"Building {args.file}")
|
|
44
|
+
subprocess.run(["bracket", "build", str(args.file)], check=True)
|
|
45
|
+
print("Packing with pyinstaller")
|
|
46
|
+
subprocess.run(["pyinstaller", "--onefile", str(args.file).replace(".bracket", ".py")], check=True)
|
|
37
47
|
|
|
38
48
|
if __name__ == "__main__":
|
|
39
49
|
main()
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bracket-lang
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Requires-Python: >=3.8
|
|
5
|
+
Description-Content-Type: text/markdown
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Requires-Dist: rich>=13.0.0
|
|
8
|
+
Requires-Dist: pyinstaller>=6.0.0
|
|
9
|
+
Dynamic: description
|
|
10
|
+
Dynamic: description-content-type
|
|
11
|
+
Dynamic: license-file
|
|
12
|
+
Dynamic: requires-dist
|
|
13
|
+
Dynamic: requires-python
|
|
14
|
+
|
|
15
|
+
# bracket
|
|
16
|
+
python制作的转译型简单编程语言
|
|
17
|
+
|
|
18
|
+
## 1 安装
|
|
19
|
+
```bash
|
|
20
|
+
pip install bracket-lang
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## 2 Hello world
|
|
24
|
+
```bracket
|
|
25
|
+
[INFO] ["Hello world!"]
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## 3 基本语法
|
|
29
|
+
```bracket
|
|
30
|
+
# main.bracket
|
|
31
|
+
|
|
32
|
+
# 打印
|
|
33
|
+
[INFO] ["这是一段文本"]
|
|
34
|
+
[INFO] ["Loading...", end=" "]
|
|
35
|
+
[INFO] ["complete"]
|
|
36
|
+
|
|
37
|
+
# 变量
|
|
38
|
+
[VAR] [integer] [2]
|
|
39
|
+
[VAR] [floating_point] [3.0]
|
|
40
|
+
[VAR] [string] ["abc"]
|
|
41
|
+
[VAR] [lst] [[1, 2, 3, 4, 5]]
|
|
42
|
+
[VAR] [t] [(1, 2, 3)]
|
|
43
|
+
[VAR] [dict] [{1: 1, 2: 4, 3: 9}]
|
|
44
|
+
[INFO] [integer, floating_point, string, lst, t, dict]
|
|
45
|
+
|
|
46
|
+
# 输入
|
|
47
|
+
[VAR] [short] [INPUT] ["单行文本"] [False]
|
|
48
|
+
[VAR] [long] [INPUT] ["多行文本"] [True]
|
|
49
|
+
[INFO] ["您这两次分别输入了: "]
|
|
50
|
+
[INFO] [short]
|
|
51
|
+
[INFO] [long]
|
|
52
|
+
|
|
53
|
+
# 分支语句
|
|
54
|
+
[VAR] [a] [6]
|
|
55
|
+
[IF] [a>0]
|
|
56
|
+
[INFO] ["正数"]
|
|
57
|
+
[ELSEIF] [a==0]
|
|
58
|
+
[INFO] ["零"]
|
|
59
|
+
[ELSE]
|
|
60
|
+
[INFO] ["负数"]
|
|
61
|
+
|
|
62
|
+
# 循环
|
|
63
|
+
[VAR] [total] [0]
|
|
64
|
+
[FOR] [i] [1, 101, 1]
|
|
65
|
+
[VAR] [total] [total+i]
|
|
66
|
+
[INFO] ["1~100的和:", total]
|
|
67
|
+
[VAR] [i] [0]
|
|
68
|
+
[WHILE] [i<10]
|
|
69
|
+
[INFO] [i]
|
|
70
|
+
[VAR] [i] [i+1]
|
|
71
|
+
[LOOP]
|
|
72
|
+
[INFO] [i]
|
|
73
|
+
[IF] [i==100]
|
|
74
|
+
[BREAK]
|
|
75
|
+
[VAR] [i] [i+1]
|
|
76
|
+
|
|
77
|
+
# 函数
|
|
78
|
+
[FUNC] [longest] [x, y]
|
|
79
|
+
[IF] [len(x)>len(y)]
|
|
80
|
+
[RETURN] [x]
|
|
81
|
+
[RETURN] [y]
|
|
82
|
+
[INFO] [longest("hi", "hello")]
|
|
83
|
+
|
|
84
|
+
# 类
|
|
85
|
+
[CLASS] [Calculator] [object]
|
|
86
|
+
[FUNC] [add] [a, b]
|
|
87
|
+
[RETURN] [a+b]
|
|
88
|
+
[FUNC] [subtract] [a, b]
|
|
89
|
+
[RETURN] [a-b]
|
|
90
|
+
[FUNC] [mul] [a, b]
|
|
91
|
+
[RETURN] [a*b]
|
|
92
|
+
[FUNC] [division] [a, b]
|
|
93
|
+
[IF] [b==0]
|
|
94
|
+
[ERROR] ["Cannot devide by zero."]
|
|
95
|
+
[RETURN] [a/b]
|
|
96
|
+
[FUNC] [percent] [a]
|
|
97
|
+
[RETURN] [a/100]
|
|
98
|
+
[INFO] [Calculator.add(1, 1)]
|
|
99
|
+
|
|
100
|
+
# 警告
|
|
101
|
+
[WARN] ["警告信息"]
|
|
102
|
+
|
|
103
|
+
# GUI
|
|
104
|
+
[USE] [GUI]
|
|
105
|
+
[VAR] [root] [Base()]
|
|
106
|
+
root.title("Hello bracket")
|
|
107
|
+
root.geometry("300x200")
|
|
108
|
+
[VAR] [label] [Tag(root, text="Hello, World!")]
|
|
109
|
+
label.pack()
|
|
110
|
+
root.mainloop()
|
|
111
|
+
```
|
|
112
|
+
输出:
|
|
113
|
+
```text
|
|
114
|
+
这是一段文本
|
|
115
|
+
Loading... complete
|
|
116
|
+
2 3.0 abc [1, 2, 3, 4, 5] (1, 2, 3) {1: 1, 2: 4, 3: 9}
|
|
117
|
+
单行文本: 1
|
|
118
|
+
多行文本: 2
|
|
119
|
+
3
|
|
120
|
+
您这两次分别输入了
|
|
121
|
+
1
|
|
122
|
+
2
|
|
123
|
+
3
|
|
124
|
+
正数
|
|
125
|
+
5050
|
|
126
|
+
1
|
|
127
|
+
2
|
|
128
|
+
3
|
|
129
|
+
...
|
|
130
|
+
100
|
|
131
|
+
hello
|
|
132
|
+
2
|
|
133
|
+
警告信息[yellow]
|
|
134
|
+
```
|
|
135
|
+

|
|
136
|
+
打包:
|
|
137
|
+
```bash
|
|
138
|
+
bracket pack main.bracket
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## 4 命令行工具参数
|
|
142
|
+
| 参数 | 用法 |
|
|
143
|
+
| ------ | ------ |
|
|
144
|
+
| `--help` `-h` | 帮助 |
|
|
145
|
+
| `build` | 转译 |
|
|
146
|
+
| `run` | 转译运行 |
|
|
147
|
+
| `pack` | 打包成二进制 |
|
|
148
|
+
|
|
149
|
+
## 6 注意事项
|
|
150
|
+
1. `INFO`的参数与python的`print`基本相同
|
|
151
|
+
2. `[VAR] [lst] [[1, 2, 3, 4, 5]]`是真正的列表, `[VAR] [t] [1, 2, 3, 4, 5]`是元组
|
|
152
|
+
3. `FOR`必须要写三个参数
|
|
153
|
+
4. `[LOOP]`是无限循环, 与`[WHILE] [True]`等效
|
|
154
|
+
5. 变量名不能与bracket关键字和python关键字重名
|
|
155
|
+
6. bracket语言不兼容python的列表推导式, 三元表达式等
|
|
156
|
+
7. bracket内置轻量编辑器bkted
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# setup.py
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from setuptools import setup, find_packages
|
|
4
|
+
|
|
5
|
+
# 读取 README
|
|
6
|
+
readme_path = Path(__file__).parent / "README.md"
|
|
7
|
+
long_description = readme_path.read_text(encoding="utf-8") if readme_path.exists() else ""
|
|
8
|
+
|
|
9
|
+
setup(
|
|
10
|
+
name="bracket-lang",
|
|
11
|
+
version="0.4.0",
|
|
12
|
+
packages=find_packages(),
|
|
13
|
+
entry_points={
|
|
14
|
+
"console_scripts": [
|
|
15
|
+
"bracket = bracket.cli:main",
|
|
16
|
+
],
|
|
17
|
+
},
|
|
18
|
+
python_requires=">=3.8",
|
|
19
|
+
install_requires=[
|
|
20
|
+
"rich>=13.0.0",
|
|
21
|
+
"pyinstaller>=6.0.0"
|
|
22
|
+
],
|
|
23
|
+
long_description=long_description,
|
|
24
|
+
long_description_content_type="text/markdown",
|
|
25
|
+
)
|
bracket_lang-0.2.0/PKG-INFO
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
rich>=13.0.0
|
bracket_lang-0.2.0/setup.py
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
# setup.py
|
|
2
|
-
from setuptools import setup, find_packages
|
|
3
|
-
|
|
4
|
-
setup(
|
|
5
|
-
name="bracket-lang",
|
|
6
|
-
version="0.2.0",
|
|
7
|
-
packages=find_packages(),
|
|
8
|
-
entry_points={
|
|
9
|
-
"console_scripts": [
|
|
10
|
-
"bracket = bracket.cli:main",
|
|
11
|
-
],
|
|
12
|
-
},
|
|
13
|
-
python_requires=">=3.8",
|
|
14
|
-
install_requires=["rich>=13.0.0"]
|
|
15
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|