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.
Files changed (31) hide show
  1. bracket_lang-0.4.0/MANIFEST.in +2 -0
  2. bracket_lang-0.4.0/PKG-INFO +156 -0
  3. {bracket_lang-0.2.0 → bracket_lang-0.4.0}/README.md +10 -3
  4. bracket_lang-0.4.0/TKGUI_helloworld.jpg +0 -0
  5. {bracket_lang-0.2.0 → bracket_lang-0.4.0}/bracket/BRANCH.py +13 -3
  6. {bracket_lang-0.2.0 → bracket_lang-0.4.0}/bracket/CLASS.py +19 -5
  7. {bracket_lang-0.2.0 → bracket_lang-0.4.0}/bracket/ERROR.py +7 -1
  8. {bracket_lang-0.2.0 → bracket_lang-0.4.0}/bracket/FUN.py +22 -6
  9. bracket_lang-0.4.0/bracket/GUI.py +16 -0
  10. {bracket_lang-0.2.0 → bracket_lang-0.4.0}/bracket/IMPORTLIB.py +2 -2
  11. {bracket_lang-0.2.0 → bracket_lang-0.4.0}/bracket/IO.py +22 -7
  12. {bracket_lang-0.2.0 → bracket_lang-0.4.0}/bracket/LOOP.py +22 -6
  13. {bracket_lang-0.2.0 → bracket_lang-0.4.0}/bracket/VAR.py +23 -7
  14. {bracket_lang-0.2.0 → bracket_lang-0.4.0}/bracket/WARN.py +7 -1
  15. {bracket_lang-0.2.0 → bracket_lang-0.4.0}/bracket/__init__.py +1 -0
  16. {bracket_lang-0.2.0 → bracket_lang-0.4.0}/bracket/cli.py +13 -3
  17. bracket_lang-0.4.0/bracket_lang.egg-info/PKG-INFO +156 -0
  18. {bracket_lang-0.2.0 → bracket_lang-0.4.0}/bracket_lang.egg-info/SOURCES.txt +3 -0
  19. bracket_lang-0.4.0/bracket_lang.egg-info/requires.txt +2 -0
  20. bracket_lang-0.4.0/setup.py +25 -0
  21. bracket_lang-0.2.0/PKG-INFO +0 -9
  22. bracket_lang-0.2.0/bracket_lang.egg-info/PKG-INFO +0 -9
  23. bracket_lang-0.2.0/bracket_lang.egg-info/requires.txt +0 -1
  24. bracket_lang-0.2.0/setup.py +0 -15
  25. {bracket_lang-0.2.0 → bracket_lang-0.4.0}/LICENSE +0 -0
  26. {bracket_lang-0.2.0 → bracket_lang-0.4.0}/bracket/bkted.py +0 -0
  27. {bracket_lang-0.2.0 → bracket_lang-0.4.0}/bracket/transpile.py +0 -0
  28. {bracket_lang-0.2.0 → bracket_lang-0.4.0}/bracket_lang.egg-info/dependency_links.txt +0 -0
  29. {bracket_lang-0.2.0 → bracket_lang-0.4.0}/bracket_lang.egg-info/entry_points.txt +0 -0
  30. {bracket_lang-0.2.0 → bracket_lang-0.4.0}/bracket_lang.egg-info/top_level.txt +0 -0
  31. {bracket_lang-0.2.0 → bracket_lang-0.4.0}/setup.cfg +0 -0
@@ -0,0 +1,2 @@
1
+ include README.md
2
+ include TKGUI_helloworld.jpg
@@ -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
+ ![窗口显示: ](./TKGUI_helloHello.jpg)
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] [TKGUI]
89
- [VAR] [root] [TKGUI.Tk()]
90
+ [USE] [GUI]
91
+ [VAR] [root] [Base()]
90
92
  root.title("Hello bracket")
91
93
  root.geometry("300x200")
92
- [VAR] [label] [TKGUI.Label(root, text="Hello, World!")]
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
  ![窗口显示: ](./TKGUI_helloHello.jpg)
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
- raise SyntaxError(f"Expect `[IF]` got {keyword}")
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
- raise SyntaxError(f"Expect `[ELSEIF]` got {keyword}")
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
- raise SyntaxError(f"Expect `[ELSE]` got {code}")
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
- raise SyntaxError(f"Expected `CLASS` got `{keyword}`.")
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
- raise SyntaxError("Usage: [CLASS] [<class name>] [<parent class>]")
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
- raise SyntaxError("Class name cannot be empty.")
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
- raise SyntaxError(f"Invalid class name: {class_name}.")
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
- raise SyntaxError(f"Invalid name: {class_name}.")
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
- raise SyntaxError(f"Expected `ERROR` got `{keyword}`.")
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
- raise SyntaxError(f"Expected `FUNC` got `{keyword}`.")
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
- raise SyntaxError("Usage: [FUNC] [<function name>] [<args>]")
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
- raise SyntaxError("Function name cannot be empty.")
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
- raise SyntaxError(f"Invalid function name: {function_name}.")
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
- raise SyntaxError(f"Invalid function name: {function_name}.")
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
- raise SyntaxError(f"Expected `RETURN` got `{keyword}`.")
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
- "TKGUI": "tkinter as TKGUI"
12
+ "GUI": "bracket.GUI",
13
13
  }
14
- return f"import {lib_dict[key]}"
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
- raise SyntaxError(f"Expected `INFO` got `{keyword}`.")
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) -> 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
- raise SyntaxError("Usage: [VAR] [<var name>] [INPUT] [<tip word>] [<multilines> (bool)]")
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
- raise SyntaxError("Var name cannot be empty.")
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
- raise SyntaxError(f"Invalid var name: {var_name}.")
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
- raise SyntaxError(f"Invalid var name: {var_name}.")
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
- raise SyntaxError(f"Expected `INPUT`, got `{keyword}`.")
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
- raise SyntaxError(f"Expected `[FOR]` got `{keyword}`")
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
- raise SyntaxError("[FOR] needs 3 range arguments")
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
- raise SyntaxError(f"Expect `[WHILE]` got {keyword}")
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
- raise SyntaxError(f"Expect `[LOOP]` got {code}")
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
- raise SyntaxError(f"Expect `[CONTINUE]` got {code}")
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
- raise SyntaxError(f"Expect `[BREAK]` got {code}")
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
- raise SyntaxError(f"Expected `VAR` got `{keyword}`.")
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
- raise SyntaxError("Usage: [VAR] [<var name>] [<value>]")
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
- raise SyntaxError("Var name cannot be empty.")
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
- raise SyntaxError(f"Invalid var name: {var_name}.")
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
- raise SyntaxError(f"Invalid var name: {var_name}.")
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
- raise SyntaxError("Value cannot be empty.")
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) -> 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
- raise SyntaxError(f"Expected `WARN` got `{keyword}`.")
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
 
@@ -1,5 +1,6 @@
1
1
  # bracket/__init__.py
2
2
  import rich
3
+ import PyInstaller
3
4
 
4
5
  from .transpile import transpile, transpile_line
5
6
  from .cli import main
@@ -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 == "run":
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 == "build":
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
- print(f"✓ transpile finished: {output}")
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
+ ![窗口显示: ](./TKGUI_helloHello.jpg)
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
@@ -1,10 +1,13 @@
1
1
  LICENSE
2
+ MANIFEST.in
2
3
  README.md
4
+ TKGUI_helloworld.jpg
3
5
  setup.py
4
6
  bracket/BRANCH.py
5
7
  bracket/CLASS.py
6
8
  bracket/ERROR.py
7
9
  bracket/FUN.py
10
+ bracket/GUI.py
8
11
  bracket/IMPORTLIB.py
9
12
  bracket/IO.py
10
13
  bracket/LOOP.py
@@ -0,0 +1,2 @@
1
+ rich>=13.0.0
2
+ pyinstaller>=6.0.0
@@ -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
+ )
@@ -1,9 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: bracket-lang
3
- Version: 0.2.0
4
- Requires-Python: >=3.8
5
- License-File: LICENSE
6
- Requires-Dist: rich>=13.0.0
7
- Dynamic: license-file
8
- Dynamic: requires-dist
9
- Dynamic: requires-python
@@ -1,9 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: bracket-lang
3
- Version: 0.2.0
4
- Requires-Python: >=3.8
5
- License-File: LICENSE
6
- Requires-Dist: rich>=13.0.0
7
- Dynamic: license-file
8
- Dynamic: requires-dist
9
- Dynamic: requires-python
@@ -1 +0,0 @@
1
- rich>=13.0.0
@@ -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