mirascript 0.0.6__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.
- mirascript-0.0.6/PKG-INFO +17 -0
- mirascript-0.0.6/README.md +24 -0
- mirascript-0.0.6/mirascript/__init__.py +11 -0
- mirascript-0.0.6/mirascript/deep_nonlocal_fix.py +136 -0
- mirascript-0.0.6/mirascript/diagnostics.py +82 -0
- mirascript-0.0.6/mirascript/emit.py +1182 -0
- mirascript-0.0.6/mirascript/main.py +26 -0
- mirascript-0.0.6/mirascript/subtle.py +5 -0
- mirascript-0.0.6/mirascript/vm/VmWrapper.py +50 -0
- mirascript-0.0.6/mirascript/vm/__init__.py +15 -0
- mirascript-0.0.6/mirascript/vm/env.py +13 -0
- mirascript-0.0.6/mirascript/vm/error.py +19 -0
- mirascript-0.0.6/mirascript/vm/helpers.py +124 -0
- mirascript-0.0.6/mirascript/vm/operations.py +592 -0
- mirascript-0.0.6/mirascript/vm/types/__init__.py +21 -0
- mirascript-0.0.6/mirascript/vm/types/checker.py +107 -0
- mirascript-0.0.6/mirascript/vm/types/const.py +39 -0
- mirascript-0.0.6/mirascript/vm/types/context.py +130 -0
- mirascript-0.0.6/mirascript/vm/types/extern.py +123 -0
- mirascript-0.0.6/mirascript/vm/types/function.py +28 -0
- mirascript-0.0.6/mirascript/vm/types/module.py +33 -0
- mirascript-0.0.6/mirascript/vm/types/script.py +17 -0
- mirascript-0.0.6/mirascript/vm/types/types.py +143 -0
- mirascript-0.0.6/mirascript/vm/types/wrapper.py +56 -0
- mirascript-0.0.6/mirascript.egg-info/PKG-INFO +17 -0
- mirascript-0.0.6/mirascript.egg-info/SOURCES.txt +36 -0
- mirascript-0.0.6/mirascript.egg-info/dependency_links.txt +1 -0
- mirascript-0.0.6/mirascript.egg-info/top_level.txt +1 -0
- mirascript-0.0.6/pyproject.toml +16 -0
- mirascript-0.0.6/setup.cfg +4 -0
- mirascript-0.0.6/setup.py +79 -0
- mirascript-0.0.6/test/test.py +19 -0
- mirascript-0.0.6/test/test2.py +15 -0
- mirascript-0.0.6/test/test3.py +22 -0
- mirascript-0.0.6/test/test4.py +279 -0
- mirascript-0.0.6/test/test5.py +57 -0
- mirascript-0.0.6/test/test6.py +0 -0
- mirascript-0.0.6/test/test_is_string_number.py +0 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: mirascript
|
|
3
|
+
Version: 0.0.6
|
|
4
|
+
Summary: cloudpss mirascript
|
|
5
|
+
Home-page: https://www.cloudpss.net
|
|
6
|
+
Author: cloudpss
|
|
7
|
+
Author-email: zhangdaming@cloudpss.net
|
|
8
|
+
License: MIT Licence
|
|
9
|
+
Keywords: cloudpss,cloudpss-mirascript,mirascript
|
|
10
|
+
Platform: any
|
|
11
|
+
Classifier: Programming Language :: Rust
|
|
12
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
13
|
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
14
|
+
Requires-Python: >=3.7
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
|
|
17
|
+
MiraScript 的 Python 绑定允许在 Python 中使用 MiraScript 编译器。它提供了一个简单的接口来编译 MiraScript 脚本,并返回编译结果和诊断信息。
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# MiraScript Python Bindings
|
|
2
|
+
|
|
3
|
+
MiraScript 的 Python 绑定允许在 Python 中使用 MiraScript 编译器。它提供了一个简单的接口来编译 MiraScript 脚本,并返回编译结果和诊断信息。
|
|
4
|
+
|
|
5
|
+
## 开发
|
|
6
|
+
|
|
7
|
+
1. 初始化虚拟环境
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
python -m venv .venv
|
|
11
|
+
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
2. 安装依赖
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install -r requirements.txt
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
3. 编译并安装 bindings
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
maturin develop
|
|
24
|
+
```
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MiraScript Python Module
|
|
3
|
+
|
|
4
|
+
This module provides the main entry point for compiling MiraScript code
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from .mirascript import Config
|
|
8
|
+
from .diagnostics import Diagnostic
|
|
9
|
+
from .main import compile
|
|
10
|
+
__version__ = '0.0.6'
|
|
11
|
+
__all__ = ["Config", "Diagnostic", "compile","__version__"]
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
## 将所有 nonlocal 声明提升到函数体顶部,有些情况下nonlocal声明可能在条件语句或循环内
|
|
2
|
+
import ast
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def deep_nonlocal_fix(node, nonlocal_vars=None):
|
|
6
|
+
"""
|
|
7
|
+
将函数体内部所有非嵌套位置的 `nonlocal` 声明收集并提升到函数体顶部。
|
|
8
|
+
对 FunctionDef / AsyncFunctionDef 递归处理,保持嵌套函数的 nonlocal 在其自身作用域内。
|
|
9
|
+
"""
|
|
10
|
+
class _Hoister(ast.NodeTransformer):
|
|
11
|
+
def visit_FunctionDef(self, fn: ast.FunctionDef):
|
|
12
|
+
# 先处理内部(从底向上)
|
|
13
|
+
self.generic_visit(fn)
|
|
14
|
+
|
|
15
|
+
# 收集当前函数作用域(不进入嵌套函数/类/lambda)的 nonlocal 名称
|
|
16
|
+
names = set()
|
|
17
|
+
|
|
18
|
+
def collect_from_nodes(stmts):
|
|
19
|
+
for s in stmts:
|
|
20
|
+
if isinstance(s, ast.Nonlocal):
|
|
21
|
+
for n in s.names:
|
|
22
|
+
names.add(n)
|
|
23
|
+
# 不进入嵌套作用域
|
|
24
|
+
elif isinstance(s, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef, ast.Lambda)):
|
|
25
|
+
continue
|
|
26
|
+
else:
|
|
27
|
+
if s is None:
|
|
28
|
+
continue
|
|
29
|
+
for field, value in ast.iter_fields(s):
|
|
30
|
+
if isinstance(value, list):
|
|
31
|
+
collect_from_nodes(value)
|
|
32
|
+
elif isinstance(value, ast.AST):
|
|
33
|
+
if isinstance(value, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef, ast.Lambda)):
|
|
34
|
+
continue
|
|
35
|
+
collect_from_nodes([value])
|
|
36
|
+
|
|
37
|
+
collect_from_nodes(fn.body)
|
|
38
|
+
|
|
39
|
+
if names:
|
|
40
|
+
# 从当前函数体及其子节点中移除所有 Nonlocal 节点(不进入嵌套函数/类/lambda)
|
|
41
|
+
def remove_from_nodes(stmts):
|
|
42
|
+
new_stmts = []
|
|
43
|
+
for s in stmts:
|
|
44
|
+
if isinstance(s, ast.Nonlocal):
|
|
45
|
+
# 跳过(已收集)
|
|
46
|
+
continue
|
|
47
|
+
elif isinstance(s, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef, ast.Lambda)):
|
|
48
|
+
new_stmts.append(s)
|
|
49
|
+
else:
|
|
50
|
+
for field, value in list(ast.iter_fields(s)):
|
|
51
|
+
if isinstance(value, list):
|
|
52
|
+
filtered = remove_from_nodes(value)
|
|
53
|
+
setattr(s, field, filtered)
|
|
54
|
+
elif isinstance(value, ast.AST):
|
|
55
|
+
if isinstance(value, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef, ast.Lambda)):
|
|
56
|
+
pass
|
|
57
|
+
else:
|
|
58
|
+
replaced = remove_from_nodes([value])
|
|
59
|
+
if replaced:
|
|
60
|
+
setattr(s, field, replaced[0])
|
|
61
|
+
new_stmts.append(s)
|
|
62
|
+
return new_stmts
|
|
63
|
+
|
|
64
|
+
fn.body = remove_from_nodes(fn.body)
|
|
65
|
+
|
|
66
|
+
# 构造新的 nonlocal 节点并插入到函数体顶部,若首节点为 Try 则插入到 Try.body 顶部
|
|
67
|
+
nl_node = ast.Nonlocal(names=sorted(names))
|
|
68
|
+
if fn.body and isinstance(fn.body[0], ast.Try):
|
|
69
|
+
try_node: ast.Try = fn.body[0]
|
|
70
|
+
try_node.body.insert(0, nl_node)
|
|
71
|
+
else:
|
|
72
|
+
fn.body.insert(0, nl_node)
|
|
73
|
+
|
|
74
|
+
return fn
|
|
75
|
+
|
|
76
|
+
def visit_AsyncFunctionDef(self, fn: ast.AsyncFunctionDef):
|
|
77
|
+
# 同样处理异步函数
|
|
78
|
+
self.generic_visit(fn)
|
|
79
|
+
|
|
80
|
+
names = set()
|
|
81
|
+
|
|
82
|
+
def collect_from_nodes(stmts):
|
|
83
|
+
for s in stmts:
|
|
84
|
+
if isinstance(s, ast.Nonlocal):
|
|
85
|
+
for n in s.names:
|
|
86
|
+
names.add(n)
|
|
87
|
+
elif isinstance(s, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef, ast.Lambda)):
|
|
88
|
+
continue
|
|
89
|
+
else:
|
|
90
|
+
for field, value in ast.iter_fields(s):
|
|
91
|
+
if isinstance(value, list):
|
|
92
|
+
collect_from_nodes(value)
|
|
93
|
+
elif isinstance(value, ast.AST):
|
|
94
|
+
if isinstance(value, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef, ast.Lambda)):
|
|
95
|
+
continue
|
|
96
|
+
collect_from_nodes([value])
|
|
97
|
+
|
|
98
|
+
collect_from_nodes(fn.body)
|
|
99
|
+
|
|
100
|
+
if names:
|
|
101
|
+
def remove_from_nodes(stmts):
|
|
102
|
+
new_stmts = []
|
|
103
|
+
for s in stmts:
|
|
104
|
+
if isinstance(s, ast.Nonlocal):
|
|
105
|
+
continue
|
|
106
|
+
elif isinstance(s, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef, ast.Lambda)):
|
|
107
|
+
new_stmts.append(s)
|
|
108
|
+
else:
|
|
109
|
+
for field, value in list(ast.iter_fields(s)):
|
|
110
|
+
if isinstance(value, list):
|
|
111
|
+
filtered = remove_from_nodes(value)
|
|
112
|
+
setattr(s, field, filtered)
|
|
113
|
+
elif isinstance(value, ast.AST):
|
|
114
|
+
if isinstance(value, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef, ast.Lambda)):
|
|
115
|
+
pass
|
|
116
|
+
else:
|
|
117
|
+
replaced = remove_from_nodes([value])
|
|
118
|
+
if replaced:
|
|
119
|
+
setattr(s, field, replaced[0])
|
|
120
|
+
new_stmts.append(s)
|
|
121
|
+
return new_stmts
|
|
122
|
+
|
|
123
|
+
fn.body = remove_from_nodes(fn.body)
|
|
124
|
+
nl_node = ast.Nonlocal(names=sorted(names),lineno=0)
|
|
125
|
+
if fn.body and isinstance(fn.body[0], ast.Try):
|
|
126
|
+
fn.body[0].body.insert(0, nl_node)
|
|
127
|
+
else:
|
|
128
|
+
fn.body.insert(0, nl_node)
|
|
129
|
+
|
|
130
|
+
return fn
|
|
131
|
+
|
|
132
|
+
hoister = _Hoister()
|
|
133
|
+
return hoister.visit(node)
|
|
134
|
+
|
|
135
|
+
# ...existing code...
|
|
136
|
+
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
|
|
2
|
+
from .mirascript import get_diagnostic_message
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
# DiagnosticLevel = Literal["Error", "Warning", "Info", "Hint", "Reference", "Unknown"]
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Diagnostic:
|
|
9
|
+
"""
|
|
10
|
+
诊断信息类
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
__cache = {}
|
|
14
|
+
|
|
15
|
+
start_line: int
|
|
16
|
+
"""起始行号"""
|
|
17
|
+
start_column: int
|
|
18
|
+
"""起始列号"""
|
|
19
|
+
end_line: int
|
|
20
|
+
"""结束行号"""
|
|
21
|
+
end_column: int
|
|
22
|
+
"""结束列号"""
|
|
23
|
+
code: int
|
|
24
|
+
"""诊断代码"""
|
|
25
|
+
level: str
|
|
26
|
+
"""诊断级别"""
|
|
27
|
+
name: str
|
|
28
|
+
"""诊断名称"""
|
|
29
|
+
message: str
|
|
30
|
+
"""诊断消息"""
|
|
31
|
+
|
|
32
|
+
def __init__(
|
|
33
|
+
self,
|
|
34
|
+
start_line: int,
|
|
35
|
+
start_column: int,
|
|
36
|
+
end_line: int,
|
|
37
|
+
end_column: int,
|
|
38
|
+
code: int,
|
|
39
|
+
):
|
|
40
|
+
self.start_line = start_line
|
|
41
|
+
self.start_column = start_column
|
|
42
|
+
self.end_line = end_line
|
|
43
|
+
self.end_column = end_column
|
|
44
|
+
self.code = code
|
|
45
|
+
info = Diagnostic.__cache.get(self.code)
|
|
46
|
+
if info is None:
|
|
47
|
+
try:
|
|
48
|
+
info = get_diagnostic_message(self.code)
|
|
49
|
+
Diagnostic.__cache[self.code] = info
|
|
50
|
+
except:
|
|
51
|
+
info = (
|
|
52
|
+
"Unknown",
|
|
53
|
+
f"{self.code}",
|
|
54
|
+
f"Unknown diagnostic code",
|
|
55
|
+
)
|
|
56
|
+
Diagnostic.__cache[self.code] = info
|
|
57
|
+
self.level = info[0]
|
|
58
|
+
self.name = info[1]
|
|
59
|
+
self.message = info[2]
|
|
60
|
+
|
|
61
|
+
def __repr__(self) -> str:
|
|
62
|
+
return f"Diagnostic(code={self.code}, level={self.level}, name={self.name}, start=({self.start_line}, {self.start_column}), end=({self.end_line}, {self.end_column}))"
|
|
63
|
+
|
|
64
|
+
def __str__(self) -> str:
|
|
65
|
+
return (
|
|
66
|
+
f"[{self.level}] {self.message} ({self.name}) at "
|
|
67
|
+
f"{self.start_line}:{self.start_column} - "
|
|
68
|
+
f"{self.end_line}:{self.end_column}"
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def decode_diagnostics(diagnostics) :
|
|
73
|
+
"""
|
|
74
|
+
解析诊断信息
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
diagnostics (list[int]): 诊断信息列表,包含 [start_line, start_column, end_line, end_column, code]
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
list[Diagnostic]: 解析后的诊断信息列表
|
|
81
|
+
"""
|
|
82
|
+
return [Diagnostic(*diagnostics[i : i + 5]) for i in range(0, len(diagnostics), 5)]
|