初始化仓库,包含format文件,ci, actions和文档。新的路开始了!
This commit is contained in:
214
.clang-format
Normal file
214
.clang-format
Normal 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
3
compile_flags.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
-std=c++2b
|
||||||
|
-static
|
||||||
|
-stdlib=libc++
|
||||||
33
src/.ci/Dockerfile
Normal file
33
src/.ci/Dockerfile
Normal 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 "✅ 核心工具就绪"
|
||||||
365
src/.gitea/workflows/build.yml
Normal file
365
src/.gitea/workflows/build.yml
Normal 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版本发布完成!"
|
||||||
79
src/ExampleCodes/1-Variables.fig
Normal file
79
src/ExampleCodes/1-Variables.fig
Normal 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
|
||||||
|
*/
|
||||||
16
src/ExampleCodes/2-Function.fig
Normal file
16
src/ExampleCodes/2-Function.fig
Normal 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));
|
||||||
30
src/ExampleCodes/3-Structure.fig
Normal file
30
src/ExampleCodes/3-Structure.fig
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import std.io;
|
||||||
|
|
||||||
|
struct Point
|
||||||
|
{
|
||||||
|
x: Int; // type specifiers are optional
|
||||||
|
y: Int; // type specifiers are optional
|
||||||
|
|
||||||
|
// x and y are private fields, can only reached by internal context
|
||||||
|
|
||||||
|
public func toString() -> String
|
||||||
|
{
|
||||||
|
return "(" + (x as String) + "," + (y as String) + ")";
|
||||||
|
}
|
||||||
|
// public func toString() {} is ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// make points
|
||||||
|
|
||||||
|
var p1 := new Point{1, 2};
|
||||||
|
io.println(p1.toString()); // (1,2)
|
||||||
|
|
||||||
|
var p2 := new Point{x: 2, y: 3};
|
||||||
|
io.println(p2.toString()); // (2,3)
|
||||||
|
|
||||||
|
var x := 114;
|
||||||
|
var y := 514;
|
||||||
|
|
||||||
|
var p3 := new Point{y, x}; // shorthand mode, can be unordered, auto match field and variable!
|
||||||
|
// = Point{x: x, y: y}
|
||||||
|
io.println(p3.toString()); // (114,514)
|
||||||
94
src/ExampleCodes/4-Interface.fig
Normal file
94
src/ExampleCodes/4-Interface.fig
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
import std.io;
|
||||||
|
|
||||||
|
interface Document
|
||||||
|
{
|
||||||
|
getDepth() -> Int; // return type is necessary
|
||||||
|
getName() -> String;
|
||||||
|
|
||||||
|
/* toString() -> String
|
||||||
|
{
|
||||||
|
// default implementation
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
struct File
|
||||||
|
{
|
||||||
|
public depth: Int;
|
||||||
|
public name: String;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Document for File
|
||||||
|
{
|
||||||
|
getDepth()
|
||||||
|
{
|
||||||
|
return depth;
|
||||||
|
}
|
||||||
|
getName()
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Folder
|
||||||
|
{
|
||||||
|
public depth: Int;
|
||||||
|
public name: String;
|
||||||
|
public childs: List = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Document for Folder
|
||||||
|
{
|
||||||
|
getDepth()
|
||||||
|
{
|
||||||
|
return depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
getName()
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const root_folder := new Folder{
|
||||||
|
0,
|
||||||
|
"root",
|
||||||
|
[
|
||||||
|
new File{
|
||||||
|
1,
|
||||||
|
"joyo.txt"
|
||||||
|
},
|
||||||
|
new Folder{
|
||||||
|
2,
|
||||||
|
"joyoyo",
|
||||||
|
[
|
||||||
|
new File{
|
||||||
|
3,
|
||||||
|
"JOYO2.txt"
|
||||||
|
},
|
||||||
|
new Folder{
|
||||||
|
3,
|
||||||
|
"joyoyoyo"
|
||||||
|
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
func print_directory(root: Document)
|
||||||
|
{
|
||||||
|
io.print(" " * root.getDepth());
|
||||||
|
io.println(root.getDepth(), root.getName());
|
||||||
|
if root is Folder
|
||||||
|
{
|
||||||
|
for var i := 0; i < root.childs.length(); i += 1
|
||||||
|
{
|
||||||
|
var child := root.childs[i];
|
||||||
|
print_directory(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print_directory(root_folder);
|
||||||
15
src/ExampleCodes/FigFig/main.fig
Normal file
15
src/ExampleCodes/FigFig/main.fig
Normal 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);
|
||||||
|
}
|
||||||
31
src/ExampleCodes/FigFig/token.fig
Normal file
31
src/ExampleCodes/FigFig/token.fig
Normal 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;
|
||||||
|
}
|
||||||
102
src/ExampleCodes/FigFig/tokenizer.fig
Normal file
102
src/ExampleCodes/FigFig/tokenizer.fig
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/ExampleCodes/SpeedTest/fib.fig
Normal file
13
src/ExampleCodes/SpeedTest/fib.fig
Normal 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);
|
||||||
11
src/ExampleCodes/SpeedTest/fib.py
Normal file
11
src/ExampleCodes/SpeedTest/fib.py
Normal 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)
|
||||||
84
src/ExampleCodes/SpeedTest/fibBenchmark.fig
Normal file
84
src/ExampleCodes/SpeedTest/fibBenchmark.fig
Normal 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");
|
||||||
27
src/ExampleCodes/SpeedTest/fibLoopTest.fig
Normal file
27
src/ExampleCodes/SpeedTest/fibLoopTest.fig
Normal 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;
|
||||||
|
}
|
||||||
29
src/ExampleCodes/use_std_test.fig
Normal file
29
src/ExampleCodes/use_std_test.fig
Normal 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();
|
||||||
2589
src/Utils/argparse/argparse.hpp
Normal file
2589
src/Utils/argparse/argparse.hpp
Normal file
File diff suppressed because it is too large
Load Diff
1508
src/Utils/magic_enum/magic_enum.hpp
Normal file
1508
src/Utils/magic_enum/magic_enum.hpp
Normal file
File diff suppressed because it is too large
Load Diff
44
src/Utils/magic_enum/magic_enum_all.hpp
Normal file
44
src/Utils/magic_enum/magic_enum_all.hpp
Normal 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
|
||||||
1174
src/Utils/magic_enum/magic_enum_containers.hpp
Normal file
1174
src/Utils/magic_enum/magic_enum_containers.hpp
Normal file
File diff suppressed because it is too large
Load Diff
222
src/Utils/magic_enum/magic_enum_flags.hpp
Normal file
222
src/Utils/magic_enum/magic_enum_flags.hpp
Normal 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
|
||||||
114
src/Utils/magic_enum/magic_enum_format.hpp
Normal file
114
src/Utils/magic_enum/magic_enum_format.hpp
Normal 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
|
||||||
89
src/Utils/magic_enum/magic_enum_fuse.hpp
Normal file
89
src/Utils/magic_enum/magic_enum_fuse.hpp
Normal 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
|
||||||
117
src/Utils/magic_enum/magic_enum_iostream.hpp
Normal file
117
src/Utils/magic_enum/magic_enum_iostream.hpp
Normal 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
|
||||||
195
src/Utils/magic_enum/magic_enum_switch.hpp
Normal file
195
src/Utils/magic_enum/magic_enum_switch.hpp
Normal 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
|
||||||
138
src/Utils/magic_enum/magic_enum_utility.hpp
Normal file
138
src/Utils/magic_enum/magic_enum_utility.hpp
Normal 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
|
||||||
BIN
src/docs/FigRuntimeValueSystem.png
Normal file
BIN
src/docs/FigRuntimeValueSystem.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 633 KiB |
24
src/docs/zh_CN/01-简介.md
Normal file
24
src/docs/zh_CN/01-简介.md
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# Fig 语言简介
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
Fig 是一门动态类型、解释执行的编程语言,专注于简洁语法和实用的语言特性。它采用树遍历解释器架构,支持多种编程范式。
|
||||||
|
|
||||||
|
## 实际观察到的特性
|
||||||
|
1. **解释执行**:基于 AST 的树遍历解释器,无编译步骤
|
||||||
|
2. **动态类型系统**:运行时类型检查,支持类型注解但不强制
|
||||||
|
3. **混合范式**:支持函数式、面向对象和命令式风格
|
||||||
|
4. **模块系统**:支持代码组织和复用
|
||||||
|
5. **内置类型**:整数、浮点数、字符串、列表、映射等
|
||||||
|
6. **垃圾回收**:基于引用计数的自动内存管理
|
||||||
|
|
||||||
|
## 语言设计特点
|
||||||
|
- **渐进类型**:支持类型注解但不强制,兼顾灵活性和可读性
|
||||||
|
- **一等公民函数**:函数可以作为参数传递和返回
|
||||||
|
- **闭包支持**:完整的词法作用域和闭包
|
||||||
|
- **错误处理**:异常机制和 try-catch 结构
|
||||||
|
- **可变与不可变**:const/var 区分,平衡安全与灵活
|
||||||
|
|
||||||
|
## 目标应用场景
|
||||||
|
- 脚本编写和自动化任务
|
||||||
|
- 教育用途和学习编程
|
||||||
|
- 配置语言和DSL
|
||||||
82
src/docs/zh_CN/02-快速开始.md
Normal file
82
src/docs/zh_CN/02-快速开始.md
Normal 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"`
|
||||||
213
src/docs/zh_CN/03-基础语法.md
Normal file
213
src/docs/zh_CN/03-基础语法.md
Normal 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());
|
||||||
|
```
|
||||||
156
src/docs/zh_CN/04-数据类型.md
Normal file
156
src/docs/zh_CN/04-数据类型.md
Normal 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
289
src/docs/zh_CN/05-函数.md
Normal 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;
|
||||||
|
});
|
||||||
|
```
|
||||||
126
src/docs/zh_CN/06-面对对象.md
Normal file
126
src/docs/zh_CN/06-面对对象.md
Normal 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)模式请规范使用:
|
||||||
|
|
||||||
|
示例:定义
|
||||||
|
```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实现
|
||||||
Reference in New Issue
Block a user