Compare commits
18 Commits
utf32_str
...
v0.4.4-bet
| Author | SHA1 | Date | |
|---|---|---|---|
| a398de07ac | |||
| eed1e10e77 | |||
| 4e7f84593a | |||
| ca0396568b | |||
| a00be02359 | |||
| e0a76ea1da | |||
| e98beb03d7 | |||
| 966b6eb805 | |||
| 9310252adc | |||
| 1dadaca4cc | |||
| 537011df32 | |||
| 764c4269a5 | |||
| e1c765aade | |||
| 52b75f17da | |||
| 27e5de3ea2 | |||
| 1e1d6c3284 | |||
| 642ba33243 | |||
| 90d4134f73 |
30
ExampleCodes/3-Structure.fig
Normal file
30
ExampleCodes/3-Structure.fig
Normal file
@@ -0,0 +1,30 @@
|
||||
import std.io;
|
||||
|
||||
struct Point
|
||||
{
|
||||
x: Int; // type specifiers are optional
|
||||
y: Int; // type specifiers are optional
|
||||
|
||||
// x and y are private fields, can only reached by internal context
|
||||
|
||||
public func toString() -> String
|
||||
{
|
||||
return "(" + (x as String) + "," + (y as String) + ")";
|
||||
}
|
||||
// public func toString() {} is ok
|
||||
}
|
||||
|
||||
// make points
|
||||
|
||||
var p1 := new Point{1, 2};
|
||||
io.println(p1.toString()); // (1,2)
|
||||
|
||||
var p2 := new Point{x: 2, y: 3};
|
||||
io.println(p2.toString()); // (2,3)
|
||||
|
||||
var x := 114;
|
||||
var y := 514;
|
||||
|
||||
var p3 := new Point{y, x}; // shorthand mode, can be unordered, auto match field and variable!
|
||||
// = Point{x: x, y: y}
|
||||
io.println(p3.toString()); // (114,514)
|
||||
94
ExampleCodes/4-Interface.fig
Normal file
94
ExampleCodes/4-Interface.fig
Normal file
@@ -0,0 +1,94 @@
|
||||
import std.io;
|
||||
|
||||
interface Document
|
||||
{
|
||||
getDepth() -> Int; // return type is necessary
|
||||
getName() -> String;
|
||||
|
||||
/* toString() -> String
|
||||
{
|
||||
// default implementation
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
struct File
|
||||
{
|
||||
public depth: Int;
|
||||
public name: String;
|
||||
}
|
||||
|
||||
impl Document for File
|
||||
{
|
||||
getDepth()
|
||||
{
|
||||
return depth;
|
||||
}
|
||||
getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
struct Folder
|
||||
{
|
||||
public depth: Int;
|
||||
public name: String;
|
||||
public childs: List = [];
|
||||
}
|
||||
|
||||
impl Document for Folder
|
||||
{
|
||||
getDepth()
|
||||
{
|
||||
return depth;
|
||||
}
|
||||
|
||||
getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
const root_folder := new Folder{
|
||||
0,
|
||||
"root",
|
||||
[
|
||||
new File{
|
||||
1,
|
||||
"joyo.txt"
|
||||
},
|
||||
new Folder{
|
||||
2,
|
||||
"joyoyo",
|
||||
[
|
||||
new File{
|
||||
3,
|
||||
"JOYO2.txt"
|
||||
},
|
||||
new Folder{
|
||||
3,
|
||||
"joyoyoyo"
|
||||
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
func print_directory(root: Document)
|
||||
{
|
||||
io.print(" " * root.getDepth());
|
||||
io.println(root.getDepth(), root.getName());
|
||||
if root is Folder
|
||||
{
|
||||
for var i := 0; i < root.childs.length(); i += 1
|
||||
{
|
||||
var child := root.childs[i];
|
||||
print_directory(child);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
print_directory(root_folder);
|
||||
@@ -6,6 +6,6 @@ def fib(x:int) -> int:
|
||||
|
||||
if __name__ == '__main__':
|
||||
t0 = tt()
|
||||
result = fib(25)
|
||||
result = fib(30)
|
||||
t1 = tt()
|
||||
print('cost: ',t1-t0, 'result:', result)
|
||||
|
||||
@@ -42,7 +42,7 @@ def resolveInstallPath(os: int):
|
||||
return default_path[os]
|
||||
|
||||
def getReleases():
|
||||
api_postfix = '/api/v1/repos/PuqiAR/Fig/releases'
|
||||
api_postfix = '/api/v1/repos/PuqiAR/Fig-TreeWalker/releases'
|
||||
api_url = GITEA_URL + api_postfix
|
||||
|
||||
rel = requests.get(api_url).text
|
||||
|
||||
32
README.md
32
README.md
@@ -35,13 +35,13 @@ Recommend view on Gitea Endpoint
|
||||
1. Clone the repository:
|
||||
|
||||
```bash
|
||||
git clone https://git.fig-lang.cn/PuqiAR/Fig.git
|
||||
git clone https://git.fig-lang.cn/PuqiAR/Fig-TreeWalker.git
|
||||
# Recommend
|
||||
```
|
||||
or
|
||||
|
||||
```bash
|
||||
git clone https://github.com/PuqiAR/Fig.git
|
||||
git clone https://github.com/PuqiAR/Fig-TreeWalker.git
|
||||
```
|
||||
|
||||
2. Navigate to the project directory:
|
||||
@@ -77,6 +77,32 @@ Replace `[file]` with the path to your input file.
|
||||
|
||||
## Performance Summary
|
||||
|
||||
**Version:** 0.4.3-alpha (Tree-walker Interpreter)
|
||||
**Test Hardware:** i5-13490F, Windows 11
|
||||
|
||||
**Execution Times for Fibonacci(30):**
|
||||
|
||||
* Naive Recursion: **5.47s** (~2.14× faster than 0.4.2-alpha)
|
||||
* Memoization: **0.55ms** (~1.69× faster than 0.4.2-alpha)
|
||||
* Iteration: **0.10ms** (~3.73× faster than 0.4.2-alpha)
|
||||
* Tail Recursion: **0.16ms** (~2.55× faster than 0.4.2-alpha)
|
||||
|
||||
**Visual Comparison:**
|
||||
|
||||
```
|
||||
Naive Recursion : █████████████████████████ 5.47s
|
||||
Memoization : ▉ 0.55ms
|
||||
Iteration : ▍ 0.10ms
|
||||
Tail Recursion : ▎ 0.16ms
|
||||
```
|
||||
|
||||
**Key Insight:** Algorithm choice still dominates performance, while 0.4.3-alpha shows significant improvements in function call and loop efficiency.
|
||||
|
||||
**Detailed Reports:** [English](./docs/benchmark_result/0.4.3-alpha/benchmark_result_en_0.4.3-alpha.pdf) | [中文](./docs/benchmark_result/0.4.3-alpha/benchmark_result_zh_0.4.3-alpha.pdf)
|
||||
|
||||
---
|
||||
## Older version reports...
|
||||
|
||||
**Version:** 0.4.2-alpha (Tree-walker Interpreter)
|
||||
**Test Hardware:** i5-13490F, Windows 11
|
||||
|
||||
@@ -96,7 +122,7 @@ Tail Recursion : ▎ 0.40ms
|
||||
|
||||
**Key Insight:** Algorithm choice dominates performance in this tree-walker implementation.
|
||||
|
||||
**Detailed Reports:** [English](./docs/benchmark_result/benchmark_result_en_0.4.2-alpha.md) | [中文](./docs/benchmark_result/benchmark_result_zh_0.4.2-alpha.md)
|
||||
**Detailed Reports:** [English](./docs/benchmark_result/0.4.2-alpha/benchmark_result_en_0.4.2-alpha.pdf) | [中文](./docs/benchmark_result/0.4.2-alpha/benchmark_result_zh_0.4.2-alpha.pdf)
|
||||
|
||||
|
||||
## Language Documents
|
||||
|
||||
@@ -27,13 +27,13 @@
|
||||
1. 克隆存储库:
|
||||
|
||||
```bash
|
||||
git clone https://git.fig-lang.cn/PuqiAR/Fig.git
|
||||
git clone https://git.fig-lang.cn/PuqiAR/Fig-TreeWalker.git
|
||||
# 推荐
|
||||
```
|
||||
|
||||
或
|
||||
```bash
|
||||
git clone https://github.com/PuqiAR/Fig.git
|
||||
git clone https://github.com/PuqiAR/Fig-TreeWalker.git
|
||||
```
|
||||
|
||||
|
||||
@@ -66,6 +66,33 @@ Fig 围绕几个核心原则设计:
|
||||
|
||||
## 性能概览
|
||||
|
||||
**版本:** 0.4.3-alpha (树遍历解释器)
|
||||
**测试硬件:** i5-13490F, Windows 11
|
||||
|
||||
**计算 Fibonacci(30) 的执行时间:**
|
||||
|
||||
* 朴素递归: **5.47秒** (~比0.4.2-alpha快2.14倍)
|
||||
* 记忆化: **0.55毫秒** (~比0.4.2-alpha快1.69倍)
|
||||
* 迭代: **0.10毫秒** (~比0.4.2-alpha快3.73倍)
|
||||
* 尾递归: **0.16毫秒** (~比0.4.2-alpha快2.55倍)
|
||||
|
||||
**可视化对比:**
|
||||
|
||||
```
|
||||
朴素递归 : █████████████████████████ 5.47秒
|
||||
记忆化递归 : ▉ 0.55毫秒
|
||||
迭代算法 : ▍ 0.10毫秒
|
||||
尾递归 : ▎ 0.16毫秒
|
||||
```
|
||||
|
||||
**核心发现:** 算法选择仍然主导性能,同时 0.4.3-alpha 在函数调用和循环效率上有明显提升。
|
||||
|
||||
**详细报告:** [English](./docs/benchmark_result/0.4.3-alpha/benchmark_result_en_0.4.3-alpha.pdf) | [中文](./docs/benchmark_result/0.4.3-alpha/benchmark_result_zh_0.4.3-alpha.pdf)
|
||||
|
||||
|
||||
---
|
||||
## 旧版本报告...
|
||||
|
||||
**版本:** 0.4.2-alpha (树遍历解释器)
|
||||
**测试硬件:** i5-13490F, Windows 11
|
||||
|
||||
@@ -85,7 +112,7 @@ Fig 围绕几个核心原则设计:
|
||||
|
||||
**核心发现:** 在此树遍历实现中,算法选择主导性能表现。
|
||||
|
||||
**详细报告:** [English](./docs/benchmark_result/benchmark_result_en_0.4.2-alpha.md) | [中文](./docs/benchmark_result/benchmark_result_zh_0.4.2-alpha.md)
|
||||
**详细报告:** [English](./docs/benchmark_result/0.4.2-alpha/benchmark_result_en_0.4.2-alpha.pdf) | [中文](./docs/benchmark_result/0.4.2-alpha/benchmark_result_zh_0.4.2-alpha.pdf)
|
||||
|
||||
|
||||
## 语言文档
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,163 @@
|
||||
# Fig Language Performance Benchmark Report
|
||||
|
||||
## Version: 0.4.3-alpha (Tree Traversal Interpreter)
|
||||
|
||||
### Preface
|
||||
|
||||
This report presents benchmark tests of Fibonacci algorithms in Fig v0.4.3-alpha tree traversal interpreter, compared with version 0.4.2-alpha. Results show significant performance improvements in function calls, loops, and recursion optimizations in 0.4.3-alpha, especially in iterative and tail-recursive implementations.
|
||||
|
||||
### Test Environment
|
||||
|
||||
* **CPU:** Intel Core i5-13490F
|
||||
* **Operating System:** Windows 11
|
||||
* **Interpreter:** Fig Tree Traversal Interpreter v0.4.3-alpha
|
||||
* **Test Date:** Current execution
|
||||
|
||||
### Executive Summary
|
||||
|
||||
This benchmark evaluates four different Fibonacci algorithm implementations in Fig, computing the 30th Fibonacci number (832,040). Algorithm choice remains the dominant factor for performance, while interpreter improvements in function call and loop efficiency are also reflected.
|
||||
|
||||
## Performance Results
|
||||
|
||||
### Latest Floating Execution Time (0.4.3-alpha)
|
||||
|
||||
| Algorithm | Time (s) | Time (ms) | Relative Speed |
|
||||
| --------------------------- | ----------- | ---------- | ---------------- |
|
||||
| `fib` (Naive Recursion) | 5.471 s | 5471.37 ms | 1.00× (baseline) |
|
||||
| `fib_memo` (Memoization) | 0.0005503 s | 0.5503 ms | 9,950× faster |
|
||||
| `fib_iter` (Iterative) | 0.0001004 s | 0.1004 ms | 54,500× faster |
|
||||
| `fib_tail` (Tail Recursion) | 0.0001573 s | 0.1573 ms | 34,800× faster |
|
||||
|
||||
### Comparison with 0.4.2-alpha
|
||||
|
||||
| Algorithm | 0.4.2-alpha Time | 0.4.3-alpha Time | Performance Gain |
|
||||
| --------------------------- | ---------------- | ---------------- | ---------------- |
|
||||
| `fib` (Naive Recursion) | 11.721 s | 5.471 s | ~2.14× |
|
||||
| `fib_memo` (Memoization) | 0.930 ms | 0.550 ms | ~1.69× |
|
||||
| `fib_iter` (Iterative) | 0.375 ms | 0.100 ms | ~3.73× |
|
||||
| `fib_tail` (Tail Recursion) | 0.401 ms | 0.157 ms | ~2.55× |
|
||||
|
||||
---
|
||||
|
||||
## Visual Performance Comparison (Horizontal Bar Placeholder)
|
||||
|
||||
0.4.2-alpha vs 0.4.3-alpha
|
||||
|
||||
**Note:** Each line contains two bars: gray for 0.4.2-alpha, blue for 0.4.3-alpha
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Algorithm</th><th>Performance Comparison</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>fib</td>
|
||||
<td>
|
||||
<span style="display:inline-block; background-color:#555555; width:350px; height:20px;"></span>
|
||||
<span style="display:inline-block;"> 11.72 s</span><br>
|
||||
<span style="display:inline-block; background-color:#1E90FF; width:165px; height:20px;"></span>
|
||||
<span style="display:inline-block;"> 5.47 s</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>fib_memo</td>
|
||||
<td>
|
||||
<span style="display:inline-block; background-color:#555555; width:28px; height:20px;"></span>
|
||||
<span style="display:inline-block;"> 0.93 ms</span><br>
|
||||
<span style="display:inline-block; background-color:#1E90FF; width:17px; height:20px;"></span>
|
||||
<span style="display:inline-block;"> 0.55 ms</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>fib_iter</td>
|
||||
<td>
|
||||
<span style="display:inline-block; background-color:#555555; width:11px; height:20px;"></span>
|
||||
<span style="display:inline-block;"> 0.375 ms</span><br>
|
||||
<span style="display:inline-block; background-color:#1E90FF; width:3px; height:20px;"></span>
|
||||
<span style="display:inline-block;"> 0.100 ms</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>fib_tail</td>
|
||||
<td>
|
||||
<span style="display:inline-block; background-color:#555555; width:12px; height:20px;"></span>
|
||||
<span style="display:inline-block;"> 0.401 ms</span><br>
|
||||
<span style="display:inline-block; background-color:#1E90FF; width:5px; height:20px;"></span>
|
||||
<span style="display:inline-block;"> 0.157 ms</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
---
|
||||
|
||||
## Detailed Analysis
|
||||
|
||||
### 1. Naive Recursion (`fib`)
|
||||
|
||||
* **Time:** 5.471 seconds (5471 ms)
|
||||
* **Algorithm Complexity:** O(2ⁿ) exponential
|
||||
* **Performance Notes:**
|
||||
|
||||
* Reduced by roughly half compared to 0.4.2-alpha
|
||||
* Function call overhead optimization effective, but exponential growth remains the bottleneck
|
||||
|
||||
### 2. Memoized Recursion (`fib_memo`)
|
||||
|
||||
* **Time:** 0.550 ms
|
||||
* **Algorithm Complexity:** O(n) linear
|
||||
* **Performance Notes:**
|
||||
|
||||
* Hash table / cache access efficiency improved
|
||||
* Sub-millisecond execution suitable for overlapping subproblems
|
||||
|
||||
### 3. Iterative (`fib_iter`)
|
||||
|
||||
* **Time:** 0.100 ms
|
||||
* **Algorithm Complexity:** O(n) linear
|
||||
* **Performance Notes:**
|
||||
|
||||
* Fastest implementation, ~3.7× improvement over 0.4.2-alpha
|
||||
* Loop and arithmetic operation optimization significant
|
||||
|
||||
### 4. Tail Recursion (`fib_tail`)
|
||||
|
||||
* **Time:** 0.157 ms
|
||||
* **Algorithm Complexity:** O(n) linear
|
||||
* **Performance Notes:**
|
||||
|
||||
* Slightly slower than iterative, ~2.5× improvement over 0.4.2-alpha
|
||||
* Tree traversal interpreter optimizations for recursion effective; TCO not implemented
|
||||
|
||||
---
|
||||
|
||||
## Technical Insights
|
||||
|
||||
* Function call overhead significantly reduced
|
||||
* Loop and arithmetic operations show greatest efficiency gains
|
||||
* Hash table / cache access highly efficient
|
||||
* Algorithm choice remains the dominant factor for performance
|
||||
|
||||
---
|
||||
|
||||
## Recommendations for Developers
|
||||
|
||||
1. Prioritize iterative solutions for performance-critical code
|
||||
2. Use memoization for recursion with overlapping subproblems
|
||||
3. Tail recursion is suitable for moderate depth, but TCO is not implemented
|
||||
4. Avoid exponential algorithms in interpreted code
|
||||
5. Benchmark different implementations, as algorithm choice dominates performance
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
Fig v0.4.3-alpha tree traversal interpreter shows significant improvements in function call and loop optimizations, particularly benefiting iterative and tail-recursive implementations.
|
||||
O(n) algorithms execute at sub-millisecond speeds, while exponential recursion remains limited. Overall interpreter performance is adequate for practical applications.
|
||||
|
||||
**Report Generated:** Based on actual benchmark execution
|
||||
**Interpreter Type:** Tree Traversal Interpreter
|
||||
**Version:** 0.4.3-alpha
|
||||
Binary file not shown.
@@ -0,0 +1,161 @@
|
||||
# Fig 语言性能基准测试报告
|
||||
|
||||
## 版本: 0.4.3-alpha (树遍历解释器)
|
||||
|
||||
### 前言
|
||||
|
||||
本报告基于 Fig v0.4.3-alpha 树遍历解释器对 Fibonacci 算法进行了基准测试,并与 0.4.2-alpha 版本对比。结果显示 0.4.3-alpha 在函数调用、循环和递归优化方面都有显著提升,尤其是迭代和尾递归实现性能改善明显。
|
||||
|
||||
### 测试环境
|
||||
|
||||
* **CPU:** Intel Core i5-13490F
|
||||
* **操作系统:** Windows 11
|
||||
* **编译器/解释器:** Fig 树遍历解释器 v0.4.3-alpha
|
||||
* **测试日期:** 当前测试执行
|
||||
|
||||
### 执行摘要
|
||||
|
||||
本基准测试评估了 Fig 中四种不同斐波那契算法实现的性能,计算第30个斐波那契数(832,040)。结果显示算法选择仍是性能主导因素,同时反映了解释器在函数调用和循环方面的优化效果。
|
||||
|
||||
## 性能结果
|
||||
|
||||
### 最新浮动执行时间 (0.4.3-alpha)
|
||||
|
||||
| 算法 | 时间(秒) | 时间(毫秒) | 相对速度 |
|
||||
| ------------------- | ----------- | ---------- | ------------ |
|
||||
| `fib` (朴素递归) | 5.471 s | 5471.37 ms | 1.00× (基准) |
|
||||
| `fib_memo` (记忆化) | 0.0005503 s | 0.5503 ms | 9,950× 更快 |
|
||||
| `fib_iter` (迭代) | 0.0001004 s | 0.1004 ms | 54,500× 更快 |
|
||||
| `fib_tail` (尾递归) | 0.0001573 s | 0.1573 ms | 34,800× 更快 |
|
||||
|
||||
### 与 0.4.2-alpha 对比
|
||||
|
||||
| 算法 | 0.4.2-alpha 时间 | 0.4.3-alpha 时间 | 性能提升倍数 |
|
||||
| ------------------- | ---------------- | ---------------- | ------------ |
|
||||
| `fib` (朴素递归) | 11.721 s | 5.471 s | ~2.14× |
|
||||
| `fib_memo` (记忆化) | 0.930 ms | 0.550 ms | ~1.69× |
|
||||
| `fib_iter` (迭代) | 0.375 ms | 0.100 ms | ~3.73× |
|
||||
| `fib_tail` (尾递归) | 0.401 ms | 0.157 ms | ~2.55× |
|
||||
|
||||
---
|
||||
|
||||
## 可视化性能对比(横向柱状图占位符)
|
||||
0.4.2-alpha vs 0.4.3-alpha
|
||||
|
||||
**说明:** 每行两条条形:灰色表示 0.4.2-alpha,蓝色表示 0.4.3-alpha
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>算法</th><th>性能对比</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>fib</td>
|
||||
<td>
|
||||
<span style="display:inline-block; background-color:#555555; width:350px; height:20px;"></span>
|
||||
<span style="display:inline-block;"> 11.72 s</span><br>
|
||||
<span style="display:inline-block; background-color:#1E90FF; width:165px; height:20px;"></span>
|
||||
<span style="display:inline-block;"> 5.47 s</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>fib_memo</td>
|
||||
<td>
|
||||
<span style="display:inline-block; background-color:#555555; width:28px; height:20px;"></span>
|
||||
<span style="display:inline-block;"> 0.93 ms</span><br>
|
||||
<span style="display:inline-block; background-color:#1E90FF; width:17px; height:20px;"></span>
|
||||
<span style="display:inline-block;"> 0.55 ms</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>fib_iter</td>
|
||||
<td>
|
||||
<span style="display:inline-block; background-color:#555555; width:11px; height:20px;"></span>
|
||||
<span style="display:inline-block;"> 0.375 ms</span><br>
|
||||
<span style="display:inline-block; background-color:#1E90FF; width:3px; height:20px;"></span>
|
||||
<span style="display:inline-block;"> 0.100 ms</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>fib_tail</td>
|
||||
<td>
|
||||
<span style="display:inline-block; background-color:#555555; width:12px; height:20px;"></span>
|
||||
<span style="display:inline-block;"> 0.401 ms</span><br>
|
||||
<span style="display:inline-block; background-color:#1E90FF; width:5px; height:20px;"></span>
|
||||
<span style="display:inline-block;"> 0.157 ms</span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
|
||||
## 详细分析
|
||||
|
||||
### 1. 朴素递归实现 (`fib`)
|
||||
|
||||
* **时间:** 5.471 秒 (5471 毫秒)
|
||||
* **算法复杂度:** O(2ⁿ) 指数级
|
||||
* **性能说明:**
|
||||
|
||||
* 相比 0.4.2-alpha 减少约一半
|
||||
* 函数调用开销优化有效,但指数增长仍是瓶颈
|
||||
|
||||
### 2. 记忆化递归实现 (`fib_memo`)
|
||||
|
||||
* **时间:** 0.550 毫秒
|
||||
* **算法复杂度:** O(n) 线性
|
||||
* **性能说明:**
|
||||
|
||||
* 哈希表/缓存访问效率进一步提高
|
||||
* 亚毫秒级执行,适合重叠子问题
|
||||
|
||||
### 3. 迭代实现 (`fib_iter`)
|
||||
|
||||
* **时间:** 0.100 毫秒
|
||||
* **算法复杂度:** O(n) 线性
|
||||
* **性能说明:**
|
||||
|
||||
* 最快实现,比 0.4.2-alpha 提升 3.7 倍
|
||||
* 循环和算术操作优化显著
|
||||
|
||||
### 4. 尾递归实现 (`fib_tail`)
|
||||
|
||||
* **时间:** 0.157 毫秒
|
||||
* **算法复杂度:** O(n) 线性
|
||||
* **性能说明:**
|
||||
|
||||
* 相比迭代略慢,但比 0.4.2-alpha 提升 2.5 倍
|
||||
* 树遍历解释器对递归调用优化有效,TCO 未实现
|
||||
|
||||
---
|
||||
|
||||
## 技术洞察
|
||||
|
||||
* 函数调用开销显著下降
|
||||
* 循环和算术操作效率提升最大
|
||||
* 哈希表/缓存访问效率高
|
||||
* 算法选择仍是性能主导
|
||||
|
||||
---
|
||||
|
||||
## 给开发者的建议
|
||||
|
||||
1. 性能关键代码优先迭代
|
||||
2. 重叠子问题递归使用记忆化
|
||||
3. 尾递归可用于中等深度,但 TCO 未实现
|
||||
4. 避免指数算法
|
||||
5. 基准测试不同实现,算法选择主导性能
|
||||
|
||||
---
|
||||
|
||||
## 结论
|
||||
|
||||
Fig v0.4.3-alpha 树遍历解释器在函数调用和循环优化上有显著提升,尤其是迭代和尾递归实现性能改善明显。
|
||||
O(n) 算法执行亚毫秒级,指数递归仍受限,但整体解释器性能在实际应用中已足够优秀。
|
||||
|
||||
**报告生成时间:** 基于实际基准测试执行
|
||||
**解释器类型:** 树遍历解释器
|
||||
**版本:** 0.4.3-alpha
|
||||
Binary file not shown.
@@ -162,9 +162,9 @@ Fig 语言的关键字包括:
|
||||
| -------- | ----------------------------------------------------------- |
|
||||
| 声明 | `func`, `var`, `const`, `struct`, `interface`, `import` |
|
||||
| 控制流 | `if`, `else`, `while`, `for`, `return`, `break`, `continue` |
|
||||
| 错误处理 | `try`, `catch`, `throw`, `Finally` |
|
||||
| 错误处理 | `try`, `catch`, `throw`, `finally` |
|
||||
| 逻辑运算 | `and`, `or`, `not` |
|
||||
| 类型相关 | `is`, `impl`, `new`, `public` |
|
||||
| 类型相关 | `is`, `as`, `impl`, `new`, `public` |
|
||||
|
||||
这些关键字不能用作标识符名称。
|
||||
|
||||
|
||||
@@ -24,26 +24,31 @@ namespace Fig::Ast
|
||||
Expression callee;
|
||||
FunctionArguments arg;
|
||||
|
||||
FunctionCallExpr() { type = AstType::FunctionCall; }
|
||||
|
||||
FunctionCallExpr(Expression _callee, FunctionArguments _arg) : callee(std::move(_callee)), arg(std::move(_arg))
|
||||
FunctionCallExpr()
|
||||
{
|
||||
type = AstType::FunctionCall;
|
||||
}
|
||||
|
||||
virtual String toString() override
|
||||
FunctionCallExpr(Expression _callee, FunctionArguments _arg) :
|
||||
callee(std::move(_callee)), arg(std::move(_arg))
|
||||
{
|
||||
String s = callee->toString();
|
||||
s += U"(";
|
||||
type = AstType::FunctionCall;
|
||||
}
|
||||
|
||||
virtual FString toString() override
|
||||
{
|
||||
FString s = callee->toString();
|
||||
s += u8"(";
|
||||
for (size_t i = 0; i < arg.argv.size(); ++i)
|
||||
{
|
||||
s += arg.argv[i]->toString();
|
||||
if (i + 1 < arg.argv.size()) s += U",";
|
||||
if (i + 1 < arg.argv.size())
|
||||
s += u8", ";
|
||||
}
|
||||
s += U")";
|
||||
s += u8")";
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
using FunctionCall = std::shared_ptr<FunctionCallExpr>;
|
||||
}; // namespace Fig::Ast
|
||||
}; // namespace Fig
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <Ast/astBase.hpp>
|
||||
#include <Ast/functionParameters.hpp>
|
||||
#include <Core/String.hpp>
|
||||
#include <Core/fig_string.hpp>
|
||||
#include <variant>
|
||||
|
||||
namespace Fig::Ast
|
||||
@@ -25,11 +25,20 @@ namespace Fig::Ast
|
||||
type = AstType::FunctionLiteralExpr;
|
||||
}
|
||||
|
||||
bool isExprMode() const { return std::holds_alternative<Expression>(body); }
|
||||
bool isExprMode() const
|
||||
{
|
||||
return std::holds_alternative<Expression>(body);
|
||||
}
|
||||
|
||||
BlockStatement &getBlockBody() { return std::get<BlockStatement>(body); }
|
||||
BlockStatement &getBlockBody()
|
||||
{
|
||||
return std::get<BlockStatement>(body);
|
||||
}
|
||||
|
||||
Expression &getExprBody() { return std::get<Expression>(body); }
|
||||
Expression &getExprBody()
|
||||
{
|
||||
return std::get<Expression>(body);
|
||||
}
|
||||
|
||||
~FunctionLiteralExprAst() = default;
|
||||
};
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Fig::Ast
|
||||
public:
|
||||
Expression structe;
|
||||
|
||||
std::vector<std::pair<String, Expression>> args;
|
||||
std::vector<std::pair<FString, Expression>> args;
|
||||
|
||||
enum class InitMode
|
||||
{
|
||||
@@ -25,9 +25,12 @@ namespace Fig::Ast
|
||||
.3 Person {name, age, sex};
|
||||
*/
|
||||
|
||||
InitExprAst() { type = AstType::InitExpr; }
|
||||
InitExprAst()
|
||||
{
|
||||
type = AstType::InitExpr;
|
||||
}
|
||||
|
||||
InitExprAst(Expression _structe, std::vector<std::pair<String, Expression>> _args, InitMode _initMode) :
|
||||
InitExprAst(Expression _structe, std::vector<std::pair<FString, Expression>> _args, InitMode _initMode) :
|
||||
structe(std::move(_structe)), args(std::move(_args)), initMode(_initMode)
|
||||
{
|
||||
type = AstType::InitExpr;
|
||||
|
||||
@@ -11,11 +11,15 @@ namespace Fig::Ast
|
||||
{
|
||||
public:
|
||||
Expression base;
|
||||
String member;
|
||||
FString member;
|
||||
|
||||
MemberExprAst() { type = AstType::MemberExpr; }
|
||||
MemberExprAst()
|
||||
{
|
||||
type = AstType::MemberExpr;
|
||||
}
|
||||
|
||||
MemberExprAst(Expression _base, String _member) : base(std::move(_base)), member(std::move(_member))
|
||||
MemberExprAst(Expression _base, FString _member) :
|
||||
base(std::move(_base)), member(std::move(_member))
|
||||
{
|
||||
type = AstType::MemberExpr;
|
||||
}
|
||||
@@ -29,9 +33,13 @@ namespace Fig::Ast
|
||||
Expression base;
|
||||
Expression index;
|
||||
|
||||
IndexExprAst() { type = AstType::IndexExpr; }
|
||||
IndexExprAst()
|
||||
{
|
||||
type = AstType::IndexExpr;
|
||||
}
|
||||
|
||||
IndexExprAst(Expression _base, Expression _index) : base(std::move(_base)), index(std::move(_index))
|
||||
IndexExprAst(Expression _base, Expression _index) :
|
||||
base(std::move(_base)), index(std::move(_index))
|
||||
{
|
||||
type = AstType::IndexExpr;
|
||||
}
|
||||
|
||||
@@ -7,10 +7,18 @@ namespace Fig::Ast
|
||||
class VarExprAst final : public ExpressionAst
|
||||
{
|
||||
public:
|
||||
const String name;
|
||||
VarExprAst() : name(U"") { type = AstType::VarExpr; }
|
||||
VarExprAst(String _name) : name(std::move(_name)) { type = AstType::VarExpr; }
|
||||
const FString name;
|
||||
VarExprAst() :
|
||||
name(u8"")
|
||||
{
|
||||
type = AstType::VarExpr;
|
||||
}
|
||||
VarExprAst(FString _name) :
|
||||
name(std::move(_name))
|
||||
{
|
||||
type = AstType::VarExpr;
|
||||
}
|
||||
};
|
||||
|
||||
using VarExpr = std::shared_ptr<VarExprAst>;
|
||||
}; // namespace Fig::Ast
|
||||
}; // namespace Fig
|
||||
@@ -9,26 +9,34 @@ namespace Fig::Ast
|
||||
public:
|
||||
Expression value;
|
||||
|
||||
ThrowSt() { type = AstType::ThrowSt; }
|
||||
ThrowSt()
|
||||
{
|
||||
type = AstType::ThrowSt;
|
||||
}
|
||||
|
||||
ThrowSt(Expression _value) : value(std::move(_value)) { type = AstType::ThrowSt; }
|
||||
ThrowSt(Expression _value) :
|
||||
value(std::move(_value))
|
||||
{
|
||||
type = AstType::ThrowSt;
|
||||
}
|
||||
};
|
||||
using Throw = std::shared_ptr<ThrowSt>;
|
||||
|
||||
struct Catch
|
||||
{
|
||||
String errVarName;
|
||||
FString errVarName;
|
||||
bool hasType = false;
|
||||
String errVarType;
|
||||
FString errVarType;
|
||||
BlockStatement body;
|
||||
|
||||
Catch() {}
|
||||
Catch(String _errVarName, String _errVarType, BlockStatement _body) :
|
||||
Catch(FString _errVarName, FString _errVarType, BlockStatement _body) :
|
||||
errVarName(std::move(_errVarName)), errVarType(std::move(_errVarType)), body(std::move(_body))
|
||||
{
|
||||
hasType = true;
|
||||
}
|
||||
Catch(String _errVarName, BlockStatement _body) : errVarName(std::move(_errVarName)), body(std::move(_body))
|
||||
Catch(FString _errVarName, BlockStatement _body) :
|
||||
errVarName(std::move(_errVarName)), body(std::move(_body))
|
||||
{
|
||||
hasType = false;
|
||||
}
|
||||
@@ -41,7 +49,10 @@ namespace Fig::Ast
|
||||
std::vector<Catch> catches;
|
||||
BlockStatement finallyBlock = nullptr;
|
||||
|
||||
TrySt() { type = AstType::TrySt; }
|
||||
TrySt()
|
||||
{
|
||||
type = AstType::TrySt;
|
||||
}
|
||||
TrySt(BlockStatement _body, std::vector<Catch> _catches, BlockStatement _finallyBlock) :
|
||||
body(std::move(_body)), catches(std::move(_catches)), finallyBlock(std::move(_finallyBlock))
|
||||
{
|
||||
|
||||
@@ -20,15 +20,17 @@ namespace Fig::Ast
|
||||
class FunctionDefSt final : public StatementAst // for definition
|
||||
{
|
||||
public:
|
||||
String name;
|
||||
FString name;
|
||||
FunctionParameters paras;
|
||||
bool isPublic;
|
||||
Expression retType;
|
||||
BlockStatement body;
|
||||
|
||||
FunctionDefSt() { type = AstType::FunctionDefSt; }
|
||||
FunctionDefSt(
|
||||
String _name, FunctionParameters _paras, bool _isPublic, Expression _retType, BlockStatement _body)
|
||||
FunctionDefSt()
|
||||
{
|
||||
type = AstType::FunctionDefSt;
|
||||
}
|
||||
FunctionDefSt(FString _name, FunctionParameters _paras, bool _isPublic, Expression _retType, BlockStatement _body)
|
||||
{
|
||||
type = AstType::FunctionDefSt;
|
||||
|
||||
@@ -40,4 +42,4 @@ namespace Fig::Ast
|
||||
}
|
||||
};
|
||||
using FunctionDef = std::shared_ptr<FunctionDefSt>;
|
||||
}; // namespace Fig::Ast
|
||||
}; // namespace Fig
|
||||
@@ -8,9 +8,19 @@ namespace Fig::Ast
|
||||
{
|
||||
public:
|
||||
BlockStatement body;
|
||||
ElseSt() { type = AstType::ElseSt; }
|
||||
ElseSt(BlockStatement _body) : body(_body) { type = AstType::ElseSt; }
|
||||
virtual String toString() override { return String(std::format("<Else Ast at {}:{}>", aai.line, aai.column)); }
|
||||
ElseSt()
|
||||
{
|
||||
type = AstType::ElseSt;
|
||||
}
|
||||
ElseSt(BlockStatement _body) :
|
||||
body(_body)
|
||||
{
|
||||
type = AstType::ElseSt;
|
||||
}
|
||||
virtual FString toString() override
|
||||
{
|
||||
return FString(std::format("<Else Ast at {}:{}>", aai.line, aai.column));
|
||||
}
|
||||
};
|
||||
using Else = std::shared_ptr<ElseSt>;
|
||||
class ElseIfSt final : public StatementAst
|
||||
@@ -18,14 +28,19 @@ namespace Fig::Ast
|
||||
public:
|
||||
Expression condition;
|
||||
BlockStatement body;
|
||||
ElseIfSt() { type = AstType::ElseIfSt; }
|
||||
ElseIfSt(Expression _condition, BlockStatement _body) : condition(_condition), body(_body)
|
||||
ElseIfSt()
|
||||
{
|
||||
type = AstType::ElseIfSt;
|
||||
}
|
||||
virtual String toString() override
|
||||
ElseIfSt(Expression _condition,
|
||||
BlockStatement _body) :
|
||||
condition(_condition), body(_body)
|
||||
{
|
||||
return String(std::format("<ElseIf Ast at {}:{}>", aai.line, aai.column));
|
||||
type = AstType::ElseIfSt;
|
||||
}
|
||||
virtual FString toString() override
|
||||
{
|
||||
return FString(std::format("<ElseIf Ast at {}:{}>", aai.line, aai.column));
|
||||
}
|
||||
};
|
||||
using ElseIf = std::shared_ptr<ElseIfSt>;
|
||||
@@ -36,12 +51,18 @@ namespace Fig::Ast
|
||||
BlockStatement body;
|
||||
std::vector<ElseIf> elifs;
|
||||
Else els;
|
||||
IfSt() { type = AstType::IfSt; }
|
||||
IfSt(Expression _condition, BlockStatement _body, std::vector<ElseIf> _elifs, Else _els) :
|
||||
IfSt()
|
||||
{
|
||||
type = AstType::IfSt;
|
||||
}
|
||||
IfSt(Expression _condition,
|
||||
BlockStatement _body,
|
||||
std::vector<ElseIf> _elifs,
|
||||
Else _els) :
|
||||
condition(_condition), body(_body), elifs(_elifs), els(_els)
|
||||
{
|
||||
type = AstType::IfSt;
|
||||
}
|
||||
};
|
||||
using If = std::shared_ptr<IfSt>;
|
||||
}; // namespace Fig::Ast
|
||||
}; // namespace Fig
|
||||
@@ -17,7 +17,7 @@ namespace Fig::Ast
|
||||
*/
|
||||
struct ImplementMethod
|
||||
{
|
||||
String name;
|
||||
FString name;
|
||||
FunctionParameters paras;
|
||||
BlockStatement body;
|
||||
};
|
||||
@@ -25,14 +25,17 @@ namespace Fig::Ast
|
||||
class ImplementAst final : public StatementAst
|
||||
{
|
||||
public:
|
||||
String interfaceName;
|
||||
String structName;
|
||||
FString interfaceName;
|
||||
FString structName;
|
||||
|
||||
std::vector<ImplementMethod> methods;
|
||||
|
||||
ImplementAst() { type = AstType::ImplementSt; }
|
||||
ImplementAst()
|
||||
{
|
||||
type = AstType::ImplementSt;
|
||||
}
|
||||
|
||||
ImplementAst(String _interfaceName, String _structName, std::vector<ImplementMethod> _methods) :
|
||||
ImplementAst(FString _interfaceName, FString _structName, std::vector<ImplementMethod> _methods) :
|
||||
interfaceName(std::move(_interfaceName)), structName(std::move(_structName)), methods(std::move(_methods))
|
||||
{
|
||||
type = AstType::ImplementSt;
|
||||
@@ -40,4 +43,4 @@ namespace Fig::Ast
|
||||
};
|
||||
|
||||
using Implement = std::shared_ptr<ImplementAst>;
|
||||
}; // namespace Fig::Ast
|
||||
};
|
||||
@@ -14,14 +14,17 @@ namespace Fig::Ast
|
||||
class ImportSt final : public StatementAst
|
||||
{
|
||||
public:
|
||||
std::vector<String> path;
|
||||
std::vector<String> names;
|
||||
std::vector<FString> path;
|
||||
std::vector<FString> names;
|
||||
|
||||
String rename;
|
||||
FString rename;
|
||||
|
||||
ImportSt() { type = AstType::ImportSt; }
|
||||
ImportSt()
|
||||
{
|
||||
type = AstType::ImportSt;
|
||||
}
|
||||
|
||||
ImportSt(std::vector<String> _path, std::vector<String> _names, const String &_rename) :
|
||||
ImportSt(std::vector<FString> _path, std::vector<FString> _names, const FString &_rename) :
|
||||
path(std::move(_path)), names(std::move(_names)), rename(_rename)
|
||||
{
|
||||
type = AstType::ImportSt;
|
||||
@@ -29,4 +32,4 @@ namespace Fig::Ast
|
||||
};
|
||||
|
||||
using Import = std::shared_ptr<ImportSt>;
|
||||
}; // namespace Fig::Ast
|
||||
};
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <Ast/functionParameters.hpp>
|
||||
#include <Ast/astBase.hpp>
|
||||
|
||||
|
||||
namespace Fig::Ast
|
||||
{
|
||||
/*
|
||||
@@ -19,33 +20,52 @@ namespace Fig::Ast
|
||||
|
||||
*/
|
||||
|
||||
|
||||
struct InterfaceMethod
|
||||
{
|
||||
String name;
|
||||
FString name;
|
||||
FunctionParameters paras;
|
||||
Expression returnType;
|
||||
|
||||
BlockStatement defaultBody = nullptr; // nullptr is non-default func
|
||||
|
||||
bool hasDefaultBody() const { return defaultBody != nullptr; }
|
||||
bool hasDefaultBody() const
|
||||
{
|
||||
return defaultBody != nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
interface IO : Writable + Readable
|
||||
{
|
||||
}
|
||||
|
||||
interface XX
|
||||
{
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
class InterfaceDefAst final : public StatementAst
|
||||
{
|
||||
public:
|
||||
String name;
|
||||
FString name;
|
||||
std::vector<Expression> bundles;
|
||||
std::vector<InterfaceMethod> methods;
|
||||
std::vector<String> parents; // Feature, NOT NOW
|
||||
std::vector<FString> parents; // Feature, NOT NOW
|
||||
bool isPublic;
|
||||
|
||||
InterfaceDefAst() { type = AstType::InterfaceDefSt; }
|
||||
InterfaceDefAst()
|
||||
{
|
||||
type = AstType::InterfaceDefSt;
|
||||
}
|
||||
|
||||
InterfaceDefAst(String _name, std::vector<InterfaceMethod> _methods, bool _isPublic) :
|
||||
name(std::move(_name)), methods(std::move(_methods)), isPublic(_isPublic)
|
||||
InterfaceDefAst(FString _name, std::vector<Expression> _bundles, std::vector<InterfaceMethod> _methods, bool _isPublic) :
|
||||
name(std::move(_name)), bundles(std::move(_bundles)), methods(std::move(_methods)), isPublic(_isPublic)
|
||||
{
|
||||
type = AstType::InterfaceDefSt;
|
||||
}
|
||||
};
|
||||
|
||||
using InterfaceDef = std::shared_ptr<InterfaceDefAst>;
|
||||
}; // namespace Fig::Ast
|
||||
};
|
||||
@@ -11,16 +11,13 @@ namespace Fig::Ast
|
||||
struct StructDefField
|
||||
{
|
||||
AccessModifier am;
|
||||
String fieldName;
|
||||
FString fieldName;
|
||||
Expression declaredType;
|
||||
Expression defaultValueExpr;
|
||||
|
||||
StructDefField() {}
|
||||
StructDefField(AccessModifier _am, String _fieldName, Expression _declaredType, Expression _defaultValueExpr) :
|
||||
am(std::move(_am)),
|
||||
fieldName(std::move(_fieldName)),
|
||||
declaredType(std::move(_declaredType)),
|
||||
defaultValueExpr(std::move(_defaultValueExpr))
|
||||
StructDefField(AccessModifier _am, FString _fieldName, Expression _declaredType, Expression _defaultValueExpr) :
|
||||
am(std::move(_am)), fieldName(std::move(_fieldName)), declaredType(std::move(_declaredType)), defaultValueExpr(std::move(_defaultValueExpr))
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -28,12 +25,15 @@ namespace Fig::Ast
|
||||
{
|
||||
public:
|
||||
bool isPublic;
|
||||
const String name;
|
||||
const FString name;
|
||||
const std::vector<StructDefField> fields; // field name (:type name = default value expression)
|
||||
// name / name: String / name: String = "Fig"
|
||||
const BlockStatement body;
|
||||
StructDefSt() { type = AstType::StructSt; }
|
||||
StructDefSt(bool _isPublic, String _name, std::vector<StructDefField> _fields, BlockStatement _body) :
|
||||
StructDefSt()
|
||||
{
|
||||
type = AstType::StructSt;
|
||||
}
|
||||
StructDefSt(bool _isPublic, FString _name, std::vector<StructDefField> _fields, BlockStatement _body) :
|
||||
isPublic(std::move(_isPublic)), name(std::move(_name)), fields(std::move(_fields)), body(std::move(_body))
|
||||
{
|
||||
type = AstType::StructSt;
|
||||
@@ -41,4 +41,4 @@ namespace Fig::Ast
|
||||
};
|
||||
|
||||
using StructDef = std::shared_ptr<StructDefSt>;
|
||||
}; // namespace Fig::Ast
|
||||
}; // namespace Fig
|
||||
@@ -10,8 +10,8 @@ namespace Fig::Ast
|
||||
public:
|
||||
bool isPublic;
|
||||
bool isConst;
|
||||
String name;
|
||||
// String typeName;
|
||||
FString name;
|
||||
// FString typeName;
|
||||
Expression declaredType;
|
||||
Expression expr;
|
||||
|
||||
@@ -24,8 +24,7 @@ namespace Fig::Ast
|
||||
expr = nullptr;
|
||||
followupType = false;
|
||||
}
|
||||
VarDefAst(
|
||||
bool _isPublic, bool _isConst, String _name, Expression _declaredType, Expression _expr, bool _followupType)
|
||||
VarDefAst(bool _isPublic, bool _isConst, FString _name, Expression _declaredType, Expression _expr, bool _followupType)
|
||||
{
|
||||
type = AstType::VarDefSt;
|
||||
isPublic = _isPublic;
|
||||
@@ -38,4 +37,4 @@ namespace Fig::Ast
|
||||
};
|
||||
|
||||
using VarDef = std::shared_ptr<VarDefAst>;
|
||||
} // namespace Fig::Ast
|
||||
} // namespace Fig
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <Token/token.hpp>
|
||||
#include <Core/String.hpp>
|
||||
#include <Core/fig_string.hpp>
|
||||
|
||||
#include <format>
|
||||
#include <unordered_map>
|
||||
@@ -66,43 +66,43 @@ namespace Fig::Ast
|
||||
ThrowSt,
|
||||
};
|
||||
|
||||
// static const std::unordered_map<AstType, String> astTypeToString{
|
||||
// static const std::unordered_map<AstType, FString> astTypeToString{
|
||||
// /* Base Class */
|
||||
// {AstType::_AstBase, String(U"Ast")},
|
||||
// {AstType::StatementBase, String(U"Statement")},
|
||||
// {AstType::ExpressionBase, String(U"Expression")},
|
||||
// {AstType::_AstBase, FString(u8"Ast")},
|
||||
// {AstType::StatementBase, FString(u8"Statement")},
|
||||
// {AstType::ExpressionBase, FString(u8"Expression")},
|
||||
// /* Expression */
|
||||
// {AstType::ValueExpr, String(U"ValueExpr")},
|
||||
// {AstType::LambdaExpr, String(U"LambdaExpr")},
|
||||
// {AstType::UnaryExpr, String(U"UnaryExpr")},
|
||||
// {AstType::BinaryExpr, String(U"BinaryExpr")},
|
||||
// {AstType::TernaryExpr, String(U"TernaryExpr")},
|
||||
// {AstType::ValueExpr, FString(u8"ValueExpr")},
|
||||
// {AstType::LambdaExpr, FString(u8"LambdaExpr")},
|
||||
// {AstType::UnaryExpr, FString(u8"UnaryExpr")},
|
||||
// {AstType::BinaryExpr, FString(u8"BinaryExpr")},
|
||||
// {AstType::TernaryExpr, FString(u8"TernaryExpr")},
|
||||
|
||||
// {AstType::InitExpr, String(U"InitExpr")},
|
||||
// {AstType::InitExpr, FString(u8"InitExpr")},
|
||||
|
||||
// /* Statement */
|
||||
// {AstType::BlockStatement, String(U"BlockStatement")},
|
||||
// {AstType::BlockStatement, FString(u8"BlockStatement")},
|
||||
|
||||
// {AstType::VarDefSt, String(U"VarSt")},
|
||||
// {AstType::FunctionDefSt, String(U"FunctionDefSt")},
|
||||
// {AstType::StructSt, String(U"StructSt")},
|
||||
// {AstType::ImplementSt, String(U"ImplementSt")},
|
||||
// {AstType::VarDefSt, FString(u8"VarSt")},
|
||||
// {AstType::FunctionDefSt, FString(u8"FunctionDefSt")},
|
||||
// {AstType::StructSt, FString(u8"StructSt")},
|
||||
// {AstType::ImplementSt, FString(u8"ImplementSt")},
|
||||
|
||||
// {AstType::IfSt, String(U"IfSt")},
|
||||
// {AstType::ElseSt, String(U"ElseSt")},
|
||||
// {AstType::ElseIfSt, String(U"ElseIfSt")},
|
||||
// {AstType::VarAssignSt, String(U"VarAssignSt")},
|
||||
// {AstType::WhileSt, String(U"WhileSt")},
|
||||
// {AstType::ReturnSt, String(U"ReturnSt")},
|
||||
// {AstType::BreakSt, String(U"BreakSt")},
|
||||
// {AstType::ContinueSt, String(U"ContinueSt")},
|
||||
// {AstType::IfSt, FString(u8"IfSt")},
|
||||
// {AstType::ElseSt, FString(u8"ElseSt")},
|
||||
// {AstType::ElseIfSt, FString(u8"ElseIfSt")},
|
||||
// {AstType::VarAssignSt, FString(u8"VarAssignSt")},
|
||||
// {AstType::WhileSt, FString(u8"WhileSt")},
|
||||
// {AstType::ReturnSt, FString(u8"ReturnSt")},
|
||||
// {AstType::BreakSt, FString(u8"BreakSt")},
|
||||
// {AstType::ContinueSt, FString(u8"ContinueSt")},
|
||||
// };
|
||||
|
||||
struct AstAddressInfo
|
||||
{
|
||||
size_t line, column;
|
||||
std::shared_ptr<String> sourcePath;
|
||||
std::shared_ptr<std::vector<String>> sourceLines;
|
||||
std::shared_ptr<FString> sourcePath;
|
||||
std::shared_ptr<std::vector<FString>> sourceLines;
|
||||
};
|
||||
|
||||
class _AstBase
|
||||
@@ -122,14 +122,14 @@ namespace Fig::Ast
|
||||
|
||||
void setAAI(AstAddressInfo _aai) { aai = std::move(_aai); }
|
||||
|
||||
virtual String typeName()
|
||||
virtual FString typeName()
|
||||
{
|
||||
const auto &name = magic_enum::enum_name(type);
|
||||
return String(std::string(name.data(), name.length()));
|
||||
return FString::fromBasicString(std::string(name.data(), name.length()));
|
||||
}
|
||||
virtual String toString()
|
||||
virtual FString toString()
|
||||
{
|
||||
return String(std::format("<Base Ast '{}' at {}:{}>", typeName().toBasicString(), aai.line, aai.column));
|
||||
return FString(std::format("<Base Ast '{}' at {}:{}>", typeName().toBasicString(), aai.line, aai.column));
|
||||
}
|
||||
|
||||
AstAddressInfo getAAI() { return aai; }
|
||||
@@ -144,9 +144,9 @@ namespace Fig::Ast
|
||||
using _AstBase::operator=;
|
||||
StatementAst() { type = AstType::StatementBase; }
|
||||
|
||||
virtual String toString() override
|
||||
virtual FString toString() override
|
||||
{
|
||||
return String(std::format("<Stmt Ast '{}' at {}:{}>", typeName().toBasicString(), aai.line, aai.column));
|
||||
return FString(std::format("<Stmt Ast '{}' at {}:{}>", typeName().toBasicString(), aai.line, aai.column));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -155,9 +155,9 @@ namespace Fig::Ast
|
||||
public:
|
||||
EofStmt() { type = AstType::StatementBase; }
|
||||
|
||||
virtual String toString() override
|
||||
virtual FString toString() override
|
||||
{
|
||||
return String(std::format("<EOF Stmt at {}:{}>", aai.line, aai.column));
|
||||
return FString(std::format("<EOF Stmt at {}:{}>", aai.line, aai.column));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -168,9 +168,9 @@ namespace Fig::Ast
|
||||
using _AstBase::operator=;
|
||||
ExpressionAst() { type = AstType::ExpressionBase; }
|
||||
|
||||
virtual String toString() override
|
||||
virtual FString toString() override
|
||||
{
|
||||
return String(std::format("<Expr Ast '{}' at {}:{}>", typeName().toBasicString(), aai.line, aai.column));
|
||||
return FString(std::format("<Expr Ast '{}' at {}:{}>", typeName().toBasicString(), aai.line, aai.column));
|
||||
}
|
||||
};
|
||||
enum class Operator : uint8_t
|
||||
@@ -326,10 +326,10 @@ namespace Fig::Ast
|
||||
std::vector<Statement> stmts;
|
||||
BlockStatementAst() { type = AstType::BlockStatement; }
|
||||
BlockStatementAst(std::vector<Statement> _stmts) : stmts(std::move(_stmts)) { type = AstType::BlockStatement; }
|
||||
virtual String typeName() override { return String(U"BlockStatement"); }
|
||||
virtual String toString() override
|
||||
virtual FString typeName() override { return FString(u8"BlockStatement"); }
|
||||
virtual FString toString() override
|
||||
{
|
||||
return String(std::format("<StmtAst '{}' at {}:{}>", typeName().toBasicString(), aai.line, aai.column));
|
||||
return FString(std::format("<StmtAst '{}' at {}:{}>", typeName().toBasicString(), aai.line, aai.column));
|
||||
}
|
||||
virtual ~BlockStatementAst() = default;
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <Ast/astBase.hpp>
|
||||
#include <Evaluator/Value/Type.hpp>
|
||||
#include <Core/String.hpp>
|
||||
#include <Core/fig_string.hpp>
|
||||
|
||||
#include <format>
|
||||
|
||||
@@ -17,15 +17,15 @@ namespace Fig::Ast
|
||||
func test2(dp1 = 10, dp2:String = "default parameter 2")
|
||||
*/
|
||||
|
||||
using PosParasType = std::vector<std::pair<String, Expression>>;
|
||||
using PosParasType = std::vector<std::pair<FString, Expression>>;
|
||||
// name type exp
|
||||
using DefParasType = std::vector<std::pair<String, std::pair<Expression, Expression>>>;
|
||||
using DefParasType = std::vector<std::pair<FString, std::pair<Expression, Expression>>>;
|
||||
// name type exp default value
|
||||
|
||||
PosParasType posParas;
|
||||
DefParasType defParas; // default parameters
|
||||
|
||||
String variadicPara;
|
||||
FString variadicPara;
|
||||
bool variadic = false;
|
||||
|
||||
FunctionParameters()
|
||||
@@ -36,7 +36,7 @@ namespace Fig::Ast
|
||||
posParas = std::move(_posParas);
|
||||
defParas = std::move(_defParas);
|
||||
}
|
||||
FunctionParameters(String _variadicPara)
|
||||
FunctionParameters(FString _variadicPara)
|
||||
{
|
||||
variadicPara = std::move(_variadicPara);
|
||||
variadic = true;
|
||||
@@ -52,46 +52,46 @@ namespace Fig::Ast
|
||||
return posParas == other.posParas && defParas == other.defParas && variadicPara == other.variadicPara && variadic == other.variadic;
|
||||
}
|
||||
|
||||
String toString() const
|
||||
FString toString() const
|
||||
{
|
||||
if (variadic)
|
||||
{
|
||||
return String(variadicPara + U"...");
|
||||
return FString(variadicPara + u8"...");
|
||||
}
|
||||
const auto posParasToString = [this]() {
|
||||
String out;
|
||||
FString out;
|
||||
for (auto &p : posParas)
|
||||
{
|
||||
out += p.first;
|
||||
if (p.second != nullptr)
|
||||
{
|
||||
out += String(String(U":") + p.second->toString());
|
||||
out += FString(u8":" + p.second->toString());
|
||||
}
|
||||
out += U",";
|
||||
out += u8",";
|
||||
}
|
||||
out.pop_back();
|
||||
return out;
|
||||
};
|
||||
const auto defParasToString = [this]() {
|
||||
String out;
|
||||
FString out;
|
||||
for (auto &p : defParas)
|
||||
{
|
||||
out += p.first;
|
||||
if (p.second.first != nullptr)
|
||||
{
|
||||
out += String(String(U":") + p.second.first->toString());
|
||||
out += FString(u8":" + p.second.first->toString());
|
||||
}
|
||||
if (p.second.second != nullptr)
|
||||
{
|
||||
out += U"=";
|
||||
out += u8"=";
|
||||
out += p.second.second->toString();
|
||||
}
|
||||
out += U",";
|
||||
out += u8",";
|
||||
}
|
||||
out.pop_back();
|
||||
return out;
|
||||
};
|
||||
return String(std::format("{},{}", posParasToString().toBasicString(), defParasToString().toBasicString()));
|
||||
return FString(std::format("{},{}", posParasToString().toBasicString(), defParasToString().toBasicString()));
|
||||
}
|
||||
};
|
||||
} // namespace Fig::Ast
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <Core/String.hpp>
|
||||
#include <Core/fig_string.hpp>
|
||||
#include <Bytecode/Instruction.hpp>
|
||||
#include <Evaluator/Value/value.hpp>
|
||||
|
||||
@@ -10,8 +10,8 @@ namespace Fig
|
||||
{
|
||||
struct ChunkAddressInfo
|
||||
{
|
||||
String sourcePath;
|
||||
std::vector<String> sourceLines;
|
||||
FString sourcePath;
|
||||
std::vector<FString> sourceLines;
|
||||
};
|
||||
|
||||
struct Chunk
|
||||
@@ -22,4 +22,4 @@ namespace Fig
|
||||
std::vector<InstructionAddressInfo> instructions_addr; // 下标和ins对齐,表示每个Instruction对应的地址
|
||||
ChunkAddressInfo addr; // 代码块独立Addr
|
||||
};
|
||||
}; // namespace Fig
|
||||
};
|
||||
@@ -8,15 +8,15 @@ namespace Fig
|
||||
{
|
||||
using AddressableError::AddressableError;
|
||||
|
||||
virtual String toString() const override
|
||||
virtual FString toString() const override
|
||||
{
|
||||
std::string msg = std::format("[CompileError] {} in [{}] {}",
|
||||
this->message.toBasicString(),
|
||||
this->src_loc.file_name(),
|
||||
this->src_loc.function_name());
|
||||
return String(msg);
|
||||
return FString(msg);
|
||||
}
|
||||
|
||||
virtual String getErrorType() const override { return String(U"\1"); }
|
||||
virtual FString getErrorType() const override { return FString(u8"CompileError"); }
|
||||
};
|
||||
};
|
||||
}; // namespace Fig
|
||||
@@ -7,9 +7,10 @@ namespace Fig
|
||||
{
|
||||
struct CompiledFunction
|
||||
{
|
||||
|
||||
Chunk chunk; // 函数代码块
|
||||
|
||||
String name; // 函数名
|
||||
FString name; // 函数名
|
||||
uint64_t posArgCount; // 位置参数数量
|
||||
uint64_t defArgCount; // 默认参数数量
|
||||
bool variadicPara; // 可变参数(是:最后为可变,否:不可变)
|
||||
@@ -17,4 +18,4 @@ namespace Fig
|
||||
uint64_t localCount; // 局部变量数量(不包括参数)
|
||||
uint64_t slotCount; // = 总参数数量 + 局部变量数量
|
||||
};
|
||||
}; // namespace Fig
|
||||
};
|
||||
@@ -56,7 +56,7 @@ int main()
|
||||
|
||||
CompiledFunction fib_fn{
|
||||
{},
|
||||
U"\1",
|
||||
u8"fib",
|
||||
1, // posArgCount
|
||||
0,
|
||||
false,
|
||||
@@ -87,7 +87,7 @@ int main()
|
||||
|
||||
Chunk main_chunk{main_ins, main_consts, {}, ChunkAddressInfo{}};
|
||||
|
||||
CompiledFunction main_fn{main_chunk, U"\1", 0, 0, false, 0, 0};
|
||||
CompiledFunction main_fn{main_chunk, u8"main", 0, 0, false, 0, 0};
|
||||
|
||||
CallFrame entry{.ip = 0, .base = 0, .fn = main_fn};
|
||||
|
||||
|
||||
@@ -1,312 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
class CharUtils
|
||||
{
|
||||
public:
|
||||
static bool isDigit(char32_t c) { return c >= U'0' && c <= U'9'; }
|
||||
|
||||
static bool isAlpha(char32_t c)
|
||||
{
|
||||
// ASCII字母
|
||||
if ((c >= U'A' && c <= U'Z') || (c >= U'a' && c <= U'z')) return true;
|
||||
|
||||
// Unicode字母检查
|
||||
// Ll - 小写字母
|
||||
// Lu - 大写字母
|
||||
// Lt - 标题字母
|
||||
// Lm - 修饰字母
|
||||
// Lo - 其他字母
|
||||
|
||||
// 基本拉丁字母
|
||||
if ((c >= 0x00C0 && c <= 0x00D6) || // Latin-1 Supplement
|
||||
(c >= 0x00D8 && c <= 0x00F6) || // Latin-1 Supplement
|
||||
(c >= 0x00F8 && c <= 0x02AF) || // Latin Extended
|
||||
(c >= 0x0370 && c <= 0x052F) || // Greek, Cyrillic
|
||||
(c >= 0x0591 && c <= 0x05F4) || // Hebrew
|
||||
(c >= 0x0600 && c <= 0x06FF) || // Arabic
|
||||
(c >= 0x0700 && c <= 0x0D7F) || // Syriac, Thaana, Devanagari, etc.
|
||||
(c >= 0x0E00 && c <= 0x0E7F) || // Thai
|
||||
(c >= 0x0F00 && c <= 0x0FFF) || // Tibetan
|
||||
(c >= 0x1000 && c <= 0x109F) || // Myanmar
|
||||
(c >= 0x10A0 && c <= 0x10FF) || // Georgian
|
||||
(c >= 0x1100 && c <= 0x11FF) || // Hangul Jamo
|
||||
(c >= 0x1200 && c <= 0x137F) || // Ethiopic
|
||||
(c >= 0x13A0 && c <= 0x13FF) || // Cherokee
|
||||
(c >= 0x1400 && c <= 0x167F) || // Unified Canadian Aboriginal Syllabics
|
||||
(c >= 0x1680 && c <= 0x169F) || // Ogham
|
||||
(c >= 0x16A0 && c <= 0x16FF) || // Runic
|
||||
(c >= 0x1700 && c <= 0x171F) || // Tagalog
|
||||
(c >= 0x1720 && c <= 0x173F) || // Hanunoo
|
||||
(c >= 0x1740 && c <= 0x175F) || // Buhid
|
||||
(c >= 0x1760 && c <= 0x177F) || // Tagbanwa
|
||||
(c >= 0x1780 && c <= 0x17FF) || // Khmer
|
||||
(c >= 0x1800 && c <= 0x18AF) || // Mongolian
|
||||
(c >= 0x1900 && c <= 0x194F) || // Limbu
|
||||
(c >= 0x1950 && c <= 0x197F) || // Tai Le
|
||||
(c >= 0x19E0 && c <= 0x19FF) || // Khmer Symbols
|
||||
(c >= 0x1D00 && c <= 0x1D7F) || // Phonetic Extensions
|
||||
(c >= 0x1E00 && c <= 0x1EFF) || // Latin Extended Additional
|
||||
(c >= 0x1F00 && c <= 0x1FFF) || // Greek Extended
|
||||
(c >= 0x2C00 && c <= 0x2C5F) || // Glagolitic
|
||||
(c >= 0x2C60 && c <= 0x2C7F) || // Latin Extended-C
|
||||
(c >= 0x2C80 && c <= 0x2CFF) || // Coptic
|
||||
(c >= 0x2D00 && c <= 0x2D2F) || // Georgian Supplement
|
||||
(c >= 0x2D30 && c <= 0x2D7F) || // Tifinagh
|
||||
(c >= 0x2D80 && c <= 0x2DDF) || // Ethiopic Extended
|
||||
(c >= 0x2DE0 && c <= 0x2DFF) || // Cyrillic Extended-A
|
||||
(c >= 0x2E00 && c <= 0x2E7F) || // Supplemental Punctuation
|
||||
(c >= 0xA640 && c <= 0xA69F) || // Cyrillic Extended-B
|
||||
(c >= 0xA720 && c <= 0xA7FF) || // Latin Extended-D
|
||||
(c >= 0xA800 && c <= 0xA82F) || // Syloti Nagri
|
||||
(c >= 0xA840 && c <= 0xA87F) || // Phags-pa
|
||||
(c >= 0xAC00 && c <= 0xD7AF) || // Hangul Syllables
|
||||
(c >= 0xF900 && c <= 0xFAFF) || // CJK Compatibility Ideographs
|
||||
(c >= 0xFB00 && c <= 0xFB4F) || // Alphabetic Presentation Forms
|
||||
(c >= 0xFE20 && c <= 0xFE2F) || // Combining Half Marks
|
||||
(c >= 0xFE70 && c <= 0xFEFF) || // Arabic Presentation Forms-B
|
||||
(c >= 0xFF00 && c <= 0xFFEF) || // Halfwidth and Fullwidth Forms
|
||||
(c >= 0x10000 && c <= 0x100FF) || // Linear B Syllabary
|
||||
(c >= 0x10140 && c <= 0x1018F) || // Ancient Greek Numbers
|
||||
(c >= 0x10300 && c <= 0x1032F) || // Old Italic
|
||||
(c >= 0x10330 && c <= 0x1034F) || // Gothic
|
||||
(c >= 0x10380 && c <= 0x1039F) || // Ugaritic
|
||||
(c >= 0x103A0 && c <= 0x103DF) || // Old Persian
|
||||
(c >= 0x10400 && c <= 0x1044F) || // Deseret
|
||||
(c >= 0x10450 && c <= 0x1047F) || // Shavian
|
||||
(c >= 0x10480 && c <= 0x104AF) || // Osmanya
|
||||
(c >= 0x10800 && c <= 0x1083F) || // Cypriot Syllabary
|
||||
(c >= 0x10900 && c <= 0x1091F) || // Phoenician
|
||||
(c >= 0x10A00 && c <= 0x10A5F) || // Kharoshthi
|
||||
(c >= 0x12000 && c <= 0x123FF) || // Cuneiform
|
||||
(c >= 0x1D400 && c <= 0x1D7FF) || // Mathematical Alphanumeric Symbols
|
||||
(c >= 0x1F130 && c <= 0x1F1FF) || // Enclosed Alphanumeric Supplement
|
||||
(c >= 0x20000 && c <= 0x2A6DF) || // CJK Unified Ideographs Extension B
|
||||
(c >= 0x2A700 && c <= 0x2B73F) || // CJK Unified Ideographs Extension C
|
||||
(c >= 0x2B740 && c <= 0x2B81F) || // CJK Unified Ideographs Extension D
|
||||
(c >= 0x2F800 && c <= 0x2FA1F)) // CJK Compatibility Ideographs Supplement
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// CJK统一表意文字 (中文、日文、韩文)
|
||||
if ((c >= 0x4E00 && c <= 0x9FFF) || // CJK Unified Ideographs
|
||||
(c >= 0x3400 && c <= 0x4DBF) || // CJK Unified Ideographs Extension A
|
||||
(c >= 0x2E80 && c <= 0x2EFF) || // CJK Radicals Supplement
|
||||
(c >= 0x2F00 && c <= 0x2FDF) || // Kangxi Radicals
|
||||
(c >= 0x2FF0 && c <= 0x2FFF) || // Ideographic Description Characters
|
||||
(c >= 0x3000 && c <= 0x303F) || // CJK Symbols and Punctuation
|
||||
(c >= 0x31C0 && c <= 0x31EF) || // CJK Strokes
|
||||
(c >= 0x3200 && c <= 0x32FF) || // Enclosed CJK Letters and Months
|
||||
(c >= 0x3300 && c <= 0x33FF) || // CJK Compatibility
|
||||
(c >= 0xF900 && c <= 0xFAFF) || // CJK Compatibility Ideographs
|
||||
(c >= 0xFE30 && c <= 0xFE4F) || // CJK Compatibility Forms
|
||||
(c >= 0x1F200 && c <= 0x1F2FF)) // Enclosed Ideographic Supplement
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool isUpper(char32_t c)
|
||||
{
|
||||
// ASCII大写字母
|
||||
if (c >= U'A' && c <= U'Z') return true;
|
||||
|
||||
// Unicode大写字母检查
|
||||
if ((c >= 0x00C0 && c <= 0x00D6) || // Latin-1 Supplement
|
||||
(c >= 0x00D8 && c <= 0x00DE) || // Latin-1 Supplement
|
||||
(c >= 0x0100 && c <= 0x012E) || // Latin Extended-A
|
||||
(c >= 0x0132 && c <= 0x0136) || (c >= 0x0139 && c <= 0x0147) || (c >= 0x014A && c <= 0x0178)
|
||||
|| (c >= 0x0179 && c <= 0x017D) || (c >= 0x0181 && c <= 0x0182) || c == 0x0186 || c == 0x0189 || c == 0x018A
|
||||
|| c == 0x018E || c == 0x018F || c == 0x0190 || c == 0x0191 || c == 0x0193 || c == 0x0194 || c == 0x0196
|
||||
|| c == 0x0197 || c == 0x0198 || c == 0x019C || c == 0x019D || c == 0x019F || c == 0x01A0 || c == 0x01A2
|
||||
|| c == 0x01A4 || c == 0x01A7 || c == 0x01A9 || c == 0x01AC || c == 0x01AE || c == 0x01AF
|
||||
|| (c >= 0x01B1 && c <= 0x01B3) || c == 0x01B5 || c == 0x01B7 || c == 0x01B8 || c == 0x01BC || c == 0x01C4
|
||||
|| c == 0x01C7 || c == 0x01CA || c == 0x01CD || c == 0x01CF || c == 0x01D1 || c == 0x01D3 || c == 0x01D5
|
||||
|| c == 0x01D7 || c == 0x01D9 || c == 0x01DB || c == 0x01DE || c == 0x01E0 || c == 0x01E2 || c == 0x01E4
|
||||
|| c == 0x01E6 || c == 0x01E8 || c == 0x01EA || c == 0x01EC || c == 0x01EE || c == 0x01F4 || c == 0x01FA
|
||||
|| (c >= 0x01FC && c <= 0x01FF) || (c >= 0x0200 && c <= 0x0220) || (c >= 0x0222 && c <= 0x0232)
|
||||
|| (c >= 0x0370 && c <= 0x0373) || (c >= 0x0376 && c <= 0x0377) || (c >= 0x03D8 && c <= 0x03EF)
|
||||
|| (c >= 0x03F4 && c <= 0x03F7) || (c >= 0x03F9 && c <= 0x03FA) || (c >= 0x03FD && c <= 0x042F)
|
||||
|| (c >= 0x0460 && c <= 0x0480) || (c >= 0x048A && c <= 0x04C0) || (c >= 0x04C1 && c <= 0x04CD)
|
||||
|| (c >= 0x04D0 && c <= 0x0528) || (c >= 0x0531 && c <= 0x0556) || (c >= 0x10A0 && c <= 0x10C5)
|
||||
|| (c >= 0x1E00 && c <= 0x1E94) || (c >= 0x1EA0 && c <= 0x1EFE) || (c >= 0x2C00 && c <= 0x2C2E)
|
||||
|| (c >= 0x2C60 && c <= 0x2C62) || (c >= 0xA640 && c <= 0xA66C) || (c >= 0xA680 && c <= 0xA69A)
|
||||
|| (c >= 0xA722 && c <= 0xA72E) || (c >= 0xA732 && c <= 0xA76E) || (c >= 0xA779 && c <= 0xA77D)
|
||||
|| (c >= 0xA77E && c <= 0xA786) || (c >= 0xA78B && c <= 0xA78D) || (c >= 0xA790 && c <= 0xA792)
|
||||
|| (c >= 0xA796 && c <= 0xA7A8) || (c >= 0xA7AA && c <= 0xA7AE) || (c >= 0xA7B0 && c <= 0xA7B4)
|
||||
|| (c >= 0xA7B6 && c <= 0xA7BE) || (c >= 0xFF21 && c <= 0xFF3A) || // 全角大写字母
|
||||
(c >= 0x10400 && c <= 0x10427) || // Deseret
|
||||
(c >= 0x104B0 && c <= 0x104D3) || // Osage
|
||||
(c >= 0x10C80 && c <= 0x10CB2) || // Old Hungarian
|
||||
(c >= 0x118A0 && c <= 0x118DF) || // Warang Citi
|
||||
(c >= 0x1D400 && c <= 0x1D419) || // Mathematical bold capital
|
||||
(c >= 0x1D434 && c <= 0x1D44D) || // Mathematical italic capital
|
||||
(c >= 0x1D468 && c <= 0x1D481) || // Mathematical bold italic capital
|
||||
(c >= 0x1D49C && c <= 0x1D4B5) || // Mathematical script capital
|
||||
(c >= 0x1D4D0 && c <= 0x1D4E9) || // Mathematical bold script capital
|
||||
(c >= 0x1D504 && c <= 0x1D51C) || // Mathematical fraktur capital
|
||||
(c >= 0x1D538 && c <= 0x1D550) || // Mathematical double-struck capital
|
||||
(c >= 0x1D56C && c <= 0x1D585) || // Mathematical bold fraktur capital
|
||||
(c >= 0x1D5A0 && c <= 0x1D5B9) || // Mathematical sans-serif capital
|
||||
(c >= 0x1D5D4 && c <= 0x1D5ED) || // Mathematical sans-serif bold capital
|
||||
(c >= 0x1D608 && c <= 0x1D621) || // Mathematical sans-serif italic capital
|
||||
(c >= 0x1D63C && c <= 0x1D655) || // Mathematical sans-serif bold italic capital
|
||||
(c >= 0x1D670 && c <= 0x1D689) || // Mathematical monospace capital
|
||||
(c >= 0x1D6A8 && c <= 0x1D6C0) || // Mathematical bold capital Greek
|
||||
(c >= 0x1D6E2 && c <= 0x1D6FA) || // Mathematical italic capital Greek
|
||||
(c >= 0x1D71C && c <= 0x1D734) || // Mathematical bold italic capital Greek
|
||||
(c >= 0x1D756 && c <= 0x1D76E) || // Mathematical sans-serif bold capital Greek
|
||||
(c >= 0x1D790 && c <= 0x1D7A8)) // Mathematical sans-serif bold italic capital Greek
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool isLower(char32_t c)
|
||||
{
|
||||
// ASCII小写字母
|
||||
if (c >= U'a' && c <= U'z') return true;
|
||||
|
||||
// Unicode小写字母检查
|
||||
if ((c >= 0x00DF && c <= 0x00F6) || // Latin-1 Supplement
|
||||
(c >= 0x00F8 && c <= 0x00FF) || // Latin-1 Supplement
|
||||
(c >= 0x0101 && c <= 0x012F) || // Latin Extended-A
|
||||
(c >= 0x0133 && c <= 0x0137) || (c >= 0x013A && c <= 0x0148) || (c >= 0x014B && c <= 0x0177)
|
||||
|| (c >= 0x017A && c <= 0x017E) || (c >= 0x0183 && c <= 0x0185) || c == 0x0188 || c == 0x018C || c == 0x0192
|
||||
|| c == 0x0195 || c == 0x0199 || c == 0x019A || c == 0x019E || c == 0x01A1 || c == 0x01A3 || c == 0x01A5
|
||||
|| c == 0x01A8 || c == 0x01AA || c == 0x01AB || c == 0x01AD || c == 0x01B0 || c == 0x01B4 || c == 0x01B6
|
||||
|| c == 0x01B9 || c == 0x01BA || c == 0x01BD || c == 0x01C6 || c == 0x01C9 || c == 0x01CC || c == 0x01CE
|
||||
|| c == 0x01D0 || c == 0x01D2 || c == 0x01D4 || c == 0x01D6 || c == 0x01D8 || c == 0x01DA || c == 0x01DC
|
||||
|| c == 0x01DD || c == 0x01DF || c == 0x01E1 || c == 0x01E3 || c == 0x01E5 || c == 0x01E7 || c == 0x01E9
|
||||
|| c == 0x01EB || c == 0x01ED || c == 0x01F3 || c == 0x01F5 || c == 0x01FB || (c >= 0x0201 && c <= 0x0217)
|
||||
|| (c >= 0x0250 && c <= 0x02A8) || (c >= 0x03B1 && c <= 0x03C1) || (c >= 0x03C3 && c <= 0x03CE)
|
||||
|| (c >= 0x0430 && c <= 0x044F) || (c >= 0x0451 && c <= 0x045C) || (c >= 0x045E && c <= 0x0481)
|
||||
|| (c >= 0x0491 && c <= 0x04BF) || (c >= 0x04C2 && c <= 0x04CE) || (c >= 0x04D1 && c <= 0x0527)
|
||||
|| (c >= 0x0561 && c <= 0x0587) || (c >= 0x1D00 && c <= 0x1D2B) || (c >= 0x1D62 && c <= 0x1D77)
|
||||
|| (c >= 0x1D79 && c <= 0x1D9A) || (c >= 0x1E01 && c <= 0x1E95) || (c >= 0x1EA1 && c <= 0x1EFF)
|
||||
|| (c >= 0x2C30 && c <= 0x2C5E) || (c >= 0x2C61 && c <= 0x2C65) || (c >= 0x2C66 && c <= 0x2C6C)
|
||||
|| (c >= 0x2C73 && c <= 0x2C74) || (c >= 0x2C76 && c <= 0x2C7B) || (c >= 0xA641 && c <= 0xA66D)
|
||||
|| (c >= 0xA681 && c <= 0xA69B) || (c >= 0xA723 && c <= 0xA72F) || (c >= 0xA733 && c <= 0xA76F)
|
||||
|| (c >= 0xA77A && c <= 0xA77C) || (c >= 0xA77F && c <= 0xA787) || (c >= 0xA78C && c <= 0xA78E)
|
||||
|| (c >= 0xA791 && c <= 0xA793) || (c >= 0xA797 && c <= 0xA7A9) || (c >= 0xA7AB && c <= 0xA7AE)
|
||||
|| (c >= 0xA7B1 && c <= 0xA7B5) || (c >= 0xA7B7 && c <= 0xA7BF) || (c >= 0xAB30 && c <= 0xAB5A)
|
||||
|| (c >= 0xAB60 && c <= 0xAB65) || (c >= 0xAB70 && c <= 0xABBF) || (c >= 0xFB00 && c <= 0xFB06)
|
||||
|| (c >= 0xFB13 && c <= 0xFB17) || (c >= 0xFF41 && c <= 0xFF5A) || // 全角小写字母
|
||||
(c >= 0x10428 && c <= 0x1044F) || // Deseret lowercase
|
||||
(c >= 0x104D8 && c <= 0x104FB) || // Osage lowercase
|
||||
(c >= 0x10CC0 && c <= 0x10CF2) || // Old Hungarian lowercase
|
||||
(c >= 0x118C0 && c <= 0x118E0) || // Warang Citi lowercase
|
||||
(c >= 0x1D41A && c <= 0x1D433) || // Mathematical bold lowercase
|
||||
(c >= 0x1D44E && c <= 0x1D467) || // Mathematical italic lowercase
|
||||
(c >= 0x1D482 && c <= 0x1D49B) || // Mathematical bold italic lowercase
|
||||
(c >= 0x1D4B6 && c <= 0x1D4CF) || // Mathematical script lowercase
|
||||
(c >= 0x1D4EA && c <= 0x1D503) || // Mathematical bold script lowercase
|
||||
(c >= 0x1D51E && c <= 0x1D537) || // Mathematical fraktur lowercase
|
||||
(c >= 0x1D552 && c <= 0x1D56B) || // Mathematical double-struck lowercase
|
||||
(c >= 0x1D586 && c <= 0x1D59F) || // Mathematical bold fraktur lowercase
|
||||
(c >= 0x1D5BA && c <= 0x1D5D3) || // Mathematical sans-serif lowercase
|
||||
(c >= 0x1D5EE && c <= 0x1D607) || // Mathematical sans-serif bold lowercase
|
||||
(c >= 0x1D622 && c <= 0x1D63B) || // Mathematical sans-serif italic lowercase
|
||||
(c >= 0x1D656 && c <= 0x1D66F) || // Mathematical sans-serif bold italic lowercase
|
||||
(c >= 0x1D68A && c <= 0x1D6A5) || // Mathematical monospace lowercase
|
||||
(c >= 0x1D6C1 && c <= 0x1D6DA) || // Mathematical bold lowercase Greek
|
||||
(c >= 0x1D6FB && c <= 0x1D714) || // Mathematical italic lowercase Greek
|
||||
(c >= 0x1D735 && c <= 0x1D74E) || // Mathematical bold italic lowercase Greek
|
||||
(c >= 0x1D76F && c <= 0x1D788) || // Mathematical sans-serif bold lowercase Greek
|
||||
(c >= 0x1D7A9 && c <= 0x1D7C2)) // Mathematical sans-serif bold italic lowercase Greek
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool isAlnum(char32_t c) { return isAlpha(c) || isDigit(c); }
|
||||
|
||||
static bool isXdigit(char32_t c)
|
||||
{
|
||||
return isDigit(c) || (c >= U'a' && c <= U'f') || (c >= U'A' && c <= U'F') || (c >= 0xFF10 && c <= 0xFF19)
|
||||
|| // 全角数字
|
||||
(c >= 0xFF21 && c <= 0xFF26) || // 全角大写A-F
|
||||
(c >= 0xFF41 && c <= 0xFF46); // 全角小写a-f
|
||||
}
|
||||
|
||||
static bool isSpace(char32_t c)
|
||||
{
|
||||
return c == U' ' || c == U'\t' || c == U'\n' || c == U'\r' || c == U'\f' || c == U'\v' || c == 0x00A0
|
||||
|| c == 0x1680 || c == 0x2000 || c == 0x2001 || c == 0x2002 || c == 0x2003 || c == 0x2004 || c == 0x2005
|
||||
|| c == 0x2006 || c == 0x2007 || c == 0x2008 || c == 0x2009 || c == 0x200A || c == 0x202F || c == 0x205F
|
||||
|| c == 0x3000;
|
||||
}
|
||||
|
||||
static bool isCntrl(char32_t c) { return (c <= 0x1F) || (c >= 0x7F && c <= 0x9F) || c == 0x2028 || c == 0x2029; }
|
||||
|
||||
static bool isGraph(char32_t c) { return !isSpace(c) && !isCntrl(c) && c != 0x00AD && c != 0x180E; }
|
||||
|
||||
static bool isPrint(char32_t c) { return isGraph(c) || isSpace(c); }
|
||||
|
||||
static bool isPunct(char32_t c) { return isGraph(c) && !isAlnum(c); }
|
||||
|
||||
// 大小写转换
|
||||
static char32_t toLower(char32_t c)
|
||||
{
|
||||
if (isLower(c)) return c;
|
||||
if (c >= U'A' && c <= U'Z') return c + 32;
|
||||
if (c >= 0xC0 && c <= 0xD6 && c != 0xD7) return c + 32;
|
||||
if (c >= 0xD8 && c <= 0xDE) return c + 32;
|
||||
|
||||
assert(false && "Unsupported yet");
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static char32_t toUpper(char32_t c)
|
||||
{
|
||||
if (isUpper(c)) return c;
|
||||
if (c >= U'a' && c <= U'z') return c - 32;
|
||||
if (c >= 0xE0 && c <= 0xF6 && c != 0xF7) return c - 32;
|
||||
if (c >= 0xF8 && c <= 0xFE) return c - 32;
|
||||
|
||||
assert(false && "Unsupported yet");
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
// 检查是否是空白字符
|
||||
static bool isWhitespace(char32_t c)
|
||||
{
|
||||
return c == U' ' || c == U'\t' || c == U'\n' || c == U'\r' || c == U'\f' || c == U'\v' || c == 0x00A0
|
||||
|| c == 0x1680 || c == 0x2000 || c == 0x2001 || c == 0x2002 || c == 0x2003 || c == 0x2004 || c == 0x2005
|
||||
|| c == 0x2006 || c == 0x2007 || c == 0x2008 || c == 0x2009 || c == 0x200A || c == 0x2028 || c == 0x2029
|
||||
|| c == 0x202F || c == 0x205F || c == 0x3000;
|
||||
}
|
||||
|
||||
// 检查是否是标点符号
|
||||
static bool isPunctuation(char32_t c)
|
||||
{
|
||||
return (c >= 0x21 && c <= 0x2F) || (c >= 0x3A && c <= 0x40) || (c >= 0x5B && c <= 0x60)
|
||||
|| (c >= 0x7B && c <= 0x7E) || (c >= 0x2000 && c <= 0x206F) || (c >= 0x2E00 && c <= 0x2E7F)
|
||||
|| (c >= 0x3000 && c <= 0x303F) || (c >= 0xFE10 && c <= 0xFE1F) || (c >= 0xFE30 && c <= 0xFE4F)
|
||||
|| (c >= 0xFF00 && c <= 0xFF0F) || (c >= 0xFF1A && c <= 0xFF20) || (c >= 0xFF3B && c <= 0xFF40)
|
||||
|| (c >= 0xFF5B && c <= 0xFF65);
|
||||
}
|
||||
|
||||
// 检查是否是表情符号
|
||||
static bool isEmoji(char32_t c)
|
||||
{
|
||||
return (c >= 0x1F600 && c <= 0x1F64F) || // Emoticons
|
||||
(c >= 0x1F300 && c <= 0x1F5FF) || // Miscellaneous Symbols and Pictographs
|
||||
(c >= 0x1F680 && c <= 0x1F6FF) || // Transport and Map Symbols
|
||||
(c >= 0x1F900 && c <= 0x1F9FF) || // Supplemental Symbols and Pictographs
|
||||
(c >= 0x2600 && c <= 0x26FF) || // Miscellaneous Symbols
|
||||
(c >= 0x2700 && c <= 0x27BF) || // Dingbats
|
||||
(c >= 0xFE00 && c <= 0xFE0F) || // Variation Selectors
|
||||
(c >= 0x1F1E6 && c <= 0x1F1FF) || // Regional Indicator Symbols
|
||||
(c >= 0xE0020 && c <= 0xE007F); // Tags
|
||||
}
|
||||
};
|
||||
@@ -1,12 +0,0 @@
|
||||
#include <Core/String.hpp>
|
||||
|
||||
namespace Fig::StringClass::DynamicCapacity
|
||||
{
|
||||
char32_t Iterator::operator*() const
|
||||
{
|
||||
if (str->is_ascii)
|
||||
return str->is_heap ? str->heap.ascii[index] : str->sso.ascii[index];
|
||||
else
|
||||
return str->is_heap ? str->heap.utf32[index] : str->sso.utf32[index];
|
||||
}
|
||||
};
|
||||
2223
src/Core/String.hpp
2223
src/Core/String.hpp
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <Core/String.hpp>
|
||||
#include <Core/fig_string.hpp>
|
||||
#include <cstdint>
|
||||
#include <string_view>
|
||||
|
||||
#define __FCORE_VERSION "0.4.3-alpha"
|
||||
#define __FCORE_VERSION "0.4.4-alpha"
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define __FCORE_PLATFORM "Windows"
|
||||
@@ -54,5 +54,6 @@ namespace Fig
|
||||
inline constexpr std::string_view COMPILER = __FCORE_COMPILER;
|
||||
inline constexpr std::string_view COMPILE_TIME = __FCORE_COMPILE_TIME;
|
||||
inline constexpr std::string_view ARCH = __FCORE_ARCH;
|
||||
inline constexpr FString MAIN_FUNCTION = u8"main";
|
||||
}; // namespace Core
|
||||
}; // namespace Fig
|
||||
@@ -18,9 +18,15 @@ namespace Fig
|
||||
return FStringView(reinterpret_cast<const char8_t *>(sv.data()));
|
||||
}
|
||||
|
||||
explicit FStringView(std::string_view sv) { *this = fromBasicStringView(sv); }
|
||||
explicit FStringView(std::string_view sv)
|
||||
{
|
||||
*this = fromBasicStringView(sv);
|
||||
}
|
||||
|
||||
explicit FStringView() { *this = fromBasicStringView(std::string_view("")); }
|
||||
explicit FStringView()
|
||||
{
|
||||
*this = fromBasicStringView(std::string_view(""));
|
||||
}
|
||||
|
||||
std::string_view toBasicStringView() const
|
||||
{
|
||||
@@ -28,26 +34,56 @@ namespace Fig
|
||||
}
|
||||
};
|
||||
|
||||
class String : public std::u8string
|
||||
class FString : public std::u8string
|
||||
{
|
||||
public:
|
||||
using std::u8string::u8string;
|
||||
using std::u8string::operator=;
|
||||
|
||||
String operator+(const String &x) { return String(toBasicString() + x.toBasicString()); }
|
||||
String operator+(const char8_t *c) { return String(*this + std::u8string(c)); }
|
||||
FString operator+(const FString &x)
|
||||
{
|
||||
return FString(toBasicString() + x.toBasicString());
|
||||
}
|
||||
FString operator+(const char8_t *c)
|
||||
{
|
||||
return FString(*this + std::u8string(c));
|
||||
}
|
||||
|
||||
explicit String(const std::u8string &str) { *this = fromU8String(str); }
|
||||
explicit String(std::string str) { *this = fromBasicString(str); }
|
||||
explicit String(FStringView sv) { *this = fromStringView(sv); }
|
||||
std::string toBasicString() const { return std::string(this->begin(), this->end()); }
|
||||
FStringView toStringView() const { return FStringView(this->data(), this->size()); }
|
||||
explicit FString(const std::u8string &str)
|
||||
{
|
||||
*this = fromU8String(str);
|
||||
}
|
||||
explicit FString(std::string str)
|
||||
{
|
||||
*this = fromBasicString(str);
|
||||
}
|
||||
explicit FString(FStringView sv)
|
||||
{
|
||||
*this = fromStringView(sv);
|
||||
}
|
||||
std::string toBasicString() const
|
||||
{
|
||||
return std::string(this->begin(), this->end());
|
||||
}
|
||||
FStringView toStringView() const
|
||||
{
|
||||
return FStringView(this->data(), this->size());
|
||||
}
|
||||
|
||||
static String fromBasicString(const std::string &str) { return String(str.begin(), str.end()); }
|
||||
static FString fromBasicString(const std::string &str)
|
||||
{
|
||||
return FString(str.begin(), str.end());
|
||||
}
|
||||
|
||||
static String fromStringView(FStringView sv) { return String(reinterpret_cast<const char *>(sv.data())); }
|
||||
static FString fromStringView(FStringView sv)
|
||||
{
|
||||
return FString(reinterpret_cast<const char *>(sv.data()));
|
||||
}
|
||||
|
||||
static String fromU8String(const std::u8string &str) { return String(str.begin(), str.end()); }
|
||||
static FString fromU8String(const std::u8string &str)
|
||||
{
|
||||
return FString(str.begin(), str.end());
|
||||
}
|
||||
|
||||
size_t length() const
|
||||
{
|
||||
@@ -55,14 +91,17 @@ namespace Fig
|
||||
size_t len = 0;
|
||||
for (auto it = this->begin(); it != this->end(); ++it)
|
||||
{
|
||||
if ((*it & 0xC0) != 0x80) { ++len; }
|
||||
if ((*it & 0xC0) != 0x80)
|
||||
{
|
||||
++len;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
String getRealChar(size_t index)
|
||||
FString getRealChar(size_t index)
|
||||
{
|
||||
String ch;
|
||||
FString ch;
|
||||
size_t cnt = 0;
|
||||
for (size_t i = 0; i < size();)
|
||||
{
|
||||
@@ -73,9 +112,13 @@ namespace Fig
|
||||
cplen = 3;
|
||||
else if ((at(i) & 0xe0) == 0xc0)
|
||||
cplen = 2;
|
||||
if (i + cplen > size()) cplen = 1;
|
||||
if (i + cplen > size())
|
||||
cplen = 1;
|
||||
|
||||
if (cnt == index) { ch += substr(i, cplen); }
|
||||
if (cnt == index)
|
||||
{
|
||||
ch += substr(i, cplen);
|
||||
}
|
||||
|
||||
i += cplen;
|
||||
++cnt;
|
||||
@@ -84,7 +127,7 @@ namespace Fig
|
||||
return ch;
|
||||
}
|
||||
|
||||
void realReplace(size_t index, const String &src)
|
||||
void realReplace(size_t index, const FString &src)
|
||||
{
|
||||
size_t cnt = 0;
|
||||
for (size_t i = 0; i < size();)
|
||||
@@ -96,9 +139,13 @@ namespace Fig
|
||||
cplen = 3;
|
||||
else if ((at(i) & 0xe0) == 0xc0)
|
||||
cplen = 2;
|
||||
if (i + cplen > size()) cplen = 1;
|
||||
if (i + cplen > size())
|
||||
cplen = 1;
|
||||
|
||||
if (cnt == index) { *this = String(substr(0, i)) + src + String(substr(i + cplen)); }
|
||||
if (cnt == index)
|
||||
{
|
||||
*this = FString(substr(0, i)) + src + FString(substr(i + cplen));
|
||||
}
|
||||
|
||||
i += cplen;
|
||||
++cnt;
|
||||
@@ -118,22 +165,32 @@ namespace Fig
|
||||
cplen = 3;
|
||||
else if ((at(i) & 0xe0) == 0xc0)
|
||||
cplen = 2;
|
||||
if (i + cplen > size()) cplen = 1;
|
||||
if (i + cplen > size())
|
||||
cplen = 1;
|
||||
|
||||
i += cplen;
|
||||
++cnt;
|
||||
|
||||
if (cnt == index) { eraseStart = i; }
|
||||
if (cnt < index + n) { eraseCplens += cplen; }
|
||||
if (cnt == index)
|
||||
{
|
||||
eraseStart = i;
|
||||
}
|
||||
if (cnt < index + n)
|
||||
{
|
||||
eraseCplens += cplen;
|
||||
}
|
||||
}
|
||||
erase(eraseStart, eraseCplens);
|
||||
}
|
||||
|
||||
void realInsert(size_t index, const String &src)
|
||||
void realInsert(size_t index, const FString &src)
|
||||
{
|
||||
if (index == length())
|
||||
{
|
||||
for (auto &c : src) { push_back(c); }
|
||||
for (auto &c : src)
|
||||
{
|
||||
push_back(c);
|
||||
}
|
||||
return;
|
||||
}
|
||||
size_t cnt = 0;
|
||||
@@ -146,9 +203,13 @@ namespace Fig
|
||||
cplen = 3;
|
||||
else if ((at(i) & 0xe0) == 0xc0)
|
||||
cplen = 2;
|
||||
if (i + cplen > size()) cplen = 1;
|
||||
if (i + cplen > size())
|
||||
cplen = 1;
|
||||
|
||||
if (cnt == index) { insert(i, src); }
|
||||
if (cnt == index)
|
||||
{
|
||||
insert(i, src);
|
||||
}
|
||||
|
||||
i += cplen;
|
||||
++cnt;
|
||||
@@ -161,9 +222,9 @@ namespace Fig
|
||||
namespace std
|
||||
{
|
||||
template <>
|
||||
struct hash<Fig::String>
|
||||
struct hash<Fig::FString>
|
||||
{
|
||||
std::size_t operator()(const Fig::String &s) const
|
||||
std::size_t operator()(const Fig::FString &s) const
|
||||
{
|
||||
return std::hash<std::u8string>{}(static_cast<const std::u8string &>(s));
|
||||
}
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
const std::unordered_map<std::size_t, String> Warning::standardWarnings = {
|
||||
{1, String(U"Identifier is too similar to a keyword or a primitive type")},
|
||||
{2, String(U"The identifier is too abstract")}
|
||||
const std::unordered_map<std::size_t, FString> Warning::standardWarnings = {
|
||||
{1, FString(u8"Identifier is too similar to a keyword or a primitive type")},
|
||||
{2, FString(u8"The identifier is too abstract")}
|
||||
};
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <Core/String.hpp>
|
||||
#include <Core/fig_string.hpp>
|
||||
|
||||
#include <Utils/magic_enum/magic_enum.hpp>
|
||||
#include <unordered_map>
|
||||
@@ -11,17 +11,16 @@ namespace Fig
|
||||
{
|
||||
private:
|
||||
size_t id; // the id (standard) of warning
|
||||
String msg;
|
||||
FString msg;
|
||||
size_t line, column;
|
||||
|
||||
public:
|
||||
static const std::unordered_map<size_t, String> standardWarnings;
|
||||
Warning(size_t _id, String _msg)
|
||||
static const std::unordered_map<size_t, FString> standardWarnings;
|
||||
Warning(size_t _id, FString _msg)
|
||||
{
|
||||
id = _id;
|
||||
msg = std::move(_msg);
|
||||
}
|
||||
Warning(size_t _id, String _msg, size_t _line, size_t _column)
|
||||
Warning(size_t _id, FString _msg, size_t _line, size_t _column)
|
||||
{
|
||||
id = _id;
|
||||
msg = std::move(_msg);
|
||||
@@ -29,12 +28,28 @@ namespace Fig
|
||||
column = _column;
|
||||
}
|
||||
|
||||
auto getIDName() { return standardWarnings.at(id); }
|
||||
auto getIDName()
|
||||
{
|
||||
return standardWarnings.at(id);
|
||||
}
|
||||
|
||||
auto getID()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
auto getMsg()
|
||||
{
|
||||
return msg;
|
||||
}
|
||||
auto getLine()
|
||||
{
|
||||
return line;
|
||||
}
|
||||
auto getColumn()
|
||||
{
|
||||
return column;
|
||||
}
|
||||
|
||||
auto getID() { return id; }
|
||||
auto getMsg() { return msg; }
|
||||
auto getLine() { return line; }
|
||||
auto getColumn() { return column; }
|
||||
};
|
||||
|
||||
}; // namespace Fig
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <Core/String.hpp>
|
||||
#include <Core/fig_string.hpp>
|
||||
|
||||
#include <exception>
|
||||
#include <format>
|
||||
@@ -14,29 +14,20 @@ namespace Fig
|
||||
{
|
||||
public:
|
||||
explicit AddressableError() {}
|
||||
explicit AddressableError(String _msg,
|
||||
explicit AddressableError(FString _msg,
|
||||
size_t _line,
|
||||
size_t _column,
|
||||
String _sourcePath,
|
||||
std::vector<String> _sourceLines,
|
||||
FString _sourcePath,
|
||||
std::vector<FString> _sourceLines,
|
||||
std::source_location loc = std::source_location::current()) :
|
||||
src_loc(loc),
|
||||
line(_line),
|
||||
column(_column),
|
||||
sourcePath(std::move(_sourcePath)),
|
||||
sourceLines(std::move(_sourceLines))
|
||||
src_loc(loc), line(_line), column(_column), sourcePath(std::move(_sourcePath)), sourceLines(std::move(_sourceLines))
|
||||
{
|
||||
message = _msg;
|
||||
}
|
||||
virtual String toString() const
|
||||
virtual FString toString() const
|
||||
{
|
||||
std::string msg = std::format("[AddressableError] {} at {}:{}, in [{}] {}",
|
||||
this->message.toBasicString(),
|
||||
this->line,
|
||||
this->column,
|
||||
this->src_loc.file_name(),
|
||||
this->src_loc.function_name());
|
||||
return String(msg);
|
||||
std::string msg = std::format("[AddressableError] {} at {}:{}, in [{}] {}", std::string(this->message.begin(), this->message.end()), this->line, this->column, this->src_loc.file_name(), this->src_loc.function_name());
|
||||
return FString(msg);
|
||||
}
|
||||
const char *what() const noexcept override
|
||||
{
|
||||
@@ -47,36 +38,37 @@ namespace Fig
|
||||
|
||||
virtual size_t getLine() const { return line; }
|
||||
virtual size_t getColumn() const { return column; }
|
||||
String getMessage() const { return message; }
|
||||
String getSourcePath() const { return sourcePath; }
|
||||
std::vector<String> getSourceLines() const { return sourceLines; }
|
||||
FString getMessage() const { return message; }
|
||||
FString getSourcePath() const { return sourcePath; }
|
||||
std::vector<FString> getSourceLines() const { return sourceLines; }
|
||||
|
||||
virtual String getErrorType() const { return String(U"\1"); }
|
||||
virtual FString getErrorType() const
|
||||
{
|
||||
return FString(u8"AddressableError");
|
||||
}
|
||||
|
||||
protected:
|
||||
size_t line, column;
|
||||
String message;
|
||||
FString message;
|
||||
|
||||
String sourcePath;
|
||||
std::vector<String> sourceLines;
|
||||
FString sourcePath;
|
||||
std::vector<FString> sourceLines;
|
||||
};
|
||||
|
||||
class UnaddressableError : public std::exception
|
||||
{
|
||||
public:
|
||||
explicit UnaddressableError() {}
|
||||
explicit UnaddressableError(String _msg, std::source_location loc = std::source_location::current()) :
|
||||
explicit UnaddressableError(FString _msg,
|
||||
std::source_location loc = std::source_location::current()) :
|
||||
src_loc(loc)
|
||||
{
|
||||
message = _msg;
|
||||
}
|
||||
virtual String toString() const
|
||||
virtual FString toString() const
|
||||
{
|
||||
std::string msg = std::format("[UnaddressableError] {} in [{}] {}",
|
||||
this->message.toBasicString(),
|
||||
this->src_loc.file_name(),
|
||||
this->src_loc.function_name());
|
||||
return String(msg);
|
||||
std::string msg = std::format("[UnaddressableError] {} in [{}] {}", this->message.toBasicString(), this->src_loc.file_name(), this->src_loc.function_name());
|
||||
return FString(msg);
|
||||
}
|
||||
const char *what() const noexcept override
|
||||
{
|
||||
@@ -84,12 +76,15 @@ namespace Fig
|
||||
return msg.c_str();
|
||||
}
|
||||
std::source_location src_loc;
|
||||
String getMessage() const { return message; }
|
||||
FString getMessage() const { return message; }
|
||||
|
||||
virtual String getErrorType() const { return String(U"\1"); }
|
||||
virtual FString getErrorType() const
|
||||
{
|
||||
return FString(u8"UnaddressableError");
|
||||
}
|
||||
|
||||
protected:
|
||||
String message;
|
||||
FString message;
|
||||
};
|
||||
|
||||
class SyntaxError : public AddressableError
|
||||
@@ -97,36 +92,37 @@ namespace Fig
|
||||
public:
|
||||
using AddressableError::AddressableError;
|
||||
|
||||
virtual String toString() const override
|
||||
virtual FString toString() const override
|
||||
{
|
||||
std::string msg = std::format("[SyntaxError] {} in [{}] {}",
|
||||
this->message.toBasicString(),
|
||||
this->src_loc.file_name(),
|
||||
this->src_loc.function_name());
|
||||
return String(msg);
|
||||
std::string msg = std::format("[SyntaxError] {} in [{}] {}", this->message.toBasicString(), this->src_loc.file_name(), this->src_loc.function_name());
|
||||
return FString(msg);
|
||||
}
|
||||
|
||||
virtual String getErrorType() const override { return String(U"\1"); }
|
||||
virtual FString getErrorType() const override
|
||||
{
|
||||
return FString(u8"SyntaxError");
|
||||
}
|
||||
};
|
||||
|
||||
class RuntimeError final : public UnaddressableError
|
||||
{
|
||||
public:
|
||||
using UnaddressableError::UnaddressableError;
|
||||
explicit RuntimeError(String _msg, std::source_location loc = std::source_location::current()) :
|
||||
explicit RuntimeError(FString _msg,
|
||||
std::source_location loc = std::source_location::current()) :
|
||||
UnaddressableError(_msg, loc)
|
||||
{
|
||||
}
|
||||
virtual String toString() const override
|
||||
virtual FString toString() const override
|
||||
{
|
||||
std::string msg = std::format("[RuntimeError] {} in [{}] {}",
|
||||
this->message.toBasicString(),
|
||||
this->src_loc.file_name(),
|
||||
this->src_loc.function_name());
|
||||
return String(msg);
|
||||
std::string msg = std::format("[RuntimeError] {} in [{}] {}", this->message.toBasicString(), this->src_loc.file_name(), this->src_loc.function_name());
|
||||
return FString(msg);
|
||||
}
|
||||
|
||||
virtual String getErrorType() const override { return String(U"\1"); }
|
||||
virtual FString getErrorType() const override
|
||||
{
|
||||
return FString(u8"RuntimeError");
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Fig
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <print>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
namespace ErrorLog
|
||||
@@ -86,7 +87,7 @@ namespace Fig
|
||||
constexpr const char *OnGray = "\033[48;2;128;128;128m";
|
||||
}; // namespace TerminalColors
|
||||
|
||||
inline void coloredPrint(const char *colorCode, String msg)
|
||||
inline void coloredPrint(const char *colorCode, FString msg)
|
||||
{
|
||||
std::print("{}{}{}", colorCode, msg.toBasicString(), TerminalColors::Reset);
|
||||
}
|
||||
@@ -96,44 +97,34 @@ namespace Fig
|
||||
std::print("{}{}{}", colorCode, msg, TerminalColors::Reset);
|
||||
}
|
||||
|
||||
inline void logFigErrorInterface(const String &errorClass, const String &errorMessage)
|
||||
inline void logFigErrorInterface(const FString &errorClass, const FString &errorMessage)
|
||||
{
|
||||
namespace TC = TerminalColors;
|
||||
coloredPrint(TC::LightWhite, U"Uncaught Fig exception:\n");
|
||||
coloredPrint(TC::LightRed, U"✖ ");
|
||||
coloredPrint(TC::LightWhite, "Uncaught Fig exception:\n");
|
||||
coloredPrint(TC::LightRed, "✖ ");
|
||||
coloredPrint(TC::Red, errorClass.toBasicString() + ": ");
|
||||
coloredPrint(TC::Red, errorMessage.toBasicString() + "\n");
|
||||
}
|
||||
|
||||
inline void logAddressableError(const AddressableError &err)
|
||||
{
|
||||
const String &fileName = err.getSourcePath();
|
||||
const std::vector<String> &sourceLines = err.getSourceLines();
|
||||
const FString &fileName = err.getSourcePath();
|
||||
const std::vector<FString> &sourceLines = err.getSourceLines();
|
||||
|
||||
std::print("\n");
|
||||
namespace TC = TerminalColors;
|
||||
coloredPrint(TC::LightWhite, U"An error occurred! ");
|
||||
coloredPrint(TC::White,
|
||||
std::format("Fig {} ({})[{} {} bit on `{}`]\n",
|
||||
Core::VERSION,
|
||||
Core::COMPILE_TIME,
|
||||
Core::COMPILER,
|
||||
Core::ARCH,
|
||||
Core::PLATFORM));
|
||||
coloredPrint(TC::LightRed, U"✖ ");
|
||||
coloredPrint(
|
||||
TC::LightRed,
|
||||
std::format("{}: {}\n", err.getErrorType().toBasicString(), String(err.getMessage()).toBasicString()));
|
||||
coloredPrint(
|
||||
TC::White,
|
||||
std::format(" at {}:{} in file '{}'\n", err.getLine(), err.getColumn(), fileName.toBasicString()));
|
||||
coloredPrint(TC::LightWhite, "An error occurred! ");
|
||||
coloredPrint(TC::White, std::format("Fig {} ({})[{} {} bit on `{}`]\n",Core::VERSION, Core::COMPILE_TIME, Core::COMPILER, Core::ARCH, Core::PLATFORM));
|
||||
coloredPrint(TC::LightRed, "✖ ");
|
||||
coloredPrint(TC::LightRed, std::format("{}: {}\n", err.getErrorType().toBasicString(), FString(err.getMessage()).toBasicString()));
|
||||
coloredPrint(TC::White, std::format(" at {}:{} in file '{}'\n", err.getLine(), err.getColumn(), fileName.toBasicString()));
|
||||
|
||||
String lineContent;
|
||||
String pointerLine;
|
||||
FString lineContent;
|
||||
FString pointerLine;
|
||||
|
||||
if (fileName != U"\1")
|
||||
if (fileName != u8"<stdin>")
|
||||
{
|
||||
lineContent = ((int64_t(err.getLine()) - int64_t(1)) >= 0 ? sourceLines[err.getLine() - 1] : U"\1");
|
||||
lineContent = ((int64_t(err.getLine()) - int64_t(1)) >= 0 ? sourceLines[err.getLine() - 1] : u8"<No Source>");
|
||||
for (size_t i = 1; i < err.getColumn(); ++i)
|
||||
{
|
||||
if (lineContent[i - 1] == U'\t') { pointerLine += U'\t'; }
|
||||
@@ -152,34 +143,18 @@ namespace Fig
|
||||
coloredPrint(TC::LightBlue, std::format(" {}\n", lineContent.toBasicString()));
|
||||
|
||||
coloredPrint(TC::LightGreen, std::format(" {}\n", pointerLine.toBasicString()));
|
||||
coloredPrint(TC::DarkGray,
|
||||
std::format("🔧 in function '{}' ({}:{})\n",
|
||||
err.src_loc.function_name(),
|
||||
err.src_loc.file_name(),
|
||||
err.src_loc.line()));
|
||||
coloredPrint(TC::DarkGray, std::format("🔧 in function '{}' ({}:{})\n", err.src_loc.function_name(), err.src_loc.file_name(), err.src_loc.line()));
|
||||
}
|
||||
|
||||
inline void logUnaddressableError(const UnaddressableError &err)
|
||||
{
|
||||
std::print("\n");
|
||||
namespace TC = TerminalColors;
|
||||
coloredPrint(TC::LightWhite, U"An error occurred! ");
|
||||
coloredPrint(TC::White,
|
||||
std::format("Fig {} ({})[{} {} bit on `{}`]\n",
|
||||
Core::VERSION,
|
||||
Core::COMPILE_TIME,
|
||||
Core::COMPILER,
|
||||
Core::ARCH,
|
||||
Core::PLATFORM));
|
||||
coloredPrint(TC::DarkRed, U"✖");
|
||||
coloredPrint(
|
||||
TC::Red,
|
||||
std::format("{}: {}\n", err.getErrorType().toBasicString(), String(err.getMessage()).toBasicString()));
|
||||
coloredPrint(TC::DarkGray,
|
||||
std::format("🔧 in function '{}' ({}:{})",
|
||||
err.src_loc.function_name(),
|
||||
err.src_loc.file_name(),
|
||||
err.src_loc.line()));
|
||||
coloredPrint(TC::LightWhite, "An error occurred! ");
|
||||
coloredPrint(TC::White, std::format("Fig {} ({})[{} {} bit on `{}`]\n", Core::VERSION, Core::COMPILE_TIME, Core::COMPILER, Core::ARCH, Core::PLATFORM));
|
||||
coloredPrint(TC::DarkRed, "✖");
|
||||
coloredPrint(TC::Red, std::format("{}: {}\n", err.getErrorType().toBasicString(), FString(err.getMessage()).toBasicString()));
|
||||
coloredPrint(TC::DarkGray, std::format("🔧 in function '{}' ({}:{})", err.src_loc.function_name(), err.src_loc.file_name(), err.src_loc.line()));
|
||||
}
|
||||
}; // namespace ErrorLog
|
||||
}; // namespace Fig
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <Evaluator/Value/interface.hpp>
|
||||
#include <Evaluator/Value/Type.hpp>
|
||||
#include <Evaluator/Context/context_forward.hpp>
|
||||
#include <Core/String.hpp>
|
||||
#include <Core/fig_string.hpp>
|
||||
#include <Evaluator/Value/value.hpp>
|
||||
#include <Evaluator/Value/VariableSlot.hpp>
|
||||
#include <Evaluator/Core/ExprResult.hpp>
|
||||
@@ -26,7 +26,7 @@ namespace Fig
|
||||
TypeInfo interfaceType;
|
||||
TypeInfo structType;
|
||||
|
||||
std::unordered_map<String, Function> implMethods;
|
||||
std::unordered_map<FString, Function> implMethods;
|
||||
};
|
||||
|
||||
struct OperationRecord
|
||||
@@ -49,11 +49,11 @@ namespace Fig
|
||||
class Context : public std::enable_shared_from_this<Context>
|
||||
{
|
||||
private:
|
||||
String scopeName;
|
||||
std::unordered_map<String, std::shared_ptr<VariableSlot>> variables;
|
||||
FString scopeName;
|
||||
std::unordered_map<FString, std::shared_ptr<VariableSlot>> variables;
|
||||
|
||||
// std::unordered_map<std::size_t, Function> functions;
|
||||
// std::unordered_map<std::size_t, String> functionNames;
|
||||
// std::unordered_map<std::size_t, FString> functionNames;
|
||||
|
||||
// implRegistry <Struct, ordered list of ImplRecord>
|
||||
std::unordered_map<TypeInfo, std::vector<ImplRecord>, TypeInfoHash> implRegistry;
|
||||
@@ -63,13 +63,13 @@ namespace Fig
|
||||
ContextPtr parent;
|
||||
|
||||
Context(const Context &) = default;
|
||||
Context(const String &name, ContextPtr p = nullptr) : scopeName(name), parent(p) {}
|
||||
Context(const FString &name, ContextPtr p = nullptr) : scopeName(name), parent(p) {}
|
||||
|
||||
void setParent(ContextPtr _parent) { parent = _parent; }
|
||||
|
||||
void setScopeName(String _name) { scopeName = std::move(_name); }
|
||||
void setScopeName(FString _name) { scopeName = std::move(_name); }
|
||||
|
||||
String getScopeName() const { return scopeName; }
|
||||
FString getScopeName() const { return scopeName; }
|
||||
|
||||
void merge(const Context &c)
|
||||
{
|
||||
@@ -80,6 +80,13 @@ namespace Fig
|
||||
// c.structTypeNames.end());
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
variables.clear();
|
||||
implRegistry.clear();
|
||||
opRegistry.clear();
|
||||
}
|
||||
|
||||
std::unordered_map<size_t, Function> getFunctions() const
|
||||
{
|
||||
std::unordered_map<size_t, Function> result;
|
||||
@@ -94,58 +101,58 @@ namespace Fig
|
||||
return result;
|
||||
}
|
||||
|
||||
std::shared_ptr<VariableSlot> get(const String &name)
|
||||
std::shared_ptr<VariableSlot> get(const FString &name)
|
||||
{
|
||||
auto it = variables.find(name);
|
||||
if (it != variables.end()) return it->second;
|
||||
if (parent) return parent->get(name);
|
||||
throw RuntimeError(String(std::format("Variable '{}' not defined", name.toBasicString())));
|
||||
throw RuntimeError(FString(std::format("Variable '{}' not defined", name.toBasicString())));
|
||||
}
|
||||
AccessModifier getAccessModifier(const String &name)
|
||||
AccessModifier getAccessModifier(const FString &name)
|
||||
{
|
||||
if (variables.contains(name)) { return variables[name]->am; }
|
||||
else if (parent != nullptr) { return parent->getAccessModifier(name); }
|
||||
else
|
||||
{
|
||||
throw RuntimeError(String(std::format("Variable '{}' not defined", name.toBasicString())));
|
||||
throw RuntimeError(FString(std::format("Variable '{}' not defined", name.toBasicString())));
|
||||
}
|
||||
}
|
||||
bool isVariableMutable(const String &name)
|
||||
bool isVariableMutable(const FString &name)
|
||||
{
|
||||
AccessModifier am = getAccessModifier(name); // may throw
|
||||
return !isAccessConst(am);
|
||||
}
|
||||
bool isVariablePublic(const String &name)
|
||||
bool isVariablePublic(const FString &name)
|
||||
{
|
||||
AccessModifier am = getAccessModifier(name); // may throw
|
||||
return isAccessPublic(am);
|
||||
}
|
||||
void set(const String &name, ObjectPtr value)
|
||||
void set(const FString &name, ObjectPtr value)
|
||||
{
|
||||
if (variables.contains(name))
|
||||
{
|
||||
if (!isVariableMutable(name))
|
||||
{
|
||||
throw RuntimeError(String(std::format("Variable '{}' is immutable", name.toBasicString())));
|
||||
throw RuntimeError(FString(std::format("Variable '{}' is immutable", name.toBasicString())));
|
||||
}
|
||||
variables[name]->value = value;
|
||||
}
|
||||
else if (parent != nullptr) { parent->set(name, value); }
|
||||
else
|
||||
{
|
||||
throw RuntimeError(String(std::format("Variable '{}' not defined", name.toBasicString())));
|
||||
throw RuntimeError(FString(std::format("Variable '{}' not defined", name.toBasicString())));
|
||||
}
|
||||
}
|
||||
void _update(const String &name, ObjectPtr value)
|
||||
void _update(const FString &name, ObjectPtr value)
|
||||
{
|
||||
if (variables.contains(name)) { variables[name]->value = value; }
|
||||
else if (parent != nullptr) { parent->_update(name, value); }
|
||||
else
|
||||
{
|
||||
throw RuntimeError(String(std::format("Variable '{}' not defined", name.toBasicString())));
|
||||
throw RuntimeError(FString(std::format("Variable '{}' not defined", name.toBasicString())));
|
||||
}
|
||||
}
|
||||
void def(const String &name,
|
||||
void def(const FString &name,
|
||||
const TypeInfo &ti,
|
||||
AccessModifier am,
|
||||
const ObjectPtr &value = Object::getNullInstance())
|
||||
@@ -153,7 +160,7 @@ namespace Fig
|
||||
if (containsInThisScope(name))
|
||||
{
|
||||
throw RuntimeError(
|
||||
String(std::format("Variable '{}' already defined in this scope", name.toBasicString())));
|
||||
FString(std::format("Variable '{}' already defined in this scope", name.toBasicString())));
|
||||
}
|
||||
variables[name] = std::make_shared<VariableSlot>(name, value, ti, am);
|
||||
// if (ti == ValueType::StructType)
|
||||
@@ -163,17 +170,17 @@ namespace Fig
|
||||
// }
|
||||
}
|
||||
void
|
||||
defReference(const String &name, const TypeInfo &ti, AccessModifier am, std::shared_ptr<VariableSlot> target)
|
||||
defReference(const FString &name, const TypeInfo &ti, AccessModifier am, std::shared_ptr<VariableSlot> target)
|
||||
{
|
||||
if (containsInThisScope(name))
|
||||
{
|
||||
throw RuntimeError(
|
||||
String(std::format("Variable '{}' already defined in this scope", name.toBasicString())));
|
||||
FString(std::format("Variable '{}' already defined in this scope", name.toBasicString())));
|
||||
}
|
||||
variables[name] = std::make_shared<VariableSlot>(name, target->value, ti, am, true, target);
|
||||
}
|
||||
|
||||
std::optional<String> getFunctionName(std::size_t id)
|
||||
std::optional<FString> getFunctionName(std::size_t id)
|
||||
{
|
||||
for (auto &[name, slot] : variables)
|
||||
{
|
||||
@@ -185,7 +192,7 @@ namespace Fig
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
// std::optional<String> getStructName(std::size_t id)
|
||||
// std::optional<FString> getStructName(std::size_t id)
|
||||
// {
|
||||
// auto it = structTypeNames.find(id);
|
||||
// if (it != structTypeNames.end())
|
||||
@@ -201,21 +208,21 @@ namespace Fig
|
||||
// return std::nullopt;
|
||||
// }
|
||||
// }
|
||||
bool contains(const String &name)
|
||||
bool contains(const FString &name)
|
||||
{
|
||||
if (variables.contains(name)) { return true; }
|
||||
else if (parent != nullptr) { return parent->contains(name); }
|
||||
return false;
|
||||
}
|
||||
bool containsInThisScope(const String &name) const { return variables.contains(name); }
|
||||
bool containsInThisScope(const FString &name) const { return variables.contains(name); }
|
||||
|
||||
TypeInfo getTypeInfo(const String &name) { return get(name)->declaredType; }
|
||||
TypeInfo getTypeInfo(const FString &name) { return get(name)->declaredType; }
|
||||
bool isInFunctionContext()
|
||||
{
|
||||
ContextPtr ctx = shared_from_this();
|
||||
while (ctx)
|
||||
{
|
||||
if (ctx->getScopeName().find(U"\1") == 0) { return true; }
|
||||
if (ctx->getScopeName().find(u8"<Function ") == 0) { return true; }
|
||||
ctx = ctx->parent;
|
||||
}
|
||||
return false;
|
||||
@@ -225,7 +232,10 @@ namespace Fig
|
||||
ContextPtr ctx = shared_from_this();
|
||||
while (ctx)
|
||||
{
|
||||
if (ctx->getScopeName().find(U"\1") == 0 or ctx->getScopeName().find(U"\1") == 0) { return true; }
|
||||
if (ctx->getScopeName().find(u8"<While ") == 0 or ctx->getScopeName().find(u8"<For ") == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
ctx = ctx->parent;
|
||||
}
|
||||
return false;
|
||||
@@ -279,7 +289,7 @@ namespace Fig
|
||||
list.push_back(record); // order is the level
|
||||
}
|
||||
|
||||
bool hasMethodImplemented(const TypeInfo &structType, const String &functionName) const
|
||||
bool hasMethodImplemented(const TypeInfo &structType, const FString &functionName) const
|
||||
{
|
||||
auto it = implRegistry.find(structType);
|
||||
if (it != implRegistry.end())
|
||||
@@ -293,7 +303,7 @@ namespace Fig
|
||||
return parent && parent->hasMethodImplemented(structType, functionName);
|
||||
}
|
||||
|
||||
bool hasDefaultImplementedMethod(const TypeInfo &structType, const String &functionName) const
|
||||
bool hasDefaultImplementedMethod(const TypeInfo &structType, const FString &functionName) const
|
||||
{
|
||||
auto it = implRegistry.find(structType);
|
||||
if (it == implRegistry.end()) return false;
|
||||
@@ -322,7 +332,7 @@ namespace Fig
|
||||
return false;
|
||||
}
|
||||
|
||||
Ast::InterfaceMethod getDefaultImplementedMethod(const TypeInfo &structType, const String &functionName)
|
||||
Ast::InterfaceMethod getDefaultImplementedMethod(const TypeInfo &structType, const FString &functionName)
|
||||
{
|
||||
// O(N²)
|
||||
// SLOW
|
||||
@@ -363,7 +373,7 @@ namespace Fig
|
||||
assert(false);
|
||||
}
|
||||
|
||||
const Function &getImplementedMethod(const TypeInfo &structType, const String &functionName) const
|
||||
const Function &getImplementedMethod(const TypeInfo &structType, const FString &functionName) const
|
||||
{
|
||||
auto it = implRegistry.find(structType);
|
||||
if (it != implRegistry.end())
|
||||
|
||||
@@ -45,11 +45,13 @@ namespace Fig
|
||||
case AstType::FunctionLiteralExpr: {
|
||||
auto fnLiteral = std::static_pointer_cast<Ast::FunctionLiteralExprAst>(exp);
|
||||
|
||||
|
||||
Ast::BlockStatement body = nullptr;
|
||||
if (fnLiteral->isExprMode())
|
||||
{
|
||||
Ast::Expression exprBody = fnLiteral->getExprBody();
|
||||
|
||||
|
||||
const Ast::AstAddressInfo &aai = exprBody->getAAI();
|
||||
Ast::Return st = std::make_shared<Ast::ReturnSt>(exprBody);
|
||||
st->setAAI(aai);
|
||||
@@ -61,8 +63,9 @@ namespace Fig
|
||||
else
|
||||
{
|
||||
body = fnLiteral->getBlockBody();
|
||||
|
||||
}
|
||||
Function fn(String(std::format("<LambdaFn>")), fnLiteral->paras, ValueType::Any, body, ctx
|
||||
Function fn(FString(std::format("<LambdaFn>")),fnLiteral->paras, ValueType::Any, body, ctx
|
||||
/*
|
||||
pass the ctx(fnLiteral eval context) as closure context
|
||||
*/
|
||||
@@ -78,6 +81,7 @@ namespace Fig
|
||||
case AstType::ListExpr: {
|
||||
auto lstExpr = std::static_pointer_cast<Ast::ListExprAst>(exp);
|
||||
|
||||
|
||||
List list;
|
||||
for (auto &exp : lstExpr->val) { list.push_back(check_unwrap(eval(exp, ctx))); }
|
||||
return std::make_shared<Object>(std::move(list));
|
||||
@@ -86,18 +90,18 @@ namespace Fig
|
||||
case AstType::MapExpr: {
|
||||
auto mapExpr = std::static_pointer_cast<Ast::MapExprAst>(exp);
|
||||
|
||||
|
||||
Map map;
|
||||
for (auto &[key, value] : mapExpr->val)
|
||||
{
|
||||
for (auto &[key, value] : mapExpr->val) {
|
||||
map[check_unwrap(eval(key, ctx))] = check_unwrap(eval(value, ctx));
|
||||
}
|
||||
return std::make_shared<Object>(std::move(map));
|
||||
}
|
||||
|
||||
default: {
|
||||
throw RuntimeError(String(std::format("err type of expr: {}", magic_enum::enum_name(type))));
|
||||
throw RuntimeError(FString(std::format("err type of expr: {}", magic_enum::enum_name(type))));
|
||||
}
|
||||
}
|
||||
return Object::getNullInstance(); // ignore warning
|
||||
}
|
||||
}; // namespace Fig
|
||||
};
|
||||
@@ -86,7 +86,7 @@ namespace Fig
|
||||
{
|
||||
ValueType::IntClass lv = lhs->as<ValueType::IntClass>();
|
||||
ValueType::IntClass rv = rhs->as<ValueType::IntClass>();
|
||||
if (rv == 0) { throw ValueError(String(std::format("Modulo by zero: {} % {}", lv, rv))); }
|
||||
if (rv == 0) { throw ValueError(FString(std::format("Modulo by zero: {} % {}", lv, rv))); }
|
||||
ValueType::IntClass result = lv / rv;
|
||||
ValueType::IntClass r = lv % rv;
|
||||
if (r != 0 && ((lv < 0) != (rv < 0))) { result -= 1; }
|
||||
@@ -139,7 +139,7 @@ namespace Fig
|
||||
return Object::getFalseInstance();
|
||||
}
|
||||
|
||||
throw EvaluatorError(U"TypeError",
|
||||
throw EvaluatorError(u8"TypeError",
|
||||
std::format("Unsupported operator `is` for '{}' && '{}'",
|
||||
prettyType(lhs).toBasicString(),
|
||||
prettyType(rhs).toBasicString()),
|
||||
@@ -155,7 +155,7 @@ namespace Fig
|
||||
if (!rhs->is<StructType>())
|
||||
{
|
||||
throw EvaluatorError(
|
||||
U"OperatorError",
|
||||
u8"OperatorError",
|
||||
std::format("Operator `as` requires right hand side operand a struct type, but got '{}'",
|
||||
prettyType(rhs).toBasicString()),
|
||||
bin->rexp);
|
||||
@@ -183,7 +183,7 @@ namespace Fig
|
||||
}
|
||||
else if (sourceType == ValueType::String)
|
||||
{
|
||||
const String &str = lhs->as<ValueType::StringClass>();
|
||||
const FString &str = lhs->as<ValueType::StringClass>();
|
||||
if (targetType == ValueType::Int)
|
||||
{
|
||||
try
|
||||
@@ -194,7 +194,7 @@ namespace Fig
|
||||
catch (std::exception &e)
|
||||
{
|
||||
return ExprResult::error(
|
||||
genTypeError(String(std::format("Cannot cast type `{}` to `{}`, bad int string {}",
|
||||
genTypeError(FString(std::format("Cannot cast type `{}` to `{}`, bad int string {}",
|
||||
prettyType(lhs).toBasicString(),
|
||||
prettyType(rhs).toBasicString(),
|
||||
str.toBasicString())),
|
||||
@@ -211,7 +211,7 @@ namespace Fig
|
||||
catch (std::exception &e)
|
||||
{
|
||||
return ExprResult::error(genTypeError(
|
||||
String(std::format("Cannot cast type `{}` to `{}`, bad double string {}",
|
||||
FString(std::format("Cannot cast type `{}` to `{}`, bad double string {}",
|
||||
prettyType(lhs).toBasicString(),
|
||||
prettyType(rhs).toBasicString(),
|
||||
str.toBasicString())),
|
||||
@@ -221,10 +221,10 @@ namespace Fig
|
||||
}
|
||||
if (targetType == ValueType::Bool)
|
||||
{
|
||||
if (str == U"true") { return Object::getTrueInstance(); }
|
||||
else if (str == U"false") { return Object::getFalseInstance(); }
|
||||
if (str == u8"true") { return Object::getTrueInstance(); }
|
||||
else if (str == u8"false") { return Object::getFalseInstance(); }
|
||||
return ExprResult::error(
|
||||
genTypeError(String(std::format("Cannot cast type `{}` to `{}`, bad bool string {}",
|
||||
genTypeError(FString(std::format("Cannot cast type `{}` to `{}`, bad bool string {}",
|
||||
prettyType(lhs).toBasicString(),
|
||||
prettyType(rhs).toBasicString(),
|
||||
str.toBasicString())),
|
||||
@@ -236,17 +236,15 @@ namespace Fig
|
||||
{
|
||||
if (targetType == ValueType::Int)
|
||||
{
|
||||
return IntPool::getInstance().createInt(
|
||||
static_cast<ValueType::IntClass>(lhs->as<ValueType::BoolClass>()));
|
||||
return IntPool::getInstance().createInt(static_cast<ValueType::IntClass>(lhs->as<ValueType::BoolClass>()));
|
||||
}
|
||||
if (targetType == ValueType::Double)
|
||||
{
|
||||
return std::make_shared<Object>(
|
||||
static_cast<ValueType::DoubleClass>(lhs->as<ValueType::BoolClass>()));
|
||||
return std::make_shared<Object>(static_cast<ValueType::DoubleClass>(lhs->as<ValueType::BoolClass>()));
|
||||
}
|
||||
}
|
||||
|
||||
return ExprResult::error(genTypeError(String(std::format("Cannot cast type `{}` to `{}`",
|
||||
return ExprResult::error(genTypeError(FString(std::format("Cannot cast type `{}` to `{}`",
|
||||
prettyType(lhs).toBasicString(),
|
||||
prettyType(rhs).toBasicString())),
|
||||
bin->rexp,
|
||||
@@ -431,7 +429,7 @@ namespace Fig
|
||||
}
|
||||
|
||||
default:
|
||||
throw EvaluatorError(U"UnsupportedOp",
|
||||
throw EvaluatorError(u8"UnsupportedOp",
|
||||
std::format("Unsupport operator '{}' for binary", magic_enum::enum_name(op)),
|
||||
bin);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Fig
|
||||
const Ast::FunctionCallArgs &args,
|
||||
ContextPtr fnCtx) // new context for fn, already filled paras
|
||||
{
|
||||
// const String &fnName = fn.name;
|
||||
// const FString &fnName = fn.name;
|
||||
if (fn.type == Function::Builtin || fn.type == Function::MemberType)
|
||||
{
|
||||
if (fn.type == Function::Builtin) { return fn.builtin(args.argv); }
|
||||
@@ -27,8 +27,14 @@ namespace Fig
|
||||
for (const auto &stmt : fn.body->stmts)
|
||||
{
|
||||
StatementResult sr = evalStatement(stmt, fnCtx);
|
||||
if (sr.isError()) { handle_error(sr, stmt, fnCtx); }
|
||||
if (!sr.isNormal()) { return sr.result; }
|
||||
if (sr.isError())
|
||||
{
|
||||
handle_error(sr, stmt, fnCtx);
|
||||
}
|
||||
if (!sr.isNormal())
|
||||
{
|
||||
return sr.result;
|
||||
}
|
||||
}
|
||||
return Object::getNullInstance();
|
||||
}
|
||||
@@ -37,14 +43,14 @@ namespace Fig
|
||||
RvObject fnObj = check_unwrap(eval(call->callee, ctx));
|
||||
if (fnObj->getTypeInfo() != ValueType::Function)
|
||||
{
|
||||
throw EvaluatorError(U"ObjectNotCallable",
|
||||
throw EvaluatorError(u8"ObjectNotCallable",
|
||||
std::format("Object `{}` isn't callable", fnObj->toString().toBasicString()),
|
||||
call->callee);
|
||||
}
|
||||
|
||||
const Function &fn = fnObj->as<Function>();
|
||||
|
||||
const String &fnName = fn.name;
|
||||
const FString &fnName = fn.name;
|
||||
const Ast::FunctionArguments &fnArgs = call->arg;
|
||||
|
||||
Ast::FunctionCallArgs evaluatedArgs;
|
||||
@@ -53,7 +59,7 @@ namespace Fig
|
||||
for (const auto &argExpr : fnArgs.argv) { evaluatedArgs.argv.push_back(check_unwrap(eval(argExpr, ctx))); }
|
||||
if (fn.builtinParamCount != -1 && fn.builtinParamCount != evaluatedArgs.getLength())
|
||||
{
|
||||
throw EvaluatorError(U"BuiltinArgumentMismatchError",
|
||||
throw EvaluatorError(u8"BuiltinArgumentMismatchError",
|
||||
std::format("Builtin function '{}' expects {} arguments, but {} were provided",
|
||||
fnName.toBasicString(),
|
||||
fn.builtinParamCount,
|
||||
@@ -67,7 +73,7 @@ namespace Fig
|
||||
Ast::FunctionParameters fnParas = fn.paras;
|
||||
|
||||
// create new context for function call
|
||||
auto newContext = std::make_shared<Context>(String(std::format("<Function {}()>", fnName.toBasicString())),
|
||||
auto newContext = std::make_shared<Context>(FString(std::format("<Function {}()>", fnName.toBasicString())),
|
||||
fn.closureContext);
|
||||
|
||||
if (fnParas.variadic)
|
||||
@@ -78,7 +84,7 @@ namespace Fig
|
||||
NormalFilling: {
|
||||
if (fnArgs.getLength() < fnParas.posParas.size() || fnArgs.getLength() > fnParas.size())
|
||||
{
|
||||
throw RuntimeError(String(std::format("Function '{}' expects {} to {} arguments, but {} were provided",
|
||||
throw RuntimeError(FString(std::format("Function '{}' expects {} to {} arguments, but {} were provided",
|
||||
fnName.toBasicString(),
|
||||
fnParas.posParas.size(),
|
||||
fnParas.size(),
|
||||
@@ -89,14 +95,13 @@ namespace Fig
|
||||
size_t i;
|
||||
for (i = 0; i < fnParas.posParas.size(); i++)
|
||||
{
|
||||
const TypeInfo &expectedType = actualType(check_unwrap(
|
||||
eval(fnParas.posParas[i].second, fn.closureContext))); // look up type info, if exists a type
|
||||
const TypeInfo &expectedType = actualType(check_unwrap(eval(fnParas.posParas[i].second, fn.closureContext))); // look up type info, if exists a type
|
||||
// with the name, use it, else throw
|
||||
ObjectPtr argVal = check_unwrap(eval(fnArgs.argv[i], ctx));
|
||||
TypeInfo actualType = argVal->getTypeInfo();
|
||||
if (!isTypeMatch(expectedType, argVal, fn.closureContext))
|
||||
{
|
||||
throw EvaluatorError(U"ArgumentTypeMismatchError",
|
||||
throw EvaluatorError(u8"ArgumentTypeMismatchError",
|
||||
std::format("In function '{}', argument '{}' expects type '{}', but got type '{}'",
|
||||
fnName.toBasicString(),
|
||||
fnParas.posParas[i].first.toBasicString(),
|
||||
@@ -117,7 +122,7 @@ namespace Fig
|
||||
if (!isTypeMatch(expectedType, defaultVal, fn.closureContext))
|
||||
{
|
||||
throw EvaluatorError(
|
||||
U"DefaultParameterTypeError",
|
||||
u8"DefaultParameterTypeError",
|
||||
std::format(
|
||||
"In function '{}', default parameter '{}' has type '{}', which does not match the expected type '{}'",
|
||||
fnName.toBasicString(),
|
||||
@@ -131,7 +136,7 @@ namespace Fig
|
||||
TypeInfo actualType = argVal->getTypeInfo();
|
||||
if (!isTypeMatch(expectedType, argVal, fn.closureContext))
|
||||
{
|
||||
throw EvaluatorError(U"ArgumentTypeMismatchError",
|
||||
throw EvaluatorError(u8"ArgumentTypeMismatchError",
|
||||
std::format("In function '{}', argument '{}' expects type '{}', but got type '{}'",
|
||||
fnName.toBasicString(),
|
||||
fnParas.defParas[defParamIndex].first.toBasicString(),
|
||||
@@ -152,7 +157,7 @@ namespace Fig
|
||||
// define parameters in new context
|
||||
for (size_t j = 0; j < fnParas.size(); j++)
|
||||
{
|
||||
String paramName;
|
||||
FString paramName;
|
||||
TypeInfo paramType;
|
||||
if (j < fnParas.posParas.size())
|
||||
{
|
||||
@@ -188,7 +193,7 @@ namespace Fig
|
||||
|
||||
if (!isTypeMatch(fn.retType, retVal, ctx))
|
||||
{
|
||||
throw EvaluatorError(U"ReturnTypeMismatchError",
|
||||
throw EvaluatorError(u8"ReturnTypeMismatchError",
|
||||
std::format("Function '{}' expects return type '{}', but got type '{}'",
|
||||
fnName.toBasicString(),
|
||||
fn.retType.toString().toBasicString(),
|
||||
|
||||
@@ -10,10 +10,10 @@ namespace Fig
|
||||
{
|
||||
LvObject structeLv = check_unwrap_lv(evalLv(initExpr->structe, ctx));
|
||||
ObjectPtr structTypeVal = structeLv.get();
|
||||
const String &structName = structeLv.name();
|
||||
const FString &structName = structeLv.name();
|
||||
if (!structTypeVal->is<StructType>())
|
||||
{
|
||||
throw EvaluatorError(U"NotAStructTypeError",
|
||||
throw EvaluatorError(u8"NotAStructTypeError",
|
||||
std::format("'{}' is not a structure type", structName.toBasicString()),
|
||||
initExpr);
|
||||
}
|
||||
@@ -27,7 +27,7 @@ namespace Fig
|
||||
|
||||
if (argSize > 1)
|
||||
{
|
||||
throw EvaluatorError(U"StructInitArgumentMismatchError",
|
||||
throw EvaluatorError(u8"StructInitArgumentMismatchError",
|
||||
std::format("Builtin class `{}` expects 0 or 1 argument, but {} were provided",
|
||||
type.toString().toBasicString(),
|
||||
argSize),
|
||||
@@ -40,7 +40,7 @@ namespace Fig
|
||||
if (type == ValueType::Any || type == ValueType::Null || type == ValueType::Function)
|
||||
{
|
||||
throw EvaluatorError(
|
||||
U"BuiltinNotConstructibleError",
|
||||
u8"BuiltinNotConstructibleError",
|
||||
std::format("Builtin type `{}` cannot be constructed", type.toString().toBasicString()),
|
||||
initExpr);
|
||||
}
|
||||
@@ -50,7 +50,7 @@ namespace Fig
|
||||
ObjectPtr val = check_unwrap(eval(args[0].second, ctx));
|
||||
|
||||
auto err = [&](const char *msg) {
|
||||
throw EvaluatorError(U"BuiltinInitTypeMismatchError",
|
||||
throw EvaluatorError(u8"BuiltinInitTypeMismatchError",
|
||||
std::format("Builtin `{}` constructor {}", type.toString().toBasicString(), msg),
|
||||
initExpr);
|
||||
};
|
||||
@@ -121,7 +121,7 @@ namespace Fig
|
||||
}
|
||||
|
||||
throw EvaluatorError(
|
||||
U"BuiltinNotConstructibleError",
|
||||
u8"BuiltinNotConstructibleError",
|
||||
std::format("Builtin type `{}` cannot be constructed", type.toString().toBasicString()),
|
||||
initExpr);
|
||||
}
|
||||
@@ -140,7 +140,7 @@ namespace Fig
|
||||
size_t got = initExpr->args.size();
|
||||
if (got > maxArgs || got < minArgs)
|
||||
{
|
||||
throw EvaluatorError(U"StructInitArgumentMismatchError",
|
||||
throw EvaluatorError(u8"StructInitArgumentMismatchError",
|
||||
std::format("Structure '{}' expects {} to {} fields, but {} were provided",
|
||||
structName.toBasicString(),
|
||||
minArgs,
|
||||
@@ -149,7 +149,7 @@ namespace Fig
|
||||
initExpr);
|
||||
}
|
||||
|
||||
std::vector<std::pair<String, ObjectPtr>> evaluatedArgs;
|
||||
std::vector<std::pair<FString, ObjectPtr>> evaluatedArgs;
|
||||
|
||||
auto evalArguments = [&evaluatedArgs, initExpr, ctx, this](){
|
||||
for (const auto &[argName, argExpr] : initExpr->args)
|
||||
@@ -159,8 +159,8 @@ namespace Fig
|
||||
return ExprResult::normal(Object::getNullInstance());
|
||||
};
|
||||
|
||||
ContextPtr instanceCtx = std::make_shared<Context>(
|
||||
String(std::format("<StructInstance {}>", structName.toBasicString())), defContext);
|
||||
ContextPtr instanceCtx =
|
||||
std::make_shared<Context>(FString(std::format("<StructInstance {}>", structName.toBasicString())), defContext);
|
||||
/*
|
||||
3 ways of calling constructor
|
||||
.1 Person {"Fig", 1, "IDK"};
|
||||
@@ -176,22 +176,22 @@ namespace Fig
|
||||
for (size_t i = 0; i < maxArgs; ++i)
|
||||
{
|
||||
const Field &field = structT.fields[i];
|
||||
const String &fieldName = field.name;
|
||||
const FString &fieldName = field.name;
|
||||
const TypeInfo &expectedType = field.type;
|
||||
if (i >= evaluatedArgs.size())
|
||||
{
|
||||
// we've checked argument count before, so here
|
||||
// must be a default value
|
||||
|
||||
// evaluate default value in definition context
|
||||
// evaluate default value in definition context!
|
||||
ObjectPtr defaultVal = check_unwrap(eval(field.defaultValue,
|
||||
ctx)); // it can't be null here
|
||||
defContext)); // it can't be null here
|
||||
|
||||
// type check
|
||||
if (!isTypeMatch(expectedType, defaultVal, ctx))
|
||||
{
|
||||
throw EvaluatorError(
|
||||
U"StructFieldTypeMismatchError",
|
||||
u8"StructFieldTypeMismatchError",
|
||||
std::format("In structure '{}', field '{}' expects type '{}', but got type '{}'",
|
||||
structName.toBasicString(),
|
||||
fieldName.toBasicString(),
|
||||
@@ -208,7 +208,7 @@ namespace Fig
|
||||
if (!isTypeMatch(expectedType, argVal, ctx))
|
||||
{
|
||||
throw EvaluatorError(
|
||||
U"StructFieldTypeMismatchError",
|
||||
u8"StructFieldTypeMismatchError",
|
||||
std::format("In structure '{}', field '{}' expects type '{}', but got type '{}'",
|
||||
structName.toBasicString(),
|
||||
fieldName.toBasicString(),
|
||||
@@ -227,10 +227,10 @@ namespace Fig
|
||||
for (size_t i = 0; i < maxArgs; ++i)
|
||||
{
|
||||
const Field &field = structT.fields[i];
|
||||
const String &fieldName = (field.name.empty() ? evaluatedArgs[i].first : field.name);
|
||||
const FString &fieldName = (field.name.empty() ? evaluatedArgs[i].first : field.name);
|
||||
if (instanceCtx->containsInThisScope(fieldName))
|
||||
{
|
||||
throw EvaluatorError(U"StructFieldRedeclarationError",
|
||||
throw EvaluatorError(u8"StructFieldRedeclarationError",
|
||||
std::format("Field '{}' already initialized in structure '{}'",
|
||||
fieldName.toBasicString(),
|
||||
structName.toBasicString()),
|
||||
@@ -248,7 +248,7 @@ namespace Fig
|
||||
if (!isTypeMatch(expectedType, defaultVal, ctx))
|
||||
{
|
||||
throw EvaluatorError(
|
||||
U"StructFieldTypeMismatchError",
|
||||
u8"StructFieldTypeMismatchError",
|
||||
std::format("In structure '{}', field '{}' expects type '{}', but got type '{}'",
|
||||
structName.toBasicString(),
|
||||
fieldName.toBasicString(),
|
||||
@@ -264,7 +264,7 @@ namespace Fig
|
||||
if (!isTypeMatch(field.type, argVal, ctx))
|
||||
{
|
||||
throw EvaluatorError(
|
||||
U"StructFieldTypeMismatchError",
|
||||
u8"StructFieldTypeMismatchError",
|
||||
std::format("In structure '{}', field '{}' expects type '{}', but got type '{}'",
|
||||
structName.toBasicString(),
|
||||
fieldName.toBasicString(),
|
||||
@@ -291,7 +291,7 @@ namespace Fig
|
||||
[&argName](const Field &f) { return f.name == argName; });
|
||||
if (fieldIt == structT.fields.end())
|
||||
{
|
||||
// throw EvaluatorError(U"StructFieldNotFoundError",
|
||||
// throw EvaluatorError(u8"StructFieldNotFoundError",
|
||||
// std::format("Field '{}' not found in structure '{}'",
|
||||
// argName.toBasicString(),
|
||||
// structName.toBasicString()),
|
||||
@@ -303,7 +303,7 @@ namespace Fig
|
||||
if (!isTypeMatch(field.type, argVal, ctx))
|
||||
{
|
||||
throw EvaluatorError(
|
||||
U"StructFieldTypeMismatchError",
|
||||
u8"StructFieldTypeMismatchError",
|
||||
std::format("In structure '{}', field '{}' expects type '{}', but got type '{}'",
|
||||
structName.toBasicString(),
|
||||
field.name.toBasicString(),
|
||||
@@ -332,7 +332,7 @@ namespace Fig
|
||||
if (!isTypeMatch(field.type, defaultVal, ctx))
|
||||
{
|
||||
throw EvaluatorError(
|
||||
U"StructFieldTypeMismatchError",
|
||||
u8"StructFieldTypeMismatchError",
|
||||
std::format("In structure '{}', field '{}' expects type '{}', but got type '{}'",
|
||||
structName.toBasicString(),
|
||||
field.name.toBasicString(),
|
||||
@@ -345,13 +345,12 @@ namespace Fig
|
||||
}
|
||||
}
|
||||
}
|
||||
ContextPtr stDefCtx = structT.defContext;
|
||||
|
||||
// load struct method
|
||||
for (auto &[id, fn] : stDefCtx->getFunctions())
|
||||
for (auto &[id, fn] : defContext->getFunctions())
|
||||
{
|
||||
const String &funcName = fn.name;
|
||||
const auto &funcSlot = stDefCtx->get(funcName);
|
||||
const FString &funcName = fn.name;
|
||||
const auto &funcSlot = defContext->get(funcName);
|
||||
|
||||
instanceCtx->def(funcName,
|
||||
ValueType::Function,
|
||||
@@ -361,4 +360,4 @@ namespace Fig
|
||||
|
||||
return std::make_shared<Object>(StructInstance(structT.type, instanceCtx));
|
||||
}
|
||||
}; // namespace Fig
|
||||
};
|
||||
@@ -8,7 +8,7 @@ namespace Fig
|
||||
{
|
||||
ExprResult Evaluator::evalVarExpr(Ast::VarExpr var, ContextPtr ctx)
|
||||
{
|
||||
const String &name = var->name;
|
||||
const FString &name = var->name;
|
||||
|
||||
// 调试信息
|
||||
// std::cerr << "=== DEBUG evalVarExpr ===" << std::endl;
|
||||
@@ -38,14 +38,14 @@ namespace Fig
|
||||
// }
|
||||
// end
|
||||
|
||||
if (!ctx->contains(name)) { throw EvaluatorError(U"UndeclaredIdentifierError", name, var); }
|
||||
if (!ctx->contains(name)) { throw EvaluatorError(u8"UndeclaredIdentifierError", name, var); }
|
||||
return LvObject(ctx->get(name), ctx);
|
||||
}
|
||||
ExprResult Evaluator::evalMemberExpr(Ast::MemberExpr me, ContextPtr ctx)
|
||||
{
|
||||
// LvObject base = evalLv(me->base, ctx);
|
||||
RvObject baseVal = check_unwrap(eval(me->base, ctx));
|
||||
const String &member = me->member;
|
||||
const FString &member = me->member;
|
||||
if (baseVal->getTypeInfo() == ValueType::Module)
|
||||
{
|
||||
// std::cerr << "=== DEBUG evalMemberExpr (Module) ===" << std::endl;
|
||||
@@ -74,7 +74,7 @@ namespace Fig
|
||||
}
|
||||
else
|
||||
{
|
||||
throw EvaluatorError(U"VariableNotFoundError",
|
||||
throw EvaluatorError(u8"VariableNotFoundError",
|
||||
std::format("`{}` has not variable '{}', check if it is public",
|
||||
baseVal->toString().toBasicString(),
|
||||
member.toBasicString()),
|
||||
@@ -118,7 +118,7 @@ namespace Fig
|
||||
if (baseVal->getTypeInfo() != ValueType::StructInstance) // and not member function found
|
||||
{
|
||||
throw EvaluatorError(
|
||||
U"NoAttributeError",
|
||||
u8"NoAttributeError",
|
||||
std::format("`{}` has not attribute '{}'", baseVal->toString().toBasicString(), member.toBasicString()),
|
||||
me->base);
|
||||
}
|
||||
@@ -153,7 +153,7 @@ namespace Fig
|
||||
}
|
||||
else
|
||||
{
|
||||
throw EvaluatorError(U"NoAttributeError",
|
||||
throw EvaluatorError(u8"NoAttributeError",
|
||||
std::format("`{}` has not attribute '{}' and no interfaces have been implemented it",
|
||||
baseVal->toString().toBasicString(),
|
||||
member.toBasicString()),
|
||||
@@ -172,7 +172,7 @@ namespace Fig
|
||||
if (index->getTypeInfo() != ValueType::Int)
|
||||
{
|
||||
throw EvaluatorError(
|
||||
U"TypeError",
|
||||
u8"TypeError",
|
||||
std::format("Type `List` indices must be `Int`, got '{}'", prettyType(index).toBasicString()),
|
||||
ie->index);
|
||||
}
|
||||
@@ -181,7 +181,7 @@ namespace Fig
|
||||
if (indexVal >= list.size())
|
||||
{
|
||||
throw EvaluatorError(
|
||||
U"IndexOutOfRangeError",
|
||||
u8"IndexOutOfRangeError",
|
||||
std::format("Index {} out of list `{}` range", indexVal, base->toString().toBasicString()),
|
||||
ie->index);
|
||||
}
|
||||
@@ -193,16 +193,16 @@ namespace Fig
|
||||
if (index->getTypeInfo() != ValueType::Int)
|
||||
{
|
||||
throw EvaluatorError(
|
||||
U"TypeError",
|
||||
u8"TypeError",
|
||||
std::format("Type `String` indices must be `Int`, got '{}'", prettyType(index).toBasicString()),
|
||||
ie->index);
|
||||
}
|
||||
String &string = base->as<ValueType::StringClass>();
|
||||
FString &string = base->as<ValueType::StringClass>();
|
||||
ValueType::IntClass indexVal = index->as<ValueType::IntClass>();
|
||||
if (indexVal >= string.length())
|
||||
{
|
||||
throw EvaluatorError(
|
||||
U"IndexOutOfRangeError",
|
||||
u8"IndexOutOfRangeError",
|
||||
std::format("Index {} out of string `{}` range", indexVal, base->toString().toBasicString()),
|
||||
ie->index);
|
||||
}
|
||||
@@ -211,7 +211,7 @@ namespace Fig
|
||||
else
|
||||
{
|
||||
throw EvaluatorError(
|
||||
U"NoSubscriptableError",
|
||||
u8"NoSubscriptableError",
|
||||
std::format("`{}` object is not subscriptable", base->getTypeInfo().toString().toBasicString()),
|
||||
ie->base);
|
||||
}
|
||||
@@ -239,7 +239,7 @@ namespace Fig
|
||||
}
|
||||
default: {
|
||||
throw EvaluatorError(
|
||||
U"TypeError",
|
||||
u8"TypeError",
|
||||
std::format("Expression '{}' doesn't refer to a lvalue", exp->typeName().toBasicString()),
|
||||
exp);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
#include <Ast/Statements/InterfaceDefSt.hpp>
|
||||
#include <Evaluator/Core/ExprResult.hpp>
|
||||
#include <Ast/AccessModifier.hpp>
|
||||
#include <Ast/Expressions/FunctionCall.hpp>
|
||||
#include <Ast/astBase.hpp>
|
||||
#include <Ast/functionParameters.hpp>
|
||||
#include <Core/String.hpp>
|
||||
#include <Core/fig_string.hpp>
|
||||
#include <Evaluator/Core/StatementResult.hpp>
|
||||
#include <Evaluator/Value/Type.hpp>
|
||||
#include <Evaluator/Value/structType.hpp>
|
||||
@@ -14,6 +15,7 @@
|
||||
|
||||
#include <Utils/utils.hpp>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
@@ -32,7 +34,7 @@ namespace Fig
|
||||
if (ctx->containsInThisScope(varDef->name))
|
||||
{
|
||||
throw EvaluatorError(
|
||||
U"RedeclarationError",
|
||||
u8"RedeclarationError",
|
||||
std::format("Variable `{}` already declared in this scope", varDef->name.toBasicString()),
|
||||
varDef);
|
||||
}
|
||||
@@ -51,7 +53,7 @@ namespace Fig
|
||||
|
||||
if (value != nullptr && !isTypeMatch(declaredType, value, ctx))
|
||||
{
|
||||
throw EvaluatorError(U"TypeError",
|
||||
throw EvaluatorError(u8"TypeError",
|
||||
std::format("Variable `{}` expects init-value type `{}`, but got '{}'",
|
||||
varDef->name.toBasicString(),
|
||||
prettyType(declaredTypeValue).toBasicString(),
|
||||
@@ -63,6 +65,10 @@ namespace Fig
|
||||
value = std::make_shared<Object>(Object::defaultValue(declaredType));
|
||||
} // else -> Ok
|
||||
} // else -> type is Any (default)
|
||||
else
|
||||
{
|
||||
value = Object::getNullInstance();
|
||||
}
|
||||
AccessModifier am =
|
||||
(varDef->isConst ? (varDef->isPublic ? AccessModifier::PublicConst : AccessModifier::Const) :
|
||||
(varDef->isPublic ? AccessModifier::Public : AccessModifier::Normal));
|
||||
@@ -73,11 +79,11 @@ namespace Fig
|
||||
case FunctionDefSt: {
|
||||
auto fnDef = std::static_pointer_cast<Ast::FunctionDefSt>(stmt);
|
||||
|
||||
const String &fnName = fnDef->name;
|
||||
const FString &fnName = fnDef->name;
|
||||
if (ctx->containsInThisScope(fnName))
|
||||
{
|
||||
throw EvaluatorError(
|
||||
U"RedeclarationError",
|
||||
u8"RedeclarationError",
|
||||
std::format("Function `{}` already declared in this scope", fnName.toBasicString()),
|
||||
fnDef);
|
||||
}
|
||||
@@ -102,13 +108,13 @@ namespace Fig
|
||||
if (ctx->containsInThisScope(stDef->name))
|
||||
{
|
||||
throw EvaluatorError(
|
||||
U"RedeclarationError",
|
||||
u8"RedeclarationError",
|
||||
std::format("Structure '{}' already defined in this scope", stDef->name.toBasicString()),
|
||||
stDef);
|
||||
}
|
||||
|
||||
TypeInfo type(stDef->name, true); // register type name
|
||||
ContextPtr defContext = std::make_shared<Context>(String(std::format("<Struct {} at {}:{}>",
|
||||
ContextPtr defContext = std::make_shared<Context>(FString(std::format("<Struct {} at {}:{}>",
|
||||
stDef->name.toBasicString(),
|
||||
stDef->getAAI().line,
|
||||
stDef->getAAI().column)),
|
||||
@@ -124,12 +130,12 @@ namespace Fig
|
||||
structTypeObj); // predef to itself, always const
|
||||
|
||||
std::vector<Field> fields;
|
||||
std::vector<String> _fieldNames;
|
||||
std::vector<FString> _fieldNames;
|
||||
for (Ast::StructDefField field : stDef->fields)
|
||||
{
|
||||
if (Utils::vectorContains(field.fieldName, _fieldNames))
|
||||
{
|
||||
throw EvaluatorError(U"RedeclarationError",
|
||||
throw EvaluatorError(u8"RedeclarationError",
|
||||
std::format("Field '{}' already defined in structure '{}'",
|
||||
field.fieldName.toBasicString(),
|
||||
stDef->name.toBasicString()),
|
||||
@@ -151,7 +157,7 @@ namespace Fig
|
||||
{
|
||||
if (st->getType() != Ast::AstType::FunctionDefSt)
|
||||
{
|
||||
throw EvaluatorError(U"UnexpectedStatementInStructError",
|
||||
throw EvaluatorError(u8"UnexpectedStatementInStructError",
|
||||
std::format("Unexpected statement `{}` in struct declaration",
|
||||
st->toString().toBasicString()),
|
||||
st);
|
||||
@@ -164,20 +170,56 @@ namespace Fig
|
||||
case InterfaceDefSt: {
|
||||
auto ifd = std::static_pointer_cast<Ast::InterfaceDefAst>(stmt);
|
||||
|
||||
const String &interfaceName = ifd->name;
|
||||
const FString &interfaceName = ifd->name;
|
||||
const std::vector<Ast::Expression> &bundle_exprs = ifd->bundles;
|
||||
|
||||
if (ctx->containsInThisScope(interfaceName))
|
||||
{
|
||||
throw EvaluatorError(
|
||||
U"RedeclarationError",
|
||||
u8"RedeclarationError",
|
||||
std::format("Interface `{}` already declared in this scope", interfaceName.toBasicString()),
|
||||
ifd);
|
||||
}
|
||||
|
||||
std::vector<Ast::InterfaceMethod> bundle_methods;
|
||||
std::unordered_map<FString, FString> cache_methods;
|
||||
// K: interface method name V: method owner (interface)
|
||||
for (const auto &exp : bundle_exprs)
|
||||
{
|
||||
ObjectPtr itf_val = check_unwrap_stres(eval(exp, ctx));
|
||||
if (!itf_val->is<InterfaceType>())
|
||||
{
|
||||
throw EvaluatorError(u8"TypeError",
|
||||
std::format("Cannot bundle type '{}' that is not interface",
|
||||
prettyType(itf_val).toBasicString()),
|
||||
exp);
|
||||
}
|
||||
const InterfaceType &itfType = itf_val->as<InterfaceType>();
|
||||
for (const auto &method : itfType.methods)
|
||||
{
|
||||
if (cache_methods.contains(method.name))
|
||||
{
|
||||
throw EvaluatorError(u8"DuplicateInterfaceMethodError",
|
||||
std::format("Interface `{}` has duplicate method '{}' with '{}.{}'",
|
||||
itfType.type.toString().toBasicString(),
|
||||
method.name.toBasicString(),
|
||||
cache_methods[method.name].toBasicString(),
|
||||
method.name.toBasicString()),
|
||||
ifd);
|
||||
}
|
||||
cache_methods[method.name] = itfType.type.toString();
|
||||
bundle_methods.push_back(method);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Ast::InterfaceMethod> methods(ifd->methods);
|
||||
methods.insert(methods.end(), bundle_methods.begin(), bundle_methods.end());
|
||||
|
||||
TypeInfo type(interfaceName, true); // register interface
|
||||
ctx->def(interfaceName,
|
||||
type,
|
||||
(ifd->isPublic ? AccessModifier::PublicConst : AccessModifier::Const),
|
||||
std::make_shared<Object>(InterfaceType(type, ifd->methods)));
|
||||
std::make_shared<Object>(InterfaceType(type, methods)));
|
||||
return StatementResult::normal();
|
||||
}
|
||||
|
||||
@@ -188,7 +230,7 @@ namespace Fig
|
||||
TypeInfo interfaceType(ip->interfaceName);
|
||||
if (ctx->hasImplRegisted(structType, interfaceType))
|
||||
{
|
||||
throw EvaluatorError(U"DuplicateImplError",
|
||||
throw EvaluatorError(u8"DuplicateImplError",
|
||||
std::format("Duplicate implement `{}` for `{}`",
|
||||
interfaceType.toString().toBasicString(),
|
||||
structType.toString().toBasicString()),
|
||||
@@ -196,13 +238,13 @@ namespace Fig
|
||||
}
|
||||
if (!ctx->contains(ip->interfaceName))
|
||||
{
|
||||
throw EvaluatorError(U"InterfaceNotFoundError",
|
||||
throw EvaluatorError(u8"InterfaceNotFoundError",
|
||||
std::format("Interface '{}' not found", ip->interfaceName.toBasicString()),
|
||||
ip);
|
||||
}
|
||||
if (!ctx->contains(ip->structName))
|
||||
{
|
||||
throw EvaluatorError(U"StructNotFoundError",
|
||||
throw EvaluatorError(u8"StructNotFoundError",
|
||||
std::format("Struct '{}' not found", ip->structName.toBasicString()),
|
||||
ip);
|
||||
}
|
||||
@@ -218,21 +260,21 @@ namespace Fig
|
||||
if (!interfaceObj->is<InterfaceType>())
|
||||
{
|
||||
throw EvaluatorError(
|
||||
U"NotAInterfaceError",
|
||||
u8"NotAInterfaceError",
|
||||
std::format("Variable `{}` is not a interface", ip->interfaceName.toBasicString()),
|
||||
ip);
|
||||
}
|
||||
if (!structTypeObj->is<StructType>())
|
||||
{
|
||||
throw EvaluatorError(
|
||||
U"NotAStructType",
|
||||
u8"NotAStructType",
|
||||
std::format("Variable `{}` is not a struct type", ip->structName.toBasicString()),
|
||||
ip);
|
||||
}
|
||||
|
||||
auto &implementMethods = ip->methods;
|
||||
|
||||
if (ip->interfaceName == U"Operation")
|
||||
if (ip->interfaceName == u8"Operation")
|
||||
{
|
||||
// 运算符重载
|
||||
/*
|
||||
@@ -243,52 +285,52 @@ namespace Fig
|
||||
*/
|
||||
if (ValueType::isTypeBuiltin(structType))
|
||||
{
|
||||
throw EvaluatorError(U"BadUserError",
|
||||
throw EvaluatorError(u8"BadUserError",
|
||||
std::format("Don't overload built-in type operators plz! `{}`",
|
||||
prettyType(structTypeObj).toBasicString()),
|
||||
ip);
|
||||
}
|
||||
|
||||
using enum Ast::Operator;
|
||||
static const std::unordered_map<String, std::pair<Ast::Operator, size_t>> magic_name_to_op = {
|
||||
static const std::unordered_map<FString, std::pair<Ast::Operator, size_t>> magic_name_to_op = {
|
||||
// 算术
|
||||
{U"Add", {Ast::Operator::Add, 2}},
|
||||
{U"Sub", {Ast::Operator::Subtract, 2}},
|
||||
{U"Mul", {Ast::Operator::Multiply, 2}},
|
||||
{U"Div", {Ast::Operator::Divide, 2}},
|
||||
{U"Mod", {Ast::Operator::Modulo, 2}},
|
||||
{U"Pow", {Ast::Operator::Power, 2}},
|
||||
{u8"Add", {Ast::Operator::Add, 2}},
|
||||
{u8"Sub", {Ast::Operator::Subtract, 2}},
|
||||
{u8"Mul", {Ast::Operator::Multiply, 2}},
|
||||
{u8"Div", {Ast::Operator::Divide, 2}},
|
||||
{u8"Mod", {Ast::Operator::Modulo, 2}},
|
||||
{u8"Pow", {Ast::Operator::Power, 2}},
|
||||
|
||||
// 逻辑(一元)
|
||||
{U"Neg", {Ast::Operator::Subtract, 1}}, // 一元负号
|
||||
{U"Not", {Ast::Operator::Not, 1}},
|
||||
{u8"Neg", {Ast::Operator::Subtract, 1}}, // 一元负号
|
||||
{u8"Not", {Ast::Operator::Not, 1}},
|
||||
|
||||
// 逻辑(二元)
|
||||
{U"And", {Ast::Operator::And, 2}},
|
||||
{U"Or", {Ast::Operator::Or, 2}},
|
||||
{u8"And", {Ast::Operator::And, 2}},
|
||||
{u8"Or", {Ast::Operator::Or, 2}},
|
||||
|
||||
// 比较
|
||||
{U"Equal", {Ast::Operator::Equal, 2}},
|
||||
{U"NotEqual", {Ast::Operator::NotEqual, 2}},
|
||||
{U"LessThan", {Ast::Operator::Less, 2}},
|
||||
{U"LessEqual", {Ast::Operator::LessEqual, 2}},
|
||||
{U"GreaterThan", {Ast::Operator::Greater, 2}},
|
||||
{U"GreaterEqual", {Ast::Operator::GreaterEqual, 2}},
|
||||
{U"Is", {Ast::Operator::Is, 2}},
|
||||
{u8"Equal", {Ast::Operator::Equal, 2}},
|
||||
{u8"NotEqual", {Ast::Operator::NotEqual, 2}},
|
||||
{u8"LessThan", {Ast::Operator::Less, 2}},
|
||||
{u8"LessEqual", {Ast::Operator::LessEqual, 2}},
|
||||
{u8"GreaterThan", {Ast::Operator::Greater, 2}},
|
||||
{u8"GreaterEqual", {Ast::Operator::GreaterEqual, 2}},
|
||||
{u8"Is", {Ast::Operator::Is, 2}},
|
||||
|
||||
// 位运算(一元)
|
||||
{U"BitNot", {Ast::Operator::BitNot, 1}},
|
||||
{u8"BitNot", {Ast::Operator::BitNot, 1}},
|
||||
|
||||
// 位运算(二元)
|
||||
{U"BitAnd", {Ast::Operator::BitAnd, 2}},
|
||||
{U"BitOr", {Ast::Operator::BitOr, 2}},
|
||||
{U"BitXor", {Ast::Operator::BitXor, 2}},
|
||||
{U"ShiftLeft", {Ast::Operator::ShiftLeft, 2}},
|
||||
{U"ShiftRight", {Ast::Operator::ShiftRight, 2}},
|
||||
{u8"BitAnd", {Ast::Operator::BitAnd, 2}},
|
||||
{u8"BitOr", {Ast::Operator::BitOr, 2}},
|
||||
{u8"BitXor", {Ast::Operator::BitXor, 2}},
|
||||
{u8"ShiftLeft", {Ast::Operator::ShiftLeft, 2}},
|
||||
{u8"ShiftRight", {Ast::Operator::ShiftRight, 2}},
|
||||
};
|
||||
for (auto &implMethod : implementMethods)
|
||||
{
|
||||
const String &opName = implMethod.name;
|
||||
const FString &opName = implMethod.name;
|
||||
if (!magic_name_to_op.contains(opName))
|
||||
{
|
||||
// ... 现在忽略
|
||||
@@ -303,7 +345,7 @@ namespace Fig
|
||||
if (ctx->hasOperatorImplemented(structType, op, (expectArgCnt == 1 ? true : false)))
|
||||
{
|
||||
throw EvaluatorError(
|
||||
U"DuplicateImplementError",
|
||||
u8"DuplicateImplementError",
|
||||
std::format("{} has already implement by another interface", opName.toBasicString()),
|
||||
ip);
|
||||
}
|
||||
@@ -312,7 +354,7 @@ namespace Fig
|
||||
if (paraCnt != expectArgCnt || implMethod.paras.size() != expectArgCnt)
|
||||
{
|
||||
// 特化报错,更详细易读
|
||||
throw EvaluatorError(U"InterfaceSignatureMismatch",
|
||||
throw EvaluatorError(u8"InterfaceSignatureMismatch",
|
||||
std::format("Operator {} for {} arg count must be {}, got {}",
|
||||
opName.toBasicString(),
|
||||
structLv.name().toBasicString(),
|
||||
@@ -321,13 +363,13 @@ namespace Fig
|
||||
ip);
|
||||
}
|
||||
|
||||
String opFnName(U"Operation." + prettyType(structTypeObj) + U"." + opName);
|
||||
FString opFnName(u8"Operation." + prettyType(structTypeObj) + u8"." + opName);
|
||||
|
||||
ContextPtr fnCtx = std::make_shared<Context>(
|
||||
String(std::format("<Function {}>", opFnName.toBasicString())), ctx);
|
||||
FString(std::format("<Function {}>", opFnName.toBasicString())), ctx);
|
||||
|
||||
const auto &fillOpFnParas = [this, structType, implMethod, opFnName, fnCtx, ctx, paraCnt](
|
||||
const std::vector<ObjectPtr> &args) {
|
||||
const std::vector<ObjectPtr> &args) -> StatementResult {
|
||||
const Ast::FunctionParameters ¶s = implMethod.paras;
|
||||
for (size_t i = 0; i < paraCnt; ++i)
|
||||
{
|
||||
@@ -336,7 +378,7 @@ namespace Fig
|
||||
if (paraType != ValueType::Any && paraType != structType)
|
||||
{
|
||||
throw EvaluatorError(
|
||||
U"ParameterTypeError",
|
||||
u8"ParameterTypeError",
|
||||
std::format("Invalid op fn parameter type '{}' of `{}`, must be `{}`",
|
||||
paraType.toString().toBasicString(),
|
||||
paras.posParas[i].first.toBasicString(),
|
||||
@@ -345,6 +387,7 @@ namespace Fig
|
||||
}
|
||||
fnCtx->def(paras.posParas[i].first, paraType, AccessModifier::Normal, args[i]);
|
||||
}
|
||||
return StatementResult::normal();
|
||||
};
|
||||
|
||||
if (paraCnt == 1)
|
||||
@@ -385,12 +428,12 @@ namespace Fig
|
||||
// ===== interface implementation validation =====
|
||||
ImplRecord record{interfaceType, structType, {}};
|
||||
|
||||
std::unordered_map<String, Ast::InterfaceMethod> ifaceMethods;
|
||||
std::unordered_map<FString, Ast::InterfaceMethod> ifaceMethods;
|
||||
for (auto &m : interface.methods)
|
||||
{
|
||||
if (ifaceMethods.contains(m.name))
|
||||
{
|
||||
throw EvaluatorError(U"InterfaceDuplicateMethodError",
|
||||
throw EvaluatorError(u8"InterfaceDuplicateMethodError",
|
||||
std::format("Interface '{}' has duplicate method '{}'",
|
||||
interfaceType.toString().toBasicString(),
|
||||
m.name.toBasicString()),
|
||||
@@ -399,16 +442,16 @@ namespace Fig
|
||||
ifaceMethods[m.name] = m;
|
||||
}
|
||||
|
||||
std::unordered_set<String> implemented;
|
||||
std::unordered_set<FString> implemented;
|
||||
|
||||
for (auto &implMethod : implementMethods)
|
||||
{
|
||||
const String &name = implMethod.name;
|
||||
const FString &name = implMethod.name;
|
||||
|
||||
// ---- redundant impl ----
|
||||
if (!ifaceMethods.contains(name))
|
||||
{
|
||||
throw EvaluatorError(U"RedundantImplementationError",
|
||||
throw EvaluatorError(u8"RedundantImplementationError",
|
||||
std::format("Struct '{}' implements extra method '{}' "
|
||||
"which is not required by interface '{}'",
|
||||
structType.toString().toBasicString(),
|
||||
@@ -419,7 +462,7 @@ namespace Fig
|
||||
|
||||
if (implemented.contains(name))
|
||||
{
|
||||
throw EvaluatorError(U"DuplicateImplementMethodError",
|
||||
throw EvaluatorError(u8"DuplicateImplementMethodError",
|
||||
std::format("Duplicate implement method '{}'", name.toBasicString()),
|
||||
ip);
|
||||
}
|
||||
@@ -429,7 +472,7 @@ namespace Fig
|
||||
// ---- signature check ----
|
||||
if (!isInterfaceSignatureMatch(implMethod, ifMethod))
|
||||
{
|
||||
throw EvaluatorError(U"InterfaceSignatureMismatch",
|
||||
throw EvaluatorError(u8"InterfaceSignatureMismatch",
|
||||
std::format("Interface method '{}({})' signature mismatch with "
|
||||
"implementation '{}({})'",
|
||||
ifMethod.name.toBasicString(),
|
||||
@@ -441,7 +484,7 @@ namespace Fig
|
||||
|
||||
if (ctx->hasMethodImplemented(structType, name))
|
||||
{
|
||||
throw EvaluatorError(U"DuplicateImplementMethodError",
|
||||
throw EvaluatorError(u8"DuplicateImplementMethodError",
|
||||
std::format("Method '{}' already implemented by another interface "
|
||||
"for struct '{}'",
|
||||
name.toBasicString(),
|
||||
@@ -463,7 +506,7 @@ namespace Fig
|
||||
|
||||
if (m.hasDefaultBody()) continue;
|
||||
|
||||
throw EvaluatorError(U"MissingImplementationError",
|
||||
throw EvaluatorError(u8"MissingImplementationError",
|
||||
std::format("Struct '{}' does not implement required interface method '{}' "
|
||||
"and interface '{}' provides no default implementation",
|
||||
structType.toString().toBasicString(),
|
||||
@@ -482,7 +525,7 @@ namespace Fig
|
||||
if (condVal->getTypeInfo() != ValueType::Bool)
|
||||
{
|
||||
throw EvaluatorError(
|
||||
U"TypeError",
|
||||
u8"TypeError",
|
||||
std::format("Condition must be boolean, but got '{}'", prettyType(condVal).toBasicString()),
|
||||
ifSt->condition);
|
||||
}
|
||||
@@ -494,7 +537,7 @@ namespace Fig
|
||||
if (elifCondVal->getTypeInfo() != ValueType::Bool)
|
||||
{
|
||||
throw EvaluatorError(
|
||||
U"TypeError",
|
||||
u8"TypeError",
|
||||
std::format("Condition must be boolean, but got '{}'", prettyType(condVal).toBasicString()),
|
||||
ifSt->condition);
|
||||
}
|
||||
@@ -511,13 +554,13 @@ namespace Fig
|
||||
if (condVal->getTypeInfo() != ValueType::Bool)
|
||||
{
|
||||
throw EvaluatorError(
|
||||
U"TypeError",
|
||||
u8"TypeError",
|
||||
std::format("Condition must be boolean, but got '{}'", prettyType(condVal).toBasicString()),
|
||||
whileSt->condition);
|
||||
}
|
||||
if (!condVal->as<ValueType::BoolClass>()) { break; }
|
||||
ContextPtr loopContext = std::make_shared<Context>(
|
||||
String(std::format("<While {}:{}>", whileSt->getAAI().line, whileSt->getAAI().column)),
|
||||
FString(std::format("<While {}:{}>", whileSt->getAAI().line, whileSt->getAAI().column)),
|
||||
ctx); // every loop has its own context
|
||||
StatementResult sr = evalBlockStatement(whileSt->body, loopContext);
|
||||
if (sr.shouldReturn()) { return sr; }
|
||||
@@ -529,13 +572,18 @@ namespace Fig
|
||||
case ForSt: {
|
||||
auto forSt = std::static_pointer_cast<Ast::ForSt>(stmt);
|
||||
ContextPtr loopContext = std::make_shared<Context>(
|
||||
String(std::format("<For {}:{}>", forSt->getAAI().line, forSt->getAAI().column)),
|
||||
FString(std::format("<For {}:{}>", forSt->getAAI().line, forSt->getAAI().column)),
|
||||
ctx); // for loop has its own context
|
||||
|
||||
evalStatement(forSt->initSt,
|
||||
loopContext); // ignore init statement result
|
||||
size_t iteration = 0;
|
||||
|
||||
ContextPtr iterationContext = std::make_shared<Context>(
|
||||
FString(std::format(
|
||||
"<For {}:{}, Iteration {}>", forSt->getAAI().line, forSt->getAAI().column, iteration)),
|
||||
loopContext); // every loop has its own context
|
||||
|
||||
while (true) // use while loop to simulate for loop, cause we
|
||||
// need to check condition type every iteration
|
||||
{
|
||||
@@ -543,17 +591,18 @@ namespace Fig
|
||||
if (condVal->getTypeInfo() != ValueType::Bool)
|
||||
{
|
||||
throw EvaluatorError(
|
||||
U"TypeError",
|
||||
u8"TypeError",
|
||||
std::format("Condition must be boolean, but got '{}'", prettyType(condVal).toBasicString()),
|
||||
forSt->condition);
|
||||
}
|
||||
if (!condVal->as<ValueType::BoolClass>()) { break; }
|
||||
iteration++;
|
||||
ContextPtr iterationContext = std::make_shared<Context>(
|
||||
String(std::format(
|
||||
"<For {}:{}, Iteration {}>", forSt->getAAI().line, forSt->getAAI().column, iteration)),
|
||||
loopContext); // every loop has its own context
|
||||
|
||||
StatementResult sr = evalBlockStatement(forSt->body, iterationContext);
|
||||
iterationContext->clear();
|
||||
iterationContext->setScopeName(FString(std::format(
|
||||
"<For {}:{}, Iteration {}>", forSt->getAAI().line, forSt->getAAI().column, iteration)));
|
||||
|
||||
if (sr.shouldReturn()) { return sr; }
|
||||
if (sr.shouldBreak()) { break; }
|
||||
if (sr.shouldContinue())
|
||||
@@ -571,7 +620,7 @@ namespace Fig
|
||||
auto tryst = std::static_pointer_cast<Ast::TrySt>(stmt);
|
||||
|
||||
ContextPtr tryCtx = std::make_shared<Context>(
|
||||
String(std::format("<Try at {}:{}>", tryst->getAAI().line, tryst->getAAI().column)), ctx);
|
||||
FString(std::format("<Try at {}:{}>", tryst->getAAI().line, tryst->getAAI().column)), ctx);
|
||||
StatementResult sr = StatementResult::normal();
|
||||
bool crashed = false;
|
||||
for (auto &stmt : tryst->body->stmts)
|
||||
@@ -586,12 +635,13 @@ namespace Fig
|
||||
bool catched = false;
|
||||
for (auto &cat : tryst->catches)
|
||||
{
|
||||
const String &errVarName = cat.errVarName;
|
||||
const FString &errVarName = cat.errVarName;
|
||||
TypeInfo errVarType = (cat.hasType ? TypeInfo(cat.errVarType) : ValueType::Any);
|
||||
if (isTypeMatch(errVarType, sr.result, ctx))
|
||||
{
|
||||
ContextPtr catchCtx = std::make_shared<Context>(
|
||||
String(std::format("<Catch at {}:{}>", cat.body->getAAI().line, cat.body->getAAI().column)),
|
||||
FString(
|
||||
std::format("<Catch at {}:{}>", cat.body->getAAI().line, cat.body->getAAI().column)),
|
||||
ctx);
|
||||
catchCtx->def(errVarName, errVarType, AccessModifier::Normal, sr.result);
|
||||
sr = evalBlockStatement(cat.body, catchCtx);
|
||||
@@ -601,7 +651,7 @@ namespace Fig
|
||||
}
|
||||
if (!catched && crashed)
|
||||
{
|
||||
throw EvaluatorError(U"UncaughtExceptionError",
|
||||
throw EvaluatorError(u8"UncaughtExceptionError",
|
||||
std::format("Uncaught exception: {}", sr.result->toString().toBasicString()),
|
||||
tryst);
|
||||
}
|
||||
@@ -615,7 +665,7 @@ namespace Fig
|
||||
ObjectPtr value = check_unwrap_stres(eval(ts->value, ctx));
|
||||
if (value->is<ValueType::NullClass>())
|
||||
{
|
||||
throw EvaluatorError(U"TypeError", U"Why did you throw a null?", ts);
|
||||
throw EvaluatorError(u8"TypeError", u8"Why did you throw a null?", ts);
|
||||
}
|
||||
return StatementResult::errorFlow(value);
|
||||
}
|
||||
@@ -631,11 +681,11 @@ namespace Fig
|
||||
case BreakSt: {
|
||||
if (!ctx->parent)
|
||||
{
|
||||
throw EvaluatorError(U"BreakOutsideLoopError", U"`break` statement outside loop", stmt);
|
||||
throw EvaluatorError(u8"BreakOutsideLoopError", u8"`break` statement outside loop", stmt);
|
||||
}
|
||||
if (!ctx->isInLoopContext())
|
||||
{
|
||||
throw EvaluatorError(U"BreakOutsideLoopError", U"`break` statement outside loop", stmt);
|
||||
throw EvaluatorError(u8"BreakOutsideLoopError", u8"`break` statement outside loop", stmt);
|
||||
}
|
||||
return StatementResult::breakFlow();
|
||||
}
|
||||
@@ -643,11 +693,11 @@ namespace Fig
|
||||
case ContinueSt: {
|
||||
if (!ctx->parent)
|
||||
{
|
||||
throw EvaluatorError(U"ContinueOutsideLoopError", U"`continue` statement outside loop", stmt);
|
||||
throw EvaluatorError(u8"ContinueOutsideLoopError", u8"`continue` statement outside loop", stmt);
|
||||
}
|
||||
if (!ctx->isInLoopContext())
|
||||
{
|
||||
throw EvaluatorError(U"ContinueOutsideLoopError", U"`continue` statement outside loop", stmt);
|
||||
throw EvaluatorError(u8"ContinueOutsideLoopError", u8"`continue` statement outside loop", stmt);
|
||||
}
|
||||
return StatementResult::continueFlow();
|
||||
}
|
||||
@@ -661,13 +711,13 @@ namespace Fig
|
||||
auto block = std::static_pointer_cast<Ast::BlockStatementAst>(stmt);
|
||||
|
||||
ContextPtr blockCtx = std::make_shared<Context>(
|
||||
String(std::format("<Block at {}:{}>", block->getAAI().line, block->getAAI().column)), ctx);
|
||||
FString(std::format("<Block at {}:{}>", block->getAAI().line, block->getAAI().column)), ctx);
|
||||
return evalBlockStatement(block, blockCtx);
|
||||
}
|
||||
|
||||
default:
|
||||
throw RuntimeError(
|
||||
String(std::format("Feature stmt {} unsupported yet", magic_enum::enum_name(stmt->getType()))));
|
||||
FString(std::format("Feature stmt {} unsupported yet", magic_enum::enum_name(stmt->getType()))));
|
||||
}
|
||||
}
|
||||
}; // namespace Fig
|
||||
@@ -11,7 +11,7 @@ namespace Fig
|
||||
if (condVal->getTypeInfo() != ValueType::Bool)
|
||||
{
|
||||
throw EvaluatorError(
|
||||
U"TypeError",
|
||||
u8"TypeError",
|
||||
std::format("Condition must be boolean, got '{}'", prettyType(condVal).toBasicString()),
|
||||
te->condition);
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace Fig
|
||||
return tryInvokeOverloadFn(value, [value]() { return std::make_shared<Object>(bit_not(*value)); });
|
||||
}
|
||||
default: {
|
||||
throw EvaluatorError(U"UnsupportedOpError",
|
||||
throw EvaluatorError(u8"UnsupportedOpError",
|
||||
std::format("Unsupported op '{}' for unary expression", magic_enum::enum_name(op)),
|
||||
un);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <Core/String.hpp>
|
||||
#include <Core/fig_string.hpp>
|
||||
#include <Evaluator/Value/value_forward.hpp>
|
||||
#include <Evaluator/Value/LvObject.hpp>
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
namespace Fig
|
||||
{
|
||||
|
||||
std::filesystem::path Evaluator::resolveModulePath(const std::vector<String> &pathVec)
|
||||
std::filesystem::path Evaluator::resolveModulePath(const std::vector<FString> &pathVec)
|
||||
{
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
@@ -32,13 +32,13 @@ namespace Fig
|
||||
import comp.config;
|
||||
*/
|
||||
|
||||
const String &modPathStrTop = pathVec.at(0);
|
||||
const FString &modPathStrTop = pathVec.at(0);
|
||||
fs::path modPath;
|
||||
|
||||
bool found = false;
|
||||
for (auto &parentFolder : pathToFind)
|
||||
{
|
||||
modPath = parentFolder / String(modPathStrTop + U".fig").toBasicString();
|
||||
modPath = parentFolder / FString(modPathStrTop + u8".fig").toBasicString();
|
||||
if (fs::exists(modPath))
|
||||
{
|
||||
path = modPath;
|
||||
@@ -50,16 +50,16 @@ namespace Fig
|
||||
modPath = parentFolder / modPathStrTop.toBasicString();
|
||||
if (fs::is_directory(modPath)) // comp is a directory
|
||||
{
|
||||
modPath = modPath / String(modPathStrTop + U".fig").toBasicString();
|
||||
modPath = modPath / FString(modPathStrTop + u8".fig").toBasicString();
|
||||
/*
|
||||
if module name is a directory, we require [module
|
||||
name].fig at the directory
|
||||
*/
|
||||
if (!fs::exists(modPath))
|
||||
{
|
||||
throw RuntimeError(String(std::format("requires module file, {}\\{}",
|
||||
throw RuntimeError(FString(std::format("requires module file, {}\\{}",
|
||||
modPathStrTop.toBasicString(),
|
||||
String(modPathStrTop + U".fig").toBasicString())));
|
||||
FString(modPathStrTop + u8".fig").toBasicString())));
|
||||
}
|
||||
found = true;
|
||||
path = modPath;
|
||||
@@ -69,19 +69,19 @@ namespace Fig
|
||||
}
|
||||
|
||||
if (!found)
|
||||
throw RuntimeError(String(std::format("Could not find module `{}`", modPathStrTop.toBasicString())));
|
||||
throw RuntimeError(FString(std::format("Could not find module `{}`", modPathStrTop.toBasicString())));
|
||||
|
||||
bool found2 = false;
|
||||
|
||||
for (size_t i = 1; i < pathVec.size(); ++i) // has next module
|
||||
{
|
||||
const String &next = pathVec.at(i);
|
||||
const FString &next = pathVec.at(i);
|
||||
modPath = modPath.parent_path(); // get the folder
|
||||
modPath = modPath / String(next + U".fig").toBasicString();
|
||||
modPath = modPath / FString(next + u8".fig").toBasicString();
|
||||
if (fs::exists(modPath))
|
||||
{
|
||||
if (i != pathVec.size() - 1)
|
||||
throw RuntimeError(String(std::format(
|
||||
throw RuntimeError(FString(std::format(
|
||||
"expects {} as parent directory and find next module, but got a file", next.toBasicString())));
|
||||
// it's the last module
|
||||
found2 = true;
|
||||
@@ -91,14 +91,14 @@ namespace Fig
|
||||
// `next` is a folder
|
||||
modPath = modPath.parent_path() / next.toBasicString();
|
||||
if (!fs::exists(modPath))
|
||||
throw RuntimeError(String(std::format("Could not find module `{}`", next.toBasicString())));
|
||||
throw RuntimeError(FString(std::format("Could not find module `{}`", next.toBasicString())));
|
||||
if (i == pathVec.size() - 1)
|
||||
{
|
||||
// `next` is the last module
|
||||
modPath = modPath / String(next + U".fig").toBasicString();
|
||||
modPath = modPath / FString(next + u8".fig").toBasicString();
|
||||
if (!fs::exists(modPath))
|
||||
{
|
||||
throw RuntimeError(String(std::format(
|
||||
throw RuntimeError(FString(std::format(
|
||||
"expects {} as parent directory and find next module, but got a file", next.toBasicString())));
|
||||
}
|
||||
found2 = true;
|
||||
@@ -107,8 +107,8 @@ namespace Fig
|
||||
}
|
||||
|
||||
if (!found2 && !fs::exists(modPath))
|
||||
throw RuntimeError(String(std::format("Could not find module `{}`", pathVec.end()->toBasicString())));
|
||||
throw RuntimeError(FString(std::format("Could not find module `{}`", pathVec.end()->toBasicString())));
|
||||
|
||||
return path;
|
||||
}
|
||||
}; // namespace Fig
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <Core/String.hpp>
|
||||
#include <Core/fig_string.hpp>
|
||||
#include <Evaluator/Value/value.hpp>
|
||||
|
||||
namespace Fig
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <Evaluator/Value/value.hpp>
|
||||
#include <Core/String.hpp>
|
||||
#include <Core/fig_string.hpp>
|
||||
#include <Evaluator/Value/value_forward.hpp>
|
||||
#include <Evaluator/Value/Type.hpp>
|
||||
#include <array>
|
||||
|
||||
@@ -24,15 +24,18 @@ namespace Fig
|
||||
|
||||
ContextPtr ctx;
|
||||
|
||||
LvObject(std::shared_ptr<VariableSlot> _slot, ContextPtr _ctx) : slot(std::move(_slot)), ctx(_ctx)
|
||||
LvObject(std::shared_ptr<VariableSlot> _slot, ContextPtr _ctx) :
|
||||
slot(std::move(_slot)), ctx(_ctx)
|
||||
{
|
||||
kind = Kind::Variable;
|
||||
}
|
||||
LvObject(ObjectPtr _v, size_t _index, Kind _kind, ContextPtr _ctx) : value(_v), numIndex(_index), ctx(_ctx)
|
||||
LvObject(ObjectPtr _v, size_t _index, Kind _kind, ContextPtr _ctx) :
|
||||
value(_v), numIndex(_index), ctx(_ctx)
|
||||
{
|
||||
kind = _kind;
|
||||
}
|
||||
LvObject(ObjectPtr _v, ObjectPtr _index, Kind _kind, ContextPtr _ctx) : value(_v), mapIndex(_index), ctx(_ctx)
|
||||
LvObject(ObjectPtr _v, ObjectPtr _index, Kind _kind, ContextPtr _ctx) :
|
||||
value(_v), mapIndex(_index), ctx(_ctx)
|
||||
{
|
||||
kind = _kind;
|
||||
}
|
||||
@@ -48,26 +51,27 @@ namespace Fig
|
||||
{
|
||||
List &list = value->as<List>();
|
||||
if (numIndex >= list.size())
|
||||
throw RuntimeError(
|
||||
String(std::format("Index {} out of range {}", numIndex, value->toString().toBasicString())));
|
||||
throw RuntimeError(FString(
|
||||
std::format("Index {} out of range {}", numIndex, value->toString().toBasicString())));
|
||||
return list.at(numIndex).value;
|
||||
}
|
||||
else if (kind == Kind::MapElement) // map
|
||||
{
|
||||
Map &map = value->as<Map>();
|
||||
if (!map.contains(mapIndex))
|
||||
throw RuntimeError(String(std::format("Key {} not found", mapIndex->toString().toBasicString())));
|
||||
throw RuntimeError(FString(
|
||||
std::format("Key {} not found", mapIndex->toString().toBasicString())));
|
||||
return map.at(mapIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
// string
|
||||
String &string = value->as<ValueType::StringClass>();
|
||||
FString &string = value->as<ValueType::StringClass>();
|
||||
if (numIndex >= string.length())
|
||||
throw RuntimeError(
|
||||
String(std::format("Index {} out of range {}", numIndex, value->toString().toBasicString())));
|
||||
throw RuntimeError(FString(
|
||||
std::format("Index {} out of range {}", numIndex, value->toString().toBasicString())));
|
||||
|
||||
return std::make_shared<Object>(String(string[numIndex]));
|
||||
return std::make_shared<Object>(string.getRealChar(numIndex));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,23 +80,27 @@ namespace Fig
|
||||
if (kind == Kind::Variable)
|
||||
{
|
||||
auto s = resolve(slot);
|
||||
if (isAccessConst(s->am))
|
||||
{
|
||||
throw RuntimeError(FString(std::format("Variable `{}` is immutable", s->name.toBasicString())));
|
||||
}
|
||||
if (!isTypeMatch(s->declaredType, v, ctx))
|
||||
{
|
||||
throw RuntimeError(String(std::format("Variable `{}` expects type `{}`, but got '{}'",
|
||||
throw RuntimeError(
|
||||
FString(
|
||||
std::format("Variable `{}` expects type `{}`, but got '{}'",
|
||||
s->name.toBasicString(),
|
||||
s->declaredType.toString().toBasicString(),
|
||||
prettyType(v).toBasicString())));
|
||||
}
|
||||
if (isAccessConst(s->am))
|
||||
{
|
||||
throw RuntimeError(String(std::format("Variable `{}` is immutable", s->name.toBasicString())));
|
||||
}
|
||||
s->value = v;
|
||||
}
|
||||
else if (kind == Kind::ListElement)
|
||||
{
|
||||
List &list = value->as<List>();
|
||||
if (numIndex >= list.size()) throw RuntimeError(String(std::format("Index {} out of range", numIndex)));
|
||||
if (numIndex >= list.size())
|
||||
throw RuntimeError(FString(
|
||||
std::format("Index {} out of range", numIndex)));
|
||||
list[numIndex] = v;
|
||||
}
|
||||
else if (kind == Kind::MapElement) // map
|
||||
@@ -102,23 +110,25 @@ namespace Fig
|
||||
}
|
||||
else if (kind == Kind::StringElement)
|
||||
{
|
||||
String &string = value->as<ValueType::StringClass>();
|
||||
FString &string = value->as<ValueType::StringClass>();
|
||||
if (numIndex >= string.length())
|
||||
throw RuntimeError(
|
||||
String(std::format("Index {} out of range {}", numIndex, value->toString().toBasicString())));
|
||||
throw RuntimeError(FString(
|
||||
std::format("Index {} out of range {}", numIndex, value->toString().toBasicString())));
|
||||
|
||||
if (v->getTypeInfo() != ValueType::String)
|
||||
throw RuntimeError(
|
||||
String(std::format("Could not assign {} to sub string", v->toString().toBasicString())));
|
||||
const String &strReplace = v->as<ValueType::StringClass>();
|
||||
throw RuntimeError(FString(
|
||||
std::format("Could not assign {} to sub string", v->toString().toBasicString())
|
||||
));
|
||||
const FString &strReplace = v->as<ValueType::StringClass>();
|
||||
if (strReplace.length() > 1)
|
||||
throw RuntimeError(String(std::format("Could not assign {} to sub string, expects length 1",
|
||||
v->toString().toBasicString())));
|
||||
string.replace(numIndex, strReplace.length(), strReplace);
|
||||
throw RuntimeError(FString(
|
||||
std::format("Could not assign {} to sub string, expects length 1", v->toString().toBasicString())
|
||||
));
|
||||
string.realReplace(numIndex, strReplace);
|
||||
}
|
||||
}
|
||||
|
||||
String name() const { return resolve(slot)->name; }
|
||||
FString name() const { return resolve(slot)->name; }
|
||||
TypeInfo declaredType() const { return resolve(slot)->declaredType; }
|
||||
AccessModifier access() const { return resolve(slot)->am; }
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <Core/String.hpp>
|
||||
#include <Core/fig_string.hpp>
|
||||
|
||||
#include <unordered_set>
|
||||
#include <variant>
|
||||
@@ -14,23 +14,23 @@ namespace Fig
|
||||
private:
|
||||
size_t id;
|
||||
|
||||
std::map<String, size_t> &getTypeMap()
|
||||
std::map<FString, size_t> &getTypeMap()
|
||||
{
|
||||
static std::map<String, size_t> typeMap;
|
||||
static std::map<FString, size_t> typeMap;
|
||||
return typeMap;
|
||||
}
|
||||
|
||||
public:
|
||||
friend class TypeInfoHash;
|
||||
|
||||
String name;
|
||||
FString name;
|
||||
|
||||
String toString() const { return name; }
|
||||
FString toString() const { return name; }
|
||||
|
||||
size_t getInstanceID() const { return id; }
|
||||
|
||||
TypeInfo();
|
||||
explicit TypeInfo(const String &_name, bool reg = false);
|
||||
explicit TypeInfo(const FString &_name, bool reg = false);
|
||||
TypeInfo(const TypeInfo &other) = default;
|
||||
|
||||
bool operator==(const TypeInfo &other) const { return id == other.id; }
|
||||
@@ -63,7 +63,7 @@ namespace Fig
|
||||
using DoubleClass = double;
|
||||
using BoolClass = bool;
|
||||
using NullClass = std::monostate;
|
||||
using StringClass = Fig::String;
|
||||
using StringClass = FString;
|
||||
|
||||
inline bool isTypeBuiltin(const TypeInfo &type)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <Ast/AccessModifier.hpp>
|
||||
#include <Core/String.hpp>
|
||||
#include <Core/fig_string.hpp>
|
||||
#include <Evaluator/Value/Type.hpp>
|
||||
#include <Evaluator/Value/value_forward.hpp>
|
||||
|
||||
@@ -11,7 +12,7 @@ namespace Fig
|
||||
|
||||
struct VariableSlot
|
||||
{
|
||||
String name;
|
||||
FString name;
|
||||
ObjectPtr value;
|
||||
TypeInfo declaredType;
|
||||
AccessModifier am;
|
||||
@@ -19,4 +20,4 @@ namespace Fig
|
||||
bool isRef = false;
|
||||
std::shared_ptr<VariableSlot> refTarget;
|
||||
};
|
||||
} // namespace Fig
|
||||
}
|
||||
@@ -16,7 +16,7 @@ namespace Fig
|
||||
{
|
||||
public:
|
||||
std::size_t id;
|
||||
String name;
|
||||
FString name;
|
||||
|
||||
enum FnType
|
||||
{
|
||||
@@ -53,7 +53,7 @@ namespace Fig
|
||||
new (&body) Ast::BlockStatement();
|
||||
}
|
||||
|
||||
Function(const String &_name,
|
||||
Function(const FString &_name,
|
||||
Ast::FunctionParameters _paras,
|
||||
TypeInfo _retType,
|
||||
Ast::BlockStatement _body,
|
||||
@@ -68,16 +68,13 @@ namespace Fig
|
||||
type = Normal;
|
||||
}
|
||||
|
||||
Function(const String &_name,
|
||||
std::function<std::shared_ptr<Object>(const std::vector<std::shared_ptr<Object>> &)> fn,
|
||||
int argc) :
|
||||
Function(const FString &_name, std::function<std::shared_ptr<Object>(const std::vector<std::shared_ptr<Object>> &)> fn, int argc) :
|
||||
id(nextId()), name(_name), type(Builtin), builtin(fn), builtinParamCount(argc)
|
||||
{
|
||||
type = Builtin;
|
||||
}
|
||||
|
||||
Function(const String &_name,
|
||||
std::function<std::shared_ptr<Object>(std::shared_ptr<Object>,
|
||||
Function(const FString &_name, std::function<std::shared_ptr<Object>(std::shared_ptr<Object>,
|
||||
const std::vector<std::shared_ptr<Object>> &)> fn,
|
||||
int argc) :
|
||||
id(nextId()), name(_name), type(MemberType), mtFn(fn), builtinParamCount(argc)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <Core/String.hpp>
|
||||
#include <Core/fig_string.hpp>
|
||||
|
||||
#include <Evaluator/Context/context_forward.hpp>
|
||||
|
||||
@@ -8,13 +8,20 @@ namespace Fig
|
||||
{
|
||||
struct Module
|
||||
{
|
||||
String name;
|
||||
FString name;
|
||||
ContextPtr ctx;
|
||||
|
||||
Module() = default;
|
||||
|
||||
Module(String n, ContextPtr c) : name(std::move(n)), ctx(std::move(c)) {}
|
||||
Module(FString n, ContextPtr c) :
|
||||
name(std::move(n)),
|
||||
ctx(std::move(c))
|
||||
{
|
||||
}
|
||||
|
||||
bool operator==(const Module &o) const noexcept { return name == o.name; }
|
||||
bool operator==(const Module &o) const noexcept
|
||||
{
|
||||
return name == o.name;
|
||||
}
|
||||
};
|
||||
};
|
||||
}; // namespace Fig
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <Core/String.hpp>
|
||||
#include <Core/fig_string.hpp>
|
||||
#include <Ast/Statements/StructDefSt.hpp>
|
||||
|
||||
#include <Evaluator/Value/Type.hpp>
|
||||
@@ -14,17 +14,21 @@ namespace Fig
|
||||
struct Field
|
||||
{
|
||||
AccessModifier am;
|
||||
String name;
|
||||
FString name;
|
||||
TypeInfo type;
|
||||
Ast::Expression defaultValue;
|
||||
|
||||
Field(AccessModifier _am, String _name, TypeInfo _type, Ast::Expression _defaultValue) :
|
||||
am(_am), name(std::move(_name)), type(std::move(_type)), defaultValue(std::move(_defaultValue))
|
||||
{
|
||||
}
|
||||
Field(AccessModifier _am, FString _name, TypeInfo _type, Ast::Expression _defaultValue) :
|
||||
am(_am), name(std::move(_name)), type(std::move(_type)), defaultValue(std::move(_defaultValue)) {}
|
||||
|
||||
bool isPublic() const { return am == AccessModifier::Public || am == AccessModifier::PublicConst; }
|
||||
bool isConst() const { return am == AccessModifier::Const || am == AccessModifier::PublicConst; }
|
||||
bool isPublic() const
|
||||
{
|
||||
return am == AccessModifier::Public || am == AccessModifier::PublicConst;
|
||||
}
|
||||
bool isConst() const
|
||||
{
|
||||
return am == AccessModifier::Const || am == AccessModifier::PublicConst;
|
||||
}
|
||||
};
|
||||
|
||||
struct StructType
|
||||
@@ -37,9 +41,7 @@ namespace Fig
|
||||
|
||||
// ===== Constructors =====
|
||||
StructType(TypeInfo _type, ContextPtr _defContext, std::vector<Field> _fields, bool _builtin = false) :
|
||||
type(std::move(_type)), defContext(std::move(_defContext)), fields(std::move(_fields)), builtin(_builtin)
|
||||
{
|
||||
}
|
||||
type(std::move(_type)), defContext(std::move(_defContext)), fields(std::move(_fields)), builtin(_builtin) {}
|
||||
|
||||
StructType(const StructType &other) = default;
|
||||
StructType(StructType &&) noexcept = default;
|
||||
@@ -47,8 +49,14 @@ namespace Fig
|
||||
StructType &operator=(StructType &&) noexcept = default;
|
||||
|
||||
// ===== Comparison =====
|
||||
bool operator==(const StructType &other) const noexcept { return type == other.type; }
|
||||
bool operator!=(const StructType &other) const noexcept { return !(*this == other); }
|
||||
bool operator==(const StructType &other) const noexcept
|
||||
{
|
||||
return type == other.type;
|
||||
}
|
||||
bool operator!=(const StructType &other) const noexcept
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
private:
|
||||
static std::size_t nextId()
|
||||
@@ -64,6 +72,9 @@ namespace std
|
||||
template <>
|
||||
struct hash<Fig::Field>
|
||||
{
|
||||
size_t operator()(const Fig::Field &f) { return std::hash<Fig::String>{}(f.name); }
|
||||
size_t operator()(const Fig::Field &f)
|
||||
{
|
||||
return std::hash<Fig::FString>{}(f.name);
|
||||
}
|
||||
};
|
||||
}; // namespace std
|
||||
@@ -11,10 +11,10 @@ namespace Fig
|
||||
{
|
||||
|
||||
TypeInfo::TypeInfo() : // only allow use in evaluate time !! <---- dynamic type system requirement
|
||||
id(1), name(String(U"Any"))
|
||||
id(1), name(FString(u8"Any"))
|
||||
{
|
||||
}
|
||||
TypeInfo::TypeInfo(const String &_name, bool reg)
|
||||
TypeInfo::TypeInfo(const FString &_name, bool reg)
|
||||
{
|
||||
static size_t id_count = 0;
|
||||
name = _name;
|
||||
@@ -28,7 +28,7 @@ namespace Fig
|
||||
{
|
||||
if (!getTypeMap().contains(_name))
|
||||
{
|
||||
throw RuntimeError(String(std::format("No type named '{}'", _name.toBasicString())));
|
||||
throw RuntimeError(FString(std::format("No type named '{}'", _name.toBasicString())));
|
||||
// *this = ValueType::String;
|
||||
}
|
||||
id = getTypeMap().at(name); // may throw
|
||||
@@ -93,29 +93,25 @@ namespace Fig
|
||||
if (t == ValueType::StructInstance) return obj->as<StructInstance>().parentType;
|
||||
return t;
|
||||
}
|
||||
String prettyType(std::shared_ptr<const Object> obj)
|
||||
FString prettyType(std::shared_ptr<const Object> obj)
|
||||
{
|
||||
return actualType(obj).toString();
|
||||
}
|
||||
|
||||
const TypeInfo ValueType::Any(U"Any", true); // id: 1
|
||||
const TypeInfo ValueType::Null(U"Null", true); // id: 2
|
||||
const TypeInfo ValueType::Int(U"Int", true); // id: 3
|
||||
const TypeInfo ValueType::String(U"String", true); // id: 4
|
||||
const TypeInfo ValueType::Bool(U"Bool", true); // id: 5
|
||||
const TypeInfo ValueType::Double(U"Double", true); // id: 6
|
||||
const TypeInfo ValueType::Function(U"Function", true); // id: 7
|
||||
const TypeInfo ValueType::StructType(U"StructType", true); // id: 8
|
||||
const TypeInfo ValueType::StructInstance(U"StructInstance", true); // id: 9
|
||||
const TypeInfo ValueType::List(U"List", true); // id: 10
|
||||
const TypeInfo ValueType::Map(U"Map", true); // id: 11
|
||||
const TypeInfo ValueType::Module(U"Module", true); // id: 12
|
||||
const TypeInfo ValueType::InterfaceType(U"InterfaceType", true); // id: 13
|
||||
const TypeInfo ValueType::Any(FString(u8"Any"), true); // id: 1
|
||||
const TypeInfo ValueType::Null(FString(u8"Null"), true); // id: 2
|
||||
const TypeInfo ValueType::Int(FString(u8"Int"), true); // id: 3
|
||||
const TypeInfo ValueType::String(FString(u8"String"), true); // id: 4
|
||||
const TypeInfo ValueType::Bool(FString(u8"Bool"), true); // id: 5
|
||||
const TypeInfo ValueType::Double(FString(u8"Double"), true); // id: 6
|
||||
const TypeInfo ValueType::Function(FString(u8"Function"), true); // id: 7
|
||||
const TypeInfo ValueType::StructType(FString(u8"StructType"), true); // id: 8
|
||||
const TypeInfo ValueType::StructInstance(FString(u8"StructInstance"), true); // id: 9
|
||||
const TypeInfo ValueType::List(FString(u8"List"), true); // id: 10
|
||||
const TypeInfo ValueType::Map(FString(u8"Map"), true); // id: 11
|
||||
const TypeInfo ValueType::Module(FString(u8"Module"), true); // id: 12
|
||||
const TypeInfo ValueType::InterfaceType(FString(u8"InterfaceType"), true); // id: 13
|
||||
|
||||
namespace ValueType
|
||||
{
|
||||
|
||||
};
|
||||
bool implements(const TypeInfo &structType, const TypeInfo &interfaceType, ContextPtr ctx)
|
||||
{
|
||||
return ctx->hasImplRegisted(structType, interfaceType);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#include <Core/String.hpp>
|
||||
#include <Core/fig_string.hpp>
|
||||
#include <Evaluator/Value/function.hpp>
|
||||
#include <Evaluator/Value/interface.hpp>
|
||||
#include <Evaluator/Value/structType.hpp>
|
||||
@@ -43,7 +43,7 @@ namespace Fig
|
||||
}
|
||||
|
||||
TypeInfo actualType(std::shared_ptr<const Object> obj);
|
||||
String prettyType(std::shared_ptr<const Object> obj);
|
||||
FString prettyType(std::shared_ptr<const Object> obj);
|
||||
|
||||
bool operator==(const Object &, const Object &);
|
||||
|
||||
@@ -93,92 +93,89 @@ namespace Fig
|
||||
Module,
|
||||
InterfaceType>;
|
||||
|
||||
static std::unordered_map<TypeInfo, std::unordered_map<String, BuiltinTypeMemberFn>, TypeInfoHash>
|
||||
static std::unordered_map<TypeInfo, std::unordered_map<FString, BuiltinTypeMemberFn>, TypeInfoHash>
|
||||
getMemberTypeFunctions()
|
||||
{
|
||||
static const std::unordered_map<TypeInfo, std::unordered_map<String, BuiltinTypeMemberFn>, TypeInfoHash>
|
||||
static const std::unordered_map<TypeInfo, std::unordered_map<FString, BuiltinTypeMemberFn>, TypeInfoHash>
|
||||
memberTypeFunctions{
|
||||
{ValueType::Null, {}},
|
||||
{ValueType::Int, {}},
|
||||
{ValueType::Double, {}},
|
||||
{ValueType::String,
|
||||
{
|
||||
{U"length",
|
||||
{u8"length",
|
||||
[](ObjectPtr object, std::vector<ObjectPtr> args) -> ObjectPtr {
|
||||
if (args.size() != 0)
|
||||
throw RuntimeError(
|
||||
String(std::format("`length` expects 0 arguments, {} got", args.size())));
|
||||
const String &str = object->as<ValueType::StringClass>();
|
||||
FString(std::format("`length` expects 0 arguments, {} got", args.size())));
|
||||
const FString &str = object->as<ValueType::StringClass>();
|
||||
return std::make_shared<Object>(static_cast<ValueType::IntClass>(str.length()));
|
||||
}},
|
||||
{U"replace",
|
||||
{u8"replace",
|
||||
[](ObjectPtr object, std::vector<ObjectPtr> args) -> ObjectPtr {
|
||||
if (args.size() != 2)
|
||||
throw RuntimeError(
|
||||
String(std::format("`replace` expects 2 arguments, {} got", args.size())));
|
||||
String &str = object->as<ValueType::StringClass>();
|
||||
FString(std::format("`replace` expects 2 arguments, {} got", args.size())));
|
||||
FString &str = object->as<ValueType::StringClass>();
|
||||
ObjectPtr arg1 = args[0];
|
||||
ObjectPtr arg2 = args[1];
|
||||
if (!arg1->is<ValueType::IntClass>())
|
||||
{
|
||||
throw RuntimeError(String("`replace` arg 1 expects type Int"));
|
||||
throw RuntimeError(FString("`replace` arg 1 expects type Int"));
|
||||
}
|
||||
if (!arg2->is<ValueType::StringClass>())
|
||||
{
|
||||
throw RuntimeError(String("`replace` arg 2 expects type String"));
|
||||
throw RuntimeError(FString("`replace` arg 2 expects type String"));
|
||||
}
|
||||
const String &target = arg2->as<ValueType::StringClass>();
|
||||
str.replace(arg1->as<ValueType::IntClass>(), target.length(), target);
|
||||
str.realReplace(arg1->as<ValueType::IntClass>(), arg2->as<ValueType::StringClass>());
|
||||
return Object::getNullInstance();
|
||||
}},
|
||||
{U"erase",
|
||||
{u8"erase",
|
||||
[](ObjectPtr object, std::vector<ObjectPtr> args) -> ObjectPtr {
|
||||
if (args.size() != 2)
|
||||
throw RuntimeError(
|
||||
String(std::format("`erase` expects 2 arguments, {} got", args.size())));
|
||||
String &str = object->as<ValueType::StringClass>();
|
||||
FString(std::format("`erase` expects 2 arguments, {} got", args.size())));
|
||||
FString &str = object->as<ValueType::StringClass>();
|
||||
ObjectPtr arg1 = args[0];
|
||||
ObjectPtr arg2 = args[1];
|
||||
if (!arg1->is<ValueType::IntClass>())
|
||||
{
|
||||
throw RuntimeError(String("`erase` arg 1 expects type Int"));
|
||||
throw RuntimeError(FString("`erase` arg 1 expects type Int"));
|
||||
}
|
||||
if (!arg2->is<ValueType::IntClass>())
|
||||
{
|
||||
throw RuntimeError(String("`erase` arg 2 expects type Int"));
|
||||
throw RuntimeError(FString("`erase` arg 2 expects type Int"));
|
||||
}
|
||||
ValueType::IntClass index = arg1->as<ValueType::IntClass>();
|
||||
ValueType::IntClass n = arg2->as<ValueType::IntClass>();
|
||||
if (index < 0 || n < 0)
|
||||
{
|
||||
throw RuntimeError(String("`erase`: index and n must greater or equal to 0"));
|
||||
throw RuntimeError(FString("`erase`: index and n must greater or equal to 0"));
|
||||
}
|
||||
if (index + n > str.length())
|
||||
{
|
||||
throw RuntimeError(String("`erase`: length is not long enough to erase"));
|
||||
throw RuntimeError(FString("`erase`: length is not long enough to erase"));
|
||||
}
|
||||
str.erase(arg1->as<ValueType::IntClass>(), arg2->as<ValueType::IntClass>());
|
||||
str.realErase(arg1->as<ValueType::IntClass>(), arg2->as<ValueType::IntClass>());
|
||||
return Object::getNullInstance();
|
||||
}},
|
||||
{U"insert",
|
||||
{u8"insert",
|
||||
[](ObjectPtr object, std::vector<ObjectPtr> args) -> ObjectPtr {
|
||||
if (args.size() != 2)
|
||||
throw RuntimeError(
|
||||
String(std::format("`insert` expects 2 arguments, {} got", args.size())));
|
||||
String &str = object->as<ValueType::StringClass>();
|
||||
FString(std::format("`insert` expects 2 arguments, {} got", args.size())));
|
||||
FString &str = object->as<ValueType::StringClass>();
|
||||
ObjectPtr arg1 = args[0];
|
||||
ObjectPtr arg2 = args[1];
|
||||
if (!arg1->is<ValueType::IntClass>())
|
||||
{
|
||||
throw RuntimeError(String("`insert` arg 1 expects type Int"));
|
||||
throw RuntimeError(FString("`insert` arg 1 expects type Int"));
|
||||
}
|
||||
if (!arg2->is<ValueType::StringClass>())
|
||||
{
|
||||
throw RuntimeError(String("`insert` arg 2 expects type String"));
|
||||
throw RuntimeError(FString("`insert` arg 2 expects type String"));
|
||||
}
|
||||
ValueType::IntClass dest = arg1->as<ValueType::IntClass>();
|
||||
const String &src = arg2->as<ValueType::StringClass>();
|
||||
str.insert(dest, src);
|
||||
str.realInsert(arg1->as<ValueType::IntClass>(), arg2->as<ValueType::StringClass>());
|
||||
return Object::getNullInstance();
|
||||
}},
|
||||
}},
|
||||
@@ -187,34 +184,34 @@ namespace Fig
|
||||
{ValueType::StructInstance, {}},
|
||||
{ValueType::List,
|
||||
{
|
||||
{U"length",
|
||||
{u8"length",
|
||||
[](ObjectPtr object, std::vector<ObjectPtr> args) -> ObjectPtr {
|
||||
if (args.size() != 0)
|
||||
throw RuntimeError(
|
||||
String(std::format("`length` expects 0 arguments, {} got", args.size())));
|
||||
FString(std::format("`length` expects 0 arguments, {} got", args.size())));
|
||||
const List &list = object->as<List>();
|
||||
return std::make_shared<Object>(static_cast<ValueType::IntClass>(list.size()));
|
||||
}},
|
||||
{U"get",
|
||||
{u8"get",
|
||||
[](ObjectPtr object, std::vector<ObjectPtr> args) -> ObjectPtr {
|
||||
if (args.size() != 1)
|
||||
throw RuntimeError(
|
||||
String(std::format("`get` expects 1 arguments, {} got", args.size())));
|
||||
FString(std::format("`get` expects 1 arguments, {} got", args.size())));
|
||||
ObjectPtr arg = args[0];
|
||||
if (arg->getTypeInfo() != ValueType::Int)
|
||||
throw RuntimeError(
|
||||
String(std::format("`get` argument 1 expects Int, {} got",
|
||||
FString(std::format("`get` argument 1 expects Int, {} got",
|
||||
arg->getTypeInfo().toString().toBasicString())));
|
||||
ValueType::IntClass i = arg->as<ValueType::IntClass>();
|
||||
const List &list = object->as<List>();
|
||||
if (i >= list.size()) return Object::getNullInstance();
|
||||
return list[i].value;
|
||||
}},
|
||||
{U"push",
|
||||
{u8"push",
|
||||
[](ObjectPtr object, std::vector<ObjectPtr> args) -> ObjectPtr {
|
||||
if (args.size() != 1)
|
||||
throw RuntimeError(
|
||||
String(std::format("`push` expects 1 arguments, {} got", args.size())));
|
||||
FString(std::format("`push` expects 1 arguments, {} got", args.size())));
|
||||
ObjectPtr arg = args[0];
|
||||
List &list = object->as<List>();
|
||||
list.push_back(arg);
|
||||
@@ -223,21 +220,21 @@ namespace Fig
|
||||
}},
|
||||
{ValueType::Map,
|
||||
{
|
||||
{U"get",
|
||||
{u8"get",
|
||||
[](ObjectPtr object, std::vector<ObjectPtr> args) -> ObjectPtr {
|
||||
if (args.size() != 1)
|
||||
throw RuntimeError(
|
||||
String(std::format("`get` expects 1 arguments, {} got", args.size())));
|
||||
FString(std::format("`get` expects 1 arguments, {} got", args.size())));
|
||||
ObjectPtr index = args[0];
|
||||
const Map &map = object->as<Map>();
|
||||
if (!map.contains(index)) return Object::getNullInstance();
|
||||
return map.at(index);
|
||||
}},
|
||||
{U"contains",
|
||||
{u8"contains",
|
||||
[](ObjectPtr object, std::vector<ObjectPtr> args) -> ObjectPtr {
|
||||
if (args.size() != 1)
|
||||
throw RuntimeError(
|
||||
String(std::format("`contains` expects 1 arguments, {} got", args.size())));
|
||||
FString(std::format("`contains` expects 1 arguments, {} got", args.size())));
|
||||
ObjectPtr index = args[0];
|
||||
const Map &map = object->as<Map>();
|
||||
return std::make_shared<Object>(map.contains(index));
|
||||
@@ -249,28 +246,29 @@ namespace Fig
|
||||
return memberTypeFunctions;
|
||||
}
|
||||
|
||||
static std::unordered_map<TypeInfo, std::unordered_map<String, int>, TypeInfoHash> getMemberTypeFunctionsParas()
|
||||
static std::unordered_map<TypeInfo, std::unordered_map<FString, int>, TypeInfoHash>
|
||||
getMemberTypeFunctionsParas()
|
||||
{
|
||||
static const std::unordered_map<TypeInfo, std::unordered_map<String, int>, TypeInfoHash>
|
||||
static const std::unordered_map<TypeInfo, std::unordered_map<FString, int>, TypeInfoHash>
|
||||
memberTypeFunctionsParas{
|
||||
{ValueType::Null, {}},
|
||||
{ValueType::Int, {}},
|
||||
{ValueType::Double, {}},
|
||||
{ValueType::String,
|
||||
{
|
||||
{U"length", 0},
|
||||
{U"replace", 2},
|
||||
{U"erase", 2},
|
||||
{U"insert", 2},
|
||||
{u8"length", 0},
|
||||
{u8"replace", 2},
|
||||
{u8"erase", 2},
|
||||
{u8"insert", 2},
|
||||
}},
|
||||
{ValueType::Function, {}},
|
||||
{ValueType::StructType, {}},
|
||||
{ValueType::StructInstance, {}},
|
||||
{ValueType::List, {{U"length", 0}, {U"get", 1}, {U"push", 1}}},
|
||||
{ValueType::List, {{u8"length", 0}, {u8"get", 1}, {u8"push", 1}}},
|
||||
{ValueType::Map,
|
||||
{
|
||||
{U"get", 1},
|
||||
{U"contains", 1},
|
||||
{u8"get", 1},
|
||||
{u8"contains", 1},
|
||||
}},
|
||||
{ValueType::Module, {}},
|
||||
{ValueType::InterfaceType, {}},
|
||||
@@ -278,15 +276,15 @@ namespace Fig
|
||||
return memberTypeFunctionsParas;
|
||||
}
|
||||
|
||||
bool hasMemberFunction(const String &name) const
|
||||
bool hasMemberFunction(const FString &name) const
|
||||
{
|
||||
return getMemberTypeFunctions().at(getTypeInfo()).contains(name);
|
||||
}
|
||||
BuiltinTypeMemberFn getMemberFunction(const String &name) const
|
||||
BuiltinTypeMemberFn getMemberFunction(const FString &name) const
|
||||
{
|
||||
return getMemberTypeFunctions().at(getTypeInfo()).at(name);
|
||||
}
|
||||
int getMemberFunctionParaCount(const String &name) const
|
||||
int getMemberFunctionParaCount(const FString &name) const
|
||||
{
|
||||
return getMemberTypeFunctionsParas().at(getTypeInfo()).at(name);
|
||||
}
|
||||
@@ -319,7 +317,7 @@ namespace Fig
|
||||
else if (ti == ValueType::Double)
|
||||
return Object(ValueType::DoubleClass(0.0));
|
||||
else if (ti == ValueType::String)
|
||||
return Object(ValueType::StringClass(U""));
|
||||
return Object(ValueType::StringClass(u8""));
|
||||
else if (ti == ValueType::Bool)
|
||||
return Object(ValueType::BoolClass(false));
|
||||
else if (ti == ValueType::List)
|
||||
@@ -422,83 +420,85 @@ namespace Fig
|
||||
else if (is<ValueType::DoubleClass>())
|
||||
return as<ValueType::DoubleClass>();
|
||||
else
|
||||
throw RuntimeError(U"getNumericValue: Not a numeric value");
|
||||
throw RuntimeError(u8"getNumericValue: Not a numeric value");
|
||||
}
|
||||
|
||||
String toStringIO() const
|
||||
FString toStringIO() const
|
||||
{
|
||||
if (is<ValueType::StringClass>()) return as<ValueType::StringClass>();
|
||||
return toString();
|
||||
}
|
||||
|
||||
String toString(std::unordered_set<const Object *> &visited) const
|
||||
FString toString(std::unordered_set<const Object *> &visited) const
|
||||
{
|
||||
if (is<ValueType::NullClass>()) return String(U"null");
|
||||
if (is<ValueType::IntClass>()) return String(std::to_string(as<ValueType::IntClass>()));
|
||||
if (is<ValueType::DoubleClass>()) return String(std::format("{}", as<ValueType::DoubleClass>()));
|
||||
if (is<ValueType::StringClass>()) return String(String(U"\"") + as<ValueType::StringClass>() + String(U"\""));
|
||||
if (is<ValueType::BoolClass>()) return as<ValueType::BoolClass>() ? String(U"true") : String(U"false");
|
||||
if (is<ValueType::NullClass>()) return FString(u8"null");
|
||||
if (is<ValueType::IntClass>()) return FString(std::to_string(as<ValueType::IntClass>()));
|
||||
if (is<ValueType::DoubleClass>()) return FString(std::format("{}", as<ValueType::DoubleClass>()));
|
||||
if (is<ValueType::StringClass>()) return FString(u8"\"" + as<ValueType::StringClass>() + u8"\"");
|
||||
if (is<ValueType::BoolClass>()) return as<ValueType::BoolClass>() ? FString(u8"true") : FString(u8"false");
|
||||
if (is<Function>())
|
||||
return String(std::format(
|
||||
"<Function '{}' at {:p}>", as<Function>().id, static_cast<const void *>(&as<Function>())));
|
||||
return FString(std::format("<Function '{}'({}) at {:p}>",
|
||||
as<Function>().name.toBasicString(),
|
||||
as<Function>().id,
|
||||
static_cast<const void *>(&as<Function>())));
|
||||
if (is<StructType>())
|
||||
return String(std::format("<StructType '{}' at {:p}>",
|
||||
return FString(std::format("<StructType '{}' at {:p}>",
|
||||
as<StructType>().type.toString().toBasicString(),
|
||||
static_cast<const void *>(&as<StructType>())));
|
||||
if (is<StructInstance>())
|
||||
return String(std::format("<StructInstance '{}' at {:p}>",
|
||||
return FString(std::format("<StructInstance '{}' at {:p}>",
|
||||
as<StructInstance>().parentType.toString().toBasicString(),
|
||||
static_cast<const void *>(&as<StructInstance>())));
|
||||
if (is<List>())
|
||||
{
|
||||
if (visited.contains(this)) { return U"[...]"; }
|
||||
if (visited.contains(this)) { return u8"[...]"; }
|
||||
visited.insert(this);
|
||||
|
||||
String output(U"[");
|
||||
FString output(u8"[");
|
||||
const List &list = as<List>();
|
||||
bool first_flag = true;
|
||||
for (auto &ele : list)
|
||||
{
|
||||
if (!first_flag) output += U", ";
|
||||
if (!first_flag) output += u8", ";
|
||||
output += ele.value->toString(visited);
|
||||
first_flag = false;
|
||||
}
|
||||
output += U"]";
|
||||
output += u8"]";
|
||||
return output;
|
||||
}
|
||||
if (is<Map>())
|
||||
{
|
||||
if (visited.contains(this)) { return U"{...}"; }
|
||||
if (visited.contains(this)) { return u8"{...}"; }
|
||||
visited.insert(this);
|
||||
|
||||
String output(U"{");
|
||||
FString output(u8"{");
|
||||
const Map &map = as<Map>();
|
||||
bool first_flag = true;
|
||||
for (auto &[key, value] : map)
|
||||
{
|
||||
if (!first_flag) output += U", ";
|
||||
output += key.value->toString(visited) + String(U" : ") + value->toString(visited);
|
||||
if (!first_flag) output += u8", ";
|
||||
output += key.value->toString(visited) + FString(u8" : ") + value->toString(visited);
|
||||
first_flag = false;
|
||||
}
|
||||
output += U"}";
|
||||
output += u8"}";
|
||||
return output;
|
||||
}
|
||||
if (is<Module>())
|
||||
{
|
||||
return String(std::format("<Module '{}' at {:p}>",
|
||||
return FString(std::format("<Module '{}' at {:p}>",
|
||||
as<Module>().name.toBasicString(),
|
||||
static_cast<const void *>(&as<Module>())));
|
||||
}
|
||||
if (is<InterfaceType>())
|
||||
{
|
||||
return String(std::format("<InterfaceType '{}' at {:p}>",
|
||||
return FString(std::format("<InterfaceType '{}' at {:p}>",
|
||||
as<InterfaceType>().type.toString().toBasicString(),
|
||||
static_cast<const void *>(&as<InterfaceType>())));
|
||||
}
|
||||
return String(U"<error>");
|
||||
return FString(u8"<error>");
|
||||
}
|
||||
|
||||
String toString() const
|
||||
FString toString() const
|
||||
{
|
||||
std::unordered_set<const Object *> visited{};
|
||||
return toString(visited);
|
||||
@@ -518,7 +518,7 @@ namespace Fig
|
||||
friend Object operator+(const Object &lhs, const Object &rhs)
|
||||
{
|
||||
if (lhs.isNull() || rhs.isNull())
|
||||
throw ValueError(String(makeTypeErrorMessage("Cannot add", "+", lhs, rhs)));
|
||||
throw ValueError(FString(makeTypeErrorMessage("Cannot add", "+", lhs, rhs)));
|
||||
if (lhs.isNumeric() && rhs.isNumeric())
|
||||
{
|
||||
bool bothInt = lhs.is<ValueType::IntClass>() && rhs.is<ValueType::IntClass>();
|
||||
@@ -527,14 +527,14 @@ namespace Fig
|
||||
return Object(result);
|
||||
}
|
||||
if (lhs.is<ValueType::StringClass>() && rhs.is<ValueType::StringClass>())
|
||||
return Object(String(lhs.as<ValueType::StringClass>() + rhs.as<ValueType::StringClass>()));
|
||||
throw ValueError(String(makeTypeErrorMessage("Unsupported operation", "+", lhs, rhs)));
|
||||
return Object(FString(lhs.as<ValueType::StringClass>() + rhs.as<ValueType::StringClass>()));
|
||||
throw ValueError(FString(makeTypeErrorMessage("Unsupported operation", "+", lhs, rhs)));
|
||||
}
|
||||
|
||||
friend Object operator-(const Object &lhs, const Object &rhs)
|
||||
{
|
||||
if (lhs.isNull() || rhs.isNull())
|
||||
throw ValueError(String(makeTypeErrorMessage("Cannot subtract", "-", lhs, rhs)));
|
||||
throw ValueError(FString(makeTypeErrorMessage("Cannot subtract", "-", lhs, rhs)));
|
||||
if (lhs.isNumeric() && rhs.isNumeric())
|
||||
{
|
||||
bool bothInt = lhs.is<ValueType::IntClass>() && rhs.is<ValueType::IntClass>();
|
||||
@@ -542,13 +542,13 @@ namespace Fig
|
||||
if (bothInt) return Object(static_cast<ValueType::IntClass>(result));
|
||||
return Object(result);
|
||||
}
|
||||
throw ValueError(String(makeTypeErrorMessage("Unsupported operation", "-", lhs, rhs)));
|
||||
throw ValueError(FString(makeTypeErrorMessage("Unsupported operation", "-", lhs, rhs)));
|
||||
}
|
||||
|
||||
friend Object operator*(const Object &lhs, const Object &rhs)
|
||||
{
|
||||
if (lhs.isNull() || rhs.isNull())
|
||||
throw ValueError(String(makeTypeErrorMessage("Cannot multiply", "*", lhs, rhs)));
|
||||
throw ValueError(FString(makeTypeErrorMessage("Cannot multiply", "*", lhs, rhs)));
|
||||
if (lhs.isNumeric() && rhs.isNumeric())
|
||||
{
|
||||
bool bothInt = lhs.is<ValueType::IntClass>() && rhs.is<ValueType::IntClass>();
|
||||
@@ -558,22 +558,22 @@ namespace Fig
|
||||
}
|
||||
if (lhs.is<ValueType::StringClass>() && rhs.is<ValueType::IntClass>())
|
||||
{
|
||||
String result;
|
||||
const String &l = lhs.as<ValueType::StringClass>();
|
||||
FString result;
|
||||
const FString &l = lhs.as<ValueType::StringClass>();
|
||||
for (size_t i = 0; i < rhs.getNumericValue(); ++i) { result += l; }
|
||||
return Object(result);
|
||||
}
|
||||
throw ValueError(String(makeTypeErrorMessage("Unsupported operation", "*", lhs, rhs)));
|
||||
throw ValueError(FString(makeTypeErrorMessage("Unsupported operation", "*", lhs, rhs)));
|
||||
}
|
||||
|
||||
friend Object operator/(const Object &lhs, const Object &rhs)
|
||||
{
|
||||
if (lhs.isNull() || rhs.isNull())
|
||||
throw ValueError(String(makeTypeErrorMessage("Cannot divide", "/", lhs, rhs)));
|
||||
throw ValueError(FString(makeTypeErrorMessage("Cannot divide", "/", lhs, rhs)));
|
||||
if (lhs.isNumeric() && rhs.isNumeric())
|
||||
{
|
||||
auto rnv = rhs.getNumericValue();
|
||||
if (rnv == 0) throw ValueError(String(makeTypeErrorMessage("Division by zero", "/", lhs, rhs)));
|
||||
if (rnv == 0) throw ValueError(FString(makeTypeErrorMessage("Division by zero", "/", lhs, rhs)));
|
||||
// bool bothInt = lhs.is<ValueType::IntClass>() && rhs.is<ValueType::IntClass>();
|
||||
auto result = lhs.getNumericValue() / rnv;
|
||||
// if (bothInt)
|
||||
@@ -583,18 +583,18 @@ namespace Fig
|
||||
// DO NOT convert it to INT
|
||||
return Object(result);
|
||||
}
|
||||
throw ValueError(String(makeTypeErrorMessage("Unsupported operation", "/", lhs, rhs)));
|
||||
throw ValueError(FString(makeTypeErrorMessage("Unsupported operation", "/", lhs, rhs)));
|
||||
}
|
||||
|
||||
friend Object operator%(const Object &lhs, const Object &rhs)
|
||||
{
|
||||
if (lhs.isNull() || rhs.isNull())
|
||||
throw ValueError(String(makeTypeErrorMessage("Cannot modulo", "%", lhs, rhs)));
|
||||
throw ValueError(FString(makeTypeErrorMessage("Cannot modulo", "%", lhs, rhs)));
|
||||
if (lhs.is<ValueType::IntClass>() && rhs.is<ValueType::IntClass>())
|
||||
{
|
||||
ValueType::IntClass lv = lhs.as<ValueType::IntClass>();
|
||||
ValueType::IntClass rv = lhs.as<ValueType::IntClass>();
|
||||
if (rv == 0) throw ValueError(String(makeTypeErrorMessage("Modulo by zero", "/", lhs, rhs)));
|
||||
if (rv == 0) throw ValueError(FString(makeTypeErrorMessage("Modulo by zero", "/", lhs, rhs)));
|
||||
|
||||
ValueType::IntClass q = lv / rv;
|
||||
ValueType::IntClass r = lv % rv;
|
||||
@@ -605,25 +605,25 @@ namespace Fig
|
||||
if (lhs.isNumeric() && rhs.isNumeric())
|
||||
{
|
||||
auto rnv = rhs.getNumericValue();
|
||||
if (rnv == 0) throw ValueError(String(makeTypeErrorMessage("Modulo by zero", "/", lhs, rhs)));
|
||||
if (rnv == 0) throw ValueError(FString(makeTypeErrorMessage("Modulo by zero", "/", lhs, rhs)));
|
||||
auto result = std::fmod(lhs.getNumericValue(), rnv);
|
||||
return Object(result);
|
||||
}
|
||||
throw ValueError(String(makeTypeErrorMessage("Unsupported operation", "%", lhs, rhs)));
|
||||
throw ValueError(FString(makeTypeErrorMessage("Unsupported operation", "%", lhs, rhs)));
|
||||
}
|
||||
|
||||
// logic
|
||||
friend Object operator&&(const Object &lhs, const Object &rhs)
|
||||
{
|
||||
if (!lhs.is<ValueType::BoolClass>() || !rhs.is<ValueType::BoolClass>())
|
||||
throw ValueError(String(makeTypeErrorMessage("Logical AND requires bool", "&&", lhs, rhs)));
|
||||
throw ValueError(FString(makeTypeErrorMessage("Logical AND requires bool", "&&", lhs, rhs)));
|
||||
return Object(lhs.as<ValueType::BoolClass>() && rhs.as<ValueType::BoolClass>());
|
||||
}
|
||||
|
||||
friend Object operator||(const Object &lhs, const Object &rhs)
|
||||
{
|
||||
if (!lhs.is<ValueType::BoolClass>() || !rhs.is<ValueType::BoolClass>())
|
||||
throw ValueError(String(makeTypeErrorMessage("Logical OR requires bool", "||", lhs, rhs)));
|
||||
throw ValueError(FString(makeTypeErrorMessage("Logical OR requires bool", "||", lhs, rhs)));
|
||||
return Object(lhs.as<ValueType::BoolClass>() || rhs.as<ValueType::BoolClass>());
|
||||
}
|
||||
|
||||
@@ -631,24 +631,24 @@ namespace Fig
|
||||
{
|
||||
if (!v.is<ValueType::BoolClass>())
|
||||
throw ValueError(
|
||||
String(std::format("Logical NOT requires bool: '{}'", v.getTypeInfo().name.toBasicString())));
|
||||
FString(std::format("Logical NOT requires bool: '{}'", v.getTypeInfo().name.toBasicString())));
|
||||
return Object(!v.as<ValueType::BoolClass>());
|
||||
}
|
||||
|
||||
friend Object operator-(const Object &v)
|
||||
{
|
||||
if (v.isNull()) throw ValueError(String(U"Unary minus cannot be applied to null"));
|
||||
if (v.isNull()) throw ValueError(FString(u8"Unary minus cannot be applied to null"));
|
||||
if (v.is<ValueType::IntClass>()) return Object(-v.as<ValueType::IntClass>());
|
||||
if (v.is<ValueType::DoubleClass>()) return Object(-v.as<ValueType::DoubleClass>());
|
||||
throw ValueError(
|
||||
String(std::format("Unary minus requires int or double: '{}'", v.getTypeInfo().name.toBasicString())));
|
||||
FString(std::format("Unary minus requires int or double: '{}'", v.getTypeInfo().name.toBasicString())));
|
||||
}
|
||||
|
||||
friend Object operator~(const Object &v)
|
||||
{
|
||||
if (!v.is<ValueType::IntClass>())
|
||||
throw ValueError(
|
||||
String(std::format("Bitwise NOT requires int: '{}'", v.getTypeInfo().name.toBasicString())));
|
||||
FString(std::format("Bitwise NOT requires int: '{}'", v.getTypeInfo().name.toBasicString())));
|
||||
return Object(~v.as<ValueType::IntClass>());
|
||||
}
|
||||
|
||||
@@ -667,7 +667,7 @@ namespace Fig
|
||||
if (lhs.isNumeric() && rhs.isNumeric()) return lhs.getNumericValue() < rhs.getNumericValue();
|
||||
if (lhs.is<ValueType::StringClass>() && rhs.is<ValueType::StringClass>())
|
||||
return lhs.as<ValueType::StringClass>() < rhs.as<ValueType::StringClass>();
|
||||
throw ValueError(String(makeTypeErrorMessage("Unsupported comparison", "<", lhs, rhs)));
|
||||
throw ValueError(FString(makeTypeErrorMessage("Unsupported comparison", "<", lhs, rhs)));
|
||||
}
|
||||
friend bool operator<=(const Object &lhs, const Object &rhs) { return lhs == rhs || lhs < rhs; }
|
||||
friend bool operator>(const Object &lhs, const Object &rhs)
|
||||
@@ -675,7 +675,7 @@ namespace Fig
|
||||
if (lhs.isNumeric() && rhs.isNumeric()) return lhs.getNumericValue() > rhs.getNumericValue();
|
||||
if (lhs.is<ValueType::StringClass>() && rhs.is<ValueType::StringClass>())
|
||||
return lhs.as<ValueType::StringClass>() > rhs.as<ValueType::StringClass>();
|
||||
throw ValueError(String(makeTypeErrorMessage("Unsupported comparison", ">", lhs, rhs)));
|
||||
throw ValueError(FString(makeTypeErrorMessage("Unsupported comparison", ">", lhs, rhs)));
|
||||
}
|
||||
friend bool operator>=(const Object &lhs, const Object &rhs) { return lhs == rhs || lhs > rhs; }
|
||||
|
||||
@@ -683,21 +683,21 @@ namespace Fig
|
||||
friend Object bit_and(const Object &lhs, const Object &rhs)
|
||||
{
|
||||
if (!lhs.is<ValueType::IntClass>() || !rhs.is<ValueType::IntClass>())
|
||||
throw ValueError(String(makeTypeErrorMessage("Bitwise AND requires int", "&", lhs, rhs)));
|
||||
throw ValueError(FString(makeTypeErrorMessage("Bitwise AND requires int", "&", lhs, rhs)));
|
||||
return Object(lhs.as<ValueType::IntClass>() & rhs.as<ValueType::IntClass>());
|
||||
}
|
||||
|
||||
friend Object bit_or(const Object &lhs, const Object &rhs)
|
||||
{
|
||||
if (!lhs.is<ValueType::IntClass>() || !rhs.is<ValueType::IntClass>())
|
||||
throw ValueError(String(makeTypeErrorMessage("Bitwise OR requires int", "|", lhs, rhs)));
|
||||
throw ValueError(FString(makeTypeErrorMessage("Bitwise OR requires int", "|", lhs, rhs)));
|
||||
return Object(lhs.as<ValueType::IntClass>() | rhs.as<ValueType::IntClass>());
|
||||
}
|
||||
|
||||
friend Object bit_xor(const Object &lhs, const Object &rhs)
|
||||
{
|
||||
if (!lhs.is<ValueType::IntClass>() || !rhs.is<ValueType::IntClass>())
|
||||
throw ValueError(String(makeTypeErrorMessage("Bitwise XOR requires int", "^", lhs, rhs)));
|
||||
throw ValueError(FString(makeTypeErrorMessage("Bitwise XOR requires int", "^", lhs, rhs)));
|
||||
return Object(lhs.as<ValueType::IntClass>() ^ rhs.as<ValueType::IntClass>());
|
||||
}
|
||||
|
||||
@@ -705,28 +705,28 @@ namespace Fig
|
||||
{
|
||||
if (!v.is<ValueType::IntClass>())
|
||||
throw ValueError(
|
||||
String(std::format("Bitwise NOT requires int: '{}'", v.getTypeInfo().name.toBasicString())));
|
||||
FString(std::format("Bitwise NOT requires int: '{}'", v.getTypeInfo().name.toBasicString())));
|
||||
return Object(~v.as<ValueType::IntClass>());
|
||||
}
|
||||
|
||||
friend Object shift_left(const Object &lhs, const Object &rhs)
|
||||
{
|
||||
if (!lhs.is<ValueType::IntClass>() || !rhs.is<ValueType::IntClass>())
|
||||
throw ValueError(String(makeTypeErrorMessage("Shift left requires int", "<<", lhs, rhs)));
|
||||
throw ValueError(FString(makeTypeErrorMessage("Shift left requires int", "<<", lhs, rhs)));
|
||||
return Object(lhs.as<ValueType::IntClass>() << rhs.as<ValueType::IntClass>());
|
||||
}
|
||||
|
||||
friend Object shift_right(const Object &lhs, const Object &rhs)
|
||||
{
|
||||
if (!lhs.is<ValueType::IntClass>() || !rhs.is<ValueType::IntClass>())
|
||||
throw ValueError(String(makeTypeErrorMessage("Shift right requires int", ">>", lhs, rhs)));
|
||||
throw ValueError(FString(makeTypeErrorMessage("Shift right requires int", ">>", lhs, rhs)));
|
||||
return Object(lhs.as<ValueType::IntClass>() >> rhs.as<ValueType::IntClass>());
|
||||
}
|
||||
|
||||
friend Object power(const Object &base, const Object &exp)
|
||||
{
|
||||
if (base.isNull() || exp.isNull())
|
||||
throw ValueError(String(makeTypeErrorMessage("Cannot exponentiate", "**", base, exp)));
|
||||
throw ValueError(FString(makeTypeErrorMessage("Cannot exponentiate", "**", base, exp)));
|
||||
if (base.isNumeric() && exp.isNumeric())
|
||||
{
|
||||
bool bothInt = base.is<ValueType::IntClass>() && exp.is<ValueType::IntClass>();
|
||||
@@ -734,7 +734,7 @@ namespace Fig
|
||||
if (bothInt) return Object(static_cast<ValueType::IntClass>(result));
|
||||
return Object(result);
|
||||
}
|
||||
throw ValueError(String(makeTypeErrorMessage("Unsupported operation", "**", base, exp)));
|
||||
throw ValueError(FString(makeTypeErrorMessage("Unsupported operation", "**", base, exp)));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -8,13 +8,10 @@ namespace Fig
|
||||
{
|
||||
public:
|
||||
using UnaddressableError::UnaddressableError;
|
||||
virtual String toString() const override
|
||||
virtual FString toString() const override
|
||||
{
|
||||
std::string msg = std::format("[ValueError] {} in [{}] {}",
|
||||
std::string(this->message.begin(), this->message.end()),
|
||||
this->src_loc.file_name(),
|
||||
this->src_loc.function_name());
|
||||
return String(msg);
|
||||
std::string msg = std::format("[ValueError] {} in [{}] {}", std::string(this->message.begin(), this->message.end()), this->src_loc.file_name(), this->src_loc.function_name());
|
||||
return FString(msg);
|
||||
}
|
||||
};
|
||||
}; // namespace Fig
|
||||
};
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <Evaluator/Value/Type.hpp>
|
||||
#include <Evaluator/Value/structInstance.hpp>
|
||||
#include <Ast/astBase.hpp>
|
||||
#include <Core/String.hpp>
|
||||
#include <Core/fig_string.hpp>
|
||||
#include <Evaluator/Core/StatementResult.hpp>
|
||||
#include <Evaluator/Value/value.hpp>
|
||||
#include <Error/errorLog.hpp>
|
||||
@@ -50,16 +50,16 @@ namespace Fig
|
||||
|
||||
ContextPtr Evaluator::loadModule(const std::filesystem::path &path)
|
||||
{
|
||||
static std::unordered_map<String, std::pair<std::vector<String>, std::vector<Ast::AstBase>>> mod_ast_cache{};
|
||||
static std::unordered_map<FString, std::pair<std::vector<FString>, std::vector<Ast::AstBase>>> mod_ast_cache{};
|
||||
|
||||
String modSourcePath(path.string());
|
||||
FString modSourcePath(path.string());
|
||||
|
||||
std::ifstream file(path);
|
||||
assert(file.is_open());
|
||||
|
||||
std::vector<Ast::AstBase> asts;
|
||||
|
||||
std::vector<String> modSourceLines;
|
||||
std::vector<FString> modSourceLines;
|
||||
|
||||
if (mod_ast_cache.contains(modSourcePath))
|
||||
{
|
||||
@@ -72,9 +72,9 @@ namespace Fig
|
||||
std::string source((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
|
||||
file.close();
|
||||
|
||||
modSourceLines = Utils::splitSource(String(source));
|
||||
modSourceLines = Utils::splitSource(FString(source));
|
||||
|
||||
Lexer lexer((String(source)), modSourcePath, modSourceLines);
|
||||
Lexer lexer((FString(source)), modSourcePath, modSourceLines);
|
||||
Parser parser(lexer, modSourcePath, modSourceLines);
|
||||
|
||||
asts = parser.parseAll();
|
||||
@@ -85,7 +85,7 @@ namespace Fig
|
||||
evaluator.SetSourcePath(modSourcePath);
|
||||
evaluator.SetSourceLines(modSourceLines);
|
||||
|
||||
ContextPtr modctx = std::make_shared<Context>(String(std::format("<Module at {}>", path.string())), nullptr);
|
||||
ContextPtr modctx = std::make_shared<Context>(FString(std::format("<Module at {}>", path.string())), nullptr);
|
||||
|
||||
evaluator.SetGlobalContext(modctx);
|
||||
evaluator.RegisterBuiltinsValue();
|
||||
@@ -96,10 +96,10 @@ namespace Fig
|
||||
|
||||
StatementResult Evaluator::evalImportSt(Ast::Import i, ContextPtr ctx)
|
||||
{
|
||||
const std::vector<String> &pathVec = i->path;
|
||||
const std::vector<FString> &pathVec = i->path;
|
||||
|
||||
String modName = pathVec.back(); // pathVec at least has 1 element
|
||||
if (modName == U"\1")
|
||||
FString modName = pathVec.back(); // pathVec at least has 1 element
|
||||
if (modName == u8"_builtins")
|
||||
{
|
||||
RegisterBuiltins();
|
||||
return StatementResult::normal();
|
||||
@@ -109,7 +109,8 @@ namespace Fig
|
||||
|
||||
if (ctx->containsInThisScope(modName))
|
||||
{
|
||||
throw EvaluatorError(U"\1", std::format("{} has already been declared.", modName.toBasicString()), i);
|
||||
throw EvaluatorError(
|
||||
u8"RedeclarationError", std::format("{} has already been declared.", modName.toBasicString()), i);
|
||||
}
|
||||
|
||||
auto path = resolveModulePath(pathVec);
|
||||
@@ -123,7 +124,7 @@ namespace Fig
|
||||
if (ctx->getOpRegistry().contains(type))
|
||||
{
|
||||
throw EvaluatorError(
|
||||
U"\1",
|
||||
u8"DuplicateOperationOverload",
|
||||
std::format("Module `{}` and current context `{}` have conflict operation overload for `{}` object",
|
||||
modCtx->getScopeName().toBasicString(),
|
||||
ctx->getScopeName().toBasicString(),
|
||||
@@ -134,7 +135,7 @@ namespace Fig
|
||||
}
|
||||
if (!i->names.empty())
|
||||
{
|
||||
for (const String &symName : i->names)
|
||||
for (const FString &symName : i->names)
|
||||
{
|
||||
LvObject tmp(modCtx->get(symName), modCtx);
|
||||
const ObjectPtr &value = tmp.get();
|
||||
@@ -182,13 +183,13 @@ namespace Fig
|
||||
*/
|
||||
const StructInstance &resInst = result->as<StructInstance>();
|
||||
|
||||
Function getErrorClassFn = ctx->getImplementedMethod(resultType, U"\1");
|
||||
Function getErrorClassFn = ctx->getImplementedMethod(resultType, u8"getErrorClass");
|
||||
getErrorClassFn = Function(getErrorClassFn.name,
|
||||
getErrorClassFn.paras,
|
||||
getErrorClassFn.retType,
|
||||
getErrorClassFn.body,
|
||||
resInst.localContext);
|
||||
Function getErrorMessageFn = ctx->getImplementedMethod(resultType, U"\1");
|
||||
Function getErrorMessageFn = ctx->getImplementedMethod(resultType, u8"getErrorMessage");
|
||||
getErrorMessageFn = Function(getErrorMessageFn.name,
|
||||
getErrorMessageFn.paras,
|
||||
getErrorMessageFn.retType,
|
||||
@@ -209,16 +210,17 @@ namespace Fig
|
||||
// std::cerr << errorClassRes.unwrap()->toString().toBasicString() << "\n";
|
||||
// std::cerr << errorMessageRes.unwrap()->toString().toBasicString() << "\n";
|
||||
|
||||
const String &errorClass = errorClassRes.unwrap()->as<ValueType::StringClass>();
|
||||
const String &errorMessage = errorMessageRes.unwrap()->as<ValueType::StringClass>();
|
||||
const FString &errorClass = errorClassRes.unwrap()->as<ValueType::StringClass>();
|
||||
const FString &errorMessage = errorMessageRes.unwrap()->as<ValueType::StringClass>();
|
||||
|
||||
ErrorLog::logFigErrorInterface(errorClass, errorMessage);
|
||||
std::exit(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw EvaluatorError(
|
||||
U"\1", std::format("Uncaught exception: {}", sr.result->toString().toBasicString()), stmt);
|
||||
throw EvaluatorError(u8"UncaughtExceptionError",
|
||||
std::format("Uncaught exception: {}", sr.result->toString().toBasicString()),
|
||||
stmt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,12 +34,12 @@ namespace Fig
|
||||
ContextPtr global;
|
||||
|
||||
public:
|
||||
String sourcePath;
|
||||
std::vector<String> sourceLines;
|
||||
FString sourcePath;
|
||||
std::vector<FString> sourceLines;
|
||||
|
||||
void SetSourcePath(const String &sp) { sourcePath = sp; }
|
||||
void SetSourcePath(const FString &sp) { sourcePath = sp; }
|
||||
|
||||
void SetSourceLines(const std::vector<String> &sl) { sourceLines = sl; }
|
||||
void SetSourceLines(const std::vector<FString> &sl) { sourceLines = sl; }
|
||||
|
||||
void SetGlobalContext(ContextPtr ctx)
|
||||
{
|
||||
@@ -47,7 +47,7 @@ namespace Fig
|
||||
global = ctx;
|
||||
}
|
||||
|
||||
void CreateGlobalContext() { global = std::make_shared<Context>(String(U"\1")); }
|
||||
void CreateGlobalContext() { global = std::make_shared<Context>(FString(u8"<Global>")); }
|
||||
|
||||
void RegisterBuiltins() // only function
|
||||
{
|
||||
@@ -67,31 +67,33 @@ namespace Fig
|
||||
.interfaceType = Builtins::getErrorInterfaceTypeInfo(),
|
||||
.structType = Builtins::getTypeErrorStructTypeInfo(),
|
||||
.implMethods = {
|
||||
{U"\1",
|
||||
Function(U"\1",
|
||||
{u8"toString",
|
||||
Function(
|
||||
u8"toString",
|
||||
Ast::FunctionParameters{},
|
||||
ValueType::String,
|
||||
std::make_shared<Ast::BlockStatementAst>(std::vector<Ast::Statement>(
|
||||
{std::make_shared<Ast::ReturnSt>(std::make_shared<Ast::BinaryExprAst>(
|
||||
std::make_shared<Ast::ValueExprAst>(std::make_shared<Object>(U"\1")),
|
||||
std::make_shared<Ast::ValueExprAst>(std::make_shared<Object>(u8"TypeError: ")),
|
||||
Ast::Operator::Add,
|
||||
std::make_shared<Ast::FunctionCallExpr>(
|
||||
std::make_shared<Ast::VarExprAst>(U"\1"), Ast::FunctionArguments{})))})),
|
||||
std::make_shared<Ast::VarExprAst>(u8"getErrorMessage"),
|
||||
Ast::FunctionArguments{})))})),
|
||||
nullptr)},
|
||||
{U"\1",
|
||||
Function(U"\1",
|
||||
{u8"getErrorClass",
|
||||
Function(u8"getErrorClass",
|
||||
Ast::FunctionParameters{},
|
||||
ValueType::String,
|
||||
std::make_shared<Ast::BlockStatementAst>(std::vector<Ast::Statement>(
|
||||
{std::make_shared<Ast::ReturnSt>(std::make_shared<Ast::ValueExprAst>(
|
||||
std::make_shared<Object>(String(U"\1"))))})),
|
||||
std::make_shared<Object>(FString(u8"TypeError"))))})),
|
||||
nullptr)},
|
||||
{U"\1",
|
||||
Function(U"\1",
|
||||
{u8"getErrorMessage",
|
||||
Function(u8"getErrorMessage",
|
||||
Ast::FunctionParameters{},
|
||||
ValueType::String,
|
||||
std::make_shared<Ast::BlockStatementAst>(std::vector<Ast::Statement>(
|
||||
{std::make_shared<Ast::ReturnSt>(std::make_shared<Ast::VarExprAst>(U"\1"))})),
|
||||
{std::make_shared<Ast::ReturnSt>(std::make_shared<Ast::VarExprAst>(u8"msg"))})),
|
||||
nullptr)},
|
||||
}});
|
||||
}
|
||||
@@ -108,13 +110,13 @@ namespace Fig
|
||||
|
||||
bool isInterfaceSignatureMatch(const Ast::ImplementMethod &, const Ast::InterfaceMethod &);
|
||||
|
||||
ObjectPtr genTypeError(const String &_msg,
|
||||
ObjectPtr genTypeError(const FString &_msg,
|
||||
const Ast::AstBase &_ast,
|
||||
ContextPtr ctx,
|
||||
std::source_location loc = std::source_location::current())
|
||||
{
|
||||
ContextPtr stCtx = std::make_shared<Context>(U"\1");
|
||||
stCtx->def(U"\1", ValueType::String, AccessModifier::Const, std::make_shared<Object>(_msg));
|
||||
ContextPtr stCtx = std::make_shared<Context>(u8"<TypeError Instance>");
|
||||
stCtx->def(u8"msg", ValueType::String, AccessModifier::Const, std::make_shared<Object>(_msg));
|
||||
return std::make_shared<Object>(StructInstance(Builtins::getTypeErrorStructTypeInfo(), stCtx));
|
||||
}
|
||||
|
||||
@@ -141,7 +143,7 @@ namespace Fig
|
||||
StatementResult evalBlockStatement(Ast::BlockStatement, ContextPtr); // block
|
||||
StatementResult evalStatement(Ast::Statement, ContextPtr); // statement
|
||||
|
||||
std::filesystem::path resolveModulePath(const std::vector<String> &);
|
||||
std::filesystem::path resolveModulePath(const std::vector<FString> &);
|
||||
ContextPtr loadModule(const std::filesystem::path &);
|
||||
|
||||
StatementResult evalImportSt(Ast::Import, ContextPtr);
|
||||
|
||||
@@ -8,15 +8,16 @@ namespace Fig
|
||||
class EvaluatorError final : public AddressableError
|
||||
{
|
||||
public:
|
||||
String typeName;
|
||||
FString typeName;
|
||||
using AddressableError::AddressableError;
|
||||
EvaluatorError(String _typeName,
|
||||
String msg,
|
||||
EvaluatorError(FString _typeName,
|
||||
FString msg,
|
||||
Ast::AstBase ast,
|
||||
std::source_location loc = std::source_location::current())
|
||||
{
|
||||
message = msg;
|
||||
|
||||
|
||||
src_loc = std::move(loc);
|
||||
|
||||
typeName = std::move(_typeName);
|
||||
@@ -28,24 +29,25 @@ namespace Fig
|
||||
sourcePath = *ast->getAAI().sourcePath;
|
||||
sourceLines = *ast->getAAI().sourceLines;
|
||||
}
|
||||
|
||||
}
|
||||
// EvaluatorError(String _typeName,
|
||||
// std::string_view msg,
|
||||
// Ast::AstBase ast,
|
||||
// std::source_location loc = std::source_location::current())
|
||||
// {
|
||||
// message = String(std::string(msg.data()));
|
||||
// line = ast->getAAI().line;
|
||||
// column = ast->getAAI().column;
|
||||
EvaluatorError(FString _typeName,
|
||||
std::string_view msg,
|
||||
Ast::AstBase ast,
|
||||
std::source_location loc = std::source_location::current())
|
||||
{
|
||||
message = FString::fromBasicString(std::string(msg.data()));
|
||||
line = ast->getAAI().line;
|
||||
column = ast->getAAI().column;
|
||||
|
||||
// src_loc = std::move(loc);
|
||||
src_loc = std::move(loc);
|
||||
|
||||
// typeName = std::move(_typeName);
|
||||
typeName = std::move(_typeName);
|
||||
|
||||
// sourcePath = *ast->getAAI().sourcePath;
|
||||
// sourceLines = *ast->getAAI().sourceLines;
|
||||
// }
|
||||
sourcePath = *ast->getAAI().sourcePath;
|
||||
sourceLines = *ast->getAAI().sourceLines;
|
||||
}
|
||||
|
||||
virtual String getErrorType() const override { return typeName; }
|
||||
virtual FString getErrorType() const override { return typeName; }
|
||||
};
|
||||
}; // namespace Fig
|
||||
@@ -1,62 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <Core/String.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
namespace Fig::IR
|
||||
{
|
||||
using Reg = uint16_t;
|
||||
using Label = uint32_t;
|
||||
|
||||
constexpr Reg INVALID_REG = 0xFFFF;
|
||||
|
||||
enum class Op : uint8_t
|
||||
{
|
||||
// ---- control ----
|
||||
Nop,
|
||||
Jmp,
|
||||
Br, // conditional branch
|
||||
Ret,
|
||||
Call,
|
||||
|
||||
// ---- arithmetic ----
|
||||
Add,
|
||||
Sub,
|
||||
Mul,
|
||||
Div,
|
||||
|
||||
// ---- compare ----
|
||||
Lt,
|
||||
Le,
|
||||
Gt,
|
||||
Ge,
|
||||
Eq,
|
||||
|
||||
// ---- data ----
|
||||
LoadImm, // immediate -> reg
|
||||
Mov,
|
||||
};
|
||||
|
||||
struct Inst
|
||||
{
|
||||
Op op;
|
||||
|
||||
Reg dst; // 结果寄存器
|
||||
Reg a; // operand a
|
||||
Reg b; // operand b
|
||||
|
||||
int64_t imm; // immediate / jump offset
|
||||
};
|
||||
|
||||
struct Function
|
||||
{
|
||||
String name;
|
||||
|
||||
uint16_t paramCount;
|
||||
uint16_t localCount; // 不含参数
|
||||
uint16_t regCount; // param + locals + temps
|
||||
|
||||
std::vector<Inst> code;
|
||||
};
|
||||
}; // namespace Fig::IR
|
||||
@@ -1,74 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <IR/IR.hpp>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace Fig::IR
|
||||
{
|
||||
struct VirtualMachine
|
||||
{
|
||||
std::vector<Function *> functions;
|
||||
|
||||
int64_t execute(Function *fn, const int64_t *args)
|
||||
{
|
||||
assert(fn != nullptr);
|
||||
std::vector<int64_t> regs(fn->regCount);
|
||||
// load params
|
||||
|
||||
size_t ip = 0;
|
||||
|
||||
while (ip < fn->code.size())
|
||||
{
|
||||
const Inst &ins = fn->code[ip++];
|
||||
|
||||
switch (ins.op)
|
||||
{
|
||||
case Op::Nop: break;
|
||||
|
||||
case Op::LoadImm: regs[ins.dst] = ins.imm; break;
|
||||
|
||||
case Op::Mov: regs[ins.dst] = regs[ins.a]; break;
|
||||
|
||||
case Op::Add: regs[ins.dst] = regs[ins.a] + regs[ins.b]; break;
|
||||
|
||||
case Op::Sub: regs[ins.dst] = regs[ins.a] - regs[ins.b]; break;
|
||||
|
||||
case Op::Mul: regs[ins.dst] = regs[ins.a] * regs[ins.b]; break;
|
||||
|
||||
case Op::Div: regs[ins.dst] = regs[ins.a] / regs[ins.b]; break;
|
||||
|
||||
case Op::Lt: regs[ins.dst] = regs[ins.a] < regs[ins.b]; break;
|
||||
|
||||
case Op::Le: regs[ins.dst] = regs[ins.a] <= regs[ins.b]; break;
|
||||
|
||||
case Op::Gt: regs[ins.dst] = regs[ins.a] > regs[ins.b]; break;
|
||||
|
||||
case Op::Ge: regs[ins.dst] = regs[ins.a] >= regs[ins.b]; break;
|
||||
|
||||
case Op::Eq: regs[ins.dst] = regs[ins.a] == regs[ins.b]; break;
|
||||
|
||||
case Op::Jmp: ip = static_cast<size_t>(static_cast<int64_t>(ip) + ins.imm); break;
|
||||
|
||||
case Op::Br:
|
||||
if (regs[ins.a] == 0) { ip = static_cast<size_t>(static_cast<int64_t>(ip) + ins.imm); }
|
||||
break;
|
||||
|
||||
case Op::Call: {
|
||||
// currently supports 1-arg call via reg a
|
||||
Function *callee = functions.at(static_cast<size_t>(ins.imm));
|
||||
int64_t arg0 = regs[ins.a];
|
||||
int64_t ret = execute(callee, &arg0);
|
||||
regs[ins.dst] = ret;
|
||||
break;
|
||||
}
|
||||
|
||||
case Op::Ret: return regs[ins.a];
|
||||
}
|
||||
}
|
||||
|
||||
// unreachable normally
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}; // namespace Fig::IR
|
||||
@@ -1,14 +0,0 @@
|
||||
#include <IR/IRInterpreter.hpp>
|
||||
#include <IR/IR.hpp>
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace Fig;
|
||||
IR::VirtualMachine vm;
|
||||
|
||||
using namespace IR;
|
||||
IR::Inst fib_ir[] = {
|
||||
|
||||
};
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
#include <Core/fig_string.hpp>
|
||||
#include <Error/error.hpp>
|
||||
#include <Token/token.hpp>
|
||||
#include <Lexer/lexer.hpp>
|
||||
|
||||
#include <Core/String.hpp>
|
||||
#include <Core/CharUtils.hpp>
|
||||
#include <Core/fig_string.hpp>
|
||||
#include <Utils/utils.hpp>
|
||||
|
||||
#if 0
|
||||
@@ -17,110 +17,113 @@
|
||||
namespace Fig
|
||||
{
|
||||
|
||||
const std::unordered_map<String, TokenType> Lexer::symbol_map{
|
||||
const std::unordered_map<FString, TokenType> Lexer::symbol_map{
|
||||
// 三字符
|
||||
{String(U"..."), TokenType::TripleDot},
|
||||
{FString(u8"..."), TokenType::TripleDot},
|
||||
// 双字符
|
||||
{String(U"=="), TokenType::Equal},
|
||||
{String(U"!="), TokenType::NotEqual},
|
||||
{String(U"<="), TokenType::LessEqual},
|
||||
{String(U">="), TokenType::GreaterEqual},
|
||||
{String(U"<<"), TokenType::ShiftLeft},
|
||||
{String(U">>"), TokenType::ShiftRight},
|
||||
{String(U"+="), TokenType::PlusEqual},
|
||||
{String(U"-="), TokenType::MinusEqual},
|
||||
{String(U"*="), TokenType::AsteriskEqual},
|
||||
{String(U"/="), TokenType::SlashEqual},
|
||||
{String(U"%="), TokenType::PercentEqual},
|
||||
{String(U"^="), TokenType::CaretEqual},
|
||||
{String(U"++"), TokenType::DoublePlus},
|
||||
{String(U"--"), TokenType::DoubleMinus},
|
||||
{String(U"&&"), TokenType::DoubleAmpersand},
|
||||
{String(U"||"), TokenType::DoublePipe},
|
||||
{String(U":="), TokenType::Walrus},
|
||||
{String(U"**"), TokenType::Power},
|
||||
{String(U"->"), TokenType::RightArrow},
|
||||
{String(U"=>"), TokenType::DoubleArrow},
|
||||
{FString(u8"=="), TokenType::Equal},
|
||||
{FString(u8"!="), TokenType::NotEqual},
|
||||
{FString(u8"<="), TokenType::LessEqual},
|
||||
{FString(u8">="), TokenType::GreaterEqual},
|
||||
{FString(u8"<<"), TokenType::ShiftLeft},
|
||||
{FString(u8">>"), TokenType::ShiftRight},
|
||||
{FString(u8"+="), TokenType::PlusEqual},
|
||||
{FString(u8"-="), TokenType::MinusEqual},
|
||||
{FString(u8"*="), TokenType::AsteriskEqual},
|
||||
{FString(u8"/="), TokenType::SlashEqual},
|
||||
{FString(u8"%="), TokenType::PercentEqual},
|
||||
{FString(u8"^="), TokenType::CaretEqual},
|
||||
{FString(u8"++"), TokenType::DoublePlus},
|
||||
{FString(u8"--"), TokenType::DoubleMinus},
|
||||
{FString(u8"&&"), TokenType::DoubleAmpersand},
|
||||
{FString(u8"||"), TokenType::DoublePipe},
|
||||
{FString(u8":="), TokenType::Walrus},
|
||||
{FString(u8"**"), TokenType::Power},
|
||||
{FString(u8"->"), TokenType::RightArrow},
|
||||
{FString(u8"=>"), TokenType::DoubleArrow},
|
||||
|
||||
// 单字符
|
||||
{String(U"+"), TokenType::Plus},
|
||||
{String(U"-"), TokenType::Minus},
|
||||
{String(U"*"), TokenType::Asterisk},
|
||||
{String(U"/"), TokenType::Slash},
|
||||
{String(U"%"), TokenType::Percent},
|
||||
{String(U"^"), TokenType::Caret},
|
||||
{String(U"&"), TokenType::Ampersand},
|
||||
{String(U"|"), TokenType::Pipe},
|
||||
{String(U"~"), TokenType::Tilde},
|
||||
{String(U"="), TokenType::Assign},
|
||||
{String(U"<"), TokenType::Less},
|
||||
{String(U">"), TokenType::Greater},
|
||||
{String(U"."), TokenType::Dot},
|
||||
{String(U","), TokenType::Comma},
|
||||
{String(U":"), TokenType::Colon},
|
||||
{String(U";"), TokenType::Semicolon},
|
||||
{String(U"'"), TokenType::SingleQuote},
|
||||
{String(U"\""), TokenType::DoubleQuote},
|
||||
{String(U"("), TokenType::LeftParen},
|
||||
{String(U")"), TokenType::RightParen},
|
||||
{String(U"["), TokenType::LeftBracket},
|
||||
{String(U"]"), TokenType::RightBracket},
|
||||
{String(U"{"), TokenType::LeftBrace},
|
||||
{String(U"}"), TokenType::RightBrace},
|
||||
{String(U"?"), TokenType::Question},
|
||||
{String(U"!"), TokenType::Not},
|
||||
{FString(u8"+"), TokenType::Plus},
|
||||
{FString(u8"-"), TokenType::Minus},
|
||||
{FString(u8"*"), TokenType::Asterisk},
|
||||
{FString(u8"/"), TokenType::Slash},
|
||||
{FString(u8"%"), TokenType::Percent},
|
||||
{FString(u8"^"), TokenType::Caret},
|
||||
{FString(u8"&"), TokenType::Ampersand},
|
||||
{FString(u8"|"), TokenType::Pipe},
|
||||
{FString(u8"~"), TokenType::Tilde},
|
||||
{FString(u8"="), TokenType::Assign},
|
||||
{FString(u8"<"), TokenType::Less},
|
||||
{FString(u8">"), TokenType::Greater},
|
||||
{FString(u8"."), TokenType::Dot},
|
||||
{FString(u8","), TokenType::Comma},
|
||||
{FString(u8":"), TokenType::Colon},
|
||||
{FString(u8";"), TokenType::Semicolon},
|
||||
{FString(u8"'"), TokenType::SingleQuote},
|
||||
{FString(u8"\""), TokenType::DoubleQuote},
|
||||
{FString(u8"("), TokenType::LeftParen},
|
||||
{FString(u8")"), TokenType::RightParen},
|
||||
{FString(u8"["), TokenType::LeftBracket},
|
||||
{FString(u8"]"), TokenType::RightBracket},
|
||||
{FString(u8"{"), TokenType::LeftBrace},
|
||||
{FString(u8"}"), TokenType::RightBrace},
|
||||
{FString(u8"?"), TokenType::Question},
|
||||
{FString(u8"!"), TokenType::Not},
|
||||
};
|
||||
|
||||
const std::unordered_map<String, TokenType> Lexer::keyword_map{
|
||||
{String(U"and"), TokenType::And},
|
||||
{String(U"or"), TokenType::Or},
|
||||
{String(U"not"), TokenType::Not},
|
||||
{String(U"import"), TokenType::Import},
|
||||
{String(U"func"), TokenType::Function},
|
||||
{String(U"var"), TokenType::Variable},
|
||||
{String(U"const"), TokenType::Const},
|
||||
// {String(U"final"), TokenType::Final},
|
||||
{String(U"while"), TokenType::While},
|
||||
{String(U"for"), TokenType::For},
|
||||
{String(U"if"), TokenType::If},
|
||||
{String(U"else"), TokenType::Else},
|
||||
{String(U"new"), TokenType::New},
|
||||
{String(U"struct"), TokenType::Struct},
|
||||
{String(U"interface"), TokenType::Interface},
|
||||
{String(U"impl"), TokenType::Implement},
|
||||
{String(U"is"), TokenType::Is},
|
||||
{String(U"public"), TokenType::Public},
|
||||
{String(U"return"), TokenType::Return},
|
||||
{String(U"break"), TokenType::Break},
|
||||
{String(U"continue"), TokenType::Continue},
|
||||
{String(U"try"), TokenType::Try},
|
||||
{String(U"catch"), TokenType::Catch},
|
||||
{String(U"throw"), TokenType::Throw},
|
||||
{String(U"Finally"), TokenType::Finally},
|
||||
{String(U"as"), TokenType::As},
|
||||
const std::unordered_map<FString, TokenType> Lexer::keyword_map{
|
||||
{FString(u8"and"), TokenType::And},
|
||||
{FString(u8"or"), TokenType::Or},
|
||||
{FString(u8"not"), TokenType::Not},
|
||||
{FString(u8"import"), TokenType::Import},
|
||||
{FString(u8"func"), TokenType::Function},
|
||||
{FString(u8"var"), TokenType::Variable},
|
||||
{FString(u8"const"), TokenType::Const},
|
||||
// {FString(u8"final"), TokenType::Final},
|
||||
{FString(u8"while"), TokenType::While},
|
||||
{FString(u8"for"), TokenType::For},
|
||||
{FString(u8"if"), TokenType::If},
|
||||
{FString(u8"else"), TokenType::Else},
|
||||
{FString(u8"new"), TokenType::New},
|
||||
{FString(u8"struct"), TokenType::Struct},
|
||||
{FString(u8"interface"), TokenType::Interface},
|
||||
{FString(u8"impl"), TokenType::Implement},
|
||||
{FString(u8"is"), TokenType::Is},
|
||||
{FString(u8"public"), TokenType::Public},
|
||||
{FString(u8"return"), TokenType::Return},
|
||||
{FString(u8"break"), TokenType::Break},
|
||||
{FString(u8"continue"), TokenType::Continue},
|
||||
{FString(u8"try"), TokenType::Try},
|
||||
{FString(u8"catch"), TokenType::Catch},
|
||||
{FString(u8"throw"), TokenType::Throw},
|
||||
{FString(u8"Finally"), TokenType::Finally},
|
||||
{FString(u8"as"), TokenType::As},
|
||||
|
||||
// {String(U"Null"), TokenType::TypeNull},
|
||||
// {String(U"Int"), TokenType::TypeInt},
|
||||
// {String(U"String"), TokenType::TypeString},
|
||||
// {String(U"Bool"), TokenType::TypeBool},
|
||||
// {String(U"Double"), TokenType::TypeDouble},
|
||||
// {FString(u8"Null"), TokenType::TypeNull},
|
||||
// {FString(u8"Int"), TokenType::TypeInt},
|
||||
// {FString(u8"String"), TokenType::TypeString},
|
||||
// {FString(u8"Bool"), TokenType::TypeBool},
|
||||
// {FString(u8"Double"), TokenType::TypeDouble},
|
||||
};
|
||||
void Lexer::skipLine()
|
||||
{
|
||||
while (current() != U'\n' and hasNext()) { next(); }
|
||||
while (*it != U'\n' and hasNext())
|
||||
{
|
||||
next();
|
||||
}
|
||||
next(); // skip '\n'
|
||||
++line;
|
||||
}
|
||||
Token Lexer::scanIdentifier()
|
||||
{
|
||||
String identifier;
|
||||
FString identifier;
|
||||
|
||||
while (hasNext())
|
||||
{
|
||||
char32_t c = current();
|
||||
if (CharUtils::isAlnum(c) || c == U'_')
|
||||
UTF8Char c = *it;
|
||||
if (c.isAlnum() || c == U'_')
|
||||
{
|
||||
identifier += c;
|
||||
identifier += c.getString();
|
||||
next();
|
||||
}
|
||||
else
|
||||
@@ -128,27 +131,23 @@ namespace Fig
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (this->keyword_map.contains(identifier)) { return Token(identifier, this->keyword_map.at(identifier)); }
|
||||
else if (identifier == U"\1" || identifier == U"\1") { return Token(identifier, TokenType::LiteralBool); }
|
||||
else if (identifier == U"\1")
|
||||
if (this->keyword_map.contains(identifier))
|
||||
{
|
||||
return Token(identifier, this->keyword_map.at(identifier));
|
||||
}
|
||||
else if (identifier == u8"true" || identifier == u8"false")
|
||||
{
|
||||
return Token(identifier, TokenType::LiteralBool);
|
||||
}
|
||||
else if (identifier == u8"null")
|
||||
{
|
||||
// null instance
|
||||
return Token(identifier, TokenType::LiteralNull);
|
||||
}
|
||||
// const auto &toLower = [](const String &str) -> String
|
||||
// {
|
||||
// String res;
|
||||
// for (auto c : str)
|
||||
// {
|
||||
// res += CharUtils::toLower(c);
|
||||
// }
|
||||
// return res;
|
||||
// };
|
||||
|
||||
// if (keyword_map.contains(toLower(identifier)))
|
||||
// {
|
||||
// pushWarning(1, identifier); // Identifier is too similar to a keyword or a primitive type
|
||||
// }
|
||||
if (keyword_map.contains(Utils::toLower(identifier)))
|
||||
{
|
||||
pushWarning(1, identifier); // Identifier is too similar to a keyword or a primitive type
|
||||
}
|
||||
if (identifier.length() <= 1)
|
||||
{
|
||||
pushWarning(2, identifier); // The identifier is too abstract
|
||||
@@ -157,13 +156,13 @@ namespace Fig
|
||||
}
|
||||
Token Lexer::scanString()
|
||||
{
|
||||
String str;
|
||||
FString str;
|
||||
bool unterminated = true;
|
||||
size_t str_start_col = column - 1;
|
||||
size_t str_start_col = it.column() - 1;
|
||||
while (hasNext())
|
||||
{
|
||||
char32_t c = current();
|
||||
if (c == U'"' || c == U'\n')
|
||||
UTF8Char c = *it;
|
||||
if (c == U'"')
|
||||
{
|
||||
next();
|
||||
unterminated = false;
|
||||
@@ -171,74 +170,74 @@ namespace Fig
|
||||
}
|
||||
else if (c == U'\\') // c is '\'
|
||||
{
|
||||
if (!hasNext())
|
||||
if (it.isEnd())
|
||||
{
|
||||
error = SyntaxError(U"\1", this->line, column, SourceInfo(this));
|
||||
error = SyntaxError(u8"Unterminated FString", this->line, it.column(), SourceInfo(this));
|
||||
return IllegalTok;
|
||||
}
|
||||
next();
|
||||
char32_t ec = current();
|
||||
UTF8Char ec = *it;
|
||||
if (ec == U'n')
|
||||
{
|
||||
next();
|
||||
str += U"\1";
|
||||
str += u8"\n";
|
||||
}
|
||||
else if (ec == U't')
|
||||
{
|
||||
next();
|
||||
str += U"\1";
|
||||
str += u8"\t";
|
||||
}
|
||||
else if (ec == U'v')
|
||||
{
|
||||
next();
|
||||
str += U"\1";
|
||||
str += u8"\v";
|
||||
}
|
||||
else if (ec == U'b')
|
||||
{
|
||||
next();
|
||||
str += U"\1";
|
||||
str += u8"\b";
|
||||
}
|
||||
else if (ec == U'"')
|
||||
{
|
||||
next();
|
||||
str += U"\1";
|
||||
str += u8"\"";
|
||||
}
|
||||
else if (ec == U'\'')
|
||||
{
|
||||
next();
|
||||
str += U"\1";
|
||||
str += u8"'";
|
||||
}
|
||||
else
|
||||
{
|
||||
error =
|
||||
SyntaxError(String(std::format("Unsupported escape character: {}", String(ec).toBasicString())),
|
||||
error = SyntaxError(FString(std::format("Unsupported escape character: {}",
|
||||
FString(ec.getString()).toBasicString())),
|
||||
this->line,
|
||||
column,
|
||||
it.column(),
|
||||
SourceInfo(this));
|
||||
return IllegalTok;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
str += c;
|
||||
str += c.getString();
|
||||
next();
|
||||
}
|
||||
}
|
||||
if (unterminated)
|
||||
{
|
||||
error = SyntaxError(U"Unterminated FString", this->line, str_start_col, SourceInfo(this));
|
||||
error = SyntaxError(u8"Unterminated FString", this->line, str_start_col, SourceInfo(this));
|
||||
return IllegalTok;
|
||||
}
|
||||
return Token(str, TokenType::LiteralString);
|
||||
}
|
||||
Token Lexer::scanRawString()
|
||||
{
|
||||
String str;
|
||||
FString str;
|
||||
bool unterminated = true;
|
||||
size_t str_start_col = column - 1;
|
||||
size_t str_start_col = it.column() - 1;
|
||||
while (hasNext())
|
||||
{
|
||||
char32_t c = current();
|
||||
UTF8Char c = *it;
|
||||
if (c == U'"' || c == U'\n')
|
||||
{
|
||||
next();
|
||||
@@ -247,27 +246,27 @@ namespace Fig
|
||||
}
|
||||
else
|
||||
{
|
||||
str += c;
|
||||
str += c.getString();
|
||||
next();
|
||||
}
|
||||
}
|
||||
if (unterminated)
|
||||
{
|
||||
error = SyntaxError(U"Unterminated FString", this->line, str_start_col, SourceInfo(this));
|
||||
error = SyntaxError(u8"Unterminated FString", this->line, str_start_col, SourceInfo(this));
|
||||
return IllegalTok;
|
||||
}
|
||||
return Token(str, TokenType::LiteralString);
|
||||
}
|
||||
Token Lexer::scanMultilineString()
|
||||
{
|
||||
String str;
|
||||
FString str;
|
||||
bool unterminated = true;
|
||||
|
||||
uint8_t end = 0;
|
||||
size_t str_start_col = column - 1;
|
||||
size_t str_start_col = it.column() - 1;
|
||||
while (hasNext())
|
||||
{
|
||||
char32_t c = current();
|
||||
UTF8Char c = *it;
|
||||
if (c == U'"')
|
||||
{
|
||||
if (end == 3)
|
||||
@@ -282,99 +281,99 @@ namespace Fig
|
||||
}
|
||||
else if (c == U'\\') // c is '\'
|
||||
{
|
||||
if (!hasNext())
|
||||
if (it.isEnd())
|
||||
{
|
||||
error = SyntaxError(U"Unterminated FString", this->line, column, SourceInfo(this));
|
||||
error = SyntaxError(u8"Unterminated FString", this->line, it.column(), SourceInfo(this));
|
||||
return IllegalTok;
|
||||
}
|
||||
next();
|
||||
char32_t ec = current();
|
||||
UTF8Char ec = *it;
|
||||
if (ec == U'n')
|
||||
{
|
||||
next();
|
||||
str += U"\n";
|
||||
str += u8"\n";
|
||||
}
|
||||
else if (ec == U't')
|
||||
{
|
||||
next();
|
||||
str += U"\t";
|
||||
str += u8"\t";
|
||||
}
|
||||
else if (ec == U'v')
|
||||
{
|
||||
next();
|
||||
str += U"\v";
|
||||
str += u8"\v";
|
||||
}
|
||||
else if (ec == U'b')
|
||||
{
|
||||
next();
|
||||
str += U"\b";
|
||||
str += u8"\b";
|
||||
}
|
||||
else if (ec == U'"')
|
||||
{
|
||||
next();
|
||||
str += U"\"";
|
||||
str += u8"\"";
|
||||
}
|
||||
else if (ec == U'\'')
|
||||
{
|
||||
next();
|
||||
str += U"\'";
|
||||
str += u8"'";
|
||||
}
|
||||
else if (ec == U'\\')
|
||||
{
|
||||
next();
|
||||
str += U"\\";
|
||||
str += u8"\\";
|
||||
}
|
||||
else
|
||||
{
|
||||
error = SyntaxError(
|
||||
String(std::format("Unsupported escape character: {}", String(ec).toBasicString())),
|
||||
error = SyntaxError(FString(std::format("Unsupported escape character: {}",
|
||||
FString(ec.getString()).toBasicString())),
|
||||
this->line,
|
||||
column,
|
||||
it.column(),
|
||||
SourceInfo(this));
|
||||
return IllegalTok;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
str += c;
|
||||
str += c.getString();
|
||||
}
|
||||
end = 0;
|
||||
}
|
||||
if (unterminated)
|
||||
{
|
||||
error = SyntaxError(U"\1", this->line, str_start_col, SourceInfo(this));
|
||||
error = SyntaxError(u8"Unterminated FString", this->line, str_start_col, SourceInfo(this));
|
||||
return IllegalTok;
|
||||
}
|
||||
return Token(str, TokenType::LiteralString);
|
||||
}
|
||||
Token Lexer::scanNumber()
|
||||
{
|
||||
String numStr;
|
||||
FString numStr;
|
||||
bool hasPoint = false;
|
||||
|
||||
while (hasNext())
|
||||
{
|
||||
char32_t ch = current();
|
||||
UTF8Char ch = *it;
|
||||
|
||||
if (CharUtils::isDigit(ch) || ch == U'e')
|
||||
if (ch.isDigit() || ch == U'e')
|
||||
{
|
||||
numStr += ch;
|
||||
numStr += ch.getString();
|
||||
next();
|
||||
}
|
||||
else if (ch == U'-' && !numStr.empty() && (numStr.ends_with(U'e') || numStr.ends_with(U'E')))
|
||||
{
|
||||
numStr += ch;
|
||||
numStr += ch.getString();
|
||||
next();
|
||||
}
|
||||
else if (ch == U'+' && !numStr.empty() && (numStr.ends_with(U'e') || numStr.ends_with(U'E')))
|
||||
{
|
||||
numStr += ch;
|
||||
numStr += ch.getString();
|
||||
next();
|
||||
}
|
||||
else if (ch == U'.' && !hasPoint)
|
||||
{
|
||||
hasPoint = true;
|
||||
numStr += ch;
|
||||
numStr += ch.getString();
|
||||
next();
|
||||
}
|
||||
else
|
||||
@@ -386,9 +385,9 @@ namespace Fig
|
||||
|
||||
if (numStr.ends_with(U'e'))
|
||||
{
|
||||
error = SyntaxError(String(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
||||
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
||||
this->line,
|
||||
column,
|
||||
it.column(),
|
||||
SourceInfo(this));
|
||||
return IllegalTok;
|
||||
}
|
||||
@@ -396,7 +395,7 @@ namespace Fig
|
||||
bool hasDigit = false;
|
||||
for (auto it = numStr.begin(); it != numStr.end(); ++it)
|
||||
{
|
||||
if (CharUtils::isDigit(*it))
|
||||
if (isdigit(*it))
|
||||
{
|
||||
hasDigit = true;
|
||||
break;
|
||||
@@ -405,55 +404,55 @@ namespace Fig
|
||||
|
||||
if (!hasDigit)
|
||||
{
|
||||
error = SyntaxError(String(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
||||
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
||||
this->line,
|
||||
column,
|
||||
it.column(),
|
||||
SourceInfo(this));
|
||||
return IllegalTok;
|
||||
}
|
||||
|
||||
size_t ePos = numStr.find(U'e');
|
||||
if (ePos != String::npos)
|
||||
if (ePos != FString::npos)
|
||||
{
|
||||
if (ePos == 0)
|
||||
{
|
||||
error = SyntaxError(String(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
||||
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
||||
this->line,
|
||||
column,
|
||||
it.column(),
|
||||
SourceInfo(this));
|
||||
return IllegalTok;
|
||||
}
|
||||
if (ePos + 1 >= numStr.length())
|
||||
{
|
||||
error = SyntaxError(String(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
||||
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
||||
this->line,
|
||||
column,
|
||||
it.column(),
|
||||
SourceInfo(this));
|
||||
return IllegalTok;
|
||||
}
|
||||
bool hasDigitAfterE = false;
|
||||
for (size_t i = ePos + 1; i < numStr.length(); ++i)
|
||||
{
|
||||
char32_t c = numStr[i];
|
||||
UTF8Char c = std::u8string(1,numStr[i]);
|
||||
if (c == U'+' || c == U'-')
|
||||
{
|
||||
if (i != ePos + 1)
|
||||
{
|
||||
error = SyntaxError(String(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
||||
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
||||
this->line,
|
||||
column,
|
||||
it.column(),
|
||||
SourceInfo(this));
|
||||
return IllegalTok;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (CharUtils::isDigit(c)) { hasDigitAfterE = true; }
|
||||
if (c.isDigit()) { hasDigitAfterE = true; }
|
||||
else
|
||||
{
|
||||
error = SyntaxError(String(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
||||
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
||||
this->line,
|
||||
column,
|
||||
it.column(),
|
||||
SourceInfo(this));
|
||||
return IllegalTok;
|
||||
}
|
||||
@@ -461,9 +460,9 @@ namespace Fig
|
||||
|
||||
if (!hasDigitAfterE)
|
||||
{
|
||||
error = SyntaxError(String(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
||||
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
||||
this->line,
|
||||
column,
|
||||
it.column(),
|
||||
SourceInfo(this));
|
||||
return IllegalTok;
|
||||
}
|
||||
@@ -473,24 +472,25 @@ namespace Fig
|
||||
}
|
||||
Token Lexer::scanSymbol()
|
||||
{
|
||||
String sym;
|
||||
char32_t ch = current();
|
||||
sym += ch;
|
||||
FString sym;
|
||||
UTF8Char ch = *it;
|
||||
sym += ch.getString();
|
||||
|
||||
auto startsWith = [&](const String &prefix) -> bool {
|
||||
auto startsWith = [&](const FString &prefix) -> bool {
|
||||
for (const auto &p : symbol_map)
|
||||
{
|
||||
const String &op = p.first;
|
||||
if (op.starts_with(prefix)) return true;
|
||||
const FString &op = p.first;
|
||||
if (op.starts_with(prefix))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if (!startsWith(sym))
|
||||
{
|
||||
error = SyntaxError(String(std::format("No such operator: {}", sym.toBasicString())),
|
||||
error = SyntaxError(FString(std::format("No such operator: {}", sym.toBasicString())),
|
||||
this->line,
|
||||
column,
|
||||
it.column(),
|
||||
SourceInfo(this));
|
||||
next();
|
||||
return IllegalTok;
|
||||
@@ -498,10 +498,11 @@ namespace Fig
|
||||
|
||||
while (hasNext())
|
||||
{
|
||||
char32_t peek_ch = peek();
|
||||
if (!CharUtils::isPunct(peek_ch)) break;
|
||||
UTF8Char peek = it.peek();
|
||||
if (!peek.isPunct())
|
||||
break;
|
||||
|
||||
String candidate = sym + peek_ch;
|
||||
FString candidate = sym + FString(peek.getString());
|
||||
|
||||
if (startsWith(candidate))
|
||||
{
|
||||
@@ -516,9 +517,9 @@ namespace Fig
|
||||
|
||||
if (!symbol_map.contains(sym))
|
||||
{
|
||||
error = SyntaxError(String(std::format("No such operator: {}", sym.toBasicString())),
|
||||
error = SyntaxError(FString(std::format("No such operator: {}", sym.toBasicString())),
|
||||
this->line,
|
||||
column,
|
||||
it.column(),
|
||||
SourceInfo(this));
|
||||
next();
|
||||
return IllegalTok;
|
||||
@@ -532,34 +533,37 @@ namespace Fig
|
||||
{
|
||||
// entry: when iterator current char is '/' and peek is '/' or '*'
|
||||
// current char is '/'
|
||||
String comment;
|
||||
FString comment;
|
||||
|
||||
if (peek() == U'/') // single-line comment
|
||||
if (it.peek() == U'/') // single-line comment
|
||||
{
|
||||
next(); // skip first '/'
|
||||
next(); // skip second '/'
|
||||
|
||||
char32_t c = current();
|
||||
UTF8Char c = *it;
|
||||
while (c != U'\n' and hasNext())
|
||||
{
|
||||
comment += c;
|
||||
comment += c.getString();
|
||||
next();
|
||||
c = current();
|
||||
c = *it;
|
||||
}
|
||||
|
||||
if (hasNext() && c == U'\n') { next(); }
|
||||
if (hasNext() && c == U'\n')
|
||||
{
|
||||
next();
|
||||
}
|
||||
}
|
||||
else // multi-line comment
|
||||
{
|
||||
next(); // skip '/'
|
||||
next(); // skip '*'
|
||||
|
||||
char32_t c = current();
|
||||
UTF8Char c = *it;
|
||||
bool terminated = false;
|
||||
|
||||
while (hasNext())
|
||||
{
|
||||
if (c == U'*' and hasNext() and peek() == U'/')
|
||||
if (c == U'*' and hasNext() and it.peek() == U'/')
|
||||
{
|
||||
next(); // skip '*'
|
||||
next(); // skip '/'
|
||||
@@ -568,15 +572,16 @@ namespace Fig
|
||||
}
|
||||
else
|
||||
{
|
||||
comment += c;
|
||||
comment += c.getString();
|
||||
next();
|
||||
c = current();
|
||||
c = *it;
|
||||
}
|
||||
}
|
||||
|
||||
if (!terminated)
|
||||
{
|
||||
error = SyntaxError(String(U"\1"), this->line, column, SourceInfo(this));
|
||||
error =
|
||||
SyntaxError(FString(u8"Unterminated multiline comment"), this->line, it.column(), SourceInfo(this));
|
||||
next();
|
||||
return IllegalTok;
|
||||
}
|
||||
@@ -586,61 +591,76 @@ namespace Fig
|
||||
}
|
||||
Token Lexer::nextToken()
|
||||
{
|
||||
if (!hasNext()) { return EOFTok.setPos(getCurrentLine(), getCurrentColumn()); }
|
||||
char32_t ch = current();
|
||||
while (hasNext())
|
||||
if (!hasNext())
|
||||
{
|
||||
ch = current();
|
||||
if (!CharUtils::isSpace(ch))
|
||||
{
|
||||
break;
|
||||
return EOFTok;
|
||||
}
|
||||
UTF8Char ch = *it;
|
||||
while (ch.isSpace())
|
||||
{
|
||||
next();
|
||||
ch = *it;
|
||||
if (!hasNext())
|
||||
{
|
||||
return EOFTok.setPos(getCurrentLine(), getCurrentColumn());
|
||||
}
|
||||
}
|
||||
last_line = getCurrentLine();
|
||||
last_column = getCurrentColumn();
|
||||
if (ch == U'/')
|
||||
{
|
||||
char32_t c;
|
||||
UTF8Char c{u8""};
|
||||
if (!hasNext())
|
||||
{
|
||||
next();
|
||||
return Token(U"\1", this->symbol_map.at(U"\1")).setPos(last_line, last_column);
|
||||
return Token(u8"/", this->symbol_map.at(u8"/")).setPos(last_line, last_column);
|
||||
}
|
||||
c = peek();
|
||||
c = it.peek();
|
||||
if (c != U'/' and c != U'*')
|
||||
{
|
||||
next();
|
||||
return Token(U"\1", this->symbol_map.at(U"\1")).setPos(last_line, last_column);
|
||||
return Token(u8"/", this->symbol_map.at(u8"/")).setPos(last_line, last_column);
|
||||
}
|
||||
scanComments().setPos(last_line, last_column);
|
||||
return nextToken();
|
||||
// now we ignore comments to avoid some stupid bugs
|
||||
}
|
||||
if (ch == U'r' and hasNext() and peek() == U'"')
|
||||
if (ch == U'r' and hasNext() and it.peek() == U'"')
|
||||
{
|
||||
// r""
|
||||
// raw String
|
||||
// raw FString
|
||||
next();
|
||||
next();
|
||||
return scanRawString().setPos(last_line, last_column);
|
||||
}
|
||||
if (CharUtils::isAlpha(ch) || ch == U'_') { return scanIdentifier().setPos(last_line, last_column); }
|
||||
if (ch.isAlpha() || ch == U'_')
|
||||
{
|
||||
return scanIdentifier().setPos(last_line, last_column);
|
||||
}
|
||||
else if (ch == U'"')
|
||||
{
|
||||
next();
|
||||
return scanString().setPos(last_line, last_column);
|
||||
}
|
||||
else if (CharUtils::isDigit(ch)) { return scanNumber().setPos(last_line, last_column); }
|
||||
else if (CharUtils::isPunct(ch)) { return scanSymbol().setPos(last_line, last_column); }
|
||||
else if (ch.isDigit())
|
||||
{
|
||||
return scanNumber().setPos(last_line, last_column);
|
||||
}
|
||||
else if (ch.isPunct())
|
||||
{
|
||||
return scanSymbol().setPos(last_line, last_column);
|
||||
}
|
||||
else
|
||||
{
|
||||
error =
|
||||
SyntaxError(String(std::format("Cannot tokenize char: '{}'", String(ch).toBasicString())),
|
||||
SyntaxError(FString(std::format("Cannot tokenize char: '{}'", FString(ch.getString()).toBasicString())),
|
||||
this->line,
|
||||
column,
|
||||
it.column(),
|
||||
SourceInfo(this));
|
||||
if (hasNext()) { next(); }
|
||||
if (hasNext())
|
||||
{
|
||||
next();
|
||||
}
|
||||
return IllegalTok.setPos(last_line, last_column);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
|
||||
#include <Token/token.hpp>
|
||||
#include <Error/error.hpp>
|
||||
#include <Core/String.hpp>
|
||||
#include <Core/fig_string.hpp>
|
||||
#include <Core/utf8_iterator.hpp>
|
||||
#include <Core/warning.hpp>
|
||||
|
||||
namespace Fig
|
||||
@@ -18,33 +19,26 @@ namespace Fig
|
||||
{
|
||||
private:
|
||||
size_t line;
|
||||
const String source;
|
||||
const FString source;
|
||||
SyntaxError error;
|
||||
UTF8Iterator it;
|
||||
|
||||
FString sourcePath;
|
||||
std::vector<FString> sourceLines;
|
||||
|
||||
String sourcePath;
|
||||
std::vector<String> sourceLines;
|
||||
std::vector<Warning> warnings;
|
||||
|
||||
int64_t idx = 0;
|
||||
|
||||
size_t last_line, last_column, column = 1;
|
||||
|
||||
char32_t current() const { return source[idx]; }
|
||||
|
||||
char32_t peek() const {
|
||||
if (idx + 1 >= source.length())
|
||||
bool hasNext()
|
||||
{
|
||||
return U'\0';
|
||||
return !this->it.isEnd();
|
||||
}
|
||||
return source[idx + 1];
|
||||
}
|
||||
|
||||
bool hasNext() { return idx < source.length(); }
|
||||
|
||||
void skipLine();
|
||||
inline void next()
|
||||
{
|
||||
if (current() == U'\n')
|
||||
if (*it == U'\n')
|
||||
{
|
||||
++this->line;
|
||||
this->column = 1;
|
||||
@@ -53,31 +47,43 @@ namespace Fig
|
||||
{
|
||||
++this->column;
|
||||
}
|
||||
++idx;
|
||||
++it;
|
||||
}
|
||||
|
||||
void pushWarning(size_t id, String msg)
|
||||
void pushWarning(size_t id, FString msg)
|
||||
{
|
||||
warnings.push_back(Warning(id, std::move(msg), getCurrentLine(), getCurrentColumn()));
|
||||
}
|
||||
void pushWarning(size_t id, String msg, size_t line, size_t column)
|
||||
void pushWarning(size_t id, FString msg, size_t line, size_t column)
|
||||
{
|
||||
warnings.push_back(Warning(id, std::move(msg), line, column));
|
||||
}
|
||||
|
||||
public:
|
||||
static const std::unordered_map<String, TokenType> symbol_map;
|
||||
static const std::unordered_map<String, TokenType> keyword_map;
|
||||
static const std::unordered_map<FString, TokenType> symbol_map;
|
||||
static const std::unordered_map<FString, TokenType> keyword_map;
|
||||
|
||||
inline Lexer(const String &_source, const String &_sourcePath, const std::vector<String> &_sourceLines) :
|
||||
source(_source), sourcePath(_sourcePath), sourceLines(_sourceLines)
|
||||
inline Lexer(const FString &_source, const FString &_sourcePath, const std::vector<FString> &_sourceLines) :
|
||||
source(_source), it(source), sourcePath(_sourcePath), sourceLines(_sourceLines)
|
||||
{
|
||||
line = 1;
|
||||
}
|
||||
inline size_t getCurrentLine() { return line; }
|
||||
inline size_t getCurrentColumn() { return column; }
|
||||
SyntaxError getError() const { return error; }
|
||||
std::vector<Warning> getWarnings() const { return warnings; }
|
||||
inline size_t getCurrentLine()
|
||||
{
|
||||
return line;
|
||||
}
|
||||
inline size_t getCurrentColumn()
|
||||
{
|
||||
return column;
|
||||
}
|
||||
SyntaxError getError() const
|
||||
{
|
||||
return error;
|
||||
}
|
||||
std::vector<Warning> getWarnings() const
|
||||
{
|
||||
return warnings;
|
||||
}
|
||||
Token nextToken();
|
||||
|
||||
Token scanNumber();
|
||||
|
||||
3
src/Module/CppLibrary/CppLibrary.hpp
Normal file
3
src/Module/CppLibrary/CppLibrary.hpp
Normal file
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#include "File/File.hpp"
|
||||
74
src/Module/CppLibrary/File/File.hpp
Normal file
74
src/Module/CppLibrary/File/File.hpp
Normal file
@@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
|
||||
namespace Fig::CppLibrary
|
||||
{
|
||||
using FileIDType = uint16_t;
|
||||
struct File
|
||||
{
|
||||
FileIDType id;
|
||||
std::fstream *fs;
|
||||
};
|
||||
class FileManager
|
||||
{
|
||||
private:
|
||||
std::vector<File *> handlers;
|
||||
std::vector<FileIDType> free_handlers;
|
||||
|
||||
FileIDType allocated = 0;
|
||||
|
||||
public:
|
||||
static constexpr FileIDType MAX_HANDLERS = std::numeric_limits<FileIDType>::max();
|
||||
static constexpr unsigned int MAX_FILE_BUF = 961200; // bytes
|
||||
|
||||
FileIDType AllocFile(std::fstream *fs)
|
||||
{
|
||||
FileIDType id = allocated++;
|
||||
File *f = new File{.id = id, .fs = fs};
|
||||
handlers.push_back(f);
|
||||
return id;
|
||||
}
|
||||
|
||||
void CloseFile(FileIDType id)
|
||||
{
|
||||
assert(id < allocated && "CloseHandler: id out of range");
|
||||
File *f = handlers[id];
|
||||
if (f == nullptr) { return; }
|
||||
f->fs->close();
|
||||
delete f->fs;
|
||||
delete f;
|
||||
free_handlers.push_back(id);
|
||||
handlers[id] = nullptr;
|
||||
}
|
||||
|
||||
File *GetNextFreeFile()
|
||||
{
|
||||
// if there is no free handler, create a new one
|
||||
if (free_handlers.size() > 0)
|
||||
{
|
||||
FileIDType id = *free_handlers.begin();
|
||||
handlers[id] = new File{.id = id, .fs = new std::fstream};
|
||||
free_handlers.erase(free_handlers.begin());
|
||||
return handlers[id];
|
||||
}
|
||||
return handlers[AllocFile(new std::fstream)];
|
||||
}
|
||||
|
||||
File *GetFile(FileIDType id)
|
||||
{
|
||||
assert(id < allocated && "GetFile: id out of range");
|
||||
return handlers[id];
|
||||
}
|
||||
|
||||
static FileManager &getInstance()
|
||||
{
|
||||
static FileManager fm;
|
||||
return fm;
|
||||
}
|
||||
};
|
||||
}; // namespace Fig::CppLibrary
|
||||
101
src/Module/Library/std/file/file.fig
Normal file
101
src/Module/Library/std/file/file.fig
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
Official Module `std.file`
|
||||
Library/std/file/file.fig
|
||||
|
||||
Copyright © 2026 PuqiAR. All rights reserved.
|
||||
*/
|
||||
|
||||
import _builtins;
|
||||
import std.io;
|
||||
|
||||
|
||||
public struct __OpenMode
|
||||
{
|
||||
public App: Int = 1;
|
||||
public Ate: Int = 2;
|
||||
public Bin: Int = 4;
|
||||
public In: Int = 8;
|
||||
public Out: Int = 16;
|
||||
public Trunc: Int = 32;
|
||||
|
||||
public __openmode_to_string: Map =
|
||||
{
|
||||
1 : "App",
|
||||
2 : "Ate",
|
||||
4 : "Bin",
|
||||
8 : "In",
|
||||
16 : "Out",
|
||||
32 : "Trunc"
|
||||
};
|
||||
}
|
||||
public const OpenMode := new __OpenMode{};
|
||||
|
||||
public func repr_mode(mode: Int) -> String
|
||||
{
|
||||
return OpenMode.__openmode_to_string[mode];
|
||||
}
|
||||
|
||||
|
||||
|
||||
public struct FileError
|
||||
{
|
||||
msg: String;
|
||||
}
|
||||
|
||||
impl Error for FileError
|
||||
{
|
||||
getErrorClass()
|
||||
{
|
||||
return "FileError";
|
||||
}
|
||||
getErrorMessage()
|
||||
{
|
||||
return msg;
|
||||
}
|
||||
toString()
|
||||
{
|
||||
return getErrorClass() + ": " + msg;
|
||||
}
|
||||
}
|
||||
|
||||
public struct File
|
||||
{
|
||||
path: String;
|
||||
mode: Int;
|
||||
|
||||
id: Int;
|
||||
|
||||
public func read() -> Any
|
||||
{
|
||||
return __fstdfile_read(id);
|
||||
}
|
||||
|
||||
public func write(object: String) -> Null
|
||||
{
|
||||
__fstdfile_write(id, object);
|
||||
}
|
||||
|
||||
public func close() -> Null
|
||||
{
|
||||
__fstdfile_close(id);
|
||||
}
|
||||
|
||||
public func getID() -> Int
|
||||
{
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
public func open(path: String, mode: Int)
|
||||
{
|
||||
const id := __fstdfile_open(path, mode);
|
||||
if not __fstdfile_is_open(id)
|
||||
{
|
||||
throw new FileError{"File " + path + " open failed"};
|
||||
}
|
||||
return new File{
|
||||
path: path,
|
||||
mode: mode,
|
||||
id: id
|
||||
};
|
||||
}
|
||||
@@ -5,13 +5,19 @@
|
||||
#include <Ast/Statements/ControlSt.hpp>
|
||||
#include <Ast/astBase.hpp>
|
||||
#include <Ast/functionParameters.hpp>
|
||||
#include <Evaluator/Context/context.hpp>
|
||||
#include <Core/String.hpp>
|
||||
#include <Ast/AccessModifier.hpp>
|
||||
|
||||
#include <Evaluator/Value/structType.hpp>
|
||||
#include <Evaluator/Value/value.hpp>
|
||||
#include <Module/builtins.hpp>
|
||||
#include <Evaluator/Value/Type.hpp>
|
||||
#include <Evaluator/Context/context.hpp>
|
||||
|
||||
#include <Module/CppLibrary/CppLibrary.hpp>
|
||||
|
||||
#include <Module/builtins.hpp>
|
||||
#include <Core/fig_string.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <print>
|
||||
#include <iostream>
|
||||
@@ -24,60 +30,60 @@ namespace Fig::Builtins
|
||||
{
|
||||
const TypeInfo &getErrorInterfaceTypeInfo()
|
||||
{
|
||||
static const TypeInfo ErrorInterfaceTypeInfo(U"Error", true);
|
||||
static const TypeInfo ErrorInterfaceTypeInfo(u8"Error", true);
|
||||
return ErrorInterfaceTypeInfo;
|
||||
}
|
||||
const TypeInfo &getTypeErrorStructTypeInfo()
|
||||
{
|
||||
static const TypeInfo TypeErrorStructTypeInfo(U"TypeError", true);
|
||||
static const TypeInfo TypeErrorStructTypeInfo(u8"TypeError", true);
|
||||
return TypeErrorStructTypeInfo;
|
||||
}
|
||||
const TypeInfo &getOperationInterfaceTypeInfo()
|
||||
{
|
||||
static const TypeInfo OperationInterfaceTypeInfo(U"Operation", true);
|
||||
static const TypeInfo OperationInterfaceTypeInfo(u8"Operation", true);
|
||||
return OperationInterfaceTypeInfo;
|
||||
}
|
||||
const std::unordered_map<String, ObjectPtr> &getBuiltinValues()
|
||||
const std::unordered_map<FString, ObjectPtr> &getBuiltinValues()
|
||||
{
|
||||
static const std::unordered_map<String, ObjectPtr> builtinValues = {
|
||||
{U"null", Object::getNullInstance()},
|
||||
{U"true", Object::getTrueInstance()},
|
||||
{U"false", Object::getFalseInstance()},
|
||||
{U"Error",
|
||||
static const std::unordered_map<FString, ObjectPtr> builtinValues = {
|
||||
{u8"null", Object::getNullInstance()},
|
||||
{u8"true", Object::getTrueInstance()},
|
||||
{u8"false", Object::getFalseInstance()},
|
||||
{u8"Error",
|
||||
std::make_shared<Object>(InterfaceType(getErrorInterfaceTypeInfo(),
|
||||
{Ast::InterfaceMethod(U"toString",
|
||||
{Ast::InterfaceMethod(u8"toString",
|
||||
Ast::FunctionParameters({}, {}),
|
||||
std::make_shared<Ast::VarExprAst>(U"String"),
|
||||
std::make_shared<Ast::VarExprAst>(u8"String"),
|
||||
nullptr),
|
||||
Ast::InterfaceMethod(U"getErrorClass",
|
||||
Ast::InterfaceMethod(u8"getErrorClass",
|
||||
Ast::FunctionParameters({}, {}),
|
||||
std::make_shared<Ast::VarExprAst>(U"String"),
|
||||
std::make_shared<Ast::VarExprAst>(u8"String"),
|
||||
nullptr),
|
||||
Ast::InterfaceMethod(U"getErrorMessage",
|
||||
Ast::InterfaceMethod(u8"getErrorMessage",
|
||||
Ast::FunctionParameters({}, {}),
|
||||
std::make_shared<Ast::VarExprAst>(U"String"),
|
||||
std::make_shared<Ast::VarExprAst>(u8"String"),
|
||||
nullptr)}))},
|
||||
{U"TypeError", std::make_shared<Object>(StructType(
|
||||
{u8"TypeError", std::make_shared<Object>(StructType(
|
||||
getTypeErrorStructTypeInfo(),
|
||||
std::make_shared<Context>(U"<Built-in `TypeError`>"),
|
||||
{Field(AccessModifier::Public, U"msg", ValueType::String, nullptr)}
|
||||
std::make_shared<Context>(u8"<Built-in `TypeError`>"),
|
||||
{Field(AccessModifier::Public, u8"msg", ValueType::String, nullptr)}
|
||||
))},
|
||||
{U"Operation", std::make_shared<Object>(InterfaceType(getOperationInterfaceTypeInfo(), {}))},
|
||||
{u8"Operation", std::make_shared<Object>(InterfaceType(getOperationInterfaceTypeInfo(), {}))},
|
||||
|
||||
{U"Any", std::make_shared<Object>(StructType(ValueType::Any, nullptr, {}, true))},
|
||||
{U"Int", std::make_shared<Object>(StructType(ValueType::Int, nullptr, {}, true))},
|
||||
{U"Null", std::make_shared<Object>(StructType(ValueType::Null, nullptr, {}, true))},
|
||||
{U"String", std::make_shared<Object>(StructType(ValueType::String, nullptr, {}, true))},
|
||||
{U"Bool", std::make_shared<Object>(StructType(ValueType::Bool, nullptr, {}, true))},
|
||||
{U"Double", std::make_shared<Object>(StructType(ValueType::Double, nullptr, {}, true))},
|
||||
{U"Function", std::make_shared<Object>(StructType(ValueType::Function, nullptr, {}, true))},
|
||||
{U"List", std::make_shared<Object>(StructType(ValueType::List, nullptr, {}, true))},
|
||||
{U"Map", std::make_shared<Object>(StructType(ValueType::Map, nullptr, {}, true))},
|
||||
{u8"Any", std::make_shared<Object>(StructType(ValueType::Any, nullptr, {}, true))},
|
||||
{u8"Int", std::make_shared<Object>(StructType(ValueType::Int, nullptr, {}, true))},
|
||||
{u8"Null", std::make_shared<Object>(StructType(ValueType::Null, nullptr, {}, true))},
|
||||
{u8"String", std::make_shared<Object>(StructType(ValueType::String, nullptr, {}, true))},
|
||||
{u8"Bool", std::make_shared<Object>(StructType(ValueType::Bool, nullptr, {}, true))},
|
||||
{u8"Double", std::make_shared<Object>(StructType(ValueType::Double, nullptr, {}, true))},
|
||||
{u8"Function", std::make_shared<Object>(StructType(ValueType::Function, nullptr, {}, true))},
|
||||
{u8"List", std::make_shared<Object>(StructType(ValueType::List, nullptr, {}, true))},
|
||||
{u8"Map", std::make_shared<Object>(StructType(ValueType::Map, nullptr, {}, true))},
|
||||
// Type `StructType` `StructInstance` `Module` `InterfaceType`
|
||||
// Not allowed to call constructor!
|
||||
|
||||
{U"type", std::make_shared<Object>(Function(
|
||||
U"type",
|
||||
{u8"type", std::make_shared<Object>(Function(
|
||||
u8"type",
|
||||
[](const std::vector<ObjectPtr> &_args) -> ObjectPtr
|
||||
{
|
||||
const ObjectPtr &arg = _args[0];
|
||||
@@ -88,86 +94,95 @@ namespace Fig::Builtins
|
||||
};
|
||||
return builtinValues;
|
||||
}
|
||||
const std::unordered_map<String, int> &getBuiltinFunctionArgCounts()
|
||||
const std::unordered_map<FString, int> &getBuiltinFunctionArgCounts()
|
||||
{
|
||||
static const std::unordered_map<String, int> builtinFunctionArgCounts = {
|
||||
{U"__fstdout_print", -1}, // variadic
|
||||
{U"__fstdout_println", -1}, // variadic
|
||||
{U"__fstdin_read", 0},
|
||||
{U"__fstdin_readln", 0},
|
||||
{U"__fvalue_type", 1},
|
||||
{U"__fvalue_int_parse", 1},
|
||||
{U"__fvalue_int_from", 1},
|
||||
{U"__fvalue_double_parse", 1},
|
||||
{U"__fvalue_double_from", 1},
|
||||
{U"__fvalue_string_from", 1},
|
||||
{U"__ftime_now_ns", 0},
|
||||
static const std::unordered_map<FString, int> builtinFunctionArgCounts = {
|
||||
{u8"__fstdout_print", -1}, // variadic
|
||||
{u8"__fstdout_println", -1}, // variadic
|
||||
{u8"__fstdin_read", 0},
|
||||
{u8"__fstdin_readln", 0},
|
||||
{u8"__fvalue_type", 1},
|
||||
{u8"__fvalue_int_parse", 1},
|
||||
{u8"__fvalue_int_from", 1},
|
||||
{u8"__fvalue_double_parse", 1},
|
||||
{u8"__fvalue_double_from", 1},
|
||||
{u8"__fvalue_string_from", 1},
|
||||
{u8"__ftime_now_ns", 0},
|
||||
/* math start */
|
||||
{U"__fmath_acos", 1},
|
||||
{U"__fmath_acosh", 1},
|
||||
{U"__fmath_asin", 1},
|
||||
{U"__fmath_asinh", 1},
|
||||
{U"__fmath_atan", 1},
|
||||
{U"__fmath_atan2", 2},
|
||||
{U"__fmath_atanh", 1},
|
||||
{U"__fmath_ceil", 1},
|
||||
{U"__fmath_cos", 1},
|
||||
{U"__fmath_cosh", 1},
|
||||
{U"__fmath_exp", 1},
|
||||
{U"__fmath_expm1", 1},
|
||||
{U"__fmath_fabs", 1},
|
||||
{U"__fmath_floor", 1},
|
||||
{U"__fmath_fmod", 2},
|
||||
{U"__fmath_frexp", 1},
|
||||
{U"__fmath_gcd", 2},
|
||||
{U"__fmath_hypot", 2},
|
||||
{U"__fmath_isequal", 2},
|
||||
{U"__fmath_log", 1},
|
||||
{U"__fmath_log10", 1},
|
||||
{U"__fmath_log1p", 1},
|
||||
{U"__fmath_log2", 1},
|
||||
{U"__fmath_sin", 1},
|
||||
{U"__fmath_sinh", 1},
|
||||
{U"__fmath_sqrt", 1},
|
||||
{U"__fmath_tan", 1},
|
||||
{U"__fmath_tanh", 1},
|
||||
{U"__fmath_trunc", 1},
|
||||
{u8"__fmath_acos", 1},
|
||||
{u8"__fmath_acosh", 1},
|
||||
{u8"__fmath_asin", 1},
|
||||
{u8"__fmath_asinh", 1},
|
||||
{u8"__fmath_atan", 1},
|
||||
{u8"__fmath_atan2", 2},
|
||||
{u8"__fmath_atanh", 1},
|
||||
{u8"__fmath_ceil", 1},
|
||||
{u8"__fmath_cos", 1},
|
||||
{u8"__fmath_cosh", 1},
|
||||
{u8"__fmath_exp", 1},
|
||||
{u8"__fmath_expm1", 1},
|
||||
{u8"__fmath_fabs", 1},
|
||||
{u8"__fmath_floor", 1},
|
||||
{u8"__fmath_fmod", 2},
|
||||
{u8"__fmath_frexp", 1},
|
||||
{u8"__fmath_gcd", 2},
|
||||
{u8"__fmath_hypot", 2},
|
||||
{u8"__fmath_isequal", 2},
|
||||
{u8"__fmath_log", 1},
|
||||
{u8"__fmath_log10", 1},
|
||||
{u8"__fmath_log1p", 1},
|
||||
{u8"__fmath_log2", 1},
|
||||
{u8"__fmath_sin", 1},
|
||||
{u8"__fmath_sinh", 1},
|
||||
{u8"__fmath_sqrt", 1},
|
||||
{u8"__fmath_tan", 1},
|
||||
{u8"__fmath_tanh", 1},
|
||||
{u8"__fmath_trunc", 1},
|
||||
|
||||
/* file start */
|
||||
{u8"__fstdfile_open", 2},
|
||||
{u8"__fstdfile_close", 1},
|
||||
{u8"__fstdfile_is_open", 1},
|
||||
|
||||
{u8"__fstdfile_read", 1},
|
||||
{u8"__fstdfile_write", 2},
|
||||
};
|
||||
return builtinFunctionArgCounts;
|
||||
}
|
||||
const std::unordered_map<String, BuiltinFunction> &getBuiltinFunctions()
|
||||
|
||||
const std::unordered_map<FString, BuiltinFunction> &getBuiltinFunctions()
|
||||
{
|
||||
static const std::unordered_map<String, BuiltinFunction> builtinFunctions{
|
||||
{U"__fstdout_print",
|
||||
static const std::unordered_map<FString, BuiltinFunction> builtinFunctions{
|
||||
{u8"__fstdout_print",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
for (auto arg : args) { std::print("{}", arg->toStringIO().toBasicString()); }
|
||||
return std::make_shared<Object>(ValueType::IntClass(args.size()));
|
||||
}},
|
||||
{U"__fstdout_println",
|
||||
{u8"__fstdout_println",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
for (auto arg : args) { std::print("{}", arg->toStringIO().toBasicString()); }
|
||||
std::print("\n");
|
||||
return std::make_shared<Object>(ValueType::IntClass(args.size()));
|
||||
}},
|
||||
{U"__fstdin_read",
|
||||
{u8"__fstdin_read",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
std::string input;
|
||||
std::cin >> input;
|
||||
return std::make_shared<Object>(String(input));
|
||||
return std::make_shared<Object>(FString::fromBasicString(input));
|
||||
}},
|
||||
{U"__fstdin_readln",
|
||||
{u8"__fstdin_readln",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
std::string line;
|
||||
std::getline(std::cin, line);
|
||||
return std::make_shared<Object>(String(line));
|
||||
return std::make_shared<Object>(FString::fromBasicString(line));
|
||||
}},
|
||||
{U"__fvalue_type",
|
||||
{u8"__fvalue_type",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
return std::make_shared<Object>(args[0]->getTypeInfo().toString());
|
||||
}},
|
||||
{U"__fvalue_int_parse",
|
||||
{u8"__fvalue_int_parse",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
String str = args[0]->as<ValueType::StringClass>();
|
||||
FString str = args[0]->as<ValueType::StringClass>();
|
||||
try
|
||||
{
|
||||
ValueType::IntClass val = std::stoi(str.toBasicString());
|
||||
@@ -175,10 +190,10 @@ namespace Fig::Builtins
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
throw RuntimeError(String(std::format("Invalid int string for parsing", str.toBasicString())));
|
||||
throw RuntimeError(FString(std::format("Invalid int string for parsing", str.toBasicString())));
|
||||
}
|
||||
}},
|
||||
{U"__fvalue_int_from",
|
||||
{u8"__fvalue_int_from",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
ObjectPtr val = args[0];
|
||||
if (val->is<ValueType::DoubleClass>())
|
||||
@@ -193,13 +208,13 @@ namespace Fig::Builtins
|
||||
}
|
||||
else
|
||||
{
|
||||
throw RuntimeError(String(std::format("Type '{}' cannot be converted to int",
|
||||
throw RuntimeError(FString(std::format("Type '{}' cannot be converted to int",
|
||||
val->getTypeInfo().toString().toBasicString())));
|
||||
}
|
||||
}},
|
||||
{U"__fvalue_double_parse",
|
||||
{u8"__fvalue_double_parse",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
String str = args[0]->as<ValueType::StringClass>();
|
||||
FString str = args[0]->as<ValueType::StringClass>();
|
||||
try
|
||||
{
|
||||
ValueType::DoubleClass val = std::stod(str.toBasicString());
|
||||
@@ -207,10 +222,10 @@ namespace Fig::Builtins
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
throw RuntimeError(String(std::format("Invalid double string for parsing", str.toBasicString())));
|
||||
throw RuntimeError(FString(std::format("Invalid double string for parsing", str.toBasicString())));
|
||||
}
|
||||
}},
|
||||
{U"__fvalue_double_from",
|
||||
{u8"__fvalue_double_from",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
ObjectPtr val = args[0];
|
||||
if (val->is<ValueType::IntClass>())
|
||||
@@ -225,16 +240,16 @@ namespace Fig::Builtins
|
||||
}
|
||||
else
|
||||
{
|
||||
throw RuntimeError(String(std::format("Type '{}' cannot be converted to double",
|
||||
throw RuntimeError(FString(std::format("Type '{}' cannot be converted to double",
|
||||
val->getTypeInfo().toString().toBasicString())));
|
||||
}
|
||||
}},
|
||||
{U"__fvalue_string_from",
|
||||
{u8"__fvalue_string_from",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
ObjectPtr val = args[0];
|
||||
return std::make_shared<Object>(val->toStringIO());
|
||||
}},
|
||||
{U"__ftime_now_ns",
|
||||
{u8"__ftime_now_ns",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
// returns nanoseconds
|
||||
using namespace Fig::Time;
|
||||
@@ -244,97 +259,97 @@ namespace Fig::Builtins
|
||||
}},
|
||||
|
||||
/* math start */
|
||||
{U"__fmath_acos",
|
||||
{u8"__fmath_acos",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
ObjectPtr val = args[0];
|
||||
ValueType::DoubleClass d = val->getNumericValue();
|
||||
return std::make_shared<Object>(acos(d));
|
||||
}},
|
||||
{U"__fmath_acosh",
|
||||
{u8"__fmath_acosh",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
ObjectPtr val = args[0];
|
||||
ValueType::DoubleClass d = val->getNumericValue();
|
||||
return std::make_shared<Object>(acosh(d));
|
||||
}},
|
||||
{U"__fmath_asin",
|
||||
{u8"__fmath_asin",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
ObjectPtr val = args[0];
|
||||
ValueType::DoubleClass d = val->getNumericValue();
|
||||
return std::make_shared<Object>(asin(d));
|
||||
}},
|
||||
{U"__fmath_asinh",
|
||||
{u8"__fmath_asinh",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
ObjectPtr val = args[0];
|
||||
ValueType::DoubleClass d = val->getNumericValue();
|
||||
return std::make_shared<Object>(asinh(d));
|
||||
}},
|
||||
{U"__fmath_atan",
|
||||
{u8"__fmath_atan",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
ObjectPtr val = args[0];
|
||||
ValueType::DoubleClass d = val->getNumericValue();
|
||||
return std::make_shared<Object>(atan(d));
|
||||
}},
|
||||
{U"__fmath_atan2",
|
||||
{u8"__fmath_atan2",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
ValueType::DoubleClass y = args[0]->getNumericValue();
|
||||
ValueType::DoubleClass x = args[1]->getNumericValue();
|
||||
return std::make_shared<Object>(atan2(y, x));
|
||||
}},
|
||||
{U"__fmath_atanh",
|
||||
{u8"__fmath_atanh",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
ObjectPtr val = args[0];
|
||||
ValueType::DoubleClass d = val->getNumericValue();
|
||||
return std::make_shared<Object>(atanh(d));
|
||||
}},
|
||||
{U"__fmath_ceil",
|
||||
{u8"__fmath_ceil",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
ObjectPtr val = args[0];
|
||||
ValueType::DoubleClass d = val->getNumericValue();
|
||||
return std::make_shared<Object>(ceil(d));
|
||||
}},
|
||||
{U"__fmath_cos",
|
||||
{u8"__fmath_cos",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
ObjectPtr val = args[0];
|
||||
ValueType::DoubleClass d = val->getNumericValue();
|
||||
return std::make_shared<Object>(cos(d));
|
||||
}},
|
||||
{U"__fmath_cosh",
|
||||
{u8"__fmath_cosh",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
ObjectPtr val = args[0];
|
||||
ValueType::DoubleClass d = val->getNumericValue();
|
||||
return std::make_shared<Object>(cosh(d));
|
||||
}},
|
||||
{U"__fmath_exp",
|
||||
{u8"__fmath_exp",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
ObjectPtr val = args[0];
|
||||
ValueType::DoubleClass d = val->getNumericValue();
|
||||
return std::make_shared<Object>(exp(d));
|
||||
}},
|
||||
{U"__fmath_expm1",
|
||||
{u8"__fmath_expm1",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
ObjectPtr val = args[0];
|
||||
ValueType::DoubleClass d = val->getNumericValue();
|
||||
return std::make_shared<Object>(expm1(d));
|
||||
}},
|
||||
{U"__fmath_fabs",
|
||||
{u8"__fmath_fabs",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
ObjectPtr val = args[0];
|
||||
ValueType::DoubleClass d = val->getNumericValue();
|
||||
return std::make_shared<Object>(fabs(d));
|
||||
}},
|
||||
{U"__fmath_floor",
|
||||
{u8"__fmath_floor",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
ObjectPtr val = args[0];
|
||||
ValueType::DoubleClass d = val->getNumericValue();
|
||||
return std::make_shared<Object>(floor(d));
|
||||
}},
|
||||
{U"__fmath_fmod",
|
||||
{u8"__fmath_fmod",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
ValueType::DoubleClass x = args[0]->getNumericValue();
|
||||
ValueType::DoubleClass y = args[1]->getNumericValue();
|
||||
return std::make_shared<Object>(fmod(x, y));
|
||||
}},
|
||||
{U"__fmath_frexp",
|
||||
{u8"__fmath_frexp",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
ObjectPtr val = args[0];
|
||||
ValueType::DoubleClass d = val->getNumericValue();
|
||||
@@ -342,85 +357,126 @@ namespace Fig::Builtins
|
||||
return std::make_shared<Object>(List({std::make_shared<Object>(frexp(d, &e)),
|
||||
std::make_shared<Object>(static_cast<ValueType::IntClass>(e))}));
|
||||
}},
|
||||
{U"__fmath_gcd",
|
||||
{u8"__fmath_gcd",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
ValueType::IntClass x = args[0]->as<ValueType::IntClass>();
|
||||
ValueType::IntClass y = args[1]->as<ValueType::IntClass>();
|
||||
return std::make_shared<Object>(std::gcd(x, y));
|
||||
}},
|
||||
{U"__fmath_hypot",
|
||||
{u8"__fmath_hypot",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
ValueType::DoubleClass x = args[0]->getNumericValue();
|
||||
ValueType::DoubleClass y = args[1]->getNumericValue();
|
||||
return std::make_shared<Object>(hypot(x, y));
|
||||
}},
|
||||
{U"__fmath_isequal",
|
||||
{u8"__fmath_isequal",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
ValueType::DoubleClass x = args[0]->getNumericValue();
|
||||
ValueType::DoubleClass y = args[1]->getNumericValue();
|
||||
static const double epsilon = 1e-9;
|
||||
return std::make_shared<Object>(fabs(x - y) < epsilon);
|
||||
}},
|
||||
{U"__fmath_log",
|
||||
{u8"__fmath_log",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
ObjectPtr val = args[0];
|
||||
ValueType::DoubleClass d = val->getNumericValue();
|
||||
return std::make_shared<Object>(log(d));
|
||||
}},
|
||||
{U"__fmath_log10",
|
||||
{u8"__fmath_log10",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
ObjectPtr val = args[0];
|
||||
ValueType::DoubleClass d = val->getNumericValue();
|
||||
return std::make_shared<Object>(log10(d));
|
||||
}},
|
||||
{U"__fmath_log1p",
|
||||
{u8"__fmath_log1p",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
ObjectPtr val = args[0];
|
||||
ValueType::DoubleClass d = val->getNumericValue();
|
||||
return std::make_shared<Object>(log1p(d));
|
||||
}},
|
||||
{U"__fmath_log2",
|
||||
{u8"__fmath_log2",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
ObjectPtr val = args[0];
|
||||
ValueType::DoubleClass d = val->getNumericValue();
|
||||
return std::make_shared<Object>(log2(d));
|
||||
}},
|
||||
{U"__fmath_sin",
|
||||
{u8"__fmath_sin",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
ObjectPtr val = args[0];
|
||||
ValueType::DoubleClass d = val->getNumericValue();
|
||||
return std::make_shared<Object>(sin(d));
|
||||
}},
|
||||
{U"__fmath_sinh",
|
||||
{u8"__fmath_sinh",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
ObjectPtr val = args[0];
|
||||
ValueType::DoubleClass d = val->getNumericValue();
|
||||
return std::make_shared<Object>(sinh(d));
|
||||
}},
|
||||
{U"__fmath_sqrt",
|
||||
{u8"__fmath_sqrt",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
ObjectPtr val = args[0];
|
||||
ValueType::DoubleClass d = val->getNumericValue();
|
||||
return std::make_shared<Object>(sqrt(d));
|
||||
}},
|
||||
{U"__fmath_tan",
|
||||
{u8"__fmath_tan",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
ObjectPtr val = args[0];
|
||||
ValueType::DoubleClass d = val->getNumericValue();
|
||||
return std::make_shared<Object>(tan(d));
|
||||
}},
|
||||
{U"__fmath_tanh",
|
||||
{u8"__fmath_tanh",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
ObjectPtr val = args[0];
|
||||
ValueType::DoubleClass d = val->getNumericValue();
|
||||
return std::make_shared<Object>(tanh(d));
|
||||
}},
|
||||
{U"__fmath_trunc",
|
||||
{u8"__fmath_trunc",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
ObjectPtr val = args[0];
|
||||
ValueType::DoubleClass d = val->getNumericValue();
|
||||
return std::make_shared<Object>(trunc(d));
|
||||
}},
|
||||
/* file start */
|
||||
{u8"__fstdfile_open",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
const FString &path = args[0]->as<ValueType::StringClass>();
|
||||
const ValueType::IntClass &mode = args[1]->as<ValueType::IntClass>();
|
||||
|
||||
CppLibrary::File *f = CppLibrary::FileManager::getInstance().GetNextFreeFile();
|
||||
f->fs->open(path.toBasicString(), static_cast<unsigned int>(mode));
|
||||
return std::make_shared<Object>(static_cast<ValueType::IntClass>(f->id));
|
||||
}},
|
||||
{u8"__fstdfile_close",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
const ValueType::IntClass &id = args[0]->as<ValueType::IntClass>();
|
||||
CppLibrary::FileManager::getInstance().CloseFile(id);
|
||||
return Object::getNullInstance();
|
||||
}},
|
||||
{u8"__fstdfile_is_open",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
const ValueType::IntClass &id = args[0]->as<ValueType::IntClass>();
|
||||
return std::make_shared<Object>(CppLibrary::FileManager::getInstance().GetFile(id)->fs->is_open());
|
||||
}},
|
||||
{u8"__fstdfile_read",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
const ValueType::IntClass &id = args[0]->as<ValueType::IntClass>();
|
||||
CppLibrary::File *f = CppLibrary::FileManager::getInstance().GetFile(id);
|
||||
|
||||
char *buf = new char[CppLibrary::FileManager::MAX_FILE_BUF];
|
||||
f->fs->read(buf, CppLibrary::FileManager::MAX_FILE_BUF);
|
||||
return std::make_shared<Object>(ValueType::StringClass(reinterpret_cast<const char8_t *>(buf)));
|
||||
}},
|
||||
{u8"__fstdfile_write",
|
||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||
const ValueType::IntClass &id = args[0]->as<ValueType::IntClass>();
|
||||
const ValueType::StringClass &str = args[1]->as<ValueType::StringClass>();
|
||||
|
||||
CppLibrary::File *f = CppLibrary::FileManager::getInstance().GetFile(id);
|
||||
const char *data = reinterpret_cast<const char *>(str.c_str());
|
||||
f->fs->write(data, str.size());
|
||||
return std::make_shared<Object>(static_cast<ValueType::IntClass>(str.length()));
|
||||
// bytes wrote
|
||||
}},
|
||||
};
|
||||
return builtinFunctions;
|
||||
}
|
||||
|
||||
@@ -3,13 +3,14 @@
|
||||
#include <Ast/Expressions/VarExpr.hpp>
|
||||
|
||||
#include <Ast/functionParameters.hpp>
|
||||
#include <Core/String.hpp>
|
||||
#include <Core/fig_string.hpp>
|
||||
#include <Evaluator/Value/value.hpp>
|
||||
#include <Core/runtimeTime.hpp>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
@@ -39,34 +40,47 @@ namespace Fig
|
||||
|
||||
const TypeInfo &getOperationInterfaceTypeInfo();
|
||||
|
||||
const std::unordered_map<String, ObjectPtr> &getBuiltinValues();
|
||||
const std::unordered_map<FString, ObjectPtr> &getBuiltinValues();
|
||||
|
||||
using BuiltinFunction = std::function<ObjectPtr(const std::vector<ObjectPtr> &)>;
|
||||
|
||||
const std::unordered_map<String, int> &getBuiltinFunctionArgCounts();
|
||||
const std::unordered_map<String, BuiltinFunction> &getBuiltinFunctions();
|
||||
const std::unordered_map<FString, int> &getBuiltinFunctionArgCounts();
|
||||
|
||||
inline bool isBuiltinFunction(const String &name)
|
||||
/*
|
||||
File
|
||||
*/
|
||||
|
||||
struct FileHandler
|
||||
{
|
||||
int64_t id;
|
||||
std::fstream *fs;
|
||||
};
|
||||
|
||||
std::vector<FileHandler *> &getFileHandlers(); // global
|
||||
|
||||
const std::unordered_map<FString, BuiltinFunction> &getBuiltinFunctions();
|
||||
|
||||
inline bool isBuiltinFunction(const FString &name)
|
||||
{
|
||||
return getBuiltinFunctions().find(name) != getBuiltinFunctions().end();
|
||||
}
|
||||
|
||||
inline BuiltinFunction getBuiltinFunction(const String &name)
|
||||
inline BuiltinFunction getBuiltinFunction(const FString &name)
|
||||
{
|
||||
auto it = getBuiltinFunctions().find(name);
|
||||
if (it == getBuiltinFunctions().end())
|
||||
{
|
||||
throw RuntimeError(String(std::format("Builtin function '{}' not found", name.toBasicString())));
|
||||
throw RuntimeError(FString(std::format("Builtin function '{}' not found", name.toBasicString())));
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
inline int getBuiltinFunctionParamCount(const String &name)
|
||||
inline int getBuiltinFunctionParamCount(const FString &name)
|
||||
{
|
||||
auto it = getBuiltinFunctionArgCounts().find(name);
|
||||
if (it == getBuiltinFunctionArgCounts().end())
|
||||
{
|
||||
throw RuntimeError(String(std::format("Builtin function '{}' not found", name.toBasicString())));
|
||||
throw RuntimeError(FString(std::format("Builtin function '{}' not found", name.toBasicString())));
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ namespace Fig
|
||||
bool isConst = (currentToken().getType() == TokenType::Const ? true : false);
|
||||
next();
|
||||
expect(TokenType::Identifier);
|
||||
String name = currentToken().getValue();
|
||||
FString name = currentToken().getValue();
|
||||
next();
|
||||
Ast::Expression declaredType = nullptr;
|
||||
bool hasSpecificType = false;
|
||||
@@ -102,12 +102,12 @@ namespace Fig
|
||||
next(); // consume `;`, no using expectConsume here cause we don't need to check again
|
||||
return makeAst<Ast::VarDefAst>(isPublic, isConst, name, declaredType, nullptr, false);
|
||||
}
|
||||
if (!isThis(TokenType::Assign) and !isThis(TokenType::Walrus)) expect(TokenType::Assign, U"\1");
|
||||
if (!isThis(TokenType::Assign) and !isThis(TokenType::Walrus)) expect(TokenType::Assign, u8"assign or walrus");
|
||||
bool followupType = false;
|
||||
|
||||
if (isThis(TokenType::Walrus))
|
||||
{
|
||||
if (hasSpecificType) throwAddressableError<SyntaxError>(String(U"\1"));
|
||||
if (hasSpecificType) throwAddressableError<SyntaxError>(FString(u8""));
|
||||
followupType = true;
|
||||
}
|
||||
next();
|
||||
@@ -118,7 +118,7 @@ namespace Fig
|
||||
|
||||
ObjectPtr Parser::__parseValue()
|
||||
{
|
||||
String _val = currentToken().getValue();
|
||||
FString _val = currentToken().getValue();
|
||||
if (currentToken().getType() == TokenType::LiteralNumber)
|
||||
{
|
||||
if (_val.contains(u8'.') || _val.contains(u8'e'))
|
||||
@@ -131,7 +131,7 @@ namespace Fig
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
throwAddressableError<SyntaxError>(String(U"\1"));
|
||||
throwAddressableError<SyntaxError>(FString(u8"Illegal number literal"));
|
||||
}
|
||||
return std::make_shared<Object>(d);
|
||||
}
|
||||
@@ -145,7 +145,7 @@ namespace Fig
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
throwAddressableError<SyntaxError>(String(U"\1"));
|
||||
throwAddressableError<SyntaxError>(FString(u8"Illegal number literal"));
|
||||
}
|
||||
return std::make_shared<Object>(i);
|
||||
}
|
||||
@@ -153,7 +153,7 @@ namespace Fig
|
||||
else if (currentToken().getType() == TokenType::LiteralString) { return std::make_shared<Object>(_val); }
|
||||
else if (currentToken().getType() == TokenType::LiteralBool)
|
||||
{
|
||||
return std::make_shared<Object>((_val == U"\1" ? true : false));
|
||||
return std::make_shared<Object>((_val == u8"true" ? true : false));
|
||||
}
|
||||
else if (currentToken().getType() == TokenType::LiteralNull) { return Object::getNullInstance(); }
|
||||
else
|
||||
@@ -176,7 +176,7 @@ namespace Fig
|
||||
|
||||
Ast::FunctionParameters::PosParasType pp;
|
||||
Ast::FunctionParameters::DefParasType dp;
|
||||
String variaPara;
|
||||
FString variaPara;
|
||||
while (true)
|
||||
{
|
||||
if (isThis(TokenType::RightParen))
|
||||
@@ -184,13 +184,13 @@ namespace Fig
|
||||
next();
|
||||
return Ast::FunctionParameters(pp, dp);
|
||||
}
|
||||
expect(TokenType::Identifier, String(U"\1")); // check current
|
||||
String pname = currentToken().getValue();
|
||||
expect(TokenType::Identifier, FString(u8"Identifier or `)`")); // check current
|
||||
FString pname = currentToken().getValue();
|
||||
next(); // skip pname
|
||||
if (isThis(TokenType::Assign)) // =
|
||||
{
|
||||
next();
|
||||
dp.push_back({pname, {makeAst<Ast::VarExprAst>(U"\1"), parseExpression(0, TokenType::Comma)}});
|
||||
dp.push_back({pname, {makeAst<Ast::VarExprAst>(u8"Any"), parseExpression(0, TokenType::Comma)}});
|
||||
if (isThis(TokenType::Comma))
|
||||
{
|
||||
next(); // only skip `,` when it's there
|
||||
@@ -224,13 +224,16 @@ namespace Fig
|
||||
variaPara = pname;
|
||||
next(); // skip `...`
|
||||
if (!isThis(TokenType::RightParen))
|
||||
throwAddressableError<SyntaxError>(U"\1", currentAAI.line, currentAAI.column);
|
||||
throwAddressableError<SyntaxError>(
|
||||
u8"Expects right paren, variable parameter function can only have one parameter",
|
||||
currentAAI.line,
|
||||
currentAAI.column);
|
||||
next(); // skip `)`
|
||||
return Ast::FunctionParameters(variaPara);
|
||||
}
|
||||
else
|
||||
{
|
||||
pp.push_back({pname, makeAst<Ast::VarExprAst>(U"\1")});
|
||||
pp.push_back({pname, makeAst<Ast::VarExprAst>(u8"Any")});
|
||||
if (isThis(TokenType::Comma))
|
||||
{
|
||||
next(); // only skip `,` when it's there
|
||||
@@ -240,7 +243,7 @@ namespace Fig
|
||||
}
|
||||
Ast::FunctionDef Parser::__parseFunctionDef(bool isPublic)
|
||||
{
|
||||
String funcName = currentToken().getValue();
|
||||
FString funcName = currentToken().getValue();
|
||||
next();
|
||||
expect(TokenType::LeftParen);
|
||||
Ast::FunctionParameters params = __parseFunctionParameters();
|
||||
@@ -259,9 +262,9 @@ namespace Fig
|
||||
Ast::StructDef Parser::__parseStructDef(bool isPublic)
|
||||
{
|
||||
// entry: current is struct name
|
||||
String structName = currentToken().getValue();
|
||||
FString structName = currentToken().getValue();
|
||||
next();
|
||||
expect(TokenType::LeftBrace, U"\1");
|
||||
expect(TokenType::LeftBrace, u8"struct body");
|
||||
next();
|
||||
bool braceClosed = false;
|
||||
|
||||
@@ -278,7 +281,7 @@ namespace Fig
|
||||
|
||||
auto __parseStructField = [this](bool isPublic) -> Ast::StructDefField {
|
||||
AccessModifier am = AccessModifier::Normal;
|
||||
String fieldName;
|
||||
FString fieldName;
|
||||
if (isThis(TokenType::Identifier))
|
||||
{
|
||||
fieldName = currentToken().getValue();
|
||||
@@ -288,13 +291,13 @@ namespace Fig
|
||||
else if (isThis(TokenType::Const))
|
||||
{
|
||||
next();
|
||||
expect(TokenType::Identifier, U"\1");
|
||||
expect(TokenType::Identifier, u8"field name");
|
||||
fieldName = currentToken().getValue();
|
||||
am = (isPublic ? AccessModifier::PublicConst : AccessModifier::Const);
|
||||
}
|
||||
else
|
||||
{
|
||||
throwAddressableError<SyntaxError>(String(std::format("expect field name or field attribute")));
|
||||
throwAddressableError<SyntaxError>(FString(std::format("expect field name or field attribute")));
|
||||
}
|
||||
Ast::Expression fieldType = nullptr;
|
||||
if (isThis(TokenType::Colon))
|
||||
@@ -306,7 +309,7 @@ namespace Fig
|
||||
if (isThis(TokenType::Assign))
|
||||
{
|
||||
next();
|
||||
if (isEOF()) throwAddressableError<SyntaxError>(String(U"\1"));
|
||||
if (isEOF()) throwAddressableError<SyntaxError>(FString(u8"expect an expression"));
|
||||
initExpr = parseExpression(0);
|
||||
}
|
||||
expectSemicolon();
|
||||
@@ -350,7 +353,7 @@ namespace Fig
|
||||
}
|
||||
else
|
||||
{
|
||||
throwAddressableError<SyntaxError>(String("Invalid syntax"));
|
||||
throwAddressableError<SyntaxError>(FString("Invalid syntax"));
|
||||
}
|
||||
}
|
||||
else if (isThis(TokenType::Function))
|
||||
@@ -367,22 +370,45 @@ namespace Fig
|
||||
else if (isThis(TokenType::Variable))
|
||||
{
|
||||
throwAddressableError<SyntaxError>(
|
||||
String("Variables are not allowed to be defined within a structure."));
|
||||
FString("Variables are not allowed to be defined within a structure."));
|
||||
}
|
||||
else
|
||||
{
|
||||
throwAddressableError<SyntaxError>(String("Invalid syntax"));
|
||||
throwAddressableError<SyntaxError>(FString("Invalid syntax"));
|
||||
}
|
||||
}
|
||||
if (!braceClosed) { throwAddressableError<SyntaxError>(String("braces are not closed")); }
|
||||
if (!braceClosed) { throwAddressableError<SyntaxError>(FString("braces are not closed")); }
|
||||
return makeAst<Ast::StructDefSt>(isPublic, structName, fields, makeAst<Ast::BlockStatementAst>(stmts));
|
||||
}
|
||||
|
||||
Ast::InterfaceDef Parser::__parseInterfaceDef(bool isPublic)
|
||||
{
|
||||
// entry: current is interface name
|
||||
String interfaceName = currentToken().getValue();
|
||||
FString interfaceName = currentToken().getValue();
|
||||
next(); // consume name
|
||||
|
||||
std::vector<Ast::Expression> bundles;
|
||||
|
||||
if (isThis(TokenType::Colon))
|
||||
{
|
||||
next(); // consume `:`
|
||||
// parse bundle interfaces
|
||||
|
||||
if (isThis(TokenType::LeftBrace))
|
||||
{
|
||||
throwAddressableError<SyntaxError>(u8"expect interfaces to bundle");
|
||||
}
|
||||
while (true)
|
||||
{
|
||||
if (isThis(TokenType::LeftBrace)) { break; }
|
||||
bundles.push_back(parseExpression(0, TokenType::Plus, TokenType::LeftBrace));
|
||||
if (isThis(TokenType::Plus))
|
||||
{
|
||||
next(); // consume `+`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expect(TokenType::LeftBrace); // `{
|
||||
next(); // consume `{`
|
||||
|
||||
@@ -397,7 +423,7 @@ namespace Fig
|
||||
}
|
||||
if (isThis(TokenType::Identifier))
|
||||
{
|
||||
String funcName = currentToken().getValue();
|
||||
FString funcName = currentToken().getValue();
|
||||
next(); // consume func name
|
||||
|
||||
expect(TokenType::LeftParen);
|
||||
@@ -421,25 +447,25 @@ namespace Fig
|
||||
}
|
||||
else
|
||||
{
|
||||
throwAddressableError<SyntaxError>(String(U"\1"), currentAAI.line, currentAAI.column);
|
||||
throwAddressableError<SyntaxError>(FString(u8"Invalid syntax"), currentAAI.line, currentAAI.column);
|
||||
}
|
||||
}
|
||||
return makeAst<Ast::InterfaceDefAst>(interfaceName, methods, isPublic);
|
||||
return makeAst<Ast::InterfaceDefAst>(interfaceName, bundles, methods, isPublic);
|
||||
}
|
||||
|
||||
Ast::Implement Parser::__parseImplement()
|
||||
{
|
||||
// entry: current is `impl`
|
||||
next(); // consume `impl`
|
||||
expect(TokenType::Identifier, U"\1");
|
||||
String interfaceName = currentToken().getValue();
|
||||
expect(TokenType::Identifier, u8"interface name");
|
||||
FString interfaceName = currentToken().getValue();
|
||||
next(); // consume interface name
|
||||
|
||||
expect(TokenType::For);
|
||||
next(); // consume `for`
|
||||
|
||||
expect(TokenType::Identifier, U"\1");
|
||||
String structName = currentToken().getValue();
|
||||
expect(TokenType::Identifier, u8"struct name");
|
||||
FString structName = currentToken().getValue();
|
||||
next(); // consume name
|
||||
expect(TokenType::LeftBrace); // {
|
||||
next(); // consume `{`
|
||||
@@ -455,7 +481,7 @@ namespace Fig
|
||||
}
|
||||
if (isThis(TokenType::Identifier))
|
||||
{
|
||||
String funcName = currentToken().getValue();
|
||||
FString funcName = currentToken().getValue();
|
||||
next(); // consume func name
|
||||
expect(TokenType::LeftParen);
|
||||
Ast::FunctionParameters paras = __parseFunctionParameters();
|
||||
@@ -465,7 +491,7 @@ namespace Fig
|
||||
}
|
||||
else
|
||||
{
|
||||
throwAddressableError<SyntaxError>(String(U"\1"), currentAAI.line, currentAAI.column);
|
||||
throwAddressableError<SyntaxError>(FString(u8"Invalid syntax"), currentAAI.line, currentAAI.column);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -510,16 +536,16 @@ namespace Fig
|
||||
next(); // consume `catch`
|
||||
expect(TokenType::LeftParen);
|
||||
next(); // consume `(`
|
||||
expect(TokenType::Identifier, U"\1");
|
||||
String errVarName = currentToken().getValue();
|
||||
expect(TokenType::Identifier, u8"error receive var name");
|
||||
FString errVarName = currentToken().getValue();
|
||||
next(); // consume name
|
||||
|
||||
bool hasType = false;
|
||||
String errVarType;
|
||||
FString errVarType;
|
||||
if (isThis(TokenType::Colon)) // :
|
||||
{
|
||||
next();
|
||||
expect(TokenType::Identifier, U"\1");
|
||||
expect(TokenType::Identifier, u8"error type");
|
||||
errVarType = currentToken().getValue();
|
||||
next(); // consume var type
|
||||
hasType = true;
|
||||
@@ -539,7 +565,8 @@ namespace Fig
|
||||
{
|
||||
if (finallyBlock != nullptr)
|
||||
{
|
||||
throwAddressableError<SyntaxError>(U"\1", currentAAI.line, currentAAI.column);
|
||||
throwAddressableError<SyntaxError>(
|
||||
u8"Duplicate try finally-block", currentAAI.line, currentAAI.column);
|
||||
}
|
||||
next(); // consume `finally`
|
||||
expect(TokenType::LeftBrace);
|
||||
@@ -575,7 +602,8 @@ namespace Fig
|
||||
else if (isThis(TokenType::Interface)) { stmt = __parseInterfaceDef(true); }
|
||||
else
|
||||
{
|
||||
throwAddressableError<SyntaxError>(String(U"\1"));
|
||||
throwAddressableError<SyntaxError>(
|
||||
FString(u8"Expected `var`, `const`, `function`, `struct` or `interface` after `public`"));
|
||||
}
|
||||
}
|
||||
else if (isThis(TokenType::Variable) || isThis(TokenType::Const)) { stmt = __parseVarDef(false); }
|
||||
@@ -586,19 +614,22 @@ namespace Fig
|
||||
}
|
||||
else if (isThis(TokenType::Struct))
|
||||
{
|
||||
expectPeek(TokenType::Identifier, U"\1");
|
||||
expectPeek(TokenType::Identifier, u8"struct name");
|
||||
next();
|
||||
stmt = __parseStructDef(false);
|
||||
}
|
||||
else if (isThis(TokenType::Interface))
|
||||
{
|
||||
expectPeek(TokenType::Identifier, U"\1");
|
||||
expectPeek(TokenType::Identifier, u8"interface name");
|
||||
next();
|
||||
stmt = __parseInterfaceDef(false);
|
||||
}
|
||||
else if (isThis(TokenType::Implement)) { stmt = __parseImplement(); }
|
||||
else if (isThis(TokenType::If)) { stmt = __parseIf(); }
|
||||
else if (isThis(TokenType::Else)) { throwAddressableError<SyntaxError>(String(U"\1")); }
|
||||
else if (isThis(TokenType::Else))
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FString(u8"`else` without matching `if`"));
|
||||
}
|
||||
else if (isThis(TokenType::LeftBrace)) { stmt = __parseBlockStatement(); }
|
||||
else if (isThis(TokenType::While)) { stmt = __parseWhile(); }
|
||||
else if (isThis(TokenType::For)) { stmt = __parseFor(); }
|
||||
@@ -616,7 +647,7 @@ namespace Fig
|
||||
}
|
||||
else
|
||||
{
|
||||
throwAddressableError<SyntaxError>(U"\1", currentAAI.line, currentAAI.column);
|
||||
throwAddressableError<SyntaxError>(u8"invalid syntax", currentAAI.line, currentAAI.column);
|
||||
}
|
||||
return stmt;
|
||||
}
|
||||
@@ -716,12 +747,15 @@ namespace Fig
|
||||
// 2. expression stmt:i++, foo()
|
||||
// ❌ not allowed:if/while/for/block stmt
|
||||
|
||||
if (isThis(TokenType::LeftBrace)) { throwAddressableError<SyntaxError>(U"\1"); }
|
||||
if (isThis(TokenType::LeftBrace))
|
||||
{
|
||||
throwAddressableError<SyntaxError>(u8"BlockStatement cannot be used as for loop increment");
|
||||
}
|
||||
|
||||
if (isThis(TokenType::If) || isThis(TokenType::While) || isThis(TokenType::For) || isThis(TokenType::Return)
|
||||
|| isThis(TokenType::Break) || isThis(TokenType::Continue))
|
||||
{
|
||||
throwAddressableError<SyntaxError>(U"\1");
|
||||
throwAddressableError<SyntaxError>(u8"Control flow statements cannot be used as for loop increment");
|
||||
}
|
||||
|
||||
Ast::Expression exp = parseExpression(0, TokenType::LeftBrace);
|
||||
@@ -775,7 +809,7 @@ namespace Fig
|
||||
return makeAst<Ast::BreakSt>();
|
||||
}
|
||||
|
||||
Ast::VarExpr Parser::__parseVarExpr(String name)
|
||||
Ast::VarExpr Parser::__parseVarExpr(FString name)
|
||||
{
|
||||
return makeAst<Ast::VarExprAst>(name);
|
||||
}
|
||||
@@ -858,7 +892,7 @@ namespace Fig
|
||||
{
|
||||
// entry: current is `{`
|
||||
next(); // consume `{`
|
||||
std::vector<std::pair<String, Ast::Expression>> args;
|
||||
std::vector<std::pair<FString, Ast::Expression>> args;
|
||||
/*
|
||||
3 ways of calling constructor
|
||||
.1 Person {"Fig", 1, "IDK"};
|
||||
@@ -882,13 +916,13 @@ namespace Fig
|
||||
{
|
||||
// 1 Person {"Fig", 1, "IDK"};
|
||||
Ast::Expression expr = parseExpression(0, TokenType::Comma, TokenType::RightBrace);
|
||||
args.push_back({String(), std::move(expr)});
|
||||
args.push_back({FString(), std::move(expr)});
|
||||
}
|
||||
else if (mode == 2)
|
||||
{
|
||||
// 2 Person {name: "Fig", age: 1, sex: "IDK"};
|
||||
expect(TokenType::Identifier);
|
||||
String fieldName = currentToken().getValue();
|
||||
FString fieldName = currentToken().getValue();
|
||||
next(); // consume identifier
|
||||
expect(TokenType::Colon);
|
||||
next(); // consume colon
|
||||
@@ -902,7 +936,7 @@ namespace Fig
|
||||
else if (!isThis(TokenType::RightBrace))
|
||||
{
|
||||
throwAddressableError<SyntaxError>(
|
||||
String(std::format("Expect `,` or `}}` in struct initialization expression, got {}",
|
||||
FString(std::format("Expect `,` or `}}` in struct initialization expression, got {}",
|
||||
currentToken().toString().toBasicString())));
|
||||
}
|
||||
}
|
||||
@@ -911,13 +945,19 @@ namespace Fig
|
||||
{
|
||||
for (auto &[name, exp] : args)
|
||||
{
|
||||
if (!name.empty()) { shorthand = false; }
|
||||
if (exp->getType() != Ast::AstType::VarExpr) { shorthand = false; }
|
||||
if (!name.empty())
|
||||
{
|
||||
shorthand = false;
|
||||
}
|
||||
if (exp->getType() != Ast::AstType::VarExpr)
|
||||
{
|
||||
shorthand = false;
|
||||
}
|
||||
}
|
||||
if (shorthand)
|
||||
{
|
||||
mode = 3; // all are identifiers, so it's shorthand mode, not positional
|
||||
std::vector<std::pair<String, Ast::Expression>> nargs;
|
||||
std::vector<std::pair<FString, Ast::Expression>> nargs;
|
||||
for (auto &[name, exp] : args)
|
||||
{
|
||||
const Ast::VarExpr var = std::static_pointer_cast<Ast::VarExprAst>(exp);
|
||||
@@ -970,7 +1010,7 @@ namespace Fig
|
||||
}
|
||||
else
|
||||
{
|
||||
throwAddressableError<SyntaxError>(String(U"\1"));
|
||||
throwAddressableError<SyntaxError>(FString(u8"Expect ')' or ',' after expression in parentheses"));
|
||||
}
|
||||
return nullptr; // to suppress compiler warning
|
||||
}
|
||||
@@ -998,12 +1038,12 @@ namespace Fig
|
||||
Ast::Import Parser::__parseImport()
|
||||
{
|
||||
next(); // consume `import`
|
||||
std::vector<String> path;
|
||||
std::vector<String> names;
|
||||
String rename;
|
||||
std::vector<FString> path;
|
||||
std::vector<FString> names;
|
||||
FString rename;
|
||||
while (true)
|
||||
{
|
||||
expect(TokenType::Identifier, U"\1");
|
||||
expect(TokenType::Identifier, u8"package name");
|
||||
path.push_back(currentToken().getValue());
|
||||
next(); // consume package name
|
||||
if (isThis(TokenType::Semicolon)) { break; }
|
||||
@@ -1015,13 +1055,13 @@ namespace Fig
|
||||
else if (isThis(TokenType::LeftBrace)) { break; }
|
||||
else
|
||||
{
|
||||
throwAddressableError<SyntaxError>(U"\1");
|
||||
throwAddressableError<SyntaxError>(u8"invalid syntax");
|
||||
}
|
||||
}
|
||||
if (isThis(TokenType::As))
|
||||
{
|
||||
next(); // consume `as`
|
||||
expect(TokenType::Identifier, U"\1");
|
||||
expect(TokenType::Identifier, u8"new name");
|
||||
rename = currentToken().getValue();
|
||||
next(); // consume name
|
||||
}
|
||||
@@ -1039,7 +1079,7 @@ namespace Fig
|
||||
{
|
||||
next(); // consume `,`
|
||||
}
|
||||
expect(TokenType::Identifier, U"\1");
|
||||
expect(TokenType::Identifier, u8"symbol name");
|
||||
names.push_back(currentToken().getValue());
|
||||
next();
|
||||
}
|
||||
@@ -1054,10 +1094,10 @@ namespace Fig
|
||||
Ast::Operator op;
|
||||
|
||||
Token tok = currentToken();
|
||||
if (tok == EOFTok) throwAddressableError<SyntaxError>(String(U"\1"));
|
||||
if (tok == EOFTok) throwAddressableError<SyntaxError>(FString(u8"Unexpected end of expression"));
|
||||
if (tok.getType() == stop || tok.getType() == stop2 || tok.getType() == stop3)
|
||||
{
|
||||
if (lhs == nullptr) throwAddressableError<SyntaxError>(String(U"\1"));
|
||||
if (lhs == nullptr) throwAddressableError<SyntaxError>(FString(u8"Expected expression"));
|
||||
return lhs;
|
||||
}
|
||||
if (tok.getType() == TokenType::LeftBracket)
|
||||
@@ -1078,7 +1118,7 @@ namespace Fig
|
||||
if (currentToken().getType() == TokenType::Identifier)
|
||||
{
|
||||
// err
|
||||
throwAddressableError<SyntaxError>(String(U"\1"));
|
||||
throwAddressableError<SyntaxError>(FString(u8"Function literal should not have a name"));
|
||||
}
|
||||
expect(TokenType::LeftParen);
|
||||
lhs = __parseFunctionLiteralExpr();
|
||||
@@ -1090,7 +1130,7 @@ namespace Fig
|
||||
}
|
||||
else if (tok.isIdentifier())
|
||||
{
|
||||
String id = tok.getValue();
|
||||
FString id = tok.getValue();
|
||||
next();
|
||||
lhs = __parseVarExpr(id);
|
||||
}
|
||||
@@ -1110,7 +1150,7 @@ namespace Fig
|
||||
}
|
||||
else
|
||||
{
|
||||
throwAddressableError<SyntaxError>(String(U"\1") + tok.toString());
|
||||
throwAddressableError<SyntaxError>(FString(u8"Unexpected token in expression:") + tok.toString());
|
||||
}
|
||||
|
||||
// infix / (postfix) ?
|
||||
@@ -1121,7 +1161,11 @@ namespace Fig
|
||||
|
||||
/* Postfix */
|
||||
|
||||
if (tok.getType() == TokenType::LeftBrace) { throwAddressableError<SyntaxError>(String(U"\1")); }
|
||||
if (tok.getType() == TokenType::LeftBrace)
|
||||
{
|
||||
throwAddressableError<SyntaxError>(
|
||||
FString(u8"Since Fig v0.4.2, please use new struct{} to avoid syntax ambiguity"));
|
||||
}
|
||||
|
||||
if (tok.getType() == TokenType::LeftParen)
|
||||
{
|
||||
@@ -1144,9 +1188,10 @@ namespace Fig
|
||||
{
|
||||
next(); // consume '.'
|
||||
Token idTok = currentToken();
|
||||
if (!idTok.isIdentifier()) throwAddressableError<SyntaxError>(String(U"\1"));
|
||||
if (!idTok.isIdentifier())
|
||||
throwAddressableError<SyntaxError>(FString(u8"Expected identifier after '.'"));
|
||||
|
||||
String member = idTok.getValue();
|
||||
FString member = idTok.getValue();
|
||||
next(); // consume identifier
|
||||
|
||||
lhs = makeAst<Ast::MemberExprAst>(lhs, member);
|
||||
@@ -1202,7 +1247,8 @@ namespace Fig
|
||||
auto stmt = __parseStatement();
|
||||
if (!output.empty() && stmt->getType() == Ast::AstType::PackageSt)
|
||||
{
|
||||
throwAddressableError<SyntaxError>(U"\1", currentAAI.line, currentAAI.column);
|
||||
throwAddressableError<SyntaxError>(
|
||||
u8"Package must be at the beginning of the file", currentAAI.line, currentAAI.column);
|
||||
}
|
||||
pushNode(stmt);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <Ast/astBase.hpp>
|
||||
#include <Ast/ast.hpp>
|
||||
#include <Lexer/lexer.hpp>
|
||||
#include <Core/String.hpp>
|
||||
#include <Core/fig_string.hpp>
|
||||
#include <Error/error.hpp>
|
||||
|
||||
#include <memory>
|
||||
@@ -23,8 +23,8 @@ namespace Fig
|
||||
std::vector<Ast::AstBase> output;
|
||||
std::vector<Token> previousTokens;
|
||||
|
||||
std::shared_ptr<String> sourcePathPtr;
|
||||
std::shared_ptr<std::vector<String>> sourceLinesPtr;
|
||||
std::shared_ptr<FString> sourcePathPtr;
|
||||
std::shared_ptr<std::vector<FString>> sourceLinesPtr;
|
||||
|
||||
size_t tokenPruduced = 0;
|
||||
size_t currentTokenIndex = 0;
|
||||
@@ -76,16 +76,16 @@ namespace Fig
|
||||
static const std::unordered_map<Ast::Operator, std::pair<Precedence, Precedence>> opPrecedence;
|
||||
static const std::unordered_map<Ast::Operator, Precedence> unaryOpPrecedence;
|
||||
|
||||
Parser(const Lexer &_lexer, String _sourcePath, std::vector<String> _sourceLines) : lexer(_lexer)
|
||||
Parser(const Lexer &_lexer, FString _sourcePath, std::vector<FString> _sourceLines) : lexer(_lexer)
|
||||
{
|
||||
sourcePathPtr = std::make_shared<String>(_sourcePath);
|
||||
sourceLinesPtr = std::make_shared<std::vector<String>>(_sourceLines);
|
||||
sourcePathPtr = std::make_shared<FString>(_sourcePath);
|
||||
sourceLinesPtr = std::make_shared<std::vector<FString>>(_sourceLines);
|
||||
}
|
||||
|
||||
AddressableError *getError() const { return error.get(); }
|
||||
|
||||
template <class _ErrT, typename = AddressableError>
|
||||
void throwAddressableError(String msg,
|
||||
void throwAddressableError(FString msg,
|
||||
size_t line,
|
||||
size_t column,
|
||||
std::source_location loc = std::source_location::current())
|
||||
@@ -96,7 +96,7 @@ namespace Fig
|
||||
throw spError;
|
||||
}
|
||||
template <class _ErrT, typename = AddressableError>
|
||||
void throwAddressableError(String msg, std::source_location loc = std::source_location::current())
|
||||
void throwAddressableError(FString msg, std::source_location loc = std::source_location::current())
|
||||
{
|
||||
static_assert(std::is_base_of_v<AddressableError, _ErrT>, "_ErrT must derive from AddressableError");
|
||||
// line, column provide by `currentAAI`
|
||||
@@ -106,7 +106,7 @@ namespace Fig
|
||||
}
|
||||
|
||||
template <class _ErrT, typename = UnaddressableError>
|
||||
void throwUnaddressableError(String msg, std::source_location loc = std::source_location::current())
|
||||
void throwUnaddressableError(FString msg, std::source_location loc = std::source_location::current())
|
||||
{
|
||||
static_assert(std::is_base_of_v<AddressableError, _ErrT>, "_ErrT must derive from AddressableError");
|
||||
_ErrT spError(msg, loc);
|
||||
@@ -202,7 +202,7 @@ namespace Fig
|
||||
{
|
||||
if (peekToken().getType() != type)
|
||||
{
|
||||
throwAddressableError<SyntaxError>(String(std::format("Expected `{}`, but got `{}`",
|
||||
throwAddressableError<SyntaxError>(FString(std::format("Expected `{}`, but got `{}`",
|
||||
magic_enum::enum_name(type),
|
||||
magic_enum::enum_name(peekToken().getType()))),
|
||||
loc);
|
||||
@@ -213,29 +213,31 @@ namespace Fig
|
||||
{
|
||||
if (currentToken().getType() != type)
|
||||
{
|
||||
throwAddressableError<SyntaxError>(String(std::format("Expected `{}`, but got `{}`",
|
||||
throwAddressableError<SyntaxError>(
|
||||
FString(std::format("Expected `{}`, but got `{}`",
|
||||
magic_enum::enum_name(type),
|
||||
magic_enum::enum_name(currentToken().getType()))),
|
||||
loc);
|
||||
}
|
||||
}
|
||||
|
||||
void expectPeek(TokenType type, String expected, std::source_location loc = std::source_location::current())
|
||||
void expectPeek(TokenType type, FString expected, std::source_location loc = std::source_location::current())
|
||||
{
|
||||
if (peekToken().getType() != type)
|
||||
{
|
||||
throwAddressableError<SyntaxError>(String(std::format("Expected `{}`, but got `{}`",
|
||||
throwAddressableError<SyntaxError>(FString(std::format("Expected `{}`, but got `{}`",
|
||||
expected.toBasicString(),
|
||||
magic_enum::enum_name(peekToken().getType()))),
|
||||
loc);
|
||||
}
|
||||
}
|
||||
|
||||
void expect(TokenType type, String expected, std::source_location loc = std::source_location::current())
|
||||
void expect(TokenType type, FString expected, std::source_location loc = std::source_location::current())
|
||||
{
|
||||
if (currentToken().getType() != type)
|
||||
{
|
||||
throwAddressableError<SyntaxError>(String(std::format("Expected `{}`, but got `{}`",
|
||||
throwAddressableError<SyntaxError>(
|
||||
FString(std::format("Expected `{}`, but got `{}`",
|
||||
expected.toBasicString(),
|
||||
magic_enum::enum_name(currentToken().getType()))),
|
||||
loc);
|
||||
@@ -262,7 +264,7 @@ namespace Fig
|
||||
expectConsume(TokenType::Semicolon, loc);
|
||||
}
|
||||
|
||||
void expectConsume(TokenType type, String expected, std::source_location loc = std::source_location::current())
|
||||
void expectConsume(TokenType type, FString expected, std::source_location loc = std::source_location::current())
|
||||
{
|
||||
expect(type, expected, loc);
|
||||
next();
|
||||
@@ -277,6 +279,8 @@ namespace Fig
|
||||
bool isNext(TokenType type) { return peekToken().getType() == type; }
|
||||
bool isThis(TokenType type) { return currentToken().getType() == type; }
|
||||
|
||||
static constexpr FString varDefTypeFollowed = u8"(Followed)";
|
||||
|
||||
Ast::VarDef __parseVarDef(bool); // entry: current is keyword `var` or `const` (isConst: Bool)
|
||||
ObjectPtr __parseValue();
|
||||
Ast::ValueExpr __parseValueExpr();
|
||||
@@ -290,7 +294,7 @@ namespace Fig
|
||||
Ast::Break __parseBreak(); // entry: current is Token::Break
|
||||
Ast::Continue __parseContinue(); // entry: current is Token::Continue
|
||||
|
||||
Ast::VarExpr __parseVarExpr(String);
|
||||
Ast::VarExpr __parseVarExpr(FString);
|
||||
Ast::FunctionDef __parseFunctionDef(bool); // entry: current is Token::Identifier (isPublic: Bool)
|
||||
Ast::StructDef __parseStructDef(bool); // entry: current is Token::Identifier (struct name) arg(isPublic: bool)
|
||||
Ast::InterfaceDef
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#include <Evaluator/Value/Type.hpp>
|
||||
#include <Ast/astBase.hpp>
|
||||
#include <Error/error.hpp>
|
||||
#include <Error/errorLog.hpp>
|
||||
#include <Core/String.hpp>
|
||||
#include <Core/fig_string.hpp>
|
||||
#include <Repl/Repl.hpp>
|
||||
#include <vector>
|
||||
|
||||
@@ -11,8 +12,8 @@ namespace Fig
|
||||
{
|
||||
ostream << getPrompt() << "\n";
|
||||
|
||||
const String &sourcePath = U"<stdin>";
|
||||
const std::vector<String> &sourceLines{};
|
||||
const FString &sourcePath = u8"<stdin>";
|
||||
const std::vector<FString> &sourceLines{};
|
||||
|
||||
Evaluator evaluator;
|
||||
|
||||
@@ -23,14 +24,8 @@ namespace Fig
|
||||
|
||||
while (true)
|
||||
{
|
||||
ostream << "\r\n>>";
|
||||
const String &line = readline();
|
||||
|
||||
if (line.empty())
|
||||
{
|
||||
ostream << Object::getNullInstance()->toString().toBasicString();
|
||||
continue;
|
||||
}
|
||||
ostream << "\r>>";
|
||||
const FString &line = readline();
|
||||
if (line == u8"!exit") { break; }
|
||||
|
||||
Lexer lexer(line, sourcePath, sourceLines);
|
||||
@@ -43,6 +38,10 @@ namespace Fig
|
||||
|
||||
StatementResult sr = evaluator.Run(program);
|
||||
ObjectPtr result = sr.result;
|
||||
if (result->is<ValueType::NullClass>())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
ostream << result->toString().toBasicString() << '\n';
|
||||
}
|
||||
catch (AddressableError &e)
|
||||
|
||||
@@ -28,12 +28,12 @@ namespace Fig
|
||||
{
|
||||
}
|
||||
|
||||
String readline() const
|
||||
FString readline() const
|
||||
{
|
||||
std::string buf;
|
||||
std::getline(istream, buf);
|
||||
|
||||
return String(buf);
|
||||
return FString(buf);
|
||||
}
|
||||
|
||||
static std::string getPrompt()
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <format>
|
||||
#include <Utils/magic_enum/magic_enum.hpp>
|
||||
|
||||
#include <Core/String.hpp>
|
||||
#include <Core/fig_string.hpp>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
@@ -54,7 +54,7 @@ namespace Fig
|
||||
|
||||
/* Literal Types (not keyword)*/
|
||||
LiteralNumber, // number (int,float...)
|
||||
LiteralString, // String
|
||||
LiteralString, // FString
|
||||
LiteralBool, // bool (true/false)
|
||||
LiteralNull, // null (Null unique instance)
|
||||
|
||||
@@ -121,15 +121,17 @@ namespace Fig
|
||||
friend bool operator==(const Token &l, const Token &r);
|
||||
|
||||
private:
|
||||
String value;
|
||||
FString value;
|
||||
TokenType type;
|
||||
|
||||
public:
|
||||
size_t line, column;
|
||||
|
||||
inline Token() {};
|
||||
inline Token(const String &_value, TokenType _type) : value(_value), type(_type) {}
|
||||
inline Token(const String &_value, TokenType _type, size_t _line, size_t _column) : value(_value), type(_type)
|
||||
inline Token(const FString &_value, TokenType _type) :
|
||||
value(_value), type(_type) {}
|
||||
inline Token(const FString &_value, TokenType _type, size_t _line, size_t _column) :
|
||||
value(_value), type(_type)
|
||||
{
|
||||
line = _line;
|
||||
column = _column;
|
||||
@@ -140,21 +142,35 @@ namespace Fig
|
||||
column = _column;
|
||||
return *this;
|
||||
}
|
||||
size_t getLength() { return value.length(); }
|
||||
const String &getValue() const { return value; }
|
||||
inline String toString() const
|
||||
size_t getLength()
|
||||
{
|
||||
return String(std::format("Token('{}',{})", this->value.toBasicString(), magic_enum::enum_name(type)));
|
||||
return value.length();
|
||||
}
|
||||
const FString& getValue() const
|
||||
{
|
||||
return value;
|
||||
}
|
||||
inline FString toString() const
|
||||
{
|
||||
return FString(std::format(
|
||||
"Token('{}',{})",
|
||||
this->value.toBasicString(),
|
||||
magic_enum::enum_name(type)));
|
||||
}
|
||||
|
||||
bool isIdentifier() { return type == TokenType::Identifier; }
|
||||
bool isIdentifier()
|
||||
{
|
||||
return type == TokenType::Identifier;
|
||||
}
|
||||
bool isLiteral()
|
||||
{
|
||||
return type == TokenType::LiteralNull || type == TokenType::LiteralBool || type == TokenType::LiteralNumber
|
||||
|| type == TokenType::LiteralString;
|
||||
return type == TokenType::LiteralNull || type == TokenType::LiteralBool || type == TokenType::LiteralNumber || type == TokenType::LiteralString;
|
||||
}
|
||||
|
||||
TokenType getType() const { return type; }
|
||||
TokenType getType() const
|
||||
{
|
||||
return type;
|
||||
}
|
||||
};
|
||||
|
||||
inline bool operator==(const Token &l, const Token &r)
|
||||
@@ -162,6 +178,6 @@ namespace Fig
|
||||
return l.type == r.type and l.value == r.value;
|
||||
}
|
||||
|
||||
static Token IllegalTok(U"ILLEGAL", TokenType::Illegal);
|
||||
static Token EOFTok(U"EOF", TokenType::EndOfFile);
|
||||
static Token IllegalTok(u8"ILLEGAL", TokenType::Illegal);
|
||||
static Token EOFTok(u8"EOF", TokenType::EndOfFile);
|
||||
} // namespace Fig
|
||||
@@ -15,32 +15,53 @@ public:
|
||||
if (!node) return;
|
||||
switch (node->getType())
|
||||
{
|
||||
case AstType::BinaryExpr: printBinaryExpr(std::static_pointer_cast<BinaryExprAst>(node), indent); break;
|
||||
case AstType::UnaryExpr: printUnaryExpr(std::static_pointer_cast<UnaryExprAst>(node), indent); break;
|
||||
case AstType::ValueExpr: printValueExpr(std::static_pointer_cast<ValueExprAst>(node), indent); break;
|
||||
case AstType::VarDefSt: printVarDef(std::static_pointer_cast<VarDefAst>(node), indent); break;
|
||||
case AstType::VarExpr: printVarExpr(std::static_pointer_cast<VarExprAst>(node), indent); break;
|
||||
case AstType::BinaryExpr:
|
||||
printBinaryExpr(std::static_pointer_cast<BinaryExprAst>(node), indent);
|
||||
break;
|
||||
case AstType::UnaryExpr:
|
||||
printUnaryExpr(std::static_pointer_cast<UnaryExprAst>(node), indent);
|
||||
break;
|
||||
case AstType::ValueExpr:
|
||||
printValueExpr(std::static_pointer_cast<ValueExprAst>(node), indent);
|
||||
break;
|
||||
case AstType::VarDefSt:
|
||||
printVarDef(std::static_pointer_cast<VarDefAst>(node), indent);
|
||||
break;
|
||||
case AstType::VarExpr:
|
||||
printVarExpr(std::static_pointer_cast<VarExprAst>(node), indent);
|
||||
break;
|
||||
case AstType::BlockStatement:
|
||||
printBlockStatement(std::static_pointer_cast<BlockStatementAst>(node), indent);
|
||||
break;
|
||||
case AstType::FunctionCall:
|
||||
printFunctionCall(std::static_pointer_cast<FunctionCallExpr>(node), indent);
|
||||
break;
|
||||
case AstType::FunctionDefSt: printFunctionSt(std::static_pointer_cast<FunctionDefSt>(node), indent); break;
|
||||
case AstType::IfSt: printIfSt(std::static_pointer_cast<IfSt>(node), indent); break;
|
||||
case AstType::TernaryExpr: printTernaryExpr(std::static_pointer_cast<TernaryExprAst>(node), indent); break;
|
||||
default: printIndent(indent); std::cout << "Unknown AST Node\n";
|
||||
case AstType::FunctionDefSt:
|
||||
printFunctionSt(std::static_pointer_cast<FunctionDefSt>(node), indent);
|
||||
break;
|
||||
case AstType::IfSt:
|
||||
printIfSt(std::static_pointer_cast<IfSt>(node), indent);
|
||||
break;
|
||||
case AstType::TernaryExpr:
|
||||
printTernaryExpr(std::static_pointer_cast<TernaryExprAst>(node), indent);
|
||||
break;
|
||||
default:
|
||||
printIndent(indent);
|
||||
std::cout << "Unknown AST Node\n";
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void printIndent(int indent) { std::cout << std::string(indent, ' '); }
|
||||
void printIndent(int indent)
|
||||
{
|
||||
std::cout << std::string(indent, ' ');
|
||||
}
|
||||
|
||||
void printFString(const Fig::String &fstr, int indent)
|
||||
void printFString(const Fig::FString &fstr, int indent)
|
||||
{
|
||||
printIndent(indent);
|
||||
std::cout << "String: \"";
|
||||
std::cout << fstr;
|
||||
std::cout << "FString: \"";
|
||||
std::cout.write(reinterpret_cast<const char *>(fstr.data()), fstr.size());
|
||||
std::cout << "\"\n";
|
||||
}
|
||||
|
||||
@@ -112,7 +133,10 @@ private:
|
||||
{
|
||||
printIndent(indent);
|
||||
std::cout << "BlockStatement\n";
|
||||
for (const auto &stmt : node->stmts) { print(stmt, indent + 2); }
|
||||
for (const auto &stmt : node->stmts)
|
||||
{
|
||||
print(stmt, indent + 2);
|
||||
}
|
||||
}
|
||||
|
||||
void printFunctionCall(const std::shared_ptr<FunctionCallExpr> &node, int indent)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <Lexer/lexer.hpp>
|
||||
#include <Core/String.hpp>
|
||||
#include <Core/fig_string.hpp>
|
||||
#include <string>
|
||||
#include <locale>
|
||||
#include <cwctype>
|
||||
@@ -11,33 +11,36 @@
|
||||
namespace Fig::Utils
|
||||
{
|
||||
|
||||
inline std::vector<String> splitSource(const String &source)
|
||||
inline std::vector<FString> splitSource(FString source)
|
||||
{
|
||||
|
||||
std::vector<String> lines;
|
||||
String currentLine;
|
||||
|
||||
for (char32_t c : source)
|
||||
UTF8Iterator it(source);
|
||||
std::vector<FString> lines;
|
||||
FString currentLine;
|
||||
while (!it.isEnd())
|
||||
{
|
||||
UTF8Char c = *it;
|
||||
if (c == U'\n')
|
||||
{
|
||||
lines.push_back(currentLine);
|
||||
currentLine = String(U"\1");
|
||||
currentLine = FString(u8"");
|
||||
}
|
||||
else
|
||||
{
|
||||
currentLine += c;
|
||||
currentLine += c.getString();
|
||||
}
|
||||
++it;
|
||||
}
|
||||
if (!currentLine.empty())
|
||||
{
|
||||
lines.push_back(currentLine);
|
||||
}
|
||||
|
||||
if (!currentLine.empty()) { lines.push_back(currentLine); }
|
||||
return lines;
|
||||
}
|
||||
inline std::u32string utf8ToUtf32(const String &s)
|
||||
inline std::u32string utf8ToUtf32(const FString &s)
|
||||
{
|
||||
std::u32string result;
|
||||
size_t i = 0;
|
||||
while (i < s.length())
|
||||
while (i < s.size())
|
||||
{
|
||||
char32_t codepoint = 0;
|
||||
unsigned char c = static_cast<unsigned char>(s[i]);
|
||||
@@ -54,15 +57,12 @@ namespace Fig::Utils
|
||||
}
|
||||
else if ((c >> 4) == 0xE)
|
||||
{
|
||||
codepoint = ((c & 0x0F) << 12) | ((static_cast<unsigned char>(s[i + 1]) & 0x3F) << 6)
|
||||
| (static_cast<unsigned char>(s[i + 2]) & 0x3F);
|
||||
codepoint = ((c & 0x0F) << 12) | ((static_cast<unsigned char>(s[i + 1]) & 0x3F) << 6) | (static_cast<unsigned char>(s[i + 2]) & 0x3F);
|
||||
i += 3;
|
||||
}
|
||||
else if ((c >> 3) == 0x1E)
|
||||
{
|
||||
codepoint = ((c & 0x07) << 18) | ((static_cast<unsigned char>(s[i + 1]) & 0x3F) << 12)
|
||||
| ((static_cast<unsigned char>(s[i + 2]) & 0x3F) << 6)
|
||||
| (static_cast<unsigned char>(s[i + 3]) & 0x3F);
|
||||
codepoint = ((c & 0x07) << 18) | ((static_cast<unsigned char>(s[i + 1]) & 0x3F) << 12) | ((static_cast<unsigned char>(s[i + 2]) & 0x3F) << 6) | (static_cast<unsigned char>(s[i + 3]) & 0x3F);
|
||||
i += 4;
|
||||
}
|
||||
else
|
||||
@@ -75,6 +75,59 @@ namespace Fig::Utils
|
||||
return result;
|
||||
}
|
||||
|
||||
inline FString utf32ToUtf8(const std::u32string &s)
|
||||
{
|
||||
FString result;
|
||||
for (char32_t cp : s)
|
||||
{
|
||||
if (cp < 0x80)
|
||||
{
|
||||
result.push_back(static_cast<char8_t>(cp));
|
||||
}
|
||||
else if (cp < 0x800)
|
||||
{
|
||||
result.push_back(static_cast<char8_t>((cp >> 6) | 0xC0));
|
||||
result.push_back(static_cast<char8_t>((cp & 0x3F) | 0x80));
|
||||
}
|
||||
else if (cp < 0x10000)
|
||||
{
|
||||
result.push_back(static_cast<char8_t>((cp >> 12) | 0xE0));
|
||||
result.push_back(static_cast<char8_t>(((cp >> 6) & 0x3F) | 0x80));
|
||||
result.push_back(static_cast<char8_t>((cp & 0x3F) | 0x80));
|
||||
}
|
||||
else
|
||||
{
|
||||
result.push_back(static_cast<char8_t>((cp >> 18) | 0xF0));
|
||||
result.push_back(static_cast<char8_t>(((cp >> 12) & 0x3F) | 0x80));
|
||||
result.push_back(static_cast<char8_t>(((cp >> 6) & 0x3F) | 0x80));
|
||||
result.push_back(static_cast<char8_t>((cp & 0x3F) | 0x80));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
inline FString toLower(const FString &s)
|
||||
{
|
||||
std::u32string u32 = utf8ToUtf32(s);
|
||||
std::locale loc("");
|
||||
for (auto &ch : u32)
|
||||
{
|
||||
ch = std::towlower(ch);
|
||||
}
|
||||
return utf32ToUtf8(u32);
|
||||
}
|
||||
|
||||
inline FString toUpper(const FString &s)
|
||||
{
|
||||
std::u32string u32 = utf8ToUtf32(s);
|
||||
std::locale loc("");
|
||||
for (auto &ch : u32)
|
||||
{
|
||||
ch = std::towupper(ch);
|
||||
}
|
||||
return utf32ToUtf8(u32);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool vectorContains(const T &t, const std::vector<T> v)
|
||||
{
|
||||
|
||||
@@ -24,7 +24,10 @@ namespace Fig
|
||||
uint64_t base = currentFrame->base;
|
||||
popFrame();
|
||||
|
||||
if (frames.empty()) { return ret; }
|
||||
if (frames.empty())
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
stack.resize(base); // 清除函数的临时值
|
||||
push(ret);
|
||||
@@ -144,8 +147,7 @@ namespace Fig
|
||||
|
||||
if (lhs.is<ValueType::IntClass>() && rhs.is<ValueType::IntClass>())
|
||||
{
|
||||
ValueType::DoubleClass result =
|
||||
(double) lhs.as<ValueType::IntClass>() / (double) rhs.as<ValueType::IntClass>();
|
||||
ValueType::DoubleClass result = (double)lhs.as<ValueType::IntClass>() / (double)rhs.as<ValueType::IntClass>();
|
||||
push(Object(result));
|
||||
break;
|
||||
}
|
||||
@@ -164,7 +166,12 @@ namespace Fig
|
||||
case OpCode::JUMP_IF_FALSE: {
|
||||
const Object &cond = pop();
|
||||
|
||||
if (!cond.is<bool>()) { throw RuntimeError(String(U"\1")); }
|
||||
if (!cond.is<bool>())
|
||||
{
|
||||
throw RuntimeError(
|
||||
FString(u8"Condition must be boolean!")
|
||||
);
|
||||
}
|
||||
if (!cond.as<bool>())
|
||||
{
|
||||
// cond is falsity
|
||||
@@ -174,13 +181,14 @@ namespace Fig
|
||||
break;
|
||||
}
|
||||
|
||||
case OpCode::CALL: {
|
||||
case OpCode::CALL:
|
||||
{
|
||||
uint16_t argCount = static_cast<uint16_t>(ins.operand); // number of max arg is UINT16_MAX
|
||||
|
||||
const Object &obj = stack.back();
|
||||
if (!obj.is<Function>())
|
||||
{
|
||||
throw RuntimeError(String(std::format("{} is not callable", obj.toString().toBasicString())));
|
||||
throw RuntimeError(FString(std::format("{} is not callable", obj.toString().toBasicString())));
|
||||
}
|
||||
|
||||
// const Function &fn_obj = obj.as<Function>();
|
||||
@@ -195,11 +203,17 @@ namespace Fig
|
||||
|
||||
pop(); // pop function
|
||||
|
||||
for (int64_t i = 0; i < fn.slotCount - argCount; ++i) { push(*Object::getNullInstance()); }
|
||||
for (int64_t i = 0; i < fn.slotCount - argCount; ++i)
|
||||
{
|
||||
push(*Object::getNullInstance());
|
||||
}
|
||||
|
||||
CallFrame newFrame{0,
|
||||
CallFrame newFrame
|
||||
{
|
||||
0,
|
||||
base, // 参数已经加载到stack, base为第一个参数
|
||||
fn};
|
||||
fn
|
||||
};
|
||||
|
||||
addFrame(newFrame);
|
||||
break;
|
||||
64
src/main.cpp
64
src/main.cpp
@@ -1,37 +1,26 @@
|
||||
/*
|
||||
███████████ █████ █████ ██████████ ███████████ █████ █████████ █████ █████████ ██████ █████
|
||||
█████████ █████ █████ █████████ █████████ ██████████ ░█░░░███░░░█░░███ ░░███ ░░███░░░░░█ ░░███░░░░░░█░░███
|
||||
███░░░░░███ ░░███ ███░░░░░███ ░░██████ ░░███ ███░░░░░███░░███ ░░███ ███░░░░░███ ███░░░░░███░░███░░░░░█
|
||||
░ ░███ ░ ░███ ░███ ░███ █ ░ ░███ █ ░ ░███ ███ ░░░ ░███ ░███ ░███ ░███░███ ░███ ███
|
||||
░░░ ░███ ░███ ░███ ░███ ███ ░░░ ░███ █ ░ ░███ ░███████████ ░██████ ░███████ ░███ ░███ ░███
|
||||
░███████████ ░███░░███░███ ░███ ░███ ░███ ░███████████ ░███ ░██████ ░███ ░███░░░░░███ ░███░░█
|
||||
░███░░░█ ░███ ░███ █████ ░███ ░███░░░░░███ ░███ ░░██████ ░███ █████ ░███ ░███ ░███░░░░░███ ░███
|
||||
█████ ░███░░█ ░███ ░███ ░███ ░███ ░ █ ░███ ░ ░███ ░░███ ░░███ ░███ █ ░███ ░███ ░███
|
||||
░░█████ ░░███ ░░███ ░███ ░███ ░███ ░███ ░░███ ░░███ ░███ ░ █ █████ █████ █████ ██████████ █████
|
||||
█████ ░░█████████ ███████████ █████ █████ █████ ░░█████ ░░█████████ ░░████████ █████ █████ ░░█████████
|
||||
██████████ ░░░░░ ░░░░░ ░░░░░ ░░░░░░░░░░ ░░░░░ ░░░░░ ░░░░░░░░░ ░░░░░░░░░░░ ░░░░░ ░░░░░ ░░░░░ ░░░░░
|
||||
░░░░░░░░░ ░░░░░░░░ ░░░░░ ░░░░░ ░░░░░░░░░ ░░░░░░░░░░
|
||||
███████████ █████ █████ ██████████ ███████████ █████ █████████ █████ █████████ ██████ █████ █████████ █████ █████ █████████ █████████ ██████████
|
||||
░█░░░███░░░█░░███ ░░███ ░░███░░░░░█ ░░███░░░░░░█░░███ ███░░░░░███ ░░███ ███░░░░░███ ░░██████ ░░███ ███░░░░░███░░███ ░░███ ███░░░░░███ ███░░░░░███░░███░░░░░█
|
||||
░ ░███ ░ ░███ ░███ ░███ █ ░ ░███ █ ░ ░███ ███ ░░░ ░███ ░███ ░███ ░███░███ ░███ ███ ░░░ ░███ ░███ ░███ ░███ ███ ░░░ ░███ █ ░
|
||||
░███ ░███████████ ░██████ ░███████ ░███ ░███ ░███ ░███████████ ░███░░███░███ ░███ ░███ ░███ ░███████████ ░███ ░██████
|
||||
░███ ░███░░░░░███ ░███░░█ ░███░░░█ ░███ ░███ █████ ░███ ░███░░░░░███ ░███ ░░██████ ░███ █████ ░███ ░███ ░███░░░░░███ ░███ █████ ░███░░█
|
||||
░███ ░███ ░███ ░███ ░ █ ░███ ░ ░███ ░░███ ░░███ ░███ █ ░███ ░███ ░███ ░░█████ ░░███ ░░███ ░███ ░███ ░███ ░███ ░░███ ░░███ ░███ ░ █
|
||||
█████ █████ █████ ██████████ █████ █████ ░░█████████ ███████████ █████ █████ █████ ░░█████ ░░█████████ ░░████████ █████ █████ ░░█████████ ██████████
|
||||
░░░░░ ░░░░░ ░░░░░ ░░░░░░░░░░ ░░░░░ ░░░░░ ░░░░░░░░░ ░░░░░░░░░░░ ░░░░░ ░░░░░ ░░░░░ ░░░░░ ░░░░░░░░░ ░░░░░░░░ ░░░░░ ░░░░░ ░░░░░░░░░ ░░░░░░░░░░
|
||||
|
||||
|
||||
.---.
|
||||
. __.....__ .--. | | _..._ __.....__
|
||||
.'| .-'' '. _.._ |__| .--./) | | .' '. .--./)
|
||||
.--./) .-'' '.
|
||||
.| < | / .-''"'-. `. .' .._|.--. /.''\\ | | . .-. . /.''\\
|
||||
/.''\\ / .-''"'-. `.
|
||||
.' |_ | | / /________\ \ | ' | || | | | | | __ | ' ' || | | |
|
||||
__ | | | |/ /________\ \
|
||||
.' || | .'''-. | | __| |__ | | \`-' / | | .:--.'. | | | | \`-' / _
|
||||
_ .:--.'. \`-' / | |
|
||||
'--. .-'| |/.'''. \\ .-------------' |__ __| | | /("'` | |/ | \ | | | | | /("'` | '
|
||||
/ | / | \ | /("'` \ .-------------' | | | / | | \ '-.____...---. | | | | \ '---. | |`"
|
||||
__ | | | | | | \ '---. .' | .' | `" __ | | \ '---. \ '-.____...---. | | | | | | `. .' | |
|
||||
|__| /'""'.\ | | .'.''| | | | | | /'""'.\ / | / | .'.''| | /'""'.\ `. .' | '.'| | |
|
||||
| `''-...... -' | | || || '---'/ / | |_| | | | || ||| `'. | / / |
|
||||
|_|| || `''-...... -' | / | '. | '. | | \'. __// \ \._,\ '/| | | |
|
||||
\'. __// ' .'| '/\ \._,\ '/\'. __//
|
||||
`'-' '---' '---' |_| `'---' `--' `" '--' '--' `'---'
|
||||
`-' `--' `--' `" `'---'
|
||||
.'| .-'' '. _.._ |__| .--./) | | .' '. .--./) .--./) .-'' '.
|
||||
.| < | / .-''"'-. `. .' .._|.--. /.''\\ | | . .-. . /.''\\ /.''\\ / .-''"'-. `.
|
||||
.' |_ | | / /________\ \ | ' | || | | | | | __ | ' ' || | | | __ | | | |/ /________\ \
|
||||
.' || | .'''-. | | __| |__ | | \`-' / | | .:--.'. | | | | \`-' / _ _ .:--.'. \`-' / | |
|
||||
'--. .-'| |/.'''. \\ .-------------' |__ __| | | /("'` | |/ | \ | | | | | /("'` | ' / | / | \ | /("'` \ .-------------'
|
||||
| | | / | | \ '-.____...---. | | | | \ '---. | |`" __ | | | | | | \ '---. .' | .' | `" __ | | \ '---. \ '-.____...---.
|
||||
| | | | | | `. .' | | |__| /'""'.\ | | .'.''| | | | | | /'""'.\ / | / | .'.''| | /'""'.\ `. .'
|
||||
| '.'| | | | `''-...... -' | | || || '---'/ / | |_| | | | || ||| `'. | / / | |_|| || `''-...... -'
|
||||
| / | '. | '. | | \'. __// \ \._,\ '/| | | | \'. __// ' .'| '/\ \._,\ '/\'. __//
|
||||
`'-' '---' '---' |_| `'---' `--' `" '--' '--' `'---' `-' `--' `--' `" `'---'
|
||||
|
||||
Copyright (C) 2020-2026 PuqiAR
|
||||
|
||||
@@ -55,14 +44,21 @@ This software is licensed under the MIT License. See LICENSE.txt for details.
|
||||
static size_t addressableErrorCount = 0;
|
||||
static size_t unaddressableErrorCount = 0;
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
Time::init();
|
||||
// init, set start_time (std::chrono::time_point)
|
||||
|
||||
|
||||
argparse::ArgumentParser program("Fig Interpreter", Fig::Core::VERSION.data());
|
||||
program.add_argument("source").help("source file to be interpreted").default_value(std::string(""));
|
||||
program.add_argument("-r", "--repl").help("start repl").default_value(false).implicit_value(true);
|
||||
program.add_argument("source")
|
||||
.help("source file to be interpreted")
|
||||
.default_value(std::string(""));
|
||||
program.add_argument("-r", "--repl")
|
||||
.help("start repl")
|
||||
.default_value(false)
|
||||
.implicit_value(true);
|
||||
// program.add_argument("-v", "--version")
|
||||
// .help("get the version of Fig Interpreter")
|
||||
// .default_value(false)
|
||||
@@ -91,7 +87,7 @@ int main(int argc, char **argv)
|
||||
exit(0);
|
||||
}
|
||||
|
||||
Fig::String sourcePath(program.get<std::string>("source"));
|
||||
Fig::FString sourcePath(program.get<std::string>("source"));
|
||||
if (sourcePath.empty())
|
||||
{
|
||||
std::cerr << "No source file provided.\n";
|
||||
@@ -106,9 +102,9 @@ int main(int argc, char **argv)
|
||||
std::string source((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
|
||||
file.close();
|
||||
|
||||
std::vector<String> sourceLines = Fig::Utils::splitSource(Fig::String(source));
|
||||
std::vector<FString> sourceLines = Fig::Utils::splitSource(Fig::FString(source));
|
||||
|
||||
Fig::Lexer lexer((Fig::String(source)), sourcePath, sourceLines);
|
||||
Fig::Lexer lexer((Fig::FString(source)), sourcePath, sourceLines);
|
||||
|
||||
// Token tok;
|
||||
// while ((tok = lexer.nextToken()).getType() != TokenType::EndOfFile)
|
||||
|
||||
19
xmake.lua
19
xmake.lua
@@ -27,7 +27,6 @@ end
|
||||
|
||||
add_files("src/Core/warning.cpp")
|
||||
add_files("src/Core/runtimeTime.cpp")
|
||||
add_files("src/Core/String.cpp")
|
||||
|
||||
add_files("src/Lexer/lexer.cpp")
|
||||
add_files("src/Parser/parser.cpp")
|
||||
@@ -43,27 +42,25 @@ target("Fig")
|
||||
set_kind("binary")
|
||||
|
||||
add_files("src/Evaluator/Core/*.cpp")
|
||||
add_files("src/VirtualMachine/VirtualMachine.cpp")
|
||||
add_files("src/Evaluator/evaluator.cpp")
|
||||
add_files("src/Repl/Repl.cpp")
|
||||
add_files("src/main.cpp")
|
||||
|
||||
set_warnings("all")
|
||||
|
||||
target("vm_test_main")
|
||||
set_kind("binary")
|
||||
-- target("vm_test_main")
|
||||
-- set_kind("binary")
|
||||
|
||||
add_files("src/VirtualMachine/VirtualMachine.cpp")
|
||||
add_files("src/Bytecode/vm_test_main.cpp")
|
||||
-- add_files("src/Bytecode/vm_test_main.cpp")
|
||||
|
||||
set_warnings("all")
|
||||
-- set_warnings("all")
|
||||
|
||||
target("ir_test_main")
|
||||
set_kind("binary")
|
||||
-- target("ir_test_main")
|
||||
-- set_kind("binary")
|
||||
|
||||
add_files("src/IR/ir_test_main.cpp")
|
||||
-- add_files("src/IR/ir_test_main.cpp")
|
||||
|
||||
set_warnings("all")
|
||||
-- set_warnings("all")
|
||||
|
||||
target("StringTest")
|
||||
set_kind("binary")
|
||||
|
||||
Reference in New Issue
Block a user