feat: 增加一个很简单的repl(还不能用) 写了readme

This commit is contained in:
2026-03-13 01:28:43 +08:00
parent c0eacfd236
commit 91b5a0e384
7 changed files with 853 additions and 7 deletions

191
README.md
View File

@@ -1,2 +1,193 @@
# Fig
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./Logo/LogoDark.svg">
<img src="./Logo/Logo.svg" alt="Fig Logo" width="200">
</picture>
> **🔔 Main Repository: https://git.fig-lang.cn/PuqiAR/Fig**
> *GitHub is only a mirror. Please submit issues and PRs to the main repository.*
[English](./README.md) | [中文](./README_zh-CN.md)
![License](https://img.shields.io/badge/license-MIT-blue)
![Status](https://img.shields.io/badge/status-0.5.0--alpha-yellow)
![C++](https://img.shields.io/badge/C++-99.5%25-blue)
![xmake](https://img.shields.io/badge/xmake-build-green)
![LLVM](https://img.shields.io/badge/LLVM-clang%2021.1.8-purple)
![Platform](https://img.shields.io/badge/Windows%20·%20Linux%20·%20macOS-lightgrey)
![Performance](https://img.shields.io/badge/fib(30)-~28ms%20(i5--13490f)-brightgreen)
**Fig** is a programming language that blends dynamic typing with optional static type annotations, built on reference-based value semantics. It offers the flexibility of scripting languages while providing optional type constraints for more robust code.
> ⚠️ **Fig is currently at version 0.5.0-alpha, and its syntax and APIs are subject to change.** Feel free to try it out and provide feedback, but do not use it in production environments.
```fig
// Get a feel for Fig
var flexible = 10 // dynamic type, can be any value
flexible = "hello" // works
var fixed := 20 // fixed to Int type
// fixed = 3.14 // error! type mismatch
func greet(name) => "Hello, " + name + "!"
println(greet("Fig")) // output: Hello, Fig!
```
## ✨ Key Features
### 🎭 Dynamic & Static Blending
Variables are dynamic by default (`Any` type), but you can lock their type using `:=` or `: Type` for static safety.
```fig
var any; // type is Any
any = 42; // now points to an Int
any = [1,2,3]; // now points to a List
var safe := 100; // inferred as Int, can only be assigned Int values
safe = 200; // ✅
// safe = "oops" // ❌ compile error
```
### 🔗 Reference-Based Value Semantics
All objects are immutable; variables are just "names" that refer to objects. Multiple variables can share the same object, and modifications to complex types (like lists) are visible to all references—this is the essence of references.
```fig
var a := [1, 2, 3];
var b := a; // b and a refer to the same list
a[0] = 99; // modify the list content
println(b) // output: [99, 2, 3] — b sees the change
// Need a true copy? Use deep copy (syntax may change)
var c := new List{a}; // deep copy of a
c[0] = 0;
println(a) // still [99, 2, 3]
```
### 🏗 Object-Oriented Features (OOP)
Fig provides lightweight OOP support based on structs, with polymorphism via interfaces.
- **Structs as classes**: defined with `struct`, can have fields and methods.
- **Access control**: `public` keyword; fields are private by default.
- **Concise construction**:
```fig
var p1 := new Point{1, 2}; // positional
var p2 := new Point{x: 2, y: 3}; // named
var x := 5, y := 10;
var p3 := new Point{y, x}; // shorthand, auto field matching
```
- **Interfaces and implementations**:
```fig
interface Drawable { draw() -> String; }
struct Circle { radius: Double }
impl Drawable for Circle {
draw() => "⚪ radius: " + radius;
}
```
- **No inheritance, polymorphism via interfaces** (currently implicit `this`, may change to explicit `self.xxx` in the future).
### 🧩 Functional Features
Functions are first-class citizens, with support for closures and concise arrow syntax.
```fig
func multiplier(factor) {
return func (n) => n * factor; // closure (upvalue)
}
var double = multiplier(2);
println(double(5)) // output: 10
```
### ⚡ High Performance
**Recursive fib(30) takes only 28ms** (i5-13490f, Windows 11, DDR4 2667, clang 21.1.8, libc++, C++23) — excellent performance among dynamic languages.
Fig achieves high performance through a series of low-level optimizations:
- **Register-based VM**: replaces the tree-walk interpreter, dramatically improving execution speed.
- **FastCall optimization**: global ordinary functions can be called directly as prototypes, avoiding runtime unwrapping overhead (traditional calls require checking if an object is a function and unwrapping it).
- **Window Slicing** (originated from Lua): a stack sliding window technique that efficiently manages function calls and closures (upvalues), reducing memory allocations.
- **Upvalue mechanism**: lightweight closure implementation, making functional programming performant.
- **Computed Goto**: leverages GCC/Clang extensions to speed up bytecode dispatch.
- **NaN-Boxing**: efficient storage and type tagging to boost dynamic typing performance.
#### Performance Comparison
Rough comparison of recursive fib(30) execution times (environment may vary, for reference only):
| Language Type | Language | Time (ms) | Notes |
|---------------|----------------|-----------|-------|
| AOT compiled | C (clang -O2) | ~0.05 | Nanoseconds, as a speed reference |
| AOT compiled | Rust (--release) | ~0.06 | Same as above |
| **Dynamic** | **Fig** | **~28** | **Register VM + optimizations** |
| Dynamic | Lua 5.4 | ~35 | Classic dynamic language |
| Dynamic | Python 3.11 | ~450 | CPython |
| Dynamic | Node.js 20 | ~60 | V8 engine |
| Dynamic | Ruby 3.2 | ~800 | CRuby |
*Fig performs admirably among dynamic languages, approaching Lua and Node.js, and significantly outperforming Python and Ruby.*
## 🚀 Quick Start
### Installation
#### Option 1: Download Pre-built Binaries
Download the binary for your platform from the [main repository Releases](https://git.fig-lang.cn/PuqiAR/Fig/releases) or the [GitHub mirror](https://github.com/PuqiAR/Fig/releases), extract it, and add it to your PATH.
#### Option 2: Build from Source with xmake
```bash
# Clone the main repository (GitHub is a mirror)
git clone https://git.fig-lang.cn/PuqiAR/Fig.git
cd Fig
# Install xmake if you haven't: https://xmake.io
# Build (must use clang because computed goto requires compiler support)
xmake f --toolchain=clang
xmake
# After building, the binary is in the build/ directory
```
### Run Your First Fig Program
Create a file `hello.fig`:
```fig
import std.io; // io module must be imported; println and others reside here
println("Hello, Fig!");
```
Run it:
```bash
./build/fig hello.fig
```
Or if you added `fig` to your PATH:
```bash
fig hello.fig
```
## 📊 Current Status & Roadmap
| Status | Module | Description |
|--------|----------------------------|-------------|
| ✅ | Frontend | Lexer, parser, AST, semantic analysis |
| ✅ | Core semantics | Variables, functions, closures, structs, interfaces, type system |
| ✅ | Built-in types | 13 built-in types (Any, Null, Int, String, Bool, Double, Function, StructType, StructInstance, List, Map, Module, InterfaceType) |
| 🚧 | Register VM | Original tree-walk interpreter deprecated; VM in development |
| 🚧 | Garbage Collection | Basic GC implemented, optimizing |
| 📝 | Standard Library | IO preliminarily available; more libraries to come |
| 📝 | FFI | Foreign function interface (C ABI) |
| 📝 | LSP | Language Server Protocol support |
## 📚 Documentation & Community
- **Documentation**: Check the [`/docs`](./docs) directory (continuously updated)
- **Example Code**: [`/ExampleCodes`](./ExampleCodes) contains various usage demonstrations
- **Contributing**: Issues and PRs are welcome at the main repository
- Report bugs
- Discuss features
- Improve documentation
- **License**: MIT © PuqiAR
- **Author**: PuqiAR · [im@puqiar.top](mailto:im@puqiar.top)
- **Links**:
- [Main Repository](https://git.fig-lang.cn/PuqiAR/Fig)
- [GitHub Mirror](https://github.com/PuqiAR/Fig)
---
**Fig** is evolving rapidly. If you're intrigued, give it a try or join us in shaping its future!

193
README_zh-CN.md Normal file
View File

@@ -0,0 +1,193 @@
# Fig
<picture>
<source media="(prefers-color-scheme: dark)" srcset="./Logo/LogoDark.svg">
<img src="./Logo/Logo.svg" alt="Fig Logo" width="200">
</picture>
> **🔔 主仓库https://git.fig-lang.cn/PuqiAR/Fig**
> *GitHub 仅为镜像Issue 与 PR 请提交至主仓库*
[English](./README.md) | [中文](./README_zh-CN.md)
![License](https://img.shields.io/badge/license-MIT-blue)
![Status](https://img.shields.io/badge/status-0.5.0--alpha-yellow)
![C++](https://img.shields.io/badge/C++-99.5%25-blue)
![xmake](https://img.shields.io/badge/xmake-构建-green)
![LLVM](https://img.shields.io/badge/LLVM-clang%2021.1.8-purple)
![Platform](https://img.shields.io/badge/Windows%20·%20Linux%20·%20macOS-lightgrey)
![Performance](https://img.shields.io/badge/fib(30)-~28ms%20(i5--13490f)-brightgreen)
**Fig** 是一门动态类型与静态类型注解混合的编程语言,采用基于引用的值语义。它既保留了脚本语言的灵活性,又提供了可选的类型约束,让代码更健壮。
> ⚠️ **Fig 当前为 0.5.0-alpha 版本,语法和 API 仍可能发生变动。** 欢迎试用和反馈,但请勿用于生产环境。
```fig
// 试试 Fig 的感觉
var flexible = 10 // 动态类型,可以是任意值
flexible = "hello" // 没问题
var fixed := 20 // 固定为 Int 类型
// fixed = 3.14 // 错误!类型不匹配
func greet(name) => "Hello, " + name + "!"
println(greet("Fig")) // 输出: Hello, Fig!
```
## ✨ 核心特性
### 🎭 动态与静态的融合
变量默认是动态的(`Any` 类型),但你可以随时用 `:=``: Type` 锁定类型,享受静态检查的安全感。
```fig
var any; // 类型为 Any
any = 42; // 现在指向 Int
any = [1,2,3]; // 现在指向 List
var safe := 100; // 推断为 Int之后只能赋 Int 值
safe = 200; // ✅
// safe = "oops" // ❌ 编译错误
```
### 🔗 基于引用的值语义
所有对象都是不可变的,变量只是指向对象的“名字”。多个变量可以共享同一个对象,修改操作会创建新对象,但复杂类型(如列表)的修改会反映在所有引用上——这正是引用的含义。
```fig
var a := [1, 2, 3];
var b := a; // b 和 a 指向同一个列表
a[0] = 99; // 修改列表内容
println(b) // 输出: [99, 2, 3] —— 因为 b 也看到了变化
// 需要真正的副本?用深拷贝 (语法可能变动)
var c := new List{a}; // 深拷贝 a
c[0] = 0;
println(a) // 仍是 [99, 2, 3]
```
### 🏗 面向对象特性 (OOP)
Fig 提供基于结构体的轻量面向对象支持,通过接口实现多态。
- **结构体即类**:用 `struct` 定义,可包含字段和方法
- **访问控制**`public` 关键字,默认为私有
- **简洁构造**
```fig
var p1 := new Point{1, 2}; // 位置参数
var p2 := new Point{x: 2, y: 3}; // 命名参数
var x := 5, y := 10;
var p3 := new Point{y, x}; // 变量名简写,自动匹配字段
```
- **接口与实现**
```fig
interface Drawable { draw() -> String; }
struct Circle { radius: Double }
impl Drawable for Circle {
draw() => "⚪ 半径: " + radius;
}
```
- **无继承,用接口实现多态**(当前为隐式 `this`,未来可能改为显式 `self.xxx`
### 🧩 函数式特性
函数是一等公民,支持闭包和简洁的箭头语法。
```fig
func multiplier(factor) {
return func (n) => n * factor; // 闭包upvalue
}
var double = multiplier(2);
println(double(5)) // 输出: 10
```
### ⚡ 高性能实现
**递归 fib(30) 仅需 28ms** (i5-13490f, Windows 11, DDR4 2667, clang 21.1.8, libc++, C++23) —— 在动态语言中表现优异。
Fig 通过一系列底层优化实现高性能:
- **寄存器虚拟机**:替代树遍历解释器,执行效率大幅提升。
- **FastCall 优化**全局普通函数直接调用原型proto避免运行时解包开销传统调用需检查是否为函数对象并解包
- **Window Slicing**(源自 Lua栈滑动窗口技术高效管理函数调用和闭包upvalue减少内存分配。
- **Upvalue 机制**:轻量闭包实现,让函数式编程无性能负担。
- **Computed Goto**:利用 GCC/Clang 扩展,加速字节码分发。
- **NaN-Boxing**:高效存储和类型判断,提升动态类型性能。
#### 性能对比
以下为递归计算 fib(30) 的粗略对比(不同环境可能存在差异,仅供参考):
| 语言类型 | 语言 | 时间 (ms) | 备注 |
|--------|------|----------|------|
| AOT 编译 | C (clang -O2) | ~0.05 | 纳秒级,作为速度参照 |
| AOT 编译 | Rust (--release) | ~0.06 | 同上 |
| **动态语言** | **Fig** | **~28** | **寄存器 VM + 上述优化** |
| 动态语言 | Lua 5.4 | ~35 | 经典的动态语言 |
| 动态语言 | Python 3.11 | ~450 | CPython |
| 动态语言 | Node.js 20 | ~60 | V8 引擎 |
| 动态语言 | Ruby 3.2 | ~800 | CRuby |
*Fig 在动态语言阵营中表现出色,接近 Lua 和 Node.js 的水平,远超 Python 和 Ruby。*
## 🚀 快速上手
### 安装
#### 方法一:下载预编译二进制
从 [主仓库 Releases](https://git.fig-lang.cn/PuqiAR/Fig/releases) 或 [GitHub 镜像](https://github.com/PuqiAR/Fig/releases) 下载对应平台的二进制,解压后加入 PATH。
#### 方法二:使用 xmake 从源码编译
```bash
# 克隆主仓库GitHub 为镜像)
git clone https://git.fig-lang.cn/PuqiAR/Fig.git
cd Fig
# 安装 xmake如未安装https://xmake.io
# 编译(必须用 clang因为 computed goto 需要编译器支持)
xmake f --toolchain=clang
xmake
# 编译完成后,二进制位于 build/ 目录下
```
### 运行第一个 Fig 程序
创建文件 `hello.fig`
```fig
import std.io; // io 模块必须导入println 等函数位于其中
println("Hello, Fig!");
```
运行:
```bash
./build/fig hello.fig
```
或已加入 PATH
```bash
fig hello.fig
```
## 📊 当前状态与路线图
| 状态 | 模块 | 说明 |
|------|------|------|
| ✅ | 前端 | 词法/语法分析、AST、语义分析 |
| ✅ | 核心语义 | 变量、函数、闭包、结构体、接口、类型系统 |
| ✅ | 内置类型 | 13 种内置类型Any, Null, Int, String, Bool, Double, Function, StructType, StructInstance, List, Map, Module, InterfaceType |
| 🚧 | 寄存器虚拟机 | 原树遍历解释器已废弃VM 开发中 |
| 🚧 | 垃圾回收 | 基础 GC 已实现,正在优化 |
| 📝 | 标准库 | IO 已初步可用,更多库待完善 |
| 📝 | FFI | 外部函数接口C ABI |
| 📝 | LSP | 语言服务器协议支持 |
## 📚 文档与社区
- **文档**:查看 [`/docs`](./docs) 目录(持续更新)
- **示例代码**[`/ExampleCodes`](./ExampleCodes) 包含各种用法演示
- **贡献**:欢迎提交 Issue 或 PR主仓库
- 报告 bug
- 讨论特性
- 改进文档
- **许可证**MIT © PuqiAR
- **作者**PuqiAR · [im@puqiar.top](mailto:im@puqiar.top)
- **相关链接**
- [主仓库](https://git.fig-lang.cn/PuqiAR/Fig)
- [GitHub 镜像](https://github.com/PuqiAR/Fig)
---
**Fig** 还在快速迭代中,如果你对它感兴趣,不妨试一试,或者加入我们一起塑造它的未来!

View File

@@ -56,12 +56,96 @@ namespace Fig
{
namespace Core
{
inline constexpr std::string_view VERSION = __FCORE_VERSION;
inline constexpr std::string_view LICENSE = "MIT";
inline constexpr std::string_view AUTHOR = "PuqiAR";
inline constexpr std::string_view PLATFORM = __FCORE_PLATFORM;
inline constexpr std::string_view COMPILER = __FCORE_COMPILER;
inline constexpr std::string_view VERSION = __FCORE_VERSION;
inline constexpr std::string_view LICENSE = "MIT";
inline constexpr std::string_view AUTHOR = "PuqiAR";
inline constexpr std::string_view PLATFORM = __FCORE_PLATFORM;
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 std::string_view ARCH = __FCORE_ARCH;
const std::string LOGO =
R"(
)";
const std::string LICENSE_TEXT =
R"(
MIT License (Fig)
Copyright (c) 2026 PuqiAR <im@puqiar.top>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
1. The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
2. This project includes code from the following projects with their respective licenses:
- argparse (MIT License)
Copyright (c) 2018 Pranav Srinivas Kumar <pranav.srinivas.kumar@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- magic_enum (MIT License)
Copyright (c) 2019 - 2024 Daniil Goncharov
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
- json (MIT LICENSE) (for LSP Server JSON-RPC)
Copyright (c) 2013-2026 Niels Lohmann
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
)";
}; // namespace Core
}; // namespace Fig

260
src/Repl/Repl.hpp Normal file
View File

@@ -0,0 +1,260 @@
/*!
@file src/Repl/Repl.hpp
@brief Repl定义
@author PuqiAR (im@puqiar.top)
@date 2026-03-11
*/
#pragma once
#include <Core/Core.hpp>
#include <Core/SourceLocations.hpp>
#include <SourceManager/SourceManager.hpp>
#include <Compiler/Compiler.hpp>
#include <Lexer/Lexer.hpp>
#include <Parser/Parser.hpp>
#include <Sema/Analyzer.hpp>
#include <VM/VM.hpp>
#include <Utils/ConsoleSize.hpp>
namespace Fig
{
class Repl
{
private:
size_t rline = 1;
std::istream &in;
std::ostream &out;
std::ostream &err;
public:
Repl(std::istream &_in, std::ostream &_out, std::ostream &_err) :
in(_in), out(_out), err(_err)
{
}
void PrintInfo()
{
out << std::format("Fig {} copyright (c) 2025-2026 PuqiAR, under the {} License",
Core::VERSION,
Core::LICENSE);
out << std::format("Build time: {} [{} x{} on {}]\n",
Core::COMPILE_TIME,
Core::COMPILER,
Core::ARCH,
Core::PLATFORM);
out << "Type '#exit' to exit, '#clear' to clear the the screen, '#license' to see the full license, '#logo' to see a GREAT logo\n";
}
void ClearConsole()
{
// \033[2J: 清除整个屏幕
// \033[H: 将光标移动到左上角
out << "\033[2J\033[H" << std::flush;
}
void PrintLicense()
{
static DynArray<std::string> license_lines{};
if (license_lines.empty())
{
std::string l;
bool last_was_r = false;
for (size_t i = 0; i < Core::LICENSE_TEXT.size(); ++i)
{
char c = Core::LICENSE_TEXT[i];
if (c == '\r')
{
last_was_r = true;
continue;
}
if (c == '\n')
{
if (!l.empty() || last_was_r)
{
license_lines.push_back(l);
l.clear();
}
last_was_r = false;
continue;
}
if (last_was_r)
{
if (!l.empty())
{
license_lines.push_back(l);
l.clear();
}
last_was_r = false;
}
l += c;
}
if (!l.empty() || last_was_r)
{
license_lines.push_back(l);
}
}
unsigned int lines_per_page = 50;
unsigned int page_printed = 0;
unsigned int lines_printed = 0;
unsigned int total_lines = license_lines.size();
while (true)
{
auto _csize = Utils::getConsoleSize();
if (_csize)
{
lines_per_page = static_cast<unsigned int>((*_csize).first * 0.75);
if (lines_per_page < 1)
lines_per_page = 1;
}
unsigned int lines_this_page =
std::min(lines_per_page, total_lines - lines_printed);
for (unsigned int i = 0; i < lines_this_page; ++i)
{
out << license_lines[lines_printed + i] << '\n';
}
lines_printed += lines_this_page;
page_printed++;
if (lines_printed >= total_lines)
{
break;
}
unsigned int pages_total = (total_lines + lines_per_page - 1) / lines_per_page;
out << "\n"
<< std::format(
"Press any key to continue... ({}/{})", page_printed, pages_total);
in.get();
out << '\n';
++rline;
}
}
void PrintError(const Error &error, const String &source)
{
err << "Oops! An error occurred!";
err << "🔥 " << 'E' << static_cast<int>(error.type) << ": " << error.message << '\n';
err << "Line " << rline << ", `" << source << "`\n";
err << "Suggestion: " << error.suggestion << '\n';
err << std::format("Thrower: {} ({}:{}:{})\n",
error.thrower_loc.function_name(),
error.thrower_loc.file_name(),
error.thrower_loc.line(),
error.thrower_loc.column());
}
unsigned int Start() // exit code: unsigned int
{
// TODO: 多行输入 Repl
PrintInfo();
String fileName = "[REPL]";
String filePath = "src/Repl/Repl.hpp";
SourceManager manager;
VM vm;
Value v = Value::GetNullInstance();
while (true)
{
std::string buf;
out << ">";
std::getline(in, buf);
if (buf.empty())
{
continue;
}
else if (buf == "#exit")
{
return 0;
}
else if (buf == "#clear")
{
ClearConsole();
continue;
}
else if (buf == "#license")
{
PrintLicense();
continue;
}
else if (buf == "#logo")
{
out << Core::LOGO << '\n';
continue;
}
String source(buf);
Lexer lexer(buf, fileName);
Parser parser(lexer, manager, fileName);
auto _program = parser.Parse();
if (!_program)
{
PrintError(_program.error(), source);
continue;
}
Program *program = *_program;
Analyzer analyzer(manager);
auto result = analyzer.Analyze(program);
if (!result)
{
PrintError(result.error(), source);
continue;
}
Compiler compiler(manager, analyzer.GetDiagnostics());
auto compile_result = compiler.Compile(program);
if (!compile_result)
{
PrintError(compile_result.error(), source);
continue;
}
CompiledModule *compiledModule = *compile_result;
auto exe_result = vm.Execute(compiledModule);
if (!exe_result)
{
PrintError(exe_result.error(), source);
continue;
}
v = *exe_result;
if (!v.IsNull())
{
out << v.ToString() << '\n';
}
}
return (v.IsInt() ? v.AsInt() : 0);
}
};
}; // namespace Fig

10
src/Repl/ReplTest.cpp Normal file
View File

@@ -0,0 +1,10 @@
#include <Repl/Repl.hpp>
#include <Core/Core.hpp>
int main()
{
using namespace Fig;
Repl repl(CoreIO::GetStdCin(), CoreIO::GetStdOut(), CoreIO::GetStdErr());
repl.Start();
}

88
src/Utils/ConsoleSize.hpp Normal file
View File

@@ -0,0 +1,88 @@
#include <optional>
#include <utility>
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/ioctl.h>
#include <unistd.h>
#endif
namespace Fig::Utils
{
/**
* 获取控制台窗口的大小(行数和列数)
* @return 如果成功,返回包含 (rows, cols) 的 optional失败返回 std::nullopt
*/
inline std::optional<std::pair<int, int>> getConsoleSize()
{
#ifdef _WIN32
// Windows: GetConsoleScreenBufferInfo
CONSOLE_SCREEN_BUFFER_INFO csbi;
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
if (hConsole == INVALID_HANDLE_VALUE)
{
return std::nullopt;
}
if (!GetConsoleScreenBufferInfo(hConsole, &csbi))
{
return std::nullopt;
}
// 窗口大小 = 右下角坐标 - 左上角坐标 + 1
int cols = csbi.srWindow.Right - csbi.srWindow.Left + 1;
int rows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
return std::make_pair(rows, cols);
#else
// Linux / macOS / Unix: ioctl
struct winsize w;
// 标准输出被重定向到文件 ?
if (!isatty(STDOUT_FILENO))
{
// 不是终端,获取环境变量
char *cols_env = getenv("COLUMNS");
char *rows_env = getenv("LINES");
if (cols_env && rows_env)
{
int cols = std::stoi(cols_env);
int rows = std::stoi(rows_env);
return std::make_pair(rows, cols);
}
return std::nullopt;
}
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) == -1)
{
return std::nullopt;
}
int cols = w.ws_col;
int rows = w.ws_row;
// 如果 ws_col 或 ws_row 为 0使用环境变量
if (cols == 0 || rows == 0)
{
char *cols_env = getenv("COLUMNS");
char *rows_env = getenv("LINES");
if (cols_env)
cols = std::stoi(cols_env);
if (rows_env)
rows = std::stoi(rows_env);
}
if (cols > 0 && rows > 0)
{
return std::make_pair(rows, cols);
}
return std::nullopt;
#endif
}
} // namespace Fig::Utils

View File

@@ -94,6 +94,26 @@ target("LSP")
add_files("src/LSP/LSPServer.cpp")
set_filename("Fig-LSP")
target("ReplTest")
add_files("src/Core/*.cpp")
add_files("src/Token/Token.cpp")
add_files("src/Error/Error.cpp")
add_files("src/Lexer/Lexer.cpp")
add_files("src/Ast/Operator.cpp")
add_files("src/Bytecode/Disassembler.cpp")
add_files("src/Parser/ExprParser.cpp")
add_files("src/Parser/StmtParser.cpp")
add_files("src/Parser/TypeExprParser.cpp")
add_files("src/Parser/Parser.cpp")
add_files("src/Object/Object.cpp")
add_files("src/Sema/Type.cpp")
add_files("src/Sema/Analyzer.cpp")
add_files("src/Compiler/ExprCompiler.cpp")
add_files("src/Compiler/StmtCompiler.cpp")
add_files("src/Compiler/Compiler.cpp")
add_files("src/VM/VM.cpp")
add_files("src/Repl/ReplTest.cpp")
target("Fig")
add_files("src/Core/*.cpp")
add_files("src/Token/Token.cpp")