Compare commits

..

2 Commits

33 changed files with 8226 additions and 0 deletions

214
.clang-format Normal file
View File

@@ -0,0 +1,214 @@
# 语言: None, Cpp, Java, JavaScript, ObjC, Proto, TableGen, TextProto
Language: Cpp
# BasedOnStyle: LLVM
# 访问说明符(public、private等)的偏移
AccessModifierOffset: -4
# 开括号(开圆括号、开尖括号、开方括号)后的对齐: Align, DontAlign, AlwaysBreak(总是在开括号后换行)
AlignAfterOpenBracket: Align
# 连续赋值时,对齐所有等号
AlignConsecutiveAssignments: false
# 连续声明时,对齐所有声明的变量名
AlignConsecutiveDeclarations: false
# 右对齐逃脱换行(使用反斜杠换行)的反斜杠
AlignEscapedNewlines: Right
# 水平对齐二元和三元表达式的操作数
AlignOperands: true
# 对齐连续的尾随的注释
AlignTrailingComments: true
# 允许函数声明的所有参数在放在下一行
AllowAllParametersOfDeclarationOnNextLine: true
# 允许短的块放在同一行
AllowShortBlocksOnASingleLine: true
# 允许短的case标签放在同一行
AllowShortCaseLabelsOnASingleLine: true
# 允许短的函数放在同一行: None, InlineOnly(定义在类中), Empty(空函数), Inline(定义在类中,空函数), All
AllowShortFunctionsOnASingleLine: Inline
# 允许短的if语句保持在同一行
AllowShortIfStatementsOnASingleLine: true
# 允许短的循环保持在同一行
AllowShortLoopsOnASingleLine: true
# 总是在返回类型后换行: None, All, TopLevel(顶级函数,不包括在类中的函数),
# AllDefinitions(所有的定义,不包括声明), TopLevelDefinitions(所有的顶级函数的定义)
AlwaysBreakAfterReturnType: None
# 总是在多行string字面量前换行
AlwaysBreakBeforeMultilineStrings: false
# 总是在template声明后换行
AlwaysBreakTemplateDeclarations: true
# false表示函数实参要么都在同一行要么都各自一行
BinPackArguments: false
# false表示所有形参要么都在同一行要么都各自一行
BinPackParameters: false
# 大括号换行只有当BreakBeforeBraces设置为Custom时才有效
BraceWrapping:
# class定义后面
AfterClass: true
# 控制语句后面
AfterControlStatement: true
# enum定义后面
AfterEnum: true
# 函数定义后面
AfterFunction: true
# 命名空间定义后面
AfterNamespace: true
# struct定义后面
AfterStruct: true
# union定义后面
AfterUnion: true
# extern之后
AfterExternBlock: false
# catch之前
BeforeCatch: true
# else之前
BeforeElse: true
# 缩进大括号
IndentBraces: false
# 分离空函数
SplitEmptyFunction: true
# 分离空语句
SplitEmptyRecord: false
# 分离空命名空间
SplitEmptyNamespace: false
# 在二元运算符前换行: None(在操作符后换行), NonAssignment(在非赋值的操作符前换行), All(在操作符前换行)
BreakBeforeBinaryOperators: NonAssignment
# 在大括号前换行: Attach(始终将大括号附加到周围的上下文), Linux(除函数、命名空间和类定义与Attach类似),
# Mozilla(除枚举、函数、记录定义与Attach类似), Stroustrup(除函数定义、catch、else与Attach类似),
# Allman(总是在大括号前换行), GNU(总是在大括号前换行,并对于控制语句的大括号增加额外的缩进), WebKit(在函数前换行), Custom
# 注:这里认为语句块也属于函数
BreakBeforeBraces: Custom
# 在三元运算符前换行
BreakBeforeTernaryOperators: false
# 在构造函数的初始化列表的冒号后换行
BreakConstructorInitializers: AfterColon
#BreakInheritanceList: AfterColon
BreakStringLiterals: false
# 每行字符的限制0表示没有限制
ColumnLimit: 120
CompactNamespaces: true
# 构造函数的初始化列表要么都在同一行,要么都各自一行
ConstructorInitializerAllOnOneLineOrOnePerLine: true
# 构造函数的初始化列表的缩进宽度
ConstructorInitializerIndentWidth: 4
# 延续的行的缩进宽度
ContinuationIndentWidth: 4
# 去除C++11的列表初始化的大括号{后和}前的空格
Cpp11BracedListStyle: true
# 继承最常用的指针和引用的对齐方式
DerivePointerAlignment: false
# 固定命名空间注释
FixNamespaceComments: true
# 缩进case标签
IndentCaseLabels: true
IndentPPDirectives: BeforeHash
# 缩进宽度
IndentWidth: 4
# 函数返回类型换行时,缩进函数声明或函数定义的函数名
IndentWrappedFunctionNames: false
# 保留在块开始处的空行
KeepEmptyLinesAtTheStartOfBlocks: false
# 连续空行的最大数量
MaxEmptyLinesToKeep: 1
# 命名空间的缩进: None, Inner(缩进嵌套的命名空间中的内容), All
NamespaceIndentation: All
# 指针和引用的对齐: Left, Right, Middle
PointerAlignment: Right
# 允许重新排版注释
ReflowComments: true
# 允许排序#include
SortIncludes: false
# 允许排序 using 声明
SortUsingDeclarations: false
# 在C风格类型转换后添加空格
SpaceAfterCStyleCast: true
# true -> (int) 0.1 false-> (int)0.1
# 在Template 关键字后面添加空格
SpaceAfterTemplateKeyword: true
# 在赋值运算符之前添加空格
SpaceBeforeAssignmentOperators: true
# SpaceBeforeCpp11BracedList: true
# SpaceBeforeCtorInitializerColon: true
# SpaceBeforeInheritanceColon: true
# 开圆括号之前添加一个空格: Never, ControlStatements, Always
SpaceBeforeParens: ControlStatements
# SpaceBeforeRangeBasedForLoopColon: true
# 在空的圆括号中添加空格
SpaceInEmptyParentheses: false
# 在尾随的评论前添加的空格数(只适用于//)
SpacesBeforeTrailingComments: 1
# 在尖括号的<后和>前添加空格
SpacesInAngles: false
# 在C风格类型转换的括号中添加空格
SpacesInCStyleCastParentheses: false
# 在容器(ObjC和JavaScript的数组和字典等)字面量中添加空格
SpacesInContainerLiterals: true
# 在圆括号的(后和)前添加空格
SpacesInParentheses: false
# 在方括号的[后和]前添加空格lamda表达式和未指明大小的数组的声明不受影响
SpacesInSquareBrackets: false
# 标准: Cpp03, Cpp11, Auto
Standard: Auto
# tab宽度
TabWidth: 4
# 使用tab字符: Never, ForIndentation, ForContinuationAndIndentation, Always
UseTab: Never

3
compile_flags.txt Normal file
View File

@@ -0,0 +1,3 @@
-std=c++2b
-static
-stdlib=libc++

33
src/.ci/Dockerfile Normal file
View File

@@ -0,0 +1,33 @@
FROM ubuntu:24.04
# 1. 设置镜像源(可选,用于加速)
RUN sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list && \
sed -i 's/security.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list
# 2. 一次性安装所有依赖工具链、库、CI工具
RUN apt-get update && \
apt-get install -y --no-install-recommends \
wget gnupg ca-certificates \
clang-19 lld-19 libc++-19-dev libc++abi-19-dev \
mingw-w64 g++-mingw-w64 \
git tar curl \
python3 python3-pip python3.12-venv libpython3.12 \
&& rm -rf /var/lib/apt/lists/* && \
update-alternatives --install /usr/bin/clang clang /usr/bin/clang-19 100 && \
update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-19 100 && \
ln -sf /usr/bin/ld.lld-19 /usr/bin/ld.lld
# 3. 安装xmake
RUN wget -O /usr/local/bin/xmake \
https://git.fig-lang.cn/PuqiAR/xmake-binary-copy/raw/commit/989d1f2dabb0bc8d5981a5f900c2cf7c2ac78ee4/xmake-bundle-v3.0.5.linux.x86_64 && \
chmod +x /usr/local/bin/xmake
# 4. 创建非root用户
RUN useradd -m -s /bin/bash builder
USER builder
WORKDIR /home/builder
RUN xmake --version | head -1 && \
clang++ --version | head -1 && \
git --version && \
echo "✅ 核心工具就绪"

View File

@@ -0,0 +1,365 @@
name: Release Build
on:
push:
tags: ["*"]
workflow_dispatch:
inputs:
version:
description: "版本号 (例如: v1.0.0)"
required: true
default: "dev-build"
jobs:
build-linux-x64:
runs-on: ubuntu
container:
image: git.fig-lang.cn/puqiar/fig-ci:base-latest
options: --network=host
steps:
- name: 验证构建环境
run: |
echo "=== 环境验证开始 ==="
xmake --version
clang++ --version | head -1
echo "=== 环境验证通过 ==="
- name: 检出代码
run: |
git clone https://git.fig-lang.cn/${{ github.repository }} .
git checkout ${{ github.ref }}
- name: 设置版本和提交信息
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
VERSION="${{ inputs.version }}"
else
VERSION="${{ github.ref_name }}"
fi
echo "构建版本: $VERSION"
echo "VERSION=$VERSION" >> $GITHUB_ENV
# 拿提交消息
COMMIT_MSG=$(git log -3 --pretty=%B)
echo "COMMIT_MSG<<EOF" >> $GITHUB_ENV
echo "$COMMIT_MSG" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
- name: 构建项目 (Linux)
run: |
echo "开始构建Linux版本..."
xmake f -p linux -a x86_64 -m release -y
xmake build -j$(nproc) Fig
echo "Linux构建成功。"
# 🔧 新增构建Linux平台安装器
- name: 构建Linux安装器
run: |
echo "开始构建Linux安装器..."
cd Installer/ConsoleInstaller
python3 -m venv venv
. venv/bin/activate
pip config set global.index-url https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple
# 安装依赖并构建
pip install --upgrade pip
pip install -r requirements.txt
python3 -m PyInstaller -F -n FigSetup-Linux --distpath ./dist/linux main.py
echo "Linux安装器构建完成"
- name: 打包Linux发布文件
run: |
VERSION="${{ env.VERSION }}"
PACKAGE_NAME="Fig-${VERSION}-linux-x86_64"
mkdir -p "${PACKAGE_NAME}"
cp build/linux/x86_64/release/Fig "${PACKAGE_NAME}/"
if [ -d "src/Module/Library" ]; then
cp -r src/Module/Library "${PACKAGE_NAME}/"
echo "已包含Library目录。"
fi
tar -czf "${PACKAGE_NAME}.tar.gz" "${PACKAGE_NAME}"
sha256sum "${PACKAGE_NAME}.tar.gz" > "${PACKAGE_NAME}.sha256"
echo "Linux打包完成: ${PACKAGE_NAME}.tar.gz"
- name: 发布Linux版本到Gitea
env:
GITEA_TOKEN: ${{ secrets.CI_TOKEN }}
run: |
VERSION="${{ env.VERSION }}"
if [ -z "$VERSION" ]; then
VERSION="${{ github.ref_name }}"
fi
COMMIT_MSG="${{ env.COMMIT_MSG }}"
API="https://git.fig-lang.cn/api/v1/repos/${{ github.repository }}"
echo "正在检查版本 $VERSION 的发布状态..."
# 准备 JSON 数据
VERSION="$VERSION" COMMIT_MSG="$COMMIT_MSG" python3 -c "import json, os; print(json.dumps({'tag_name': os.environ.get('VERSION', ''), 'name': 'Fig ' + os.environ.get('VERSION', ''), 'body': os.environ.get('COMMIT_MSG', ''), 'draft': False, 'prerelease': False}))" > release_body.json
# 1. 尝试获取已有发布
RESPONSE_TAG=$(curl -sS -H "Authorization: token $GITEA_TOKEN" "$API/releases/tags/$VERSION" 2>/dev/null || echo '{"id":0}')
RELEASE_ID=$(echo "$RESPONSE_TAG" | grep -o '"id":[0-9]*' | head -1 | cut -d':' -f2)
if [ -n "$RELEASE_ID" ] && [ "$RELEASE_ID" != "0" ]; then
echo "✅ 找到已有发布 (ID: $RELEASE_ID),正在更新说明..."
curl -sS -X PATCH -H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/json" \
-d @release_body.json \
"$API/releases/$RELEASE_ID" > /dev/null
else
echo "未找到已有发布,准备创建新发布..."
RESPONSE=$(curl -sS -X POST -H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/json" \
-d @release_body.json \
"$API/releases" 2>/dev/null || echo '{"id":0}')
RELEASE_ID=$(echo "$RESPONSE" | grep -o '"id":[0-9]*' | head -1 | cut -d':' -f2)
if [ -z "$RELEASE_ID" ] || [ "$RELEASE_ID" = "0" ]; then
# 再次尝试获取,防止并发冲突
RESPONSE_TAG=$(curl -sS -H "Authorization: token $GITEA_TOKEN" "$API/releases/tags/$VERSION" 2>/dev/null || echo '{"id":0}')
RELEASE_ID=$(echo "$RESPONSE_TAG" | grep -o '"id":[0-9]*' | head -1 | cut -d':' -f2)
fi
fi
if [ -z "$RELEASE_ID" ] || [ "$RELEASE_ID" = "0" ]; then
echo "❌ 错误:无法获取或创建发布 ID"
exit 1
fi
echo "✅ 使用发布 ID: $RELEASE_ID 进行上传"
# 上传资产
PACKAGE_ZIP="Fig-$VERSION-linux-x86_64.tar.gz"
PACKAGE_SHA="Fig-$VERSION-linux-x86_64.sha256"
echo "正在上传 $PACKAGE_ZIP ..."
curl -sS -X POST -H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/octet-stream" \
--data-binary "@$PACKAGE_ZIP" \
"$API/releases/$RELEASE_ID/assets?name=$PACKAGE_ZIP" > /dev/null
echo "正在上传 $PACKAGE_SHA ..."
curl -sS -X POST -H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: text/plain" \
--data-binary "@$PACKAGE_SHA" \
"$API/releases/$RELEASE_ID/assets?name=$PACKAGE_SHA" > /dev/null
# 🔧 上传Linux安装器
INSTALLER="Installer/ConsoleInstaller/dist/linux/FigSetup-Linux"
if [ -f "$INSTALLER" ]; then
echo "正在上传Linux安装器..."
curl -sS -X POST -H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/octet-stream" \
--data-binary "@$INSTALLER" \
"$API/releases/$RELEASE_ID/assets?name=FigSetup-Linux" > /dev/null
fi
echo "✅ Linux版本发布完成"
build-windows-x64:
runs-on: windows
steps:
- name: 验证Windows工具链
run: |
Set-ExecutionPolicy Bypass -Scope Process -Force
# 检查 xmake
if (Get-Command xmake -ErrorAction SilentlyContinue) {
Write-Host '✅ xmake 已安装'
xmake --version
} else { Write-Host '警告: xmake 未找到' }
# 检查 clang++
if (Get-Command clang++ -ErrorAction SilentlyContinue) {
Write-Host '✅ clang++ 已安装'
clang++ --version
} else { Write-Host '警告: clang++ 未找到' }
- name: 检出代码
run: |
$env:Path = "C:\Program Files\Git\cmd;$env:Path"
git clone https://git.fig-lang.cn/$env:GITHUB_REPOSITORY .
git checkout ${{ github.ref }}
- name: 设置版本和提交信息
run: |
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
if ($env:GITHUB_EVENT_NAME -eq 'workflow_dispatch') {
$VERSION = $env:INPUT_VERSION
if (-not $VERSION) { $VERSION = $env:VERSION_INPUT }
if (-not $VERSION) { $VERSION = "dev-build" }
} else {
$VERSION = "${{ github.ref_name }}"
}
Write-Host "构建版本: $VERSION"
# 确保无 BOM 的 UTF8
[System.IO.File]::AppendAllText($env:GITHUB_ENV, "VERSION=$VERSION`n")
# 提交消息
$COMMIT_MSG = git log -3 --pretty=%B
[System.IO.File]::AppendAllText($env:GITHUB_ENV, "COMMIT_MSG<<EOF`n$COMMIT_MSG`nEOF`n")
- name: 构建项目 (Windows Native)
run: |
xmake f -p windows -a x86_64 -m release -y
xmake build -j $env:NUMBER_OF_PROCESSORS Fig
Write-Host 'Windows构建成功。'
# 🔧 新增构建Windows平台安装器
- name: 构建Windows安装器
run: |
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
Write-Host "开始构建Windows安装器..."
cd Installer\ConsoleInstaller
pip install -r requirements.txt
pyinstaller -F -i logo.ico -n FigSetup --distpath .\dist\windows main.py
Write-Host "Windows安装器构建完成"
- name: 打包Windows发布文件
run: |
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$VERSION = $env:VERSION
if (-not $VERSION) {
$VERSION = "${{ github.ref_name }}"
Write-Host "⚠️ 警告:从环境变量获取 VERSION 失败,回退到 github.ref_name: $VERSION"
}
Write-Host "打包版本: $VERSION"
$PACKAGE_NAME = "Fig-${VERSION}-windows-x86_64"
Write-Host "打包名称: $PACKAGE_NAME"
New-Item -ItemType Directory -Force -Path $PACKAGE_NAME
# 查找可执行文件
if (Test-Path 'build\windows\x86_64\release\Fig.exe') {
Copy-Item 'build\windows\x86_64\release\Fig.exe' $PACKAGE_NAME\
} elseif (Test-Path 'build\windows\x86_64\release\Fig') {
Copy-Item 'build\windows\x86_64\release\Fig' $PACKAGE_NAME\Fig.exe
} else {
Write-Host '错误:未找到构建输出文件'
exit 1
}
if (Test-Path 'src\Module\Library') {
Copy-Item -Recurse 'src\Module\Library' $PACKAGE_NAME\
}
# 压缩文件
$ZIP_NAME = "$PACKAGE_NAME.zip"
Compress-Archive -Path $PACKAGE_NAME -DestinationPath $ZIP_NAME
# 生成校验文件
$Hash = Get-FileHash $ZIP_NAME -Algorithm SHA256
"$($Hash.Hash) $ZIP_NAME" | Out-File "$PACKAGE_NAME.sha256" -Encoding UTF8
Write-Host "Windows打包完成: $ZIP_NAME"
- name: 发布Windows版本到Gitea
env:
GITEA_TOKEN: ${{ secrets.CI_TOKEN }}
run: |
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$VERSION = $env:VERSION
$COMMIT_MSG = $env:COMMIT_MSG
if (-not $VERSION) {
$VERSION = "${{ github.ref_name }}"
Write-Host "⚠️ 警告:从环境变量获取 VERSION 失败,回退到 github.ref_name: $VERSION"
}
if (-not $VERSION) {
Write-Host "❌ 错误:版本号仍然为空,无法创建发布。"
exit 1
}
$REPO = $env:GITHUB_REPOSITORY
$API = "https://git.fig-lang.cn/api/v1/repos/$REPO"
$TOKEN = $env:GITEA_TOKEN
$HEADERS = @{
Authorization = "token $TOKEN"
'Content-Type' = 'application/json'
}
$ZIP_FILE = "Fig-$VERSION-windows-x86_64.zip"
$HASH_FILE = "Fig-$VERSION-windows-x86_64.sha256"
$INSTALLER_PATH = "Installer\ConsoleInstaller\dist\windows\FigSetup.exe"
if (-not (Test-Path $ZIP_FILE)) {
Write-Host "❌ 错误找不到ZIP文件 $ZIP_FILE"
exit 1
}
$CREATE_BODY = @{
tag_name = $VERSION
name = "Fig $VERSION"
body = $COMMIT_MSG
draft = $false
prerelease = $false
} | ConvertTo-Json -Compress
Write-Host "正在检查版本 $VERSION 的发布状态..."
$RELEASE_ID = $null
try {
$EXISTING = Invoke-RestMethod -Uri "$API/releases/tags/$VERSION" -Headers $HEADERS -ErrorAction Stop
if ($EXISTING -and $EXISTING.id) {
$RELEASE_ID = $EXISTING.id
Write-Host "✅ 找到已有发布 (ID: $RELEASE_ID),正在更新..."
Invoke-RestMethod -Method Patch -Uri "$API/releases/$RELEASE_ID" -Headers $HEADERS -Body $CREATE_BODY -ErrorAction Stop | Out-Null
}
} catch {
Write-Host "未找到已有发布,准备创建新发布..."
}
if (-not $RELEASE_ID) {
try {
Write-Host "正在创建新发布: $VERSION ..."
$RESPONSE = Invoke-RestMethod -Method Post -Uri "$API/releases" -Headers $HEADERS -Body $CREATE_BODY -ErrorAction Stop
$RELEASE_ID = $RESPONSE.id
Write-Host "✅ 发布创建成功 (ID: $RELEASE_ID)"
} catch {
$err = $_.Exception.Message
Write-Host "❌ 创建发布失败: $err"
# 最后一次尝试:再次尝试按标签获取,防止由于并发导致的冲突
try {
$RETRY = Invoke-RestMethod -Uri "$API/releases/tags/$VERSION" -Headers $HEADERS -ErrorAction Stop
$RELEASE_ID = $RETRY.id
Write-Host "✅ 重试获取发布成功 (ID: $RELEASE_ID)"
} catch {
Write-Host "❌ 无法获取或创建发布 ID"
exit 1
}
}
}
# 上传资产
Write-Host "正在上传文件..."
$ASSETS = @(
@{ Name = $ZIP_FILE; Path = $ZIP_FILE; ContentType = "application/octet-stream" },
@{ Name = $HASH_FILE; Path = $HASH_FILE; ContentType = "text/plain" }
)
if (Test-Path $INSTALLER_PATH) {
$ASSETS += @{ Name = "FigSetup.exe"; Path = $INSTALLER_PATH; ContentType = "application/octet-stream" }
}
foreach ($asset in $ASSETS) {
Write-Host "正在上传 $($asset.Name) ..."
try {
# 如果资产已存在Gitea 可能会报错,这里简单处理
Invoke-RestMethod -Method Post -Uri "$API/releases/$RELEASE_ID/assets?name=$($asset.Name)" `
-Headers @{ Authorization = "token $TOKEN"; 'Content-Type' = $asset.ContentType } `
-InFile $asset.Path -ErrorAction SilentlyContinue | Out-Null
} catch {
Write-Host "⚠️ 上传 $($asset.Name) 失败,可能已存在。"
}
}
Write-Host "✅ Windows版本发布完成"

View File

@@ -0,0 +1,79 @@
var any_var; // type is Any
var number = 10; // type is Int
number = "123"; // valid
var number2 := 10; // specific type is Int
var number3: Int = 10; // both is ok
/*
number2 = 3.14;
invalid!
*/
const Pi := 3.14; // recommended, auto detect type
// equal -> const Pi: Double = 3.14;
/*
In fig, we have 13 builtin-type
01 Any
02 Null
03 Int
04 String
05 Bool
06 Double
07 Function
08 StructType
09 StructInstance
10 List
11 Map
12 Module
13 InterfaceType
3, 4, 5, 6, 10, 11 are initable
value system:
object is immutable
(included basic types: Int, String...)
`variable` is a name, refers to an object
assignment is to bind name to value
Example: var a := 10;
[name] 'a' ---> variable slot (name, declared type, access modifier, [value) ---> ObjectPtr ---> raw Object class
bind bind (shared_ptr)
For example:
var a := 10;
var b := 10;
`a` and `b` reference to the same object in memory
a = 20;
now a refers to a new object (20, Int)
what about complex types?
they actually have same behaviors with basic types
var a := [1, 2, 3, 4];
var b := a;
> a
[1, 2, 3, 4]
> b
[1, 2, 3, 4]
set a[0] to 5
> a
[5, 2, 3, 4]
> b
[5, 2, 3, 4]
Why did such a result occur?
" `a` and `b` reference to the same object in memory "
If you wish to obtain a copy, use List {a} to deeply copy it
*/

View File

@@ -0,0 +1,16 @@
import std.io;
func greeting(name:String) -> String
{
return "Hello " + name + "!";
}
io.println(greeting("Fig"));
func adder(x)
{
return func (n) => x + n; // closure
}
const add2 = adder(2);
io.println(add2(3));

View 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)

View 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);

View File

@@ -0,0 +1,15 @@
import std.io;
import token {Token, TokenType};
import tokenizer {Tokenizer};
const src := "abc egaD";
const tokenizer := new Tokenizer{src};
const result := tokenizer.TokenizeAll();
for var i := 0; i < result.length(); i += 1
{
const tok := result[i];
io.printf("{}: {}\n", tok.literal, tok.type);
}

View File

@@ -0,0 +1,31 @@
/*
Example code: FigFig
Token.fig
Copyright (C) 2020-2026 PuqiAR
*/
struct _TokenTypes
{
public EOF = -1;
public Identifier = 0;
public StringLiteral = 1;
public NumberLiteral = 2;
public True = 3;
public False = 4;
public Null = 5;
public Plus = 6;
public Minus = 7;
public Asterisk = 8;
public Slash = 9;
}
public const TokenType := new _TokenTypes{};
public struct Token
{
public literal: String = "";
public type: Int = TokenType.EOF;
}

View File

@@ -0,0 +1,102 @@
/*
Example code: FigFig
Tokenizer.fig
Copyright (C) 2020-2026 PuqiAR
*/
import token {Token, TokenType};
func list_contains(lst: List, value: Any) -> Bool
{
for var i := 0; i < lst.length(); i += 1
{
if lst[i] == value
{
return true;
}
}
return false;
}
func isspace(c: String) -> Bool
{
return c == " " || c == "\n" || c == "\t";
}
func isalpha(c: String) -> Bool
{
const alb := [
"a", "b", "c", "d",
"e", "f", "g", "h",
"i", "j", "k", "l",
"m", "n", "o", "p",
"q", "r", "s", "t",
"u", "v", "w", "x",
"y", "z",
"A", "B", "C", "D",
"E", "F", "G", "H",
"I", "J", "K", "L",
"M", "N", "O", "P",
"Q", "R", "S", "T",
"U", "V", "W", "X",
"Y", "Z"
];
return list_contains(alb, c);
}
public struct Tokenizer
{
src: String = "";
idx: Int = 0;
func next() -> Null
{
idx += 1;
}
func hasNext() -> Bool
{
return idx < src.length();
}
func produce() -> String
{
const tmp := src[idx];
idx += 1;
return tmp;
}
func current() -> String
{
return src[idx];
}
public func TokenizeAll() -> List
{
var output := [];
const push := func (tok: Token) => output.push(tok);
while hasNext()
{
while hasNext() && isspace(current())
{
next();
}
if isalpha(current())
{
var identi := "";
while hasNext() && isalpha(current())
{
identi += produce();
}
push(new Token{identi, TokenType.Identifier});
}
}
return output;
}
}

View File

@@ -0,0 +1,13 @@
import std.io;
func fib(x:Int) -> Int
{
if (x <= 1)
{
return x;
}
return fib(x-1) + fib(x-2);
}
var result := fib(25);
io.println("result: ", result);

View File

@@ -0,0 +1,11 @@
from time import time as tt
def fib(x:int) -> int:
if x <= 1: return x;
return fib(x-1) + fib(x-2)
if __name__ == '__main__':
t0 = tt()
result = fib(30)
t1 = tt()
print('cost: ',t1-t0, 'result:', result)

View File

@@ -0,0 +1,84 @@
import std.io;
import std.time;
import std.value;
func benchmark(fn: Function, arg: Any) -> Null
{
io.println("Testing fn:", fn, "with arg:", arg);
const start := time.now();
const result := fn(arg);
const end := time.now();
const duration := new time.Time{
end.since(start)
};
io.println("=" * 50);
io.println("fn returns:", result, "\n");
io.println("Cost:", duration.toSeconds(), "s");
io.println(" ", duration.toMillis(), "ms");
}
var memo := {};
func fib_memo(x)
{
if memo.contains(x)
{
return memo.get(x);
}
if x <= 1
{
memo[x] = x;
return x;
}
var result := fib_memo(x - 1) + fib_memo(x - 2);
memo[x] = result;
return result;
}
func fib_iter(n)
{
var a := 0;
var b := 1;
for var i := 0; i < n; i = i + 1
{
var temp := a + b;
a = b;
b = temp;
}
return a;
}
func fib(x)
{
if x <= 1
{
return x;
}
return fib(x - 1) + fib(x - 2);
}
func fib_tail(n, a=0, b=1) {
if n == 0 { return a; }
if n == 1 { return b; }
return fib_tail(n-1, b, a+b);
}
const n := 30;
io.println("! fib(" + value.string_from(n) + "):");
benchmark(fib, n);
io.print("\n\n");
io.println("! fib_memo(" + value.string_from(n) + "):");
benchmark(fib_memo, n);
io.print("\n\n");
io.println("! fib_iter(" + value.string_from(n) + "):");
benchmark(fib_iter, n);
io.print("\n\n");
io.println("! fib_tail(" + value.string_from(n) + "):");
benchmark(fib_tail, n);
io.print("\n\n");

View File

@@ -0,0 +1,27 @@
import std.io;
import std.value;
var callCnt:Int = 0;
func fib(x:Int) -> Int
{
callCnt = callCnt + 1;
if (x <= 1)
{
return x;
}
return fib(x-1) + fib(x-2);
}
var fibx:Int;
io.print("input an index of fib ");
fibx = value.int_parse(io.read());
var cnt:Int = 0;
io.println("test forever");
while (true)
{
cnt = cnt + 1;
io.println("test ", cnt,",result: ", fib(fibx));
io.println("func `fib` called ", callCnt);
callCnt = 0;
}

View File

@@ -0,0 +1,29 @@
import std.io;
import std.test;
var ascii_string_test := new test.Test{
"ascii_string_test",
func () => io.println("Hello," + " world!"),
2
};
var unicode_string_test := new test.Test{
"unicode_string_test",
func () => io.println("你好," + " 世界!"),
2
};
var unicode_string_inserting_test := new test.Test{
"unicode_string_inserting_test",
func (){
var str := "我是你的粑粑";
str.insert(1, "不");
return str;
},
"我不是你的粑粑"
};
var tests := [ascii_string_test, unicode_string_test, unicode_string_inserting_test];
var tester := new test.Tester{tests};
tester.TestAll();

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,44 @@
// __ __ _ ______ _____
// | \/ | (_) | ____| / ____|_ _
// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_
// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _|
// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_|
// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____|
// __/ | https://github.com/Neargye/magic_enum
// |___/ version 0.9.7
//
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
// SPDX-License-Identifier: MIT
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@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.
#ifndef NEARGYE_MAGIC_ENUM_ALL_HPP
#define NEARGYE_MAGIC_ENUM_ALL_HPP
#include "magic_enum.hpp"
#include "magic_enum_containers.hpp"
#include "magic_enum_flags.hpp"
#include "magic_enum_format.hpp"
#include "magic_enum_fuse.hpp"
#include "magic_enum_iostream.hpp"
#include "magic_enum_switch.hpp"
#include "magic_enum_utility.hpp"
#endif // NEARGYE_MAGIC_ENUM_ALL_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,222 @@
// __ __ _ ______ _____
// | \/ | (_) | ____| / ____|_ _
// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_
// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _|
// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_|
// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____|
// __/ | https://github.com/Neargye/magic_enum
// |___/ version 0.9.7
//
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
// SPDX-License-Identifier: MIT
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@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.
#ifndef NEARGYE_MAGIC_ENUM_FLAGS_HPP
#define NEARGYE_MAGIC_ENUM_FLAGS_HPP
#include "magic_enum.hpp"
#if defined(__clang__)
# pragma clang diagnostic push
#elif defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // May be used uninitialized 'return {};'.
#elif defined(_MSC_VER)
# pragma warning(push)
#endif
namespace magic_enum {
namespace detail {
template <typename E, enum_subtype S, typename U = std::underlying_type_t<E>>
constexpr U values_ors() noexcept {
static_assert(S == enum_subtype::flags, "magic_enum::detail::values_ors requires valid subtype.");
auto ors = U{0};
for (std::size_t i = 0; i < count_v<E, S>; ++i) {
ors |= static_cast<U>(values_v<E, S>[i]);
}
return ors;
}
} // namespace magic_enum::detail
// Returns name from enum-flags value.
// If enum-flags value does not have name or value out of range, returns empty string.
template <typename E>
[[nodiscard]] auto enum_flags_name(E value, char_type sep = static_cast<char_type>('|')) -> detail::enable_if_t<E, string> {
using D = std::decay_t<E>;
using U = underlying_type_t<D>;
constexpr auto S = detail::enum_subtype::flags;
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
string name;
auto check_value = U{0};
for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
if (const auto v = static_cast<U>(enum_value<D, S>(i)); (static_cast<U>(value) & v) != 0) {
if (const auto n = detail::names_v<D, S>[i]; !n.empty()) {
check_value |= v;
if (!name.empty()) {
name.append(1, sep);
}
name.append(n.data(), n.size());
} else {
return {}; // Value out of range.
}
}
}
if (check_value != 0 && check_value == static_cast<U>(value)) {
return name;
}
return {}; // Invalid value or out of range.
}
// Obtains enum-flags value from integer value.
// Returns optional with enum-flags value.
template <typename E>
[[nodiscard]] constexpr auto enum_flags_cast(underlying_type_t<E> value) noexcept -> detail::enable_if_t<E, optional<std::decay_t<E>>> {
using D = std::decay_t<E>;
using U = underlying_type_t<D>;
constexpr auto S = detail::enum_subtype::flags;
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
if constexpr (detail::count_v<D, S> == 0) {
static_cast<void>(value);
return {}; // Empty enum.
} else {
if constexpr (detail::is_sparse_v<D, S>) {
auto check_value = U{0};
for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
if (const auto v = static_cast<U>(enum_value<D, S>(i)); (value & v) != 0) {
check_value |= v;
}
}
if (check_value != 0 && check_value == value) {
return static_cast<D>(value);
}
} else {
constexpr auto min = detail::min_v<D, S>;
constexpr auto max = detail::values_ors<D, S>();
if (value >= min && value <= max) {
return static_cast<D>(value);
}
}
return {}; // Invalid value or out of range.
}
}
// Obtains enum-flags value from name.
// Returns optional with enum-flags value.
template <typename E, typename BinaryPredicate = std::equal_to<>>
[[nodiscard]] constexpr auto enum_flags_cast(string_view value, [[maybe_unused]] BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable<BinaryPredicate>()) -> detail::enable_if_t<E, optional<std::decay_t<E>>, BinaryPredicate> {
using D = std::decay_t<E>;
using U = underlying_type_t<D>;
constexpr auto S = detail::enum_subtype::flags;
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
if constexpr (detail::count_v<D, S> == 0) {
static_cast<void>(value);
return {}; // Empty enum.
} else {
auto result = U{0};
while (!value.empty()) {
const auto d = detail::find(value, '|');
const auto s = (d == string_view::npos) ? value : value.substr(0, d);
auto f = U{0};
for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
if (detail::cmp_equal(s, detail::names_v<D, S>[i], p)) {
f = static_cast<U>(enum_value<D, S>(i));
result |= f;
break;
}
}
if (f == U{0}) {
return {}; // Invalid value or out of range.
}
value.remove_prefix((d == string_view::npos) ? value.size() : d + 1);
}
if (result != U{0}) {
return static_cast<D>(result);
}
return {}; // Invalid value or out of range.
}
}
// Checks whether enum-flags contains value with such value.
template <typename E>
[[nodiscard]] constexpr auto enum_flags_contains(E value) noexcept -> detail::enable_if_t<E, bool> {
using D = std::decay_t<E>;
using U = underlying_type_t<D>;
return static_cast<bool>(enum_flags_cast<D>(static_cast<U>(value)));
}
// Checks whether enum-flags contains value with such integer value.
template <typename E>
[[nodiscard]] constexpr auto enum_flags_contains(underlying_type_t<E> value) noexcept -> detail::enable_if_t<E, bool> {
using D = std::decay_t<E>;
return static_cast<bool>(enum_flags_cast<D>(value));
}
// Checks whether enum-flags contains enumerator with such name.
template <typename E, typename BinaryPredicate = std::equal_to<>>
[[nodiscard]] constexpr auto enum_flags_contains(string_view value, BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable<BinaryPredicate>()) -> detail::enable_if_t<E, bool, BinaryPredicate> {
using D = std::decay_t<E>;
return static_cast<bool>(enum_flags_cast<D>(value, std::move(p)));
}
// Checks whether `flags set` contains `flag`.
// Note: If `flag` equals 0, it returns false, as 0 is not a flag.
template <typename E>
constexpr auto enum_flags_test(E flags, E flag) noexcept -> detail::enable_if_t<E, bool> {
using U = underlying_type_t<E>;
return static_cast<U>(flag) && ((static_cast<U>(flags) & static_cast<U>(flag)) == static_cast<U>(flag));
}
// Checks whether `lhs flags set` and `rhs flags set` have common flags.
// Note: If `lhs flags set` or `rhs flags set` equals 0, it returns false, as 0 is not a flag, and therfore cannot have any matching flag.
template <typename E>
constexpr auto enum_flags_test_any(E lhs, E rhs) noexcept -> detail::enable_if_t<E, bool> {
using U = underlying_type_t<E>;
return (static_cast<U>(lhs) & static_cast<U>(rhs)) != 0;
}
} // namespace magic_enum
#if defined(__clang__)
# pragma clang diagnostic pop
#elif defined(__GNUC__)
# pragma GCC diagnostic pop
#elif defined(_MSC_VER)
# pragma warning(pop)
#endif
#endif // NEARGYE_MAGIC_ENUM_FLAGS_HPP

View File

@@ -0,0 +1,114 @@
// __ __ _ ______ _____
// | \/ | (_) | ____| / ____|_ _
// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_
// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _|
// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_|
// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____|
// __/ | https://github.com/Neargye/magic_enum
// |___/ version 0.9.7
//
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
// SPDX-License-Identifier: MIT
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@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.
#ifndef NEARGYE_MAGIC_ENUM_FORMAT_HPP
#define NEARGYE_MAGIC_ENUM_FORMAT_HPP
#include "magic_enum.hpp"
#include "magic_enum_flags.hpp"
#if !defined(MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT)
# define MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT 1
# define MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT_AUTO_DEFINE
#endif
namespace magic_enum::customize {
// customize enum to enable/disable automatic std::format
template <typename E>
constexpr bool enum_format_enabled() noexcept {
return MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT;
}
} // magic_enum::customize
#if defined(__cpp_lib_format)
#ifndef MAGIC_ENUM_USE_STD_MODULE
#include <format>
#endif
template <typename E>
struct std::formatter<E, std::enable_if_t<std::is_enum_v<std::decay_t<E>> && magic_enum::customize::enum_format_enabled<E>(), char>> : std::formatter<std::string_view, char> {
template <class FormatContext>
auto format(E e, FormatContext& ctx) const {
static_assert(std::is_same_v<char, string_view::value_type>, "formatter requires string_view::value_type type same as char.");
using D = std::decay_t<E>;
if constexpr (magic_enum::detail::supported<D>::value) {
if constexpr (magic_enum::detail::subtype_v<D> == magic_enum::detail::enum_subtype::flags) {
if (const auto name = magic_enum::enum_flags_name<D>(e); !name.empty()) {
return formatter<std::string_view, char>::format(std::string_view{name.data(), name.size()}, ctx);
}
} else {
if (const auto name = magic_enum::enum_name<D>(e); !name.empty()) {
return formatter<std::string_view, char>::format(std::string_view{name.data(), name.size()}, ctx);
}
}
}
return formatter<std::string_view, char>::format(std::to_string(magic_enum::enum_integer<D>(e)), ctx);
}
};
#endif
#if defined(FMT_VERSION)
#include <fmt/format.h>
template <typename E>
struct fmt::formatter<E, std::enable_if_t<std::is_enum_v<std::decay_t<E>> && magic_enum::customize::enum_format_enabled<E>(), char>> : fmt::formatter<std::string_view> {
template <class FormatContext>
auto format(E e, FormatContext& ctx) const {
static_assert(std::is_same_v<char, string_view::value_type>, "formatter requires string_view::value_type type same as char.");
using D = std::decay_t<E>;
if constexpr (magic_enum::detail::supported<D>::value) {
if constexpr (magic_enum::detail::subtype_v<D> == magic_enum::detail::enum_subtype::flags) {
if (const auto name = magic_enum::enum_flags_name<D>(e); !name.empty()) {
return formatter<std::string_view, char>::format(std::string_view{name.data(), name.size()}, ctx);
}
} else {
if (const auto name = magic_enum::enum_name<D>(e); !name.empty()) {
return formatter<std::string_view, char>::format(std::string_view{name.data(), name.size()}, ctx);
}
}
}
return formatter<std::string_view, char>::format(std::to_string(magic_enum::enum_integer<D>(e)), ctx);
}
};
#endif
#if defined(MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT_AUTO_DEFINE)
# undef MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT
# undef MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT_AUTO_DEFINE
#endif
#endif // NEARGYE_MAGIC_ENUM_FORMAT_HPP

View File

@@ -0,0 +1,89 @@
// __ __ _ ______ _____
// | \/ | (_) | ____| / ____|_ _
// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_
// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _|
// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_|
// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____|
// __/ | https://github.com/Neargye/magic_enum
// |___/ version 0.9.7
//
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
// SPDX-License-Identifier: MIT
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@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.
#ifndef NEARGYE_MAGIC_ENUM_FUSE_HPP
#define NEARGYE_MAGIC_ENUM_FUSE_HPP
#include "magic_enum.hpp"
namespace magic_enum {
namespace detail {
template <typename E>
constexpr optional<std::uintmax_t> fuse_one_enum(optional<std::uintmax_t> hash, E value) noexcept {
if (hash) {
if (const auto index = enum_index(value)) {
return (*hash << log2((enum_count<E>() << 1) - 1)) | *index;
}
}
return {};
}
template <typename E>
constexpr optional<std::uintmax_t> fuse_enum(E value) noexcept {
return fuse_one_enum(0, value);
}
template <typename E, typename... Es>
constexpr optional<std::uintmax_t> fuse_enum(E head, Es... tail) noexcept {
return fuse_one_enum(fuse_enum(tail...), head);
}
template <typename... Es>
constexpr auto typesafe_fuse_enum(Es... values) noexcept {
enum class enum_fuse_t : std::uintmax_t;
const auto fuse = fuse_enum(values...);
if (fuse) {
return optional<enum_fuse_t>{static_cast<enum_fuse_t>(*fuse)};
}
return optional<enum_fuse_t>{};
}
} // namespace magic_enum::detail
// Returns a bijective mix of several enum values. This can be used to emulate 2D switch/case statements.
template <typename... Es>
[[nodiscard]] constexpr auto enum_fuse(Es... values) noexcept {
static_assert((std::is_enum_v<std::decay_t<Es>> && ...), "magic_enum::enum_fuse requires enum type.");
static_assert(sizeof...(Es) >= 2, "magic_enum::enum_fuse requires at least 2 values.");
static_assert((detail::log2(enum_count<std::decay_t<Es>>() + 1) + ...) <= (sizeof(std::uintmax_t) * 8), "magic_enum::enum_fuse does not work for large enums");
#if defined(MAGIC_ENUM_NO_TYPESAFE_ENUM_FUSE)
const auto fuse = detail::fuse_enum<std::decay_t<Es>...>(values...);
#else
const auto fuse = detail::typesafe_fuse_enum<std::decay_t<Es>...>(values...);
#endif
return MAGIC_ENUM_ASSERT(fuse), fuse;
}
} // namespace magic_enum
#endif // NEARGYE_MAGIC_ENUM_FUSE_HPP

View File

@@ -0,0 +1,117 @@
// __ __ _ ______ _____
// | \/ | (_) | ____| / ____|_ _
// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_
// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _|
// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_|
// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____|
// __/ | https://github.com/Neargye/magic_enum
// |___/ version 0.9.7
//
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
// SPDX-License-Identifier: MIT
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@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.
#ifndef NEARGYE_MAGIC_ENUM_IOSTREAM_HPP
#define NEARGYE_MAGIC_ENUM_IOSTREAM_HPP
#include "magic_enum.hpp"
#include "magic_enum_flags.hpp"
#ifndef MAGIC_ENUM_USE_STD_MODULE
#include <iosfwd>
#endif
namespace magic_enum {
namespace ostream_operators {
template <typename Char, typename Traits, typename E, detail::enable_if_t<E, int> = 0>
std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os, E value) {
using D = std::decay_t<E>;
using U = underlying_type_t<D>;
if constexpr (detail::supported<D>::value) {
if constexpr (detail::subtype_v<D> == detail::enum_subtype::flags) {
if (const auto name = enum_flags_name<D>(value); !name.empty()) {
for (const auto c : name) {
os.put(c);
}
return os;
}
} else {
if (const auto name = enum_name<D>(value); !name.empty()) {
for (const auto c : name) {
os.put(c);
}
return os;
}
}
}
return (os << static_cast<U>(value));
}
template <typename Char, typename Traits, typename E, detail::enable_if_t<E, int> = 0>
std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os, optional<E> value) {
return value ? (os << *value) : os;
}
} // namespace magic_enum::ostream_operators
namespace istream_operators {
template <typename Char, typename Traits, typename E, detail::enable_if_t<E, int> = 0>
std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& is, E& value) {
using D = std::decay_t<E>;
std::basic_string<Char, Traits> s;
is >> s;
if constexpr (detail::supported<D>::value) {
if constexpr (detail::subtype_v<D> == detail::enum_subtype::flags) {
if (const auto v = enum_flags_cast<D>(s)) {
value = *v;
} else {
is.setstate(std::basic_ios<Char>::failbit);
}
} else {
if (const auto v = enum_cast<D>(s)) {
value = *v;
} else {
is.setstate(std::basic_ios<Char>::failbit);
}
}
} else {
is.setstate(std::basic_ios<Char>::failbit);
}
return is;
}
} // namespace magic_enum::istream_operators
namespace iostream_operators {
using magic_enum::ostream_operators::operator<<;
using magic_enum::istream_operators::operator>>;
} // namespace magic_enum::iostream_operators
} // namespace magic_enum
#endif // NEARGYE_MAGIC_ENUM_IOSTREAM_HPP

View File

@@ -0,0 +1,195 @@
// __ __ _ ______ _____
// | \/ | (_) | ____| / ____|_ _
// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_
// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _|
// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_|
// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____|
// __/ | https://github.com/Neargye/magic_enum
// |___/ version 0.9.7
//
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
// SPDX-License-Identifier: MIT
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@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.
#ifndef NEARGYE_MAGIC_ENUM_SWITCH_HPP
#define NEARGYE_MAGIC_ENUM_SWITCH_HPP
#include "magic_enum.hpp"
namespace magic_enum {
namespace detail {
struct default_result_type {};
template <typename T>
struct identity {
using type = T;
};
struct nonesuch {};
template <typename F, typename V, bool = std::is_invocable_v<F, V>>
struct invoke_result : identity<nonesuch> {};
template <typename F, typename V>
struct invoke_result<F, V, true> : std::invoke_result<F, V> {};
template <typename F, typename V>
using invoke_result_t = typename invoke_result<F, V>::type;
template <typename E, enum_subtype S, typename F, std::size_t... I>
constexpr auto common_invocable(std::index_sequence<I...>) noexcept {
static_assert(std::is_enum_v<E>, "magic_enum::detail::invocable_index requires enum type.");
if constexpr (count_v<E, S> == 0) {
return identity<nonesuch>{};
} else {
return std::common_type<invoke_result_t<F, enum_constant<values_v<E, S>[I]>>...>{};
}
}
template <typename E, enum_subtype S, typename Result, typename F>
constexpr auto result_type() noexcept {
static_assert(std::is_enum_v<E>, "magic_enum::detail::result_type requires enum type.");
constexpr auto seq = std::make_index_sequence<count_v<E, S>>{};
using R = typename decltype(common_invocable<E, S, F>(seq))::type;
if constexpr (std::is_same_v<Result, default_result_type>) {
if constexpr (std::is_same_v<R, nonesuch>) {
return identity<void>{};
} else {
return identity<R>{};
}
} else {
if constexpr (std::is_convertible_v<R, Result>) {
return identity<Result>{};
} else if constexpr (std::is_convertible_v<Result, R>) {
return identity<R>{};
} else {
return identity<nonesuch>{};
}
}
}
template <typename E, enum_subtype S, typename Result, typename F, typename D = std::decay_t<E>, typename R = typename decltype(result_type<D, S, Result, F>())::type>
using result_t = std::enable_if_t<std::is_enum_v<D> && !std::is_same_v<R, nonesuch>, R>;
#if !defined(MAGIC_ENUM_ENABLE_HASH) && !defined(MAGIC_ENUM_ENABLE_HASH_SWITCH)
template <typename T = void>
inline constexpr auto default_result_type_lambda = []() noexcept(std::is_nothrow_default_constructible_v<T>) { return T{}; };
template <>
inline constexpr auto default_result_type_lambda<void> = []() noexcept {};
template <std::size_t I, std::size_t End, typename R, typename E, enum_subtype S, typename F, typename Def>
constexpr decltype(auto) constexpr_switch_impl(F&& f, E value, Def&& def) {
if constexpr(I < End) {
constexpr auto v = enum_constant<enum_value<E, I, S>()>{};
if (value == v) {
if constexpr (std::is_invocable_r_v<R, F, decltype(v)>) {
return static_cast<R>(std::forward<F>(f)(v));
} else {
return def();
}
} else {
return constexpr_switch_impl<I + 1, End, R, E, S>(std::forward<F>(f), value, std::forward<Def>(def));
}
} else {
return def();
}
}
template <typename R, typename E, enum_subtype S, typename F, typename Def>
constexpr decltype(auto) constexpr_switch(F&& f, E value, Def&& def) {
static_assert(is_enum_v<E>, "magic_enum::detail::constexpr_switch requires enum type.");
if constexpr (count_v<E, S> == 0) {
return def();
} else {
return constexpr_switch_impl<0, count_v<E, S>, R, E, S>(std::forward<F>(f), value, std::forward<Def>(def));
}
}
#endif
} // namespace magic_enum::detail
template <typename Result = detail::default_result_type, typename E, detail::enum_subtype S = detail::subtype_v<E>, typename F, typename R = detail::result_t<E, S, Result, F>>
constexpr decltype(auto) enum_switch(F&& f, E value) {
using D = std::decay_t<E>;
static_assert(std::is_enum_v<D>, "magic_enum::enum_switch requires enum type.");
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
#if defined(MAGIC_ENUM_ENABLE_HASH) || defined(MAGIC_ENUM_ENABLE_HASH_SWITCH)
return detail::constexpr_switch<&detail::values_v<D, S>, detail::case_call_t::value>(
std::forward<F>(f),
value,
detail::default_result_type_lambda<R>);
#else
return detail::constexpr_switch<R, D, S>(
std::forward<F>(f),
value,
detail::default_result_type_lambda<R>);
#endif
}
template <typename Result = detail::default_result_type, detail::enum_subtype S, typename E, typename F, typename R = detail::result_t<E, S, Result, F>>
constexpr decltype(auto) enum_switch(F&& f, E value) {
return enum_switch<Result, E, S>(std::forward<F>(f), value);
}
template <typename Result, typename E, detail::enum_subtype S = detail::subtype_v<E>, typename F, typename R = detail::result_t<E, S, Result, F>>
constexpr decltype(auto) enum_switch(F&& f, E value, Result&& result) {
using D = std::decay_t<E>;
static_assert(std::is_enum_v<D>, "magic_enum::enum_switch requires enum type.");
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
#if defined(MAGIC_ENUM_ENABLE_HASH) || defined(MAGIC_ENUM_ENABLE_HASH_SWITCH)
return detail::constexpr_switch<&detail::values_v<D, S>, detail::case_call_t::value>(
std::forward<F>(f),
value,
[&result]() -> R { return std::forward<Result>(result); });
#else
return detail::constexpr_switch<R, D, S>(
std::forward<F>(f),
value,
[&result]() -> R { return std::forward<Result>(result); });
#endif
}
template <typename Result, detail::enum_subtype S, typename E, typename F, typename R = detail::result_t<E, S, Result, F>>
constexpr decltype(auto) enum_switch(F&& f, E value, Result&& result) {
return enum_switch<Result, E, S>(std::forward<F>(f), value, std::forward<Result>(result));
}
} // namespace magic_enum
template <>
struct std::common_type<magic_enum::detail::nonesuch, magic_enum::detail::nonesuch> : magic_enum::detail::identity<magic_enum::detail::nonesuch> {};
template <typename T>
struct std::common_type<T, magic_enum::detail::nonesuch> : magic_enum::detail::identity<T> {};
template <typename T>
struct std::common_type<magic_enum::detail::nonesuch, T> : magic_enum::detail::identity<T> {};
#endif // NEARGYE_MAGIC_ENUM_SWITCH_HPP

View File

@@ -0,0 +1,138 @@
// __ __ _ ______ _____
// | \/ | (_) | ____| / ____|_ _
// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_
// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _|
// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_|
// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____|
// __/ | https://github.com/Neargye/magic_enum
// |___/ version 0.9.7
//
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
// SPDX-License-Identifier: MIT
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@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.
#ifndef NEARGYE_MAGIC_ENUM_UTILITY_HPP
#define NEARGYE_MAGIC_ENUM_UTILITY_HPP
#include "magic_enum.hpp"
namespace magic_enum {
namespace detail {
template <typename E, enum_subtype S, typename F, std::size_t... I>
constexpr auto for_each(F&& f, std::index_sequence<I...>) {
constexpr bool has_void_return = (std::is_void_v<std::invoke_result_t<F, enum_constant<values_v<E, S>[I]>>> || ...);
constexpr bool all_same_return = (std::is_same_v<std::invoke_result_t<F, enum_constant<values_v<E, S>[0]>>, std::invoke_result_t<F, enum_constant<values_v<E, S>[I]>>> && ...);
if constexpr (has_void_return) {
(f(enum_constant<values_v<E, S>[I]>{}), ...);
} else if constexpr (all_same_return) {
return std::array{f(enum_constant<values_v<E, S>[I]>{})...};
} else {
return std::tuple{f(enum_constant<values_v<E, S>[I]>{})...};
}
}
template <typename E, enum_subtype S, typename F,std::size_t... I>
constexpr bool all_invocable(std::index_sequence<I...>) {
if constexpr (count_v<E, S> == 0) {
return false;
} else {
return (std::is_invocable_v<F, enum_constant<values_v<E, S>[I]>> && ...);
}
}
} // namespace magic_enum::detail
template <typename E, detail::enum_subtype S = detail::subtype_v<E>, typename F, detail::enable_if_t<E, int> = 0>
constexpr auto enum_for_each(F&& f) {
using D = std::decay_t<E>;
static_assert(std::is_enum_v<D>, "magic_enum::enum_for_each requires enum type.");
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
constexpr auto sep = std::make_index_sequence<detail::count_v<D, S>>{};
if constexpr (detail::all_invocable<D, S, F>(sep)) {
return detail::for_each<D, S>(std::forward<F>(f), sep);
} else {
static_assert(detail::always_false_v<D>, "magic_enum::enum_for_each requires invocable of all enum value.");
}
}
template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
[[nodiscard]] constexpr auto enum_next_value(E value, std::ptrdiff_t n = 1) noexcept -> detail::enable_if_t<E, optional<std::decay_t<E>>> {
using D = std::decay_t<E>;
constexpr std::ptrdiff_t count = detail::count_v<D, S>;
if (const auto i = enum_index<D, S>(value)) {
const std::ptrdiff_t index = (static_cast<std::ptrdiff_t>(*i) + n);
if (index >= 0 && index < count) {
return enum_value<D, S>(static_cast<std::size_t>(index));
}
}
return {};
}
template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
[[nodiscard]] constexpr auto enum_next_value_circular(E value, std::ptrdiff_t n = 1) noexcept -> detail::enable_if_t<E, std::decay_t<E>> {
using D = std::decay_t<E>;
constexpr std::ptrdiff_t count = detail::count_v<D, S>;
if (const auto i = enum_index<D, S>(value)) {
const std::ptrdiff_t index = ((((static_cast<std::ptrdiff_t>(*i) + n) % count) + count) % count);
if (index >= 0 && index < count) {
return enum_value<D, S>(static_cast<std::size_t>(index));
}
}
return MAGIC_ENUM_ASSERT(false), value;
}
template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
[[nodiscard]] constexpr auto enum_prev_value(E value, std::ptrdiff_t n = 1) noexcept -> detail::enable_if_t<E, optional<std::decay_t<E>>> {
using D = std::decay_t<E>;
constexpr std::ptrdiff_t count = detail::count_v<D, S>;
if (const auto i = enum_index<D, S>(value)) {
const std::ptrdiff_t index = (static_cast<std::ptrdiff_t>(*i) - n);
if (index >= 0 && index < count) {
return enum_value<D, S>(static_cast<std::size_t>(index));
}
}
return {};
}
template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
[[nodiscard]] constexpr auto enum_prev_value_circular(E value, std::ptrdiff_t n = 1) noexcept -> detail::enable_if_t<E, std::decay_t<E>> {
using D = std::decay_t<E>;
constexpr std::ptrdiff_t count = detail::count_v<D, S>;
if (const auto i = enum_index<D, S>(value)) {
const std::ptrdiff_t index = ((((static_cast<std::ptrdiff_t>(*i) - n) % count) + count) % count);
if (index >= 0 && index < count) {
return enum_value<D, S>(static_cast<std::size_t>(index));
}
}
return MAGIC_ENUM_ASSERT(false), value;
}
} // namespace magic_enum
#endif // NEARGYE_MAGIC_ENUM_UTILITY_HPP

Binary file not shown.

After

Width:  |  Height:  |  Size: 633 KiB

View File

@@ -0,0 +1,24 @@
# Fig 语言简介
## 概述
Fig 是一门动态类型、解释执行的编程语言,专注于简洁语法和实用的语言特性。它采用树遍历解释器架构,支持多种编程范式。
## 实际观察到的特性
1. **解释执行**:基于 AST 的树遍历解释器,无编译步骤
2. **动态类型系统**:运行时类型检查,支持类型注解但不强制
3. **混合范式**:支持函数式、面向对象和命令式风格
4. **模块系统**:支持代码组织和复用
5. **内置类型**:整数、浮点数、字符串、列表、映射等
6. **垃圾回收**:基于引用计数的自动内存管理
## 语言设计特点
- **渐进类型**:支持类型注解但不强制,兼顾灵活性和可读性
- **一等公民函数**:函数可以作为参数传递和返回
- **闭包支持**:完整的词法作用域和闭包
- **错误处理**:异常机制和 try-catch 结构
- **可变与不可变**const/var 区分,平衡安全与灵活
## 目标应用场景
- 脚本编写和自动化任务
- 教育用途和学习编程
- 配置语言和DSL

View File

@@ -0,0 +1,82 @@
# 快速开始
## 运行 Fig 程序
Fig 语言通过解释器直接执行源代码文件。基本执行命令如下:
`./Fig 你的脚本.fig`
### 查看帮助和版本
显示帮助信息:
`./Fig -h``./Fig --help`
显示版本信息:
`./Fig -v``./Fig --version`
### 示例
创建一个名为 `hello.fig` 的文件,内容为:
```go
import std.io;
io.println("Hello, Fig!");
```
在终端中运行:
`./Fig hello.fig`
你会看到输出:`Hello, Fig!`
## 程序示例
### 简单表达式程序
Fig 程序可以只包含表达式:
```go
1 + 2 * 3
```
运行此程序会输出计算结果 `7`
### 带变量的程序
```go
var x = 10;
var y = x * 2;
y + 5
```
运行输出 `25`
## 错误处理
当源代码有语法或类型错误时,解释器会显示详细的错误信息。例如:
```rust
An error occurred! Fig 0.4.2-alpha (2026-01-23 01:30:46)[llvm-mingw 64 bit on `Windows`]
TypeError: Variable `x` expects init-value type `Int`, but got 'Double'
at 1:14 in file 'your_file.fig'
var x: Int = 3.14;
^
```
错误信息包括:
- 错误类型和描述
- 发生错误的文件和位置
- 相关的堆栈跟踪信息
## 运行流程
1. **编写代码**:使用任何文本编辑器创建 `.fig` 文件
2. **保存文件**:确保文件扩展名为 `.fig`
3. **执行程序**:在终端中运行 `./Fig 文件名.fig`
4. **查看结果**:程序输出显示在终端中
5. **调试错误**:根据错误信息修改代码
## 注意事项
- Fig 源文件必须使用 UTF-8 编码
- 语句通常以分号结束,但程序最后一条表达式可以省略分号
- 文件路径可以包含空格,但建议使用引号包裹:`./Fig "my script.fig"`

View File

@@ -0,0 +1,213 @@
# 基础语法
## 注释
Fig 支持两种注释格式:
单行注释:
```go
// 这是一个单行注释
var x = 10; // 注释可以在语句后面
```
多行注释:
```go
/* 这是一个
多行注释 */
/* 注释内可以有 // 嵌套的单行注释 */
```
注释不能嵌套多个多行注释:`/* /* 嵌套 */ */` 会导致错误。
## 变量声明
### 可变变量
```go
var name = "Fig";
var count = 0;
count = count + 1; // 可以重新赋值
```
### 常量
```go
const PI = 3.14159;
const MAX_SIZE = 100;
// PI = 3.14; // 错误:常量不能重新赋值
```
常量必须在声明时初始化。
### 类型注解(可选)
```go
var name: String = "Fig";
var age: Int = 14;
const VERSION: Double = 0.4;
```
类型注解提供额外的类型信息,但解释器会在运行时进行类型检查。
## 标识符命名
### 规则
- 可以包含字母、数字和下划线
- 不能以数字开头
- 区分大小写
- 支持 Unicode 字符
### 有效示例
```go
var count = 0;
var user_name = "Alice";
var 计数器 = 0; // 中文标识符
var π = 3.14159; // Unicode 符号
var _private = true; // 以下划线开头
```
### 无效示例
```
var 123abc = 0; // 不能以数字开头
var my-var = 0; // 不能包含连字符
```
## 基本字面量
### 数字
```go
// 整数
var a = 42; // 十进制
var b = -100; // 负数
var c = 0; // 零
// 浮点数
var d = 3.14;
var e = 1.0;
var f = -0.5;
var g = 1.23e-10; // 科学计数法
```
### 字符串
```go
var s1 = "Hello";
var s2 = "World";
var s3 = "包含\"引号\"的字符串"; // 转义引号
var s4 = "第一行\n第二行"; // 转义换行符
```
多行字符串直接跨行书写:
```rust
var message = "这是一个
多行字符串
可以包含多行内容";
```
### 布尔值
```go
var yes = true;
var no = false;
```
### 空值
```dart
var nothing = null;
```
## 分号使用
所有语句都必须以分号结束:
```go
var x = 10; // 正确
var y = 20 // 错误:缺少分号
func add(a, b) {
return a + b; // return 语句需要分号
} // 函数体右花括号后不需要分号
```
表达式作为独立语句时也需要分号:
```go
1 + 2 * 3; // 表达式语句需要分号
io.println("test"); // 函数调用语句需要分号
```
## 表达式与语句
### 表达式
表达式会产生一个值(包括 `null`
```go
1 + 2 // 值为 3
x * y // 值为乘积
funcCall(arg) // 值为函数返回值
```
### 语句
语句执行操作但不产生值:
```go
var x = 10; // 声明语句
if condition {} // 条件语句
return value; // 返回语句
```
表达式可以作为语句使用(表达式语句):
```go
1 + 2; // 计算但丢弃结果
io.println("hi"); // 函数调用作为语句
```
## 关键字
Fig 语言的关键字包括:
| 类别 | 关键字 |
| -------- | ----------------------------------------------------------- |
| 声明 | `func`, `var`, `const`, `struct`, `interface`, `import` |
| 控制流 | `if`, `else`, `while`, `for`, `return`, `break`, `continue` |
| 错误处理 | `try`, `catch`, `throw`, `finally` |
| 逻辑运算 | `and`, `or`, `not` |
| 类型相关 | `is`, `as`, `impl`, `new`, `public` |
这些关键字不能用作标识符名称。
## 操作符
### 算术运算符
`+`, `-`, `*`, `/`, `%`, `**`(幂运算)
### 比较运算符
`==`, `!=`, `<`, `>`, `<=`, `>=`
### 逻辑运算符
`and`, `or`, `not`, `&&`, `||`, `!`
### 位运算符
`&`, `|`, `^`, `~`, `<<`, `>>`
### 赋值运算符
`=`, `:=`, `+=`, `-=`, `*=`, `/=`, `%=`, `^=`
### 其他运算符
`.`(成员访问), `?`(三元运算), `...`(可变参数), `->`(箭头), `=>`(双箭头)
## 空白字符
Fig 对空白字符没有特殊要求:
- 空格和制表符可以互换使用
- 缩进不影响程序语义
- 操作符周围的空格是可选的(但建议添加以提高可读性)
## 代码示例
```go
// 完整的程序示例
import std.io;
func calculate(a: Int, b: Int) -> Int {
var result = a * b;
return result + 10;
}
const x = 5;
const y = 3;
var answer = calculate(x, y);
io.println("结果是:" + answer.toString());
```

View File

@@ -0,0 +1,156 @@
# 数据类型
## 类型系统
Fig 语言是动态类型语言,运行时进行类型检查。
## 基本类型
### Null 类型
表示空值,只有一个值 `null`
```dart
var a = null;
```
### Int 类型
64位有符号整数。
```go
var x = 42;
var y = -100;
```
### Double 类型
双精度浮点数。
```go
var pi = 3.14;
var speed = 2.998e8;
```
### String 类型
字符串。
```go
var s1 = "Hello";
```
### Bool 类型
布尔值,`true``false`
```go
var yes = true;
var no = false;
```
## 复合类型
### List 类型
有序集合。
```go
var list = [1, 2, 3];
var mixed = [1, "text", true];
```
可以通过 **length()** 方法获取长度返回Int
通过 **get()** 方法获取指定下标不存在的下标返回null
### Map 类型
键值对集合。
```go
var map = {"key": "value", "num": 42};
```
通过 **get()** 方法获取指定下标,不存在的下标返回 `null`
### Function 类型
函数。
```go
var f = func(x, y) { return x + y; };
```
## 自定义类型
### 结构体定义
```rust
struct Person {
name: String;
age: Int;
}
```
默认字段为私有,如需声明为外部可见的字段,使用 public关键字
```go
struct Person {
public name: String;
public age: Int;
public func greeting()
{
io.println("hello!");
}
}
```
### 创建实例
使用 `new` 关键字:
```go
var p = new Person {name: "Alice", age: 20};
```
支持三种初始化方式:
1. 命名参数:`new Person {name: "Alice", age: 20}`
2. 位置参数:`new Person {"Alice", 20}`
3. 简写方式:`new Person {name, age}`(使用同名变量)
## 类型操作
### 类型检查
使用 `is` 运算符:
```go
var x = "hello";
io.println(x is String); // true
var p = new Person {name: "Alice", age: 20};
io.println(p is Person); // true
```
### 获取类型
使用 `value.type()` 函数(获取内部类型)
```go
import std.value;
var num = 42;
var str = "hello";
var lst = [1, 2, 3];
io.println(value.type(num)); // 获取 num 的类型
io.println(value.type(str)); // 获取 str 的类型
io.println(value.type(lst)); // 获取 lst 的类型
```
## 类型转换
### 转换函数
通过 `std.value` 模块:
```go
import std.value;
var str = value.string_from(42); // "42"
var num = value.int_parse("123"); // 123
var dbl = value.double_parse("3.14"); // 3.14
```
## 错误处理
### try-catch 语法
```rust
try
{
// 可能抛出异常的代码
}
catch(e: ErrorType)
{
// 处理特定类型的错误
}
catch(e: AnotherError)
{
// 处理另一种错误
}
```

289
src/docs/zh_CN/05-函数.md Normal file
View File

@@ -0,0 +1,289 @@
# 函数
## 函数定义
### 基本语法
```go
func 函数名(参数列表) -> 返回类型 {
函数体
}
```
### 示例
```go
// 简单函数
func greet() -> Null {
io.println("Hello!");
}
// 带参数的函数
func add(a: Int, b: Int) -> Int {
return a + b;
}
// 省略返回类型(默认为 Any
func say(message: String) {
io.println(message);
// 没有 return返回 null
}
```
## 参数
### 必需参数
```go
func power(base: Double, exponent: Double) -> Double {
return base ** exponent;
}
```
### 默认参数
参数可以指定默认值:
```go
func createPerson(name: String, age: Int = 18) -> Null {
io.println(name + " is " + age + " years old");
}
// 调用
createPerson("Alice"); // 使用默认 age=18
createPerson("Bob", 25); // 指定 age=25
```
### 可变参数
使用 `...` 表示可变参数,接收一个 List
```go
func sum(numbers...) -> Int {
var total = 0;
var i = 0;
for i = 0; i < numbers.length(); i = i + 1 {
total = total + numbers.get(i);
}
return total;
}
// 调用
sum(1, 2, 3); // 返回 6
sum(1, 2, 3, 4, 5); // 返回 15
```
可变参数不支持类型限制,获取到的总是 List 类型。
## 返回值
### 显式返回
使用 `return` 语句返回值:
```go
func max(a: Int, b: Int) -> Int {
if a > b {
return a;
} else {
return b;
}
}
```
### 无返回值
函数如果没有 return 语句,返回 null
```go
func log(message: String) -> Null {
io.println("[LOG] " + message);
// 函数结束,返回 null
}
func process(data: List) {
if data.length() == 0 {
return; // 提前返回 null
}
// 处理数据...
// 函数结束,返回 null
}
```
## 函数作为值
### 函数赋值
函数是一等公民,可以赋值给变量:
```go
var addFunc = func(a: Int, b: Int) -> Int {
return a + b;
};
// 调用
var result = addFunc(3, 4); // result = 7
```
### 函数作为参数
```go
func applyOperation(x: Int, y: Int, op: Function) -> Int {
return op(x, y);
}
func multiply(a: Int, b: Int) -> Int {
return a * b;
}
// 调用
var product = applyOperation(3, 4, multiply); // product = 12
```
### 函数作为返回值
```go
func makeMultiplier(factor: Int) -> Function {
return func(x: Int) -> Int {
return x * factor;
};
}
// 调用
var double = makeMultiplier(2);
var triple = makeMultiplier(3);
io.println(double(5)); // 输出 10
io.println(triple(5)); // 输出 15
```
## 匿名函数
### Lambda 表达式
```go
// 完整形式
var square = func(x: Int) {
return x * x;
};
// 简写形式(单表达式)
var squareShort = func(x: Int) => x * x;
// 调用
io.println(square(5)); // 输出 25
io.println(squareShort(5)); // 输出 25
```
### 立即调用函数表达式
```go
var result = func(x: Int, y: Int){
return x + y;
}(3, 4); // result = 7
```
## 闭包
### 捕获外部变量
函数可以捕获其定义作用域中的变量:
```go
func makeCounter() -> Function {
var count = 0;
return func(){
count = count + 1;
return count;
};
}
// 使用
var counter = makeCounter();
io.println(counter()); // 输出 1
io.println(counter()); // 输出 2
io.println(counter()); // 输出 3
```
每个闭包有自己独立的捕获变量:
```go
var c1 = makeCounter();
var c2 = makeCounter();
io.println(c1()); // 输出 1
io.println(c1()); // 输出 2
io.println(c2()); // 输出 1独立的计数
```
## 递归函数
函数可以调用自身:
```go
func factorial(n: Int) -> Int {
if n <= 1 {
return 1;
}
return n * factorial(n - 1);
}
// 调用
io.println(factorial(5)); // 输出 120
```
### 嵌套函数定义
```go
func outer(x: Int) -> Int {
func inner(y: Int) -> Int {
return y * 2;
}
return inner(x) + 1;
}
// 调用
io.println(outer(10)); // 输出 21
```
## 函数调用
### 普通调用
```go
func calculate(a: Int, b: Int, c: Int) -> Int {
return a + b * c;
}
// 位置参数调用
var result = calculate(1, 2, 3); // 1 + 2*3 = 7
```
### 方法调用语法
对象的方法调用:
```go
var list = [1, 2, 3];
var length = list.length(); // 方法调用
```
## 函数示例
### 实用函数组合
```go
import std.io;
// 高阶函数示例
func compose(f: Function, g: Function) -> Function {
return func(x: Any) -> Any {
return f(g(x));
};
}
// 使用
func addOne(x: Int) -> Int {
return x + 1;
}
func double(x: Int) -> Int {
return x * 2;
}
var addThenDouble = compose(double, addOne);
io.println(addThenDouble(5)); // (5+1)*2 = 12
```
### 回调函数模式
```go
func processData(data: List, callback: Function) -> Null {
var i = 0;
for i = 0; i < data.length(); i = i + 1 {
var result = callback(data.get(i));
io.println("处理结果: " + result);
}
}
// 使用
var numbers = [1, 2, 3, 4, 5];
processData(numbers, func(x){
return x * x;
});
```

View File

@@ -0,0 +1,126 @@
# 面对对象
> Fig中只有结构体(`struct`) 遵循go圣经 组合由于继承 (struct组合尚未推出)
## 结构体定义
完整语法:
```cpp
struct Point
{
public x: Int; // 公开字段
public y: Int; // 公开字段
}
struct Person
{
name: String; // 私有字段,无法被外部访问
age: Int; // 私有字段,无法被外部访问
sex: String = "Airplane"; // 私有字段,无法被外部访问
public func getName() -> String // 公开类函数
{
return name;
}
}
```
## 结构体初始化
语法:
```go
// 位置参数构造
var person := new Person{
"Fig", // name
1, // age
"Language" // sex
};
```
```go
// 命名参数构造模式,可以无序
var person := new Person{
name: "Fig",
age: 1,
sex: "Language"
};
```
```go
// 语法糖:同名变量构造
const name := "Fig";
const age := 1;
const sex := "Language";
var person := new Person{sex, name, age}; // 可以无序,自动匹配
```
请注意,同名变量构造(shorthand)模式请规范使用:
&nbsp;
示例:定义
```cpp
struct Point
{
public x;
public y;
}
```
使用:
```go
var a := Point{1,2};
io.println(a.x, a.y); // 1 2
var x := 7;
var y := 6;
var b := Point{y, x};
io.println(b.x, b.y); // 7 6
// ??
```
使用该模式最好有序构造,如果你清楚你在做什么,完全可以利用它
## 结构体运算符重载
**目前不支持**
## 接口与实现
`interface``implement`
### 定义接口
```go
interface Printable
{
toString() -> String;
getName() -> String
{
return "Printable";
}
}
```
使用 `interface` + 名字 {内容}定义结构体
方法签名为 `method() -> type`,其中必须提供返回类型,这是约定。
提供默认方法将在子类实现为实现情况下自动替补
### 实现
```rust
struct Person
{
name: String;
age: Int;
}
impl Printable for Person
{
toString()
{
return name + ":" + age;
}
getName()
{
return "Person";
}
}
```
实现时不需要也不允许提供返回类型,必须与`interface`约定一致
内部通过动态派发 vtable实现