9 Commits

Author SHA1 Message Date
d398d457b5 [VER] v0.3.9-alpha
All checks were successful
Release Build / build-windows-x64 (push) Successful in 1m0s
Release Build / build-linux-x64 (push) Successful in 1m2s
[Feat] is 操作符现在可以直接判断内置数据类型, 如 10 is Int
[Fix] evalMemberExpr的lhs可以为右值,修复原来限制为左值的BUG,如调用一个函数返回结果为struct且访问member触发此bug
[Impl] 可更换的std::dynamic_pointer_cast更换为static版本,更快!
[Feat] 增加标准库 std.time,以及用到的builtin: __ftime_now_ns,但目前 Time类有点BUG
[...] 剩下的忘了
2026-01-15 17:51:01 +08:00
ccf80536b3 [Fix] 蠢蛋clang!
All checks were successful
Release Build / build-windows-x64 (push) Successful in 47s
Release Build / build-linux-x64 (push) Successful in 58s
2026-01-14 21:35:48 +08:00
13fdbec0c4 [VER] v0.3.8-alpha
Some checks failed
Release Build / build-linux-x64 (push) Failing after 18s
Release Build / build-windows-x64 (push) Successful in 46s
[Impl][Fix] 更改resolveModulePath实现,使用绝对路径查找内置库
2026-01-14 21:31:11 +08:00
99e00492f5 删除蠢蛋注释
All checks were successful
Release Build / build-windows-x64 (push) Successful in 46s
Release Build / build-linux-x64 (push) Successful in 59s
2026-01-14 17:37:27 +08:00
310d79acc5 我忘记改版本号了
Some checks failed
Release Build / build-windows-x64 (push) Failing after 48s
Release Build / build-linux-x64 (push) Successful in 58s
2026-01-14 17:34:24 +08:00
e28921ae02 [VER] 0.3.7-alpha
[Fix] 修复科学表达式数字解析的问题(Lexer引起) 由 Satklomi发现,感谢
[Feat] 增加Compiler相关定义,将开发BytecodeVM
[Tip] Evaluator进入Bug fix阶段,新功能延缓开发。转向VM
2026-01-14 17:28:38 +08:00
1ccc63419d [VER] v0.3.6-alpha 发布, 完整的Installer已准备!
All checks were successful
Release Build / build-windows-x64 (push) Successful in 58s
Release Build / build-linux-x64 (push) Successful in 1m0s
[w] Change log 在之前的提交
2026-01-04 14:51:32 +08:00
3b5e99242f [Action] 尝试修复win打包计算问题 2026-01-04 14:22:33 +08:00
85bdab5db3 [Action] 重写win发布
Some checks failed
Release Build / build-windows-x64 (push) Failing after 43s
Release Build / build-linux-x64 (push) Successful in 54s
2026-01-04 14:19:38 +08:00
38 changed files with 1068 additions and 385 deletions

View File

@@ -61,7 +61,7 @@ jobs:
# 安装依赖并构建 # 安装依赖并构建
pip install --upgrade pip pip install --upgrade pip
pip install -r requirements.txt pip install -r requirements.txt
python3 -m PyInstaller -F -n fig-setup --distpath ./dist/linux main.py python3 -m PyInstaller -F -n FigSetup-Linux --distpath ./dist/linux main.py
echo "Linux安装器构建完成" echo "Linux安装器构建完成"
- name: 打包Linux发布文件 - name: 打包Linux发布文件
@@ -119,12 +119,12 @@ jobs:
"$API/releases/$RELEASE_ID/assets?name=Fig-$VERSION-linux-x86_64.sha256" "$API/releases/$RELEASE_ID/assets?name=Fig-$VERSION-linux-x86_64.sha256"
# 🔧 新增上传Linux安装器 # 🔧 新增上传Linux安装器
if [ -f "Installer/ConsoleInstaller/dist/linux/fig-setup" ]; then if [ -f "Installer/ConsoleInstaller/dist/linux/FigSetup-Linux" ]; then
echo "正在上传Linux安装器..." echo "正在上传Linux安装器..."
curl -sS -X POST -H "Authorization: token $GITEA_TOKEN" \ curl -sS -X POST -H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/octet-stream" \ -H "Content-Type: application/octet-stream" \
--data-binary @Installer/ConsoleInstaller/dist/linux/fig-setup \ --data-binary @Installer/ConsoleInstaller/dist/linux/FigSetup-Linux \
"$API/releases/$RELEASE_ID/assets?name=fig-setup" "$API/releases/$RELEASE_ID/assets?name=FigSetup-Linux"
fi fi
echo "✅ Linux版本发布完成" echo "✅ Linux版本发布完成"
@@ -186,13 +186,16 @@ jobs:
run: | run: |
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8 [Console]::OutputEncoding = [System.Text.Encoding]::UTF8
# 确保版本号不为空 # 🔧 修改:与发布步骤使用相同的版本号计算逻辑
$VERSION = $env:VERSION if ($env:GITHUB_EVENT_NAME -eq 'workflow_dispatch') {
if ([string]::IsNullOrEmpty($VERSION)) { $VERSION = $env:INPUT_VERSION
Write-Host "警告:版本号为空,使用默认值 dev-build" if (-not $VERSION) { $VERSION = "dev-build" }
$VERSION = "dev-build" } else {
$VERSION = $env:GITHUB_REF_NAME
} }
Write-Host "打包版本: $VERSION"
$PACKAGE_NAME = "Fig-${VERSION}-windows-x86_64" $PACKAGE_NAME = "Fig-${VERSION}-windows-x86_64"
Write-Host "打包名称: $PACKAGE_NAME" Write-Host "打包名称: $PACKAGE_NAME"
@@ -242,43 +245,77 @@ jobs:
$API = "https://git.fig-lang.cn/api/v1/repos/$REPO" $API = "https://git.fig-lang.cn/api/v1/repos/$REPO"
$TOKEN = $env:GITEA_TOKEN $TOKEN = $env:GITEA_TOKEN
Write-Host "正在上传Windows版本到发布 $VERSION ..." # 🔧 新增:检查必需的文件是否存在
$ZIP_FILE = "Fig-$VERSION-windows-x86_64.zip"
$HASH_FILE = "Fig-$VERSION-windows-x86_64.sha256"
$INSTALLER_PATH = "Installer\ConsoleInstaller\dist\windows\FigSetup.exe"
# 1. 尝试通过标签获取 Release ID if (-not (Test-Path $ZIP_FILE)) {
$RELEASE_RESPONSE = Invoke-RestMethod -Uri "$API/releases/tags/$VERSION" -Headers @{Authorization = "token $TOKEN" } -ErrorAction SilentlyContinue Write-Host "❌ 错误找不到ZIP文件 $ZIP_FILE"
if ($RELEASE_RESPONSE -and $RELEASE_RESPONSE.id) { Get-ChildItem *.zip
$RELEASE_ID = $RELEASE_RESPONSE.id
Write-Host "找到已有发布 ID: $RELEASE_ID"
} else {
# 如果不存在,则创建新发布
Write-Host '发布不存在,正在创建...'
$CREATE_BODY = @{tag_name = $VERSION; name = "Fig $VERSION"; draft = $false; prerelease = $false } | ConvertTo-Json
$CREATE_RESPONSE = Invoke-RestMethod -Method Post -Uri "$API/releases" -Headers @{Authorization = "token $TOKEN"; 'Content-Type' = 'application/json' } -Body $CREATE_BODY
if ($CREATE_RESPONSE -and $CREATE_RESPONSE.id) {
$RELEASE_ID = $CREATE_RESPONSE.id
Write-Host "创建新发布 ID: $RELEASE_ID"
} else {
Write-Host '错误:无法获取或创建发布'
exit 1 exit 1
} }
Write-Host "正在为Windows版本创建/更新发布 $VERSION ..."
# 🔧 关键修改直接创建发布不先检查与Linux逻辑一致
$CREATE_BODY = @{
tag_name = $VERSION
name = "Fig $VERSION"
draft = $false
prerelease = $false
} | ConvertTo-Json -Compress
Write-Host "创建发布请求体: $CREATE_BODY"
# 直接创建发布Gitea会自动处理重复创建
$RESPONSE = Invoke-RestMethod -Method Post -Uri "$API/releases" `
-Headers @{
Authorization = "token $TOKEN"
'Content-Type' = 'application/json'
} -Body $CREATE_BODY -ErrorAction SilentlyContinue
if (-not $RESPONSE -or -not $RESPONSE.id) {
# 如果创建失败尝试通过标签获取已有发布的ID
Write-Host "创建失败,尝试获取已有发布..."
$RESPONSE = Invoke-RestMethod -Uri "$API/releases/tags/$VERSION" `
-Headers @{Authorization = "token $TOKEN" } `
-ErrorAction SilentlyContinue
} }
# 2. 使用 Release ID 上传资产 if ($RESPONSE -and $RESPONSE.id) {
Write-Host '正在上传 ZIP 文件...' $RELEASE_ID = $RESPONSE.id
Invoke-RestMethod -Method Post -Uri "$API/releases/$RELEASE_ID/assets?name=Fig-$VERSION-windows-x86_64.zip" -Headers @{Authorization = "token $TOKEN"; 'Content-Type' = 'application/octet-stream' } -InFile "Fig-$VERSION-windows-x86_64.zip" Write-Host "✅ 使用发布 ID: $RELEASE_ID 进行上传"
} else {
Write-Host "❌ 错误:无法获取或创建发布 ID"
exit 1
}
Write-Host '正在上传校验文件...' # 上传资产
Invoke-RestMethod -Method Post -Uri "$API/releases/$RELEASE_ID/assets?name=Fig-$VERSION-windows-x86_64.sha256" -Headers @{Authorization = "token $TOKEN"; 'Content-Type' = 'text/plain' } -InFile "Fig-$VERSION-windows-x86_64.sha256" Write-Host "正在上传 ZIP 文件..."
Invoke-RestMethod -Method Post -Uri "$API/releases/$RELEASE_ID/assets?name=$ZIP_FILE" `
-Headers @{
Authorization = "token $TOKEN"
'Content-Type' = 'application/octet-stream'
} -InFile $ZIP_FILE -ErrorAction SilentlyContinue
# 🔧 新增上传Windows安装器 Write-Host "正在上传校验文件..."
$InstallerPath = "Installer\ConsoleInstaller\dist\windows\FigSetup.exe" Invoke-RestMethod -Method Post -Uri "$API/releases/$RELEASE_ID/assets?name=$HASH_FILE" `
if (Test-Path $InstallerPath) { -Headers @{
Write-Host '正在上传Windows安装器...' Authorization = "token $TOKEN"
'Content-Type' = 'text/plain'
} -InFile $HASH_FILE -ErrorAction SilentlyContinue
# 上传Windows安装器
if (Test-Path $INSTALLER_PATH) {
Write-Host "正在上传Windows安装器..."
Invoke-RestMethod -Method Post -Uri "$API/releases/$RELEASE_ID/assets?name=FigSetup.exe" ` Invoke-RestMethod -Method Post -Uri "$API/releases/$RELEASE_ID/assets?name=FigSetup.exe" `
-Headers @{ -Headers @{
Authorization = "token $TOKEN" Authorization = "token $TOKEN"
'Content-Type' = 'application/octet-stream' 'Content-Type' = 'application/octet-stream'
} -InFile $InstallerPath } -InFile $INSTALLER_PATH -ErrorAction SilentlyContinue
} else {
Write-Host "⚠️ 警告:未找到安装器文件 $INSTALLER_PATH"
} }
Write-Host '✅ Windows版本发布完成' Write-Host "✅ Windows版本发布完成"

View File

@@ -9,7 +9,7 @@ import json
import zipfile import zipfile
import platform import platform
from os import path as ospath from os import path as ospath
from os import mkdir,chdir from os import mkdir,chdir,remove,rename
from sys import exit, argv from sys import exit, argv
@@ -49,12 +49,7 @@ def getReleases():
# print(rel) # print(rel)
return rel return rel
def install(url, path:str) -> None: def install(url, path:str, filename:str) -> None:
if not ospath.exists(path):
mkdir(path)
filename = path.split('/')[-1]
response = requests.get(url, stream=True) response = requests.get(url, stream=True)
total_size = int(response.headers.get('content-length', 0)) total_size = int(response.headers.get('content-length', 0))
@@ -64,12 +59,29 @@ def install(url, path:str) -> None:
f.write(data) f.write(data)
b.update(len(data)) b.update(len(data))
print()
print(f'{filename} download completed.') print(f'{filename} download completed.')
print(f'unziping to {path} ...') print(f'unziping to {path} ...')
destZipPath = ospath.dirname(path)
with zipfile.ZipFile(filename) as zip: with zipfile.ZipFile(filename) as zip:
zip.extractall(path) zip.extractall(destZipPath) # 解压到安装目录上一层
rename(ospath.join(destZipPath, ospath.splitext(filename)[0]), path)
print()
print('unziping completed') print('unziping completed')
print('\n==========')
print('cleaning...')
remove(filename)
def osEnumToStr(os: int) -> str:
if os == Windows:
return 'windows'
elif os == Linux:
return 'linux'
elif os == Darwin:
return 'darwin'
return 'other'
def main() -> None: def main() -> None:
@@ -84,7 +96,7 @@ def main() -> None:
print(f'Install to (default: {dpath}): ', end='') print(f'Install to (default: {dpath}): ', end='')
path = input() path = input()
if path.isspace(): if not path:
path = dpath path = dpath
print() print()
@@ -97,7 +109,7 @@ def main() -> None:
print('No version has been released!') print('No version has been released!')
exit(0) exit(0)
print('There are {} versions:' % len(releases)) print(f'There are {len(releases)} versions:')
i = 1 i = 1
for release in releases: for release in releases:
print(f" {i} {release['name']} - {release['body']}") print(f" {i} {release['name']} - {release['body']}")
@@ -114,8 +126,7 @@ def main() -> None:
print() print()
version = insVersion version = insVersion
if not usrInput.isspace(): if usrInput:
if '.' in usrInput: if '.' in usrInput:
for release in releases: for release in releases:
if release['tag_name'].find(usrInput) != -1: if release['tag_name'].find(usrInput) != -1:
@@ -135,13 +146,15 @@ def main() -> None:
print(f"Installing Fig-{version['tag_name']}") print(f"Installing Fig-{version['tag_name']}")
url = None url = None
assetName = None
for asset in version['assets']: for asset in version['assets']:
if asset['name'].find(osName) != -1: assetName = asset['name']
if assetName.find(osEnumToStr(osName)) != -1 and assetName.find('.zip') != -1:
url = asset['browser_download_url'] url = asset['browser_download_url']
break break
if url: if url:
install(url, path) install(url, path, assetName)
else: else:
print('Could not find artifact:') print('Could not find artifact:')
print(version['assets']) print(version['assets'])

View File

@@ -7,7 +7,7 @@ namespace Fig::Ast
class InitExprAst final : public ExpressionAst class InitExprAst final : public ExpressionAst
{ {
public: public:
FString structName; Expression structe;
std::vector<std::pair<FString, Expression>> args; std::vector<std::pair<FString, Expression>> args;
@@ -30,8 +30,8 @@ namespace Fig::Ast
type = AstType::InitExpr; type = AstType::InitExpr;
} }
InitExprAst(FString _structName, std::vector<std::pair<FString, Expression>> _args, InitMode _initMode) : InitExprAst(Expression _structe, std::vector<std::pair<FString, Expression>> _args, InitMode _initMode) :
structName(std::move(_structName)), args(std::move(_args)), initMode(_initMode) structe(std::move(_structe)), args(std::move(_args)), initMode(_initMode)
{ {
type = AstType::InitExpr; type = AstType::InitExpr;
} }

View File

@@ -238,9 +238,11 @@ namespace Fig::Ast
}; };
static const std::unordered_set<Operator> unaryOps{ static const std::unordered_set<Operator> unaryOps{
Operator::Not, Operator::Not, // !
Operator::Subtract, Operator::Subtract, // -
Operator::BitNot, Operator::BitNot, // ~
Operator::BitAnd, // reference operator &
}; };
static const std::unordered_set<Operator> binaryOps{ static const std::unordered_set<Operator> binaryOps{
Operator::Add, Operator::Add,

125
src/Bytecode/Bytecode.hpp Normal file
View File

@@ -0,0 +1,125 @@
#pragma once
/*
从树遍历到虚拟机!
*/
#include "Core/fig_string.hpp"
#include "Utils/magic_enum/magic_enum.hpp"
#include <cstdint>
#include <format>
#include <string_view>
namespace Fig
{
using OpCodeType = uint8_t;
enum class Bytecode : OpCodeType
{
HALT = 0x01, // 程序终止,后跟 8 位退出码
POP = 0x10,
LOAD_NULL = 0x20,
LOAD_TRUE = 0x21,
LOAD_FALSE = 0x22,
LOAD_CON8 = 0x23, // 跟 8 位索引 (0 - 255)
LOAD_CON16 = 0x24, // 跟 16 位索引 (255 - 65535)
LOAD_CON32 = 0x25, // 跟 32 位索引 (65536 - 2^32-1)
ADD = 0x30, // +
SUB = 0x31, // -
MUL = 0x32, // *
DIV = 0x33, // /
MOD = 0x34, // %
AND = 0x40, // &
OR = 0x41, // |
XOR = 0x42, // ~
NOT = 0x43, // ! (not)
EQ = 0x50, // ==
GT = 0x51, // >
GTEQ = 0x52, // >=
LT = 0x53, // <
LTEQ = 0x54, // <=
JUMP16 = 0x60, // 跟 16 位索引 无条件
JUMP32 = 0x61, // 跟 32 位索引 无条件
JUMP16_IF_TRUE = 0x62, // 跟 16 位索引 栈顶为真跳转
JUMP32_IF_TRUE = 0x63, // 跟 32 位索引 栈顶为真跳转
JUMP16_IF_FALSE = 0x64, // 跟 16 位索引 栈顶为假跳转
JUMP32_IF_FALSE = 0x65, // 跟 32 位索引 栈顶为假跳转
LOAD_LOCAL16 = 0x70, // 后跟 16 位索引
LOAD_LOCAL32 = 0x71, // 后跟 32 位索引
};
inline FString bytecode2string(Bytecode code)
{
const std::string_view &name = magic_enum::enum_name(code);
return FString(FStringView(name));
}
inline FString reverseCompile(const std::vector<uint8_t> &src)
{
assert(src.size() >= 1);
FString result;
using enum Bytecode;
for (size_t i = 0; i < src.size();)
{
Bytecode code = Bytecode(src[i]);
switch (code)
{
case HALT: {
uint8_t quitCode = src[++i];
result += FString(std::format("HALT {}", static_cast<uint8_t>(quitCode))) + u8"\n";
break;
}
case LOAD_CON8: {
uint8_t id = src[++i];
result += FString(std::format("LOAD_CON8 {}", static_cast<uint8_t>(id))) + u8"\n";
break;
}
case LOAD_CON16:
case JUMP16:
case JUMP16_IF_TRUE:
case JUMP16_IF_FALSE:
case LOAD_LOCAL16: {
uint8_t high = src[++i];
uint8_t low = src[++i];
int32_t id = (high << 8) | low;
result += FString(std::format("{} {}", bytecode2string(code).toBasicString(), id))
+ u8"\n";
break;
}
case LOAD_CON32:
case JUMP32:
case JUMP32_IF_TRUE:
case JUMP32_IF_FALSE:
case LOAD_LOCAL32: {
uint32_t b0 = static_cast<uint32_t>(src[++i]);
uint32_t b1 = static_cast<uint32_t>(src[++i]);
uint32_t b2 = static_cast<uint32_t>(src[++i]);
uint32_t b3 = static_cast<uint32_t>(src[++i]);
uint32_t id = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
result += FString(std::format("{} {}", bytecode2string(code).toBasicString(), id))
+ u8"\n";
break;
}
default: {
result += bytecode2string(code) + u8"\n";
}
}
++i;
}
return result;
}
}; // namespace Fig

21
src/Compiler/Compiler.cpp Normal file
View File

@@ -0,0 +1,21 @@
#include <Ast/astBase.hpp>
#include <Compiler/Compiler.hpp>
#include <memory>
namespace Fig
{
void Compiler::compile(Ast::Statement stmt)
{
using enum Ast::AstType;
using namespace Ast;
Ast::AstType type = stmt->getType();
switch (type)
{
case VarDefSt: {
auto vd = std::static_pointer_cast<VarDefAst>(stmt);
const FString name = vd->name;
}
}
}
}; // namespace Fig

32
src/Compiler/Compiler.hpp Normal file
View File

@@ -0,0 +1,32 @@
#pragma once
#include "Ast/astBase.hpp"
#include <Ast/ast.hpp>
#include <Bytecode/Bytecode.hpp>
#include <VMValue/VMValue.hpp>
#include <vector>
namespace Fig
{
class Compiler
{
private:
std::vector<Ast::Statement> source;
std::vector<OpCodeType> output; // std::vector<uint8_t>
std::vector<Value> constants;
public:
std::vector<OpCodeType> getOutput() const { return output; }
std::vector<Value> getConstantPool() const { return constants; }
Compiler() {}
Compiler(std::vector<Ast::Statement> _source) : source(std::move(_source)) {}
void compile_expr(Ast::Expression);
void compile(Ast::Statement);
void CompileAll();
};
}; // namespace Fig

View File

@@ -4,7 +4,7 @@
#include <cstdint> #include <cstdint>
#include <string_view> #include <string_view>
#define __FCORE_VERSION "0.3.6-alpha" #define __FCORE_VERSION "0.3.9-alpha"
#if defined(_WIN32) #if defined(_WIN32)
#define __FCORE_PLATFORM "Windows" #define __FCORE_PLATFORM "Windows"

View File

@@ -0,0 +1,21 @@
#pragma once
#include <filesystem>
#ifdef _WIN32
#include <libloaderapi.h>
#endif
namespace Fig
{
inline std::filesystem::path getExecutablePath()
{
#ifdef _WIN32
wchar_t buffer[MAX_PATH];
GetModuleFileNameW(nullptr, buffer, MAX_PATH);
return std::filesystem::path(buffer);
#else
return std::filesystem::canonical("/proc/self/exe");
#endif
}
}; // namespace Fig

View File

@@ -43,6 +43,10 @@ namespace Fig
{ {
return FString(toBasicString() + x.toBasicString()); return FString(toBasicString() + x.toBasicString());
} }
FString operator+(const char8_t *c)
{
return FString(*this + std::u8string(c));
}
explicit FString(const std::u8string &str) explicit FString(const std::u8string &str)
{ {

18
src/Core/runtimeTime.cpp Normal file
View File

@@ -0,0 +1,18 @@
#include <Core/runtimeTime.hpp>
#include <cassert>
namespace Fig::Time
{
Clock::time_point start_time;
void init()
{
static bool flag = false;
if (flag)
{
assert(false);
}
start_time = Clock::now();
flag = true;
}
};

10
src/Core/runtimeTime.hpp Normal file
View File

@@ -0,0 +1,10 @@
#pragma once
#include <chrono>
namespace Fig::Time
{
using Clock = std::chrono::steady_clock;
extern Clock::time_point start_time; // since process start
void init();
};

View File

@@ -33,17 +33,13 @@ namespace Fig
std::unordered_map<std::size_t, FString> functionNames; std::unordered_map<std::size_t, FString> functionNames;
// implRegistry <Struct, ordered list of ImplRecord> // implRegistry <Struct, ordered list of ImplRecord>
std::unordered_map<TypeInfo, std::vector<ImplRecord>, TypeInfoHash> std::unordered_map<TypeInfo, std::vector<ImplRecord>, TypeInfoHash> implRegistry;
implRegistry;
public: public:
ContextPtr parent; ContextPtr parent;
Context(const Context &) = default; Context(const Context &) = default;
Context(const FString &name, ContextPtr p = nullptr) : Context(const FString &name, ContextPtr p = nullptr) : scopeName(name), parent(p) {}
scopeName(name), parent(p)
{
}
void setParent(ContextPtr _parent) { parent = _parent; } void setParent(ContextPtr _parent) { parent = _parent; }
@@ -55,37 +51,28 @@ namespace Fig
{ {
variables.insert(c.variables.begin(), c.variables.end()); variables.insert(c.variables.begin(), c.variables.end());
functions.insert(c.functions.begin(), c.functions.end()); functions.insert(c.functions.begin(), c.functions.end());
functionNames.insert(c.functionNames.begin(), functionNames.insert(c.functionNames.begin(), c.functionNames.end());
c.functionNames.end());
implRegistry.insert(c.implRegistry.begin(), c.implRegistry.end()); implRegistry.insert(c.implRegistry.begin(), c.implRegistry.end());
// structTypeNames.insert(c.structTypeNames.begin(), // structTypeNames.insert(c.structTypeNames.begin(),
// c.structTypeNames.end()); // c.structTypeNames.end());
} }
std::unordered_map<size_t, Function> getFunctions() const std::unordered_map<size_t, Function> getFunctions() const { return functions; }
{
return functions;
}
std::shared_ptr<VariableSlot> get(const FString &name) std::shared_ptr<VariableSlot> get(const FString &name)
{ {
auto it = variables.find(name); auto it = variables.find(name);
if (it != variables.end()) return it->second; if (it != variables.end()) return it->second;
if (parent) return parent->get(name); if (parent) return parent->get(name);
throw RuntimeError(FString(std::format("Variable '{}' not defined", throw RuntimeError(FString(std::format("Variable '{}' not defined", name.toBasicString())));
name.toBasicString())));
} }
AccessModifier getAccessModifier(const FString &name) AccessModifier getAccessModifier(const FString &name)
{ {
if (variables.contains(name)) { return variables[name]->am; } if (variables.contains(name)) { return variables[name]->am; }
else if (parent != nullptr) else if (parent != nullptr) { return parent->getAccessModifier(name); }
{
return parent->getAccessModifier(name);
}
else else
{ {
throw RuntimeError(FString(std::format( throw RuntimeError(FString(std::format("Variable '{}' not defined", name.toBasicString())));
"Variable '{}' not defined", name.toBasicString())));
} }
} }
bool isVariableMutable(const FString &name) bool isVariableMutable(const FString &name)
@@ -104,16 +91,14 @@ namespace Fig
{ {
if (!isVariableMutable(name)) if (!isVariableMutable(name))
{ {
throw RuntimeError(FString(std::format( throw RuntimeError(FString(std::format("Variable '{}' is immutable", name.toBasicString())));
"Variable '{}' is immutable", name.toBasicString())));
} }
variables[name]->value = value; variables[name]->value = value;
} }
else if (parent != nullptr) { parent->set(name, value); } else if (parent != nullptr) { parent->set(name, value); }
else else
{ {
throw RuntimeError(FString(std::format( throw RuntimeError(FString(std::format("Variable '{}' not defined", name.toBasicString())));
"Variable '{}' not defined", name.toBasicString())));
} }
} }
void _update(const FString &name, ObjectPtr value) void _update(const FString &name, ObjectPtr value)
@@ -122,8 +107,7 @@ namespace Fig
else if (parent != nullptr) { parent->_update(name, value); } else if (parent != nullptr) { parent->_update(name, value); }
else else
{ {
throw RuntimeError(FString(std::format( throw RuntimeError(FString(std::format("Variable '{}' not defined", name.toBasicString())));
"Variable '{}' not defined", name.toBasicString())));
} }
} }
void def(const FString &name, void def(const FString &name,
@@ -133,14 +117,11 @@ namespace Fig
{ {
if (containsInThisScope(name)) if (containsInThisScope(name))
{ {
throw RuntimeError(FString( throw RuntimeError(
std::format("Variable '{}' already defined in this scope", FString(std::format("Variable '{}' already defined in this scope", name.toBasicString())));
name.toBasicString())));
} }
variables[name] = variables[name] = std::make_shared<VariableSlot>(name, value, ti, am);
std::make_shared<VariableSlot>(name, value, ti, am); if (ti == ValueType::Function and value->getTypeInfo() == ValueType::Function)
if (ti == ValueType::Function
and value->getTypeInfo() == ValueType::Function)
{ {
auto &fn = value->as<Function>(); auto &fn = value->as<Function>();
functions[fn.id] = fn; functions[fn.id] = fn;
@@ -152,19 +133,42 @@ namespace Fig
// structTypeNames[st.id] = name; // structTypeNames[st.id] = name;
// } // }
} }
void
defReference(const FString &name, const TypeInfo &ti, AccessModifier am, std::shared_ptr<VariableSlot> target)
{
if (containsInThisScope(name))
{
throw RuntimeError(
FString(std::format("Variable '{}' already defined in this scope", name.toBasicString())));
}
variables[name] = std::make_shared<VariableSlot>(
name,
target->value,
ti,
am,
true,
target
);
}
std::optional<Function> getFunction(std::size_t id) std::optional<Function> getFunction(std::size_t id)
{ {
auto it = functions.find(id); auto it = functions.find(id);
if (it != functions.end()) { return it->second; } if (it != functions.end()) { return it->second; }
else if (parent) { return parent->getFunction(id); } else if (parent) { return parent->getFunction(id); }
else { return std::nullopt; } else
{
return std::nullopt;
}
} }
std::optional<FString> getFunctionName(std::size_t id) std::optional<FString> getFunctionName(std::size_t id)
{ {
auto it = functionNames.find(id); auto it = functionNames.find(id);
if (it != functionNames.end()) { return it->second; } if (it != functionNames.end()) { return it->second; }
else if (parent) { return parent->getFunctionName(id); } else if (parent) { return parent->getFunctionName(id); }
else { return std::nullopt; } else
{
return std::nullopt;
}
} }
// std::optional<FString> getStructName(std::size_t id) // std::optional<FString> getStructName(std::size_t id)
// { // {
@@ -188,24 +192,15 @@ namespace Fig
else if (parent != nullptr) { return parent->contains(name); } else if (parent != nullptr) { return parent->contains(name); }
return false; return false;
} }
bool containsInThisScope(const FString &name) const bool containsInThisScope(const FString &name) const { return variables.contains(name); }
{
return variables.contains(name);
}
TypeInfo getTypeInfo(const FString &name) TypeInfo getTypeInfo(const FString &name) { return get(name)->declaredType; }
{
return get(name)->declaredType;
}
bool isInFunctionContext() bool isInFunctionContext()
{ {
ContextPtr ctx = shared_from_this(); ContextPtr ctx = shared_from_this();
while (ctx) while (ctx)
{ {
if (ctx->getScopeName().find(u8"<Function ") == 0) if (ctx->getScopeName().find(u8"<Function ") == 0) { return true; }
{
return true;
}
ctx = ctx->parent; ctx = ctx->parent;
} }
return false; return false;
@@ -215,8 +210,7 @@ namespace Fig
ContextPtr ctx = shared_from_this(); ContextPtr ctx = shared_from_this();
while (ctx) while (ctx)
{ {
if (ctx->getScopeName().find(u8"<While ") == 0 if (ctx->getScopeName().find(u8"<While ") == 0 or ctx->getScopeName().find(u8"<For ") == 0)
or ctx->getScopeName().find(u8"<For ") == 0)
{ {
return true; return true;
} }
@@ -225,8 +219,7 @@ namespace Fig
return false; return false;
} }
bool hasImplRegisted(const TypeInfo &structType, bool hasImplRegisted(const TypeInfo &structType, const TypeInfo &interfaceType) const
const TypeInfo &interfaceType) const
{ {
auto it = implRegistry.find(structType); auto it = implRegistry.find(structType);
if (it != implRegistry.end()) if (it != implRegistry.end())
@@ -239,9 +232,7 @@ namespace Fig
return parent && parent->hasImplRegisted(structType, interfaceType); return parent && parent->hasImplRegisted(structType, interfaceType);
} }
std::optional<ImplRecord> std::optional<ImplRecord> getImplRecord(const TypeInfo &structType, const TypeInfo &interfaceType) const
getImplRecord(const TypeInfo &structType,
const TypeInfo &interfaceType) const
{ {
auto it = implRegistry.find(structType); auto it = implRegistry.find(structType);
if (it != implRegistry.end()) if (it != implRegistry.end())
@@ -257,9 +248,7 @@ namespace Fig
return std::nullopt; return std::nullopt;
} }
void setImplRecord(const TypeInfo &structType, void setImplRecord(const TypeInfo &structType, const TypeInfo &interfaceType, const ImplRecord &record)
const TypeInfo &interfaceType,
const ImplRecord &record)
{ {
auto &list = implRegistry[structType]; auto &list = implRegistry[structType];
@@ -271,8 +260,7 @@ namespace Fig
list.push_back(record); // order is the level list.push_back(record); // order is the level
} }
bool hasMethodImplemented(const TypeInfo &structType, bool hasMethodImplemented(const TypeInfo &structType, const FString &functionName) const
const FString &functionName) const
{ {
auto it = implRegistry.find(structType); auto it = implRegistry.find(structType);
if (it != implRegistry.end()) if (it != implRegistry.end())
@@ -283,19 +271,16 @@ namespace Fig
} }
} }
return parent return parent && parent->hasMethodImplemented(structType, functionName);
&& parent->hasMethodImplemented(structType, functionName);
} }
bool hasDefaultImplementedMethod(const TypeInfo &structType, bool hasDefaultImplementedMethod(const TypeInfo &structType, const FString &functionName) const
const FString &functionName) const
{ {
auto it = implRegistry.find(structType); auto it = implRegistry.find(structType);
if (it == implRegistry.end()) return false; if (it == implRegistry.end()) return false;
std::vector<TypeInfo> implementedInterfaces; std::vector<TypeInfo> implementedInterfaces;
for (auto &record : it->second) for (auto &record : it->second) implementedInterfaces.push_back(record.interfaceType);
implementedInterfaces.push_back(record.interfaceType);
for (auto &[_, slot] : variables) for (auto &[_, slot] : variables)
{ {
@@ -303,8 +288,7 @@ namespace Fig
InterfaceType &interface = slot->value->as<InterfaceType>(); InterfaceType &interface = slot->value->as<InterfaceType>();
bool implemented = std::any_of( bool implemented = std::any_of(implementedInterfaces.begin(),
implementedInterfaces.begin(),
implementedInterfaces.end(), implementedInterfaces.end(),
[&](const TypeInfo &ti) { return ti == interface.type; }); [&](const TypeInfo &ti) { return ti == interface.type; });
@@ -312,16 +296,14 @@ namespace Fig
for (auto &method : interface.methods) for (auto &method : interface.methods)
{ {
if (method.name == functionName && method.hasDefaultBody()) if (method.name == functionName && method.hasDefaultBody()) return true;
return true;
} }
} }
return false; return false;
} }
Function getDefaultImplementedMethod(const TypeInfo &structType, Function getDefaultImplementedMethod(const TypeInfo &structType, const FString &functionName)
const FString &functionName)
{ {
// O(N²) // O(N²)
// SLOW // SLOW
@@ -335,8 +317,7 @@ namespace Fig
if (it == implRegistry.end()) assert(false); if (it == implRegistry.end()) assert(false);
std::vector<TypeInfo> implementedInterfaces; std::vector<TypeInfo> implementedInterfaces;
for (auto &record : it->second) for (auto &record : it->second) implementedInterfaces.push_back(record.interfaceType);
implementedInterfaces.push_back(record.interfaceType);
for (auto &[_, slot] : variables) for (auto &[_, slot] : variables)
{ {
@@ -344,8 +325,7 @@ namespace Fig
InterfaceType &interface = slot->value->as<InterfaceType>(); InterfaceType &interface = slot->value->as<InterfaceType>();
bool implemented = std::any_of( bool implemented = std::any_of(implementedInterfaces.begin(),
implementedInterfaces.begin(),
implementedInterfaces.end(), implementedInterfaces.end(),
[&](const TypeInfo &ti) { return ti == interface.type; }); [&](const TypeInfo &ti) { return ti == interface.type; });
@@ -357,10 +337,8 @@ namespace Fig
{ {
if (!method.hasDefaultBody()) assert(false); if (!method.hasDefaultBody()) assert(false);
return Function(method.paras, return Function(
TypeInfo(method.returnType), method.paras, TypeInfo(method.returnType), method.defaultBody, shared_from_this());
method.defaultBody,
shared_from_this());
} }
} }
} }
@@ -369,8 +347,7 @@ namespace Fig
return Function(); // ignore warning return Function(); // ignore warning
} }
const Function &getImplementedMethod(const TypeInfo &structType, const Function &getImplementedMethod(const TypeInfo &structType, const FString &functionName) const
const FString &functionName) const
{ {
auto it = implRegistry.find(structType); auto it = implRegistry.find(structType);
if (it != implRegistry.end()) if (it != implRegistry.end())
@@ -382,8 +359,7 @@ namespace Fig
} }
} }
if (parent) if (parent) return parent->getImplementedMethod(structType, functionName);
return parent->getImplementedMethod(structType, functionName);
assert(false); // not found assert(false); // not found
throw ""; // ignore warning throw ""; // ignore warning
@@ -403,8 +379,7 @@ namespace Fig
os << "[STACK TRACE]\n"; os << "[STACK TRACE]\n";
for (int i = static_cast<int>(chain.size()) - 1; i >= 0; --i) for (int i = static_cast<int>(chain.size()) - 1; i >= 0; --i)
{ {
os << " #" << (chain.size() - 1 - i) << " " os << " #" << (chain.size() - 1 - i) << " " << chain[i]->scopeName.toBasicString() << "\n";
<< chain[i]->scopeName.toBasicString() << "\n";
} }
} }
}; };

View File

@@ -2,6 +2,7 @@
#include <Core/fig_string.hpp> #include <Core/fig_string.hpp>
#include <unordered_set>
#include <variant> #include <variant>
#include <map> #include <map>
@@ -75,6 +76,28 @@ namespace Fig
using BoolClass = bool; using BoolClass = bool;
using NullClass = std::monostate; using NullClass = std::monostate;
using StringClass = FString; using StringClass = FString;
static const std::unordered_set<TypeInfo, TypeInfoHash> builtinTypes
{
Any,
Null,
Int,
String,
Bool,
Double,
Function,
StructType,
StructInstance,
List,
Map,
Module,
InterfaceType
};
inline bool isTypeBuiltin(const TypeInfo &type)
{
return builtinTypes.contains(type);
}
}; // namespace ValueType }; // namespace ValueType
}; // namespace Fig }; // namespace Fig

View File

@@ -557,10 +557,13 @@ namespace Fig
auto rnv = rhs.getNumericValue(); auto rnv = rhs.getNumericValue();
if (rnv == 0) if (rnv == 0)
throw ValueError(FString(makeTypeErrorMessage("Division by zero", "/", lhs, rhs))); throw ValueError(FString(makeTypeErrorMessage("Division by zero", "/", lhs, rhs)));
bool bothInt = lhs.is<ValueType::IntClass>() && rhs.is<ValueType::IntClass>(); // bool bothInt = lhs.is<ValueType::IntClass>() && rhs.is<ValueType::IntClass>();
auto result = lhs.getNumericValue() / rnv; auto result = lhs.getNumericValue() / rnv;
if (bothInt && !isNumberExceededIntLimit(result)) // if (bothInt && !isNumberExceededIntLimit(result))
return Object(static_cast<ValueType::IntClass>(result)); // return Object(static_cast<ValueType::IntClass>(result));
// int / int maybe decimals
// DO NOT convert it to INT
return Object(result); return Object(result);
} }
throw ValueError(FString(makeTypeErrorMessage("Unsupported operation", "/", lhs, rhs))); throw ValueError(FString(makeTypeErrorMessage("Unsupported operation", "/", lhs, rhs)));

View File

@@ -1,5 +1,5 @@
#include <Ast/Statements/ErrorFlow.hpp> #include <Ast/Statements/ErrorFlow.hpp>
#include "Value/VariableSlot.hpp" #include <Value/VariableSlot.hpp>
#include <Value/value.hpp> #include <Value/value.hpp>
#include <Ast/AccessModifier.hpp> #include <Ast/AccessModifier.hpp>
#include <Ast/Statements/ImplementSt.hpp> #include <Ast/Statements/ImplementSt.hpp>
@@ -17,10 +17,12 @@
#include <Context/context.hpp> #include <Context/context.hpp>
#include <Utils/utils.hpp> #include <Utils/utils.hpp>
#include <Parser/parser.hpp> #include <Parser/parser.hpp>
#include <Core/executablePath.hpp>
#include <filesystem> #include <filesystem>
#include <fstream> #include <fstream>
#include <memory> #include <memory>
#include <unordered_map>
namespace Fig namespace Fig
{ {
@@ -39,8 +41,8 @@ namespace Fig
} }
LvObject Evaluator::evalMemberExpr(Ast::MemberExpr me, ContextPtr ctx) LvObject Evaluator::evalMemberExpr(Ast::MemberExpr me, ContextPtr ctx)
{ {
LvObject base = evalLv(me->base, ctx); // LvObject base = evalLv(me->base, ctx);
RvObject baseVal = base.get(); RvObject baseVal = eval(me->base, ctx);
const FString &member = me->member; const FString &member = me->member;
if (baseVal->getTypeInfo() == ValueType::Module) if (baseVal->getTypeInfo() == ValueType::Module)
{ {
@@ -193,25 +195,26 @@ namespace Fig
switch (exp->getType()) switch (exp->getType())
{ {
case AstType::VarExpr: { case AstType::VarExpr: {
Ast::VarExpr var = std::dynamic_pointer_cast<Ast::VarExprAst>(exp); Ast::VarExpr var = std::static_pointer_cast<Ast::VarExprAst>(exp);
assert(var != nullptr); assert(var != nullptr);
return evalVarExpr(var, ctx); return evalVarExpr(var, ctx);
} }
case AstType::MemberExpr: { case AstType::MemberExpr: {
Ast::MemberExpr me = std::dynamic_pointer_cast<Ast::MemberExprAst>(exp); Ast::MemberExpr me = std::static_pointer_cast<Ast::MemberExprAst>(exp);
assert(me != nullptr); assert(me != nullptr);
return evalMemberExpr(me, ctx); return evalMemberExpr(me, ctx);
} }
case AstType::IndexExpr: { case AstType::IndexExpr: {
Ast::IndexExpr ie = std::dynamic_pointer_cast<Ast::IndexExprAst>(exp); Ast::IndexExpr ie = std::static_pointer_cast<Ast::IndexExprAst>(exp);
assert(ie != nullptr); assert(ie != nullptr);
return evalIndexExpr(ie, ctx); return evalIndexExpr(ie, ctx);
} }
default: { default: {
throw EvaluatorError( // throw EvaluatorError(
u8"TypeError", // u8"TypeError",
std::format("Expression '{}' doesn't refer to a lvalue", exp->typeName().toBasicString()), // std::format("Expression '{}' doesn't refer to a lvalue", exp->typeName().toBasicString()),
exp); // exp);
} }
} }
} }
@@ -297,6 +300,9 @@ namespace Fig
ObjectPtr lhs = eval(lexp, ctx); ObjectPtr lhs = eval(lexp, ctx);
ObjectPtr rhs = eval(rexp, ctx); ObjectPtr rhs = eval(rexp, ctx);
const TypeInfo &lhsType = lhs->getTypeInfo();
const TypeInfo &rhsType = rhs->getTypeInfo();
if (lhs->is<StructInstance>() && rhs->is<StructType>()) if (lhs->is<StructInstance>() && rhs->is<StructType>())
{ {
const StructInstance &si = lhs->as<StructInstance>(); const StructInstance &si = lhs->as<StructInstance>();
@@ -309,10 +315,37 @@ namespace Fig
const InterfaceType &it = rhs->as<InterfaceType>(); const InterfaceType &it = rhs->as<InterfaceType>();
return std::make_shared<Object>(implements(si.parentType, it.type, ctx)); return std::make_shared<Object>(implements(si.parentType, it.type, ctx));
} }
if (ValueType::isTypeBuiltin(lhsType) && rhsType == ValueType::StructType)
{
const StructType &st = rhs->as<StructType>();
const TypeInfo &type = st.type;
/*
如果是内置类型(e.g. Int, String)
那么 eval出来String这个字出来的是StructType
而出来的StructType.type就不会是一个独立的TypeInfo,而是内置的ValueType::String
依次我们可以判断内置类型
e.g:
"123" is String
L OP R
其中 L 类型为 String
而 R 类型为 StructType (builtins.hpp) 中注册
拿到 R 的 StructType, 其中的 type 为 String
*/
if (lhs->getTypeInfo() == type)
{
return Object::getTrueInstance();
}
return Object::getFalseInstance();
}
throw EvaluatorError( throw EvaluatorError(
u8"TypeError", u8"TypeError",
std::format("Operator `is` requires an struct instance on left-hand side, got '{}'", std::format("Unsupported operator `is` for '{}' && '{}'",
lhs->getTypeInfo().toString().toBasicString()), lhsType.toString().toBasicString(),
rhsType.toString().toBasicString()),
bin->lexp); bin->lexp);
} }
@@ -573,6 +606,12 @@ namespace Fig
for (const auto &stmt : fnStruct.body->stmts) for (const auto &stmt : fnStruct.body->stmts)
{ {
StatementResult sr = evalStatement(stmt, newContext); StatementResult sr = evalStatement(stmt, newContext);
if (sr.isError())
{
throw EvaluatorError(u8"UncaughtExceptionError",
std::format("Uncaught exception: {}", sr.result->toString().toBasicString()),
stmt);
}
if (!sr.isNormal()) if (!sr.isNormal())
{ {
retVal = sr.result; retVal = sr.result;
@@ -599,27 +638,27 @@ namespace Fig
switch (type) switch (type)
{ {
case AstType::ValueExpr: { case AstType::ValueExpr: {
auto val = std::dynamic_pointer_cast<Ast::ValueExprAst>(exp); auto val = std::static_pointer_cast<Ast::ValueExprAst>(exp);
assert(val != nullptr); assert(val != nullptr);
return val->val; return val->val;
} }
case AstType::VarExpr: { case AstType::VarExpr: {
auto varExpr = std::dynamic_pointer_cast<Ast::VarExprAst>(exp); auto varExpr = std::static_pointer_cast<Ast::VarExprAst>(exp);
assert(varExpr != nullptr); assert(varExpr != nullptr);
return evalVarExpr(varExpr, ctx).get(); // LvObject -> RvObject return evalVarExpr(varExpr, ctx).get(); // LvObject -> RvObject
} }
case AstType::BinaryExpr: { case AstType::BinaryExpr: {
auto bin = std::dynamic_pointer_cast<Ast::BinaryExprAst>(exp); auto bin = std::static_pointer_cast<Ast::BinaryExprAst>(exp);
assert(bin != nullptr); assert(bin != nullptr);
return evalBinary(bin, ctx); return evalBinary(bin, ctx);
} }
case AstType::UnaryExpr: { case AstType::UnaryExpr: {
auto un = std::dynamic_pointer_cast<Ast::UnaryExprAst>(exp); auto un = std::static_pointer_cast<Ast::UnaryExprAst>(exp);
assert(un != nullptr); assert(un != nullptr);
return evalUnary(un, ctx); return evalUnary(un, ctx);
} }
case AstType::TernaryExpr: { case AstType::TernaryExpr: {
auto te = std::dynamic_pointer_cast<Ast::TernaryExprAst>(exp); auto te = std::static_pointer_cast<Ast::TernaryExprAst>(exp);
assert(te != nullptr); assert(te != nullptr);
return evalTernary(te, ctx); return evalTernary(te, ctx);
} }
@@ -627,7 +666,7 @@ namespace Fig
case AstType::IndexExpr: return evalLv(exp, ctx).get(); case AstType::IndexExpr: return evalLv(exp, ctx).get();
case AstType::FunctionCall: { case AstType::FunctionCall: {
auto fnCall = std::dynamic_pointer_cast<Ast::FunctionCallExpr>(exp); auto fnCall = std::static_pointer_cast<Ast::FunctionCallExpr>(exp);
assert(fnCall != nullptr); assert(fnCall != nullptr);
Ast::Expression callee = fnCall->callee; Ast::Expression callee = fnCall->callee;
@@ -652,7 +691,7 @@ namespace Fig
return evalFunctionCall(fn, fnCall->arg, fnName, ctx); return evalFunctionCall(fn, fnCall->arg, fnName, ctx);
} }
case AstType::FunctionLiteralExpr: { case AstType::FunctionLiteralExpr: {
auto fnLiteral = std::dynamic_pointer_cast<Ast::FunctionLiteralExprAst>(exp); auto fnLiteral = std::static_pointer_cast<Ast::FunctionLiteralExprAst>(exp);
assert(fnLiteral != nullptr); assert(fnLiteral != nullptr);
Ast::BlockStatement body = nullptr; Ast::BlockStatement body = nullptr;
@@ -682,20 +721,14 @@ namespace Fig
return std::make_shared<Object>(std::move(fn)); return std::make_shared<Object>(std::move(fn));
} }
case AstType::InitExpr: { case AstType::InitExpr: {
auto initExpr = std::dynamic_pointer_cast<Ast::InitExprAst>(exp); auto initExpr = std::static_pointer_cast<Ast::InitExprAst>(exp);
if (!ctx->contains(initExpr->structName)) LvObject structeLv = evalLv(initExpr->structe, ctx);
{ ObjectPtr structTypeVal = structeLv.get();
throw EvaluatorError( const FString &structName = structeLv.name();
u8"StructNotFoundError",
std::format("Structure type '{}' not found", initExpr->structName.toBasicString()),
initExpr);
}
ObjectPtr structTypeVal = ctx->get(initExpr->structName)->value;
if (!structTypeVal->is<StructType>()) if (!structTypeVal->is<StructType>())
{ {
throw EvaluatorError( throw EvaluatorError(u8"NotAStructTypeError",
u8"NotAStructTypeError", std::format("'{}' is not a structure type", structName.toBasicString()),
std::format("'{}' is not a structure type", initExpr->structName.toBasicString()),
initExpr); initExpr);
} }
const StructType &structT = structTypeVal->as<StructType>(); const StructType &structT = structTypeVal->as<StructType>();
@@ -717,7 +750,8 @@ namespace Fig
} }
// default value // default value
if (argSize == 0) { if (argSize == 0)
{
if (type == ValueType::Any || type == ValueType::Null || type == ValueType::Function) if (type == ValueType::Any || type == ValueType::Null || type == ValueType::Function)
{ {
throw EvaluatorError( throw EvaluatorError(
@@ -824,7 +858,7 @@ namespace Fig
{ {
throw EvaluatorError(u8"StructInitArgumentMismatchError", throw EvaluatorError(u8"StructInitArgumentMismatchError",
std::format("Structure '{}' expects {} to {} fields, but {} were provided", std::format("Structure '{}' expects {} to {} fields, but {} were provided",
initExpr->structName.toBasicString(), structName.toBasicString(),
minArgs, minArgs,
maxArgs, maxArgs,
initExpr->args.size()), initExpr->args.size()),
@@ -837,7 +871,7 @@ namespace Fig
evaluatedArgs.push_back({argName, eval(argExpr, ctx)}); evaluatedArgs.push_back({argName, eval(argExpr, ctx)});
} }
ContextPtr instanceCtx = std::make_shared<Context>( ContextPtr instanceCtx = std::make_shared<Context>(
FString(std::format("<StructInstance {}>", initExpr->structName.toBasicString())), ctx); FString(std::format("<StructInstance {}>", structName.toBasicString())), ctx);
/* /*
3 ways of calling constructor 3 ways of calling constructor
.1 Person {"Fig", 1, "IDK"}; .1 Person {"Fig", 1, "IDK"};
@@ -869,7 +903,7 @@ namespace Fig
u8"StructFieldTypeMismatchError", u8"StructFieldTypeMismatchError",
std::format( std::format(
"In structure '{}', field '{}' expects type '{}', but got type '{}'", "In structure '{}', field '{}' expects type '{}', but got type '{}'",
initExpr->structName.toBasicString(), structName.toBasicString(),
fieldName.toBasicString(), fieldName.toBasicString(),
expectedType.toString().toBasicString(), expectedType.toString().toBasicString(),
prettyType(defaultVal).toBasicString()), prettyType(defaultVal).toBasicString()),
@@ -886,7 +920,7 @@ namespace Fig
throw EvaluatorError( throw EvaluatorError(
u8"StructFieldTypeMismatchError", u8"StructFieldTypeMismatchError",
std::format("In structure '{}', field '{}' expects type '{}', but got type '{}'", std::format("In structure '{}', field '{}' expects type '{}', but got type '{}'",
initExpr->structName.toBasicString(), structName.toBasicString(),
fieldName.toBasicString(), fieldName.toBasicString(),
expectedType.toString().toBasicString(), expectedType.toString().toBasicString(),
prettyType(argVal).toBasicString()), prettyType(argVal).toBasicString()),
@@ -907,7 +941,7 @@ namespace Fig
throw EvaluatorError(u8"StructFieldRedeclarationError", throw EvaluatorError(u8"StructFieldRedeclarationError",
std::format("Field '{}' already initialized in structure '{}'", std::format("Field '{}' already initialized in structure '{}'",
fieldName.toBasicString(), fieldName.toBasicString(),
initExpr->structName.toBasicString()), structName.toBasicString()),
initExpr); initExpr);
} }
if (i + 1 > got) if (i + 1 > got)
@@ -925,7 +959,7 @@ namespace Fig
u8"StructFieldTypeMismatchError", u8"StructFieldTypeMismatchError",
std::format( std::format(
"In structure '{}', field '{}' expects type '{}', but got type '{}'", "In structure '{}', field '{}' expects type '{}', but got type '{}'",
initExpr->structName.toBasicString(), structName.toBasicString(),
fieldName.toBasicString(), fieldName.toBasicString(),
expectedType.toString().toBasicString(), expectedType.toString().toBasicString(),
prettyType(defaultVal).toBasicString()), prettyType(defaultVal).toBasicString()),
@@ -941,7 +975,7 @@ namespace Fig
throw EvaluatorError( throw EvaluatorError(
u8"StructFieldTypeMismatchError", u8"StructFieldTypeMismatchError",
std::format("In structure '{}', field '{}' expects type '{}', but got type '{}'", std::format("In structure '{}', field '{}' expects type '{}', but got type '{}'",
initExpr->structName.toBasicString(), structName.toBasicString(),
fieldName.toBasicString(), fieldName.toBasicString(),
field.type.toString().toBasicString(), field.type.toString().toBasicString(),
prettyType(argVal).toBasicString()), prettyType(argVal).toBasicString()),
@@ -966,7 +1000,7 @@ namespace Fig
} }
case AstType::ListExpr: { case AstType::ListExpr: {
auto lstExpr = std::dynamic_pointer_cast<Ast::ListExprAst>(exp); auto lstExpr = std::static_pointer_cast<Ast::ListExprAst>(exp);
assert(lstExpr != nullptr); assert(lstExpr != nullptr);
List list; List list;
@@ -975,7 +1009,7 @@ namespace Fig
} }
case AstType::MapExpr: { case AstType::MapExpr: {
auto mapExpr = std::dynamic_pointer_cast<Ast::MapExprAst>(exp); auto mapExpr = std::static_pointer_cast<Ast::MapExprAst>(exp);
assert(mapExpr != nullptr); assert(mapExpr != nullptr);
Map map; Map map;
@@ -983,10 +1017,15 @@ namespace Fig
return std::make_shared<Object>(std::move(map)); return std::make_shared<Object>(std::move(map));
} }
default: assert(false); default:
return Object::getNullInstance(); // ignore warning {
throw RuntimeError(FString(
std::format("err type of expr: {}", magic_enum::enum_name(type))
));
} }
} }
return Object::getNullInstance(); // ignore warning
}
StatementResult Evaluator::evalBlockStatement(Ast::BlockStatement block, ContextPtr ctx) StatementResult Evaluator::evalBlockStatement(Ast::BlockStatement block, ContextPtr ctx)
{ {
StatementResult sr = StatementResult::normal(); StatementResult sr = StatementResult::normal();
@@ -1003,12 +1042,12 @@ namespace Fig
switch (stmt->getType()) switch (stmt->getType())
{ {
case ImportSt: { case ImportSt: {
auto i = std::dynamic_pointer_cast<Ast::ImportSt>(stmt); auto i = std::static_pointer_cast<Ast::ImportSt>(stmt);
assert(i != nullptr); assert(i != nullptr);
return evalImportSt(i, ctx); return evalImportSt(i, ctx);
} }
case VarDefSt: { case VarDefSt: {
auto varDef = std::dynamic_pointer_cast<Ast::VarDefAst>(stmt); auto varDef = std::static_pointer_cast<Ast::VarDefAst>(stmt);
assert(varDef != nullptr); assert(varDef != nullptr);
if (ctx->containsInThisScope(varDef->name)) if (ctx->containsInThisScope(varDef->name))
@@ -1049,7 +1088,7 @@ namespace Fig
} }
case FunctionDefSt: { case FunctionDefSt: {
auto fnDef = std::dynamic_pointer_cast<Ast::FunctionDefSt>(stmt); auto fnDef = std::static_pointer_cast<Ast::FunctionDefSt>(stmt);
assert(fnDef != nullptr); assert(fnDef != nullptr);
const FString &fnName = fnDef->name; const FString &fnName = fnDef->name;
@@ -1069,7 +1108,7 @@ namespace Fig
} }
case StructSt: { case StructSt: {
auto stDef = std::dynamic_pointer_cast<Ast::StructDefSt>(stmt); auto stDef = std::static_pointer_cast<Ast::StructDefSt>(stmt);
assert(stDef != nullptr); assert(stDef != nullptr);
if (ctx->containsInThisScope(stDef->name)) if (ctx->containsInThisScope(stDef->name))
@@ -1121,7 +1160,7 @@ namespace Fig
} }
case InterfaceDefSt: { case InterfaceDefSt: {
auto ifd = std::dynamic_pointer_cast<Ast::InterfaceDefAst>(stmt); auto ifd = std::static_pointer_cast<Ast::InterfaceDefAst>(stmt);
assert(ifd != nullptr); assert(ifd != nullptr);
const FString &interfaceName = ifd->name; const FString &interfaceName = ifd->name;
@@ -1142,7 +1181,7 @@ namespace Fig
} }
case ImplementSt: { case ImplementSt: {
auto ip = std::dynamic_pointer_cast<Ast::ImplementAst>(stmt); auto ip = std::static_pointer_cast<Ast::ImplementAst>(stmt);
assert(ip != nullptr); assert(ip != nullptr);
TypeInfo structType(ip->structName); TypeInfo structType(ip->structName);
@@ -1286,7 +1325,7 @@ namespace Fig
} }
case IfSt: { case IfSt: {
auto ifSt = std::dynamic_pointer_cast<Ast::IfSt>(stmt); auto ifSt = std::static_pointer_cast<Ast::IfSt>(stmt);
ObjectPtr condVal = eval(ifSt->condition, ctx); ObjectPtr condVal = eval(ifSt->condition, ctx);
if (condVal->getTypeInfo() != ValueType::Bool) if (condVal->getTypeInfo() != ValueType::Bool)
{ {
@@ -1313,7 +1352,7 @@ namespace Fig
return StatementResult::normal(); return StatementResult::normal();
}; };
case WhileSt: { case WhileSt: {
auto whileSt = std::dynamic_pointer_cast<Ast::WhileSt>(stmt); auto whileSt = std::static_pointer_cast<Ast::WhileSt>(stmt);
while (true) while (true)
{ {
ObjectPtr condVal = eval(whileSt->condition, ctx); ObjectPtr condVal = eval(whileSt->condition, ctx);
@@ -1336,7 +1375,7 @@ namespace Fig
return StatementResult::normal(); return StatementResult::normal();
}; };
case ForSt: { case ForSt: {
auto forSt = std::dynamic_pointer_cast<Ast::ForSt>(stmt); auto forSt = std::static_pointer_cast<Ast::ForSt>(stmt);
ContextPtr loopContext = std::make_shared<Context>( ContextPtr loopContext = std::make_shared<Context>(
FString(std::format("<For {}:{}>", forSt->getAAI().line, forSt->getAAI().column)), FString(std::format("<For {}:{}>", forSt->getAAI().line, forSt->getAAI().column)),
ctx); // for loop has its own context ctx); // for loop has its own context
@@ -1377,7 +1416,7 @@ namespace Fig
} }
case TrySt: { case TrySt: {
auto tryst = std::dynamic_pointer_cast<Ast::TrySt>(stmt); auto tryst = std::static_pointer_cast<Ast::TrySt>(stmt);
assert(tryst != nullptr); assert(tryst != nullptr);
ContextPtr tryCtx = std::make_shared<Context>( ContextPtr tryCtx = std::make_shared<Context>(
@@ -1416,7 +1455,7 @@ namespace Fig
} }
case ThrowSt: { case ThrowSt: {
auto ts = std::dynamic_pointer_cast<Ast::ThrowSt>(stmt); auto ts = std::static_pointer_cast<Ast::ThrowSt>(stmt);
assert(ts != nullptr); assert(ts != nullptr);
ObjectPtr value = eval(ts->value, ctx); ObjectPtr value = eval(ts->value, ctx);
@@ -1428,7 +1467,7 @@ namespace Fig
} }
case ReturnSt: { case ReturnSt: {
auto returnSt = std::dynamic_pointer_cast<Ast::ReturnSt>(stmt); auto returnSt = std::static_pointer_cast<Ast::ReturnSt>(stmt);
assert(returnSt != nullptr); assert(returnSt != nullptr);
ObjectPtr returnValue = Object::getNullInstance(); // default is null ObjectPtr returnValue = Object::getNullInstance(); // default is null
@@ -1461,7 +1500,7 @@ namespace Fig
} }
case ExpressionStmt: { case ExpressionStmt: {
auto exprStmt = std::dynamic_pointer_cast<Ast::ExpressionStmtAst>(stmt); auto exprStmt = std::static_pointer_cast<Ast::ExpressionStmtAst>(stmt);
assert(exprStmt != nullptr); assert(exprStmt != nullptr);
return StatementResult::normal(eval(exprStmt->exp, ctx)); return StatementResult::normal(eval(exprStmt->exp, ctx));
@@ -1480,6 +1519,14 @@ namespace Fig
static const std::vector<fs::path> defaultLibraryPath{"Library", "Library/fpm"}; static const std::vector<fs::path> defaultLibraryPath{"Library", "Library/fpm"};
std::vector<fs::path> pathToFind(defaultLibraryPath); std::vector<fs::path> pathToFind(defaultLibraryPath);
fs::path interpreterPath = getExecutablePath().parent_path();
for (fs::path &p : pathToFind)
{
p = interpreterPath / p; // 相对路径 -> 绝对路径
}
pathToFind.insert( pathToFind.insert(
pathToFind.begin(), pathToFind.begin(),
fs::path(this->sourcePath.toBasicString()).parent_path()); // first search module at the source file path fs::path(this->sourcePath.toBasicString()).parent_path()); // first search module at the source file path
@@ -1631,14 +1678,14 @@ namespace Fig
for (auto &ast : asts) for (auto &ast : asts)
{ {
Ast::Expression exp; Ast::Expression exp;
if ((exp = std::dynamic_pointer_cast<Ast::ExpressionAst>(ast))) if ((exp = std::dynamic_pointer_cast<Ast::ExpressionAst>(ast))) // 保持 dynamic_pointer_cast !
{ {
sr = StatementResult::normal(eval(exp, global)); sr = StatementResult::normal(eval(exp, global));
} }
else else
{ {
// statement // statement
Ast::Statement stmt = std::dynamic_pointer_cast<Ast::StatementAst>(ast); Ast::Statement stmt = std::static_pointer_cast<Ast::StatementAst>(ast);
assert(stmt != nullptr); assert(stmt != nullptr);
sr = evalStatement(stmt, global); sr = evalStatement(stmt, global);
if (sr.isError()) if (sr.isError())

View File

@@ -28,7 +28,7 @@ This software is licensed under the MIT License. See LICENSE.txt for details.
*/ */
#include <Utils/argparse/argparse.hpp> #include <Utils/argparse/argparse.hpp>
#include <print> // #include <print>
#include <fstream> #include <fstream>
#include <Core/core.hpp> #include <Core/core.hpp>
@@ -38,6 +38,7 @@ This software is licensed under the MIT License. See LICENSE.txt for details.
#include <Utils/AstPrinter.hpp> #include <Utils/AstPrinter.hpp>
#include <Utils/utils.hpp> #include <Utils/utils.hpp>
#include <Error/errorLog.hpp> #include <Error/errorLog.hpp>
#include <Core/runtimeTime.hpp>
static size_t addressableErrorCount = 0; static size_t addressableErrorCount = 0;
static size_t unaddressableErrorCount = 0; static size_t unaddressableErrorCount = 0;
@@ -45,14 +46,18 @@ static size_t unaddressableErrorCount = 0;
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
Time::init();
// init, set start_time (std::chrono::time_point)
argparse::ArgumentParser program("Fig Interpreter", Fig::Core::VERSION.data()); argparse::ArgumentParser program("Fig Interpreter", Fig::Core::VERSION.data());
program.add_argument("source") program.add_argument("source")
.help("source file to be interpreted") .help("source file to be interpreted")
.default_value(std::string("")); .default_value(std::string(""));
program.add_argument("-v", "--version") // program.add_argument("-v", "--version")
.help("get the version of Fig Interpreter") // .help("get the version of Fig Interpreter")
.default_value(false) // .default_value(false)
.implicit_value(true); // .implicit_value(true);
// interpreter // interpreter
try try
@@ -64,11 +69,11 @@ int main(int argc, char **argv)
std::cerr << e.what() << '\n'; std::cerr << e.what() << '\n';
return 1; return 1;
} }
if (program.get<bool>("--version")) // if (program.get<bool>("--version"))
{ // {
std::print("Fig Interpreter version {}\n", Fig::Core::VERSION); // std::print("Fig Interpreter version {}\n", Fig::Core::VERSION);
return 0; // return 0;
} // }
Fig::FString sourcePath(program.get<std::string>("source")); Fig::FString sourcePath(program.get<std::string>("source"));
if (sourcePath.empty()) if (sourcePath.empty())
{ {

View File

@@ -6,6 +6,10 @@
#include <Core/fig_string.hpp> #include <Core/fig_string.hpp>
#include <Utils/utils.hpp> #include <Utils/utils.hpp>
#if 0
#include <iostream> // debug
#endif
namespace Fig namespace Fig
{ {
@@ -339,21 +343,27 @@ namespace Fig
{ {
FString numStr; FString numStr;
bool hasPoint = false; bool hasPoint = false;
// 负号(减号) 直接交由 scanSymbol处理在parser中被分类->与数字结合/变为操作数
while (hasNext()) while (hasNext())
{ {
UTF8Char ch = *it; UTF8Char ch = *it;
if (ch.isDigit() or ch == U'e') // . / e / - for scientific counting
if (ch.isDigit() || ch == U'e')
{ {
numStr += ch.getString(); numStr += ch.getString();
next(); next();
} }
else if (ch == U'-' and numStr.ends_with(U'-')) else if (ch == U'-' && !numStr.empty() && (numStr.ends_with(U'e') || numStr.ends_with(U'E')))
{ {
numStr += ch.getString(); numStr += ch.getString();
next(); next();
} }
else if (ch == U'.' and not hasPoint) else if (ch == U'+' && !numStr.empty() && (numStr.ends_with(U'e') || numStr.ends_with(U'E')))
{
numStr += ch.getString();
next();
}
else if (ch == U'.' && !hasPoint)
{ {
hasPoint = true; hasPoint = true;
numStr += ch.getString(); numStr += ch.getString();
@@ -364,22 +374,84 @@ namespace Fig
break; break;
} }
} }
// Numbers in Fig-lang if (numStr.empty()) { return IllegalTok; }
/*
114514 if (numStr.ends_with(U'e'))
1145.14
1.14e3 -> 1140
1.14e-3 -> 0.00114
.3 -> 0.3
*/
// checking legality
if ((*numStr.end()) == u'e') // e 后面必须跟整数表示科学计数
{ {
error = SyntaxError(FString( error = SyntaxError(
std::format("Ellegal number literal: {}", numStr.toBasicString())), FString(std::format("Illegal number literal: {}", numStr.toBasicString())), this->line, it.column());
this->line, it.column());
return IllegalTok; return IllegalTok;
} }
bool hasDigit = false;
for (auto it = numStr.begin(); it != numStr.end(); ++it)
{
if (isdigit(*it))
{
hasDigit = true;
break;
}
}
if (!hasDigit)
{
error = SyntaxError(
FString(std::format("Illegal number literal: {}", numStr.toBasicString())), this->line, it.column());
return IllegalTok;
}
size_t ePos = numStr.find(U'e');
if (ePos != FString::npos)
{
if (ePos == 0)
{
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
this->line,
it.column());
return IllegalTok;
}
if (ePos + 1 >= numStr.length())
{
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
this->line,
it.column());
return IllegalTok;
}
bool hasDigitAfterE = false;
for (size_t i = ePos + 1; i < numStr.length(); ++i)
{
UTF8Char c = std::u8string(1,numStr[i]);
if (c == U'+' || c == U'-')
{
if (i != ePos + 1)
{
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
this->line,
it.column());
return IllegalTok;
}
continue;
}
if (c.isDigit()) { hasDigitAfterE = true; }
else
{
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
this->line,
it.column());
return IllegalTok;
}
}
if (!hasDigitAfterE)
{
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
this->line,
it.column());
return IllegalTok;
}
}
return Token(numStr, TokenType::LiteralNumber); return Token(numStr, TokenType::LiteralNumber);
} }
Token Lexer::scanSymbol() Token Lexer::scanSymbol()
@@ -434,7 +506,7 @@ namespace Fig
next(); next();
return IllegalTok; return IllegalTok;
} }
// std::cerr << Token(sym, symbol_map.at(sym)).toString().toBasicString() << '\n;
next(); next();
return Token(sym, symbol_map.at(sym)); return Token(sym, symbol_map.at(sym));
} }
@@ -522,13 +594,13 @@ namespace Fig
if (!hasNext()) if (!hasNext())
{ {
next(); next();
// return Token(u8"/", this->symbol_map.at(u8"/")).setPos(last_line, last_column); return Token(u8"/", this->symbol_map.at(u8"/")).setPos(last_line, last_column);
} }
c = it.peek(); c = it.peek();
if (c != U'/' and c != U'*') if (c != U'/' and c != U'*')
{ {
next(); next();
// return Token(u8"/", this->symbol_map.at(u8"/")).setPos(last_line, last_column); return Token(u8"/", this->symbol_map.at(u8"/")).setPos(last_line, last_column);
} }
scanComments().setPos(last_line, last_column); scanComments().setPos(last_line, last_column);
return nextToken(); return nextToken();

View File

@@ -7,17 +7,40 @@
import std.value; // `type` function and string_from import std.value; // `type` function and string_from
struct FormatError
{
public msg: String;
}
impl Error for FormatError
{
getErrorClass()
{
return "FormatError";
}
getErrorMessage()
{
return getErrorClass() + ": " + msg;
}
toString()
{
return getErrorMessage();
}
}
public func format(objects ...) -> Any public func format(objects ...) -> Any
{ {
if objects.length() < 1 if objects.length() < 1
{ {
return null; throw FormatError{"Require format string"};
} }
var fmt := objects[0]; var fmt := objects[0];
if value.type(fmt) != "String" var fmtType := value.type(fmt);
if fmtType != "String"
{ {
return null; throw FormatError{"arg 0 (fmt) must be String type, got " + fmtType};
} }
var result := ""; var result := "";
@@ -33,7 +56,7 @@ public func format(objects ...) -> Any
{ {
if (i + 1 >= length) if (i + 1 >= length)
{ {
return null; throw FormatError{"unclosed brace"};
} }
var nextChar = fmt[i + 1]; var nextChar = fmt[i + 1];
@@ -57,12 +80,12 @@ public func format(objects ...) -> Any
if endIndex == -1 if endIndex == -1
{ {
return null; throw FormatError{"unclosed brace"};
} }
if argIndex >= objects.length() if argIndex >= objects.length()
{ {
return null; throw FormatError{"require enough format expression"};
} }
result += value.string_from(objects[argIndex]); result += value.string_from(objects[argIndex]);
@@ -79,7 +102,7 @@ public func format(objects ...) -> Any
continue; continue;
} }
return null; throw FormatError{"invalid format syntax"};
} }
else else
{ {
@@ -99,13 +122,14 @@ public func formatByListArgs(objects) -> Any
} }
if objects.length() < 1 if objects.length() < 1
{ {
return null; throw FormatError{"Require format string"};
} }
var fmt := objects[0]; var fmt := objects[0];
if value.type(fmt) != "String" var fmtType := value.type(fmt);
if fmtType != "String"
{ {
return null; throw FormatError{"arg 0 (fmt) must be String type, got " + fmtType};
} }
var result := ""; var result := "";
@@ -121,7 +145,7 @@ public func formatByListArgs(objects) -> Any
{ {
if (i + 1 >= length) if (i + 1 >= length)
{ {
return null; throw FormatError{"unclosed brace"};
} }
var nextChar = fmt[i + 1]; var nextChar = fmt[i + 1];
@@ -145,12 +169,12 @@ public func formatByListArgs(objects) -> Any
if endIndex == -1 if endIndex == -1
{ {
return null; throw FormatError{"unclosed brace"};
} }
if argIndex >= objects.length() if argIndex >= objects.length()
{ {
return null; throw FormatError{"require enough format expression"};
} }
result += value.string_from(objects[argIndex]); result += value.string_from(objects[argIndex]);
@@ -167,7 +191,7 @@ public func formatByListArgs(objects) -> Any
continue; continue;
} }
return null; throw FormatError{"invalid format syntax"};
} }
else else
{ {

View File

@@ -43,7 +43,8 @@ public func println(objects...) -> Int
public func printf(objects...) -> Any public func printf(objects...) -> Any
{ {
__fstdout_print(formater.formatByListArgs(objects)); var result := formater.formatByListArgs(objects);
__fstdout_print(result);
} }
// inputs // inputs

View File

@@ -0,0 +1,51 @@
/*
Official Module `time`
Library/time/time.fig
Copyright © 2026 PuqiAR. All rights reserved.
*/
import _builtins; // provides __ftime_now_ns (int64_t)
public struct Time
{
ns: Int; // int64_t, private
public func toNanos() -> Int
{
return ns;
}
public func toMicros() -> Int
{
return __fvalue_int_from(ns / 1000); // convert double to int
}
public func toMillis() -> Double
{
return ns / 1000 / 1000;
}
public func toSeconds() -> Double
{
return ns / 1000 / 1000 / 1000;
}
public func since(other: Time) -> Int
{
const time_ns := other.toNanos();
const result := ns - time_ns;
if result < 0
{
throw "time has reversed! 😢";
}
return result;
}
// TODO: support `-` operator when Fig supports overload
}
public func now() -> Time
{
return Time{__ftime_now_ns()};
}

View File

@@ -1,10 +1,12 @@
#pragma once #pragma once
#include "Ast/Statements/InterfaceDefSt.hpp" #include <Ast/Statements/InterfaceDefSt.hpp>
#include "Ast/functionParameters.hpp" #include <Ast/functionParameters.hpp>
#include <Core/fig_string.hpp> #include <Core/fig_string.hpp>
#include <Value/value.hpp> #include <Value/value.hpp>
#include <Core/runtimeTime.hpp>
#include <chrono>
#include <numeric> #include <numeric>
#include <unordered_map> #include <unordered_map>
#include <functional> #include <functional>
@@ -65,6 +67,7 @@ namespace Fig
{u8"__fvalue_double_parse", 1}, {u8"__fvalue_double_parse", 1},
{u8"__fvalue_double_from", 1}, {u8"__fvalue_double_from", 1},
{u8"__fvalue_string_from", 1}, {u8"__fvalue_string_from", 1},
{u8"__ftime_now_ns", 0},
/* math start */ /* math start */
{u8"__fmath_acos", 1}, {u8"__fmath_acos", 1},
{u8"__fmath_acosh", 1}, {u8"__fmath_acosh", 1},
@@ -194,6 +197,15 @@ namespace Fig
ObjectPtr val = args[0]; ObjectPtr val = args[0];
return std::make_shared<Object>(val->toStringIO()); return std::make_shared<Object>(val->toStringIO());
}}, }},
{u8"__ftime_now_ns",
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
// returns nanoseconds
using namespace Fig::Time;
auto now = Clock::now();
return std::make_shared<Object>(static_cast<ValueType::IntClass>(
std::chrono::duration_cast<std::chrono::nanoseconds>(now - start_time).count()));
}},
/* math start */ /* math start */
{u8"__fmath_acos", {u8"__fmath_acos",
[](const std::vector<ObjectPtr> &args) -> ObjectPtr { [](const std::vector<ObjectPtr> &args) -> ObjectPtr {

View File

@@ -56,7 +56,15 @@ namespace Fig
// {Ast::Operator::Dot, {40, 41}}, // {Ast::Operator::Dot, {40, 41}},
}; };
Ast::VarDef Parser::__parseVarDef(bool isPublic) const std::unordered_map<Ast::Operator, Parser::Precedence> Parser::unaryOpPrecedence = {
{Ast::Operator::Subtract, 150}, // -
{Ast::Operator::BitAnd, 150}, // &
{Ast::Operator::BitNot, 150}, // ~
{Ast::Operator::Not, 150}, // !
};
Ast::VarDef
Parser::__parseVarDef(bool isPublic)
{ {
// entry: current is keyword `var` or `const` // entry: current is keyword `var` or `const`
bool isConst = (currentToken().getType() == TokenType::Const ? true : false); bool isConst = (currentToken().getType() == TokenType::Const ? true : false);
@@ -416,8 +424,7 @@ namespace Fig
block)); block));
continue; continue;
} }
expect(TokenType::Semicolon); expectSemicolon();
next(); // consume `;`
methods.push_back(Ast::InterfaceMethod( methods.push_back(Ast::InterfaceMethod(
funcName, funcName,
@@ -563,7 +570,7 @@ namespace Fig
return makeAst<Ast::TrySt>(body, catches, finallyBlock); return makeAst<Ast::TrySt>(body, catches, finallyBlock);
} }
Ast::Statement Parser::__parseStatement() Ast::Statement Parser::__parseStatement(bool allowExp)
{ {
Ast::Statement stmt; Ast::Statement stmt;
if (isThis(TokenType::EndOfFile)) { return makeAst<Ast::EofStmt>(); } if (isThis(TokenType::EndOfFile)) { return makeAst<Ast::EofStmt>(); }
@@ -585,6 +592,7 @@ namespace Fig
} }
else if (isThis(TokenType::Struct)) else if (isThis(TokenType::Struct))
{ {
next();
stmt = __parseStructDef(true); stmt = __parseStructDef(true);
} }
else if (isThis(TokenType::Interface)) else if (isThis(TokenType::Interface))
@@ -661,13 +669,21 @@ namespace Fig
{ {
stmt = __parseTry(); stmt = __parseTry();
} }
else else if (allowExp)
{ {
// expression statement // expression statement
Ast::Expression exp = parseExpression(0); Ast::Expression exp = parseExpression(0);
expectSemicolon(); expectSemicolon();
stmt = makeAst<Ast::ExpressionStmtAst>(exp); stmt = makeAst<Ast::ExpressionStmtAst>(exp);
} }
else
{
throw SyntaxError(
u8"invalid syntax",
currentAAI.line,
currentAAI.column
);
}
return stmt; return stmt;
} }
Ast::BlockStatement Parser::__parseBlockStatement() Ast::BlockStatement Parser::__parseBlockStatement()
@@ -700,7 +716,7 @@ namespace Fig
} }
else else
{ {
condition = parseExpression(0); condition = parseExpression(0, TokenType::LeftBrace);
} }
// parenthesis is not required // parenthesis is not required
expect(TokenType::LeftBrace); // { expect(TokenType::LeftBrace); // {
@@ -723,7 +739,7 @@ namespace Fig
} }
else else
{ {
elifCondition = parseExpression(0); elifCondition = parseExpression(0, TokenType::LeftBrace);
} }
expect(TokenType::LeftBrace); // { expect(TokenType::LeftBrace); // {
Ast::BlockStatement elifBody = __parseBlockStatement(); Ast::BlockStatement elifBody = __parseBlockStatement();
@@ -776,7 +792,9 @@ namespace Fig
throwAddressableError<SyntaxError>(u8"Control flow statements cannot be used as for loop increment"); throwAddressableError<SyntaxError>(u8"Control flow statements cannot be used as for loop increment");
} }
return __parseStatement(); Ast::Expression exp = parseExpression(0, TokenType::LeftBrace);
// expectSemicolon(); we dont check the semicolon
return makeAst<Ast::ExpressionStmtAst>(exp);
} }
Ast::For Parser::__parseFor() Ast::For Parser::__parseFor()
{ {
@@ -788,14 +806,14 @@ namespace Fig
next(); // consume `(` next(); // consume `(`
// support 3-part for loop // support 3-part for loop
// for init; condition; increment {} // for init; condition; increment {}
Ast::Statement initStmt = __parseStatement(); // auto check `` Ast::Statement initStmt = __parseStatement(false); // auto check ``
Ast::Expression condition = parseExpression(0); Ast::Expression condition = parseExpression(0);
expectSemicolon(); // auto consume `;` expectSemicolon(); // auto consume `;`
Ast::Statement incrementStmt = nullptr; Ast::Statement incrementStmt = nullptr;
if (!isThis(paren ? TokenType::RightParen : TokenType::LeftBrace)) // need parse increment? if (!isThis(paren ? TokenType::RightParen : TokenType::LeftBrace)) // need parse increment?
{ {
auto guard = disableSemicolon(); // auto guard = disableSemicolon();
incrementStmt = __parseIncrementStatement(); incrementStmt = __parseIncrementStatement();
} // after parse increment, semicolon check state restored } // after parse increment, semicolon check state restored
if (paren) if (paren)
@@ -906,7 +924,7 @@ namespace Fig
return makeAst<Ast::MapExprAst>(val); return makeAst<Ast::MapExprAst>(val);
} }
Ast::InitExpr Parser::__parseInitExpr(FString structName) Ast::InitExpr Parser::__parseInitExpr(Ast::Expression structe)
{ {
// entry: current is `{` // entry: current is `{`
next(); // consume `{` next(); // consume `{`
@@ -917,7 +935,7 @@ namespace Fig
.2 Person {name: "Fig", age: 1, sex: "IDK"}; // can be unordered .2 Person {name: "Fig", age: 1, sex: "IDK"}; // can be unordered
.3 Person {name, age, sex}; .3 Person {name, age, sex};
*/ */
uint8_t mode; // 0=undetermined, 1=positional, 2=named, 3=shorthand uint8_t mode = 0; // 0=undetermined, 1=positional, 2=named, 3=shorthand
while (!isThis(TokenType::RightBrace)) while (!isThis(TokenType::RightBrace))
{ {
@@ -977,7 +995,7 @@ namespace Fig
} }
expect(TokenType::RightBrace); expect(TokenType::RightBrace);
next(); // consume `}` next(); // consume `}`
return makeAst<Ast::InitExprAst>(structName, args, return makeAst<Ast::InitExprAst>(structe, args,
(mode == 1 ? Ast::InitExprAst::InitMode::Positional : (mode == 1 ? Ast::InitExprAst::InitMode::Positional :
(mode == 2 ? Ast::InitExprAst::InitMode::Named : Ast::InitExprAst::InitMode::Shorthand))); (mode == 2 ? Ast::InitExprAst::InitMode::Named : Ast::InitExprAst::InitMode::Shorthand)));
} }
@@ -1067,8 +1085,7 @@ namespace Fig
throw SyntaxError(); throw SyntaxError();
} }
} }
expect(TokenType::Semicolon); expectSemicolon();
next(); // consume `;`
return makeAst<Ast::ImportSt>(path); return makeAst<Ast::ImportSt>(path);
} }
@@ -1117,31 +1134,24 @@ namespace Fig
{ {
FString id = tok.getValue(); FString id = tok.getValue();
next(); next();
if (currentToken().getType() == TokenType::LeftBrace)
{
lhs = __parseInitExpr(id); // a_struct{init...}
}
else
{
lhs = __parseVarExpr(id); lhs = __parseVarExpr(id);
} }
}
else if (isTokenOp(tok) && isOpUnary((op = Ast::TokenToOp.at(tok.getType())))) else if (isTokenOp(tok) && isOpUnary((op = Ast::TokenToOp.at(tok.getType()))))
{ {
// prefix // prefix
next(); next();
lhs = __parsePrefix(op, getRightBindingPower(op)); lhs = makeAst<Ast::UnaryExprAst>(op, parseExpression(bp, stop, stop2));
} }
else else
{ {
throwAddressableError<SyntaxError>(FString(u8"Unexpected token in expression")); throwAddressableError<SyntaxError>(FString(u8"Unexpected token in expression:") + tok.toString());
} }
// infix / (postfix) ? // infix / (postfix) ?
while (true) while (true)
{ {
tok = currentToken(); tok = currentToken();
if (tok.getType() == TokenType::Semicolon || tok == EOFTok) break; if (tok.getType() == stop || tok.getType() == stop2|| tok == EOFTok) break;
/* Postfix */ /* Postfix */
@@ -1151,6 +1161,12 @@ namespace Fig
continue; continue;
} }
if (tok.getType() == TokenType::LeftBrace)
{
lhs = __parseInitExpr(lhs);
continue;
}
// member access: a.b // member access: a.b
if (tok.getType() == TokenType::Dot) if (tok.getType() == TokenType::Dot)
{ {
@@ -1169,7 +1185,7 @@ namespace Fig
if (tok.getType() == TokenType::LeftBracket) if (tok.getType() == TokenType::LeftBracket)
{ {
next(); // consume '[' next(); // consume '['
auto indexExpr = parseExpression(0, TokenType::RightBracket); auto indexExpr = parseExpression(0, TokenType::RightBracket, stop2);
expect(TokenType::RightBracket); expect(TokenType::RightBracket);
next(); // consume ']' next(); // consume ']'
@@ -1181,7 +1197,7 @@ namespace Fig
if (tok.getType() == TokenType::Question) if (tok.getType() == TokenType::Question)
{ {
next(); // consume ? next(); // consume ?
Ast::Expression trueExpr = parseExpression(0, TokenType::Colon); Ast::Expression trueExpr = parseExpression(0, TokenType::Colon, stop2);
expect(TokenType::Colon); expect(TokenType::Colon);
next(); // consume : next(); // consume :
Ast::Expression falseExpr = parseExpression(0, TokenType::Semicolon, stop2); Ast::Expression falseExpr = parseExpression(0, TokenType::Semicolon, stop2);
@@ -1196,7 +1212,7 @@ namespace Fig
if (bp >= lbp) break; if (bp >= lbp) break;
next(); // consume op next(); // consume op
lhs = __parseInfix(lhs, op, getRightBindingPower(op)); lhs = makeAst<Ast::BinaryExprAst>(lhs, op, parseExpression(bp, stop, stop2));
} }
return lhs; return lhs;

View File

@@ -1,5 +1,6 @@
#pragma once #pragma once
#include "Ast/astBase.hpp"
#include <Ast/ast.hpp> #include <Ast/ast.hpp>
#include <Lexer/lexer.hpp> #include <Lexer/lexer.hpp>
#include <Core/fig_string.hpp> #include <Core/fig_string.hpp>
@@ -38,15 +39,8 @@ namespace Fig
bool original; bool original;
public: public:
SemicolonDisabler(Parser *parser) : SemicolonDisabler(Parser *parser) : p(parser), original(p->needSemicolon) { p->needSemicolon = false; }
p(parser), original(p->needSemicolon) ~SemicolonDisabler() { p->needSemicolon = original; }
{
p->needSemicolon = false;
}
~SemicolonDisabler()
{
p->needSemicolon = original;
}
// disable copy and assign // disable copy and assign
SemicolonDisabler(const SemicolonDisabler &) = delete; SemicolonDisabler(const SemicolonDisabler &) = delete;
SemicolonDisabler &operator=(const SemicolonDisabler &) = delete; SemicolonDisabler &operator=(const SemicolonDisabler &) = delete;
@@ -65,14 +59,8 @@ namespace Fig
output.push_back(node); output.push_back(node);
} }
bool isTokenSymbol(Token tok) bool isTokenSymbol(Token tok) { return Lexer::symbol_map.contains(tok.getValue()); }
{ bool isTokenOp(Token tok) { return Ast::TokenToOp.contains(tok.getType()); }
return Lexer::symbol_map.contains(tok.getValue());
}
bool isTokenOp(Token tok)
{
return Ast::TokenToOp.contains(tok.getType());
}
bool isEOF() bool isEOF()
{ {
if (tokenPruduced == 0) return false; if (tokenPruduced == 0) return false;
@@ -82,21 +70,19 @@ namespace Fig
public: public:
using Precedence = uint32_t; using Precedence = uint32_t;
static const std::unordered_map<Ast::Operator, std::pair<Precedence, Precedence>> opPrecedence; static const std::unordered_map<Ast::Operator, std::pair<Precedence, Precedence>> opPrecedence;
Parser(const Lexer &_lexer) : static const std::unordered_map<Ast::Operator, Precedence> unaryOpPrecedence;
lexer(_lexer)
{
}
AddressableError* getError() const Parser(const Lexer &_lexer) : lexer(_lexer) {}
{
return error.get(); AddressableError *getError() const { return error.get(); }
}
template <class _ErrT, typename = AddressableError> template <class _ErrT, typename = AddressableError>
void throwAddressableError(FString msg, size_t line, size_t column, std::source_location loc = std::source_location::current()) void throwAddressableError(FString msg,
size_t line,
size_t column,
std::source_location loc = std::source_location::current())
{ {
static_assert(std::is_base_of_v<AddressableError, _ErrT>, static_assert(std::is_base_of_v<AddressableError, _ErrT>, "_ErrT must derive from AddressableError");
"_ErrT must derive from AddressableError");
_ErrT spError(msg, line, column, loc); _ErrT spError(msg, line, column, loc);
error = std::make_unique<_ErrT>(spError); error = std::make_unique<_ErrT>(spError);
throw spError; throw spError;
@@ -104,8 +90,7 @@ namespace Fig
template <class _ErrT, typename = AddressableError> template <class _ErrT, typename = AddressableError>
void throwAddressableError(FString msg, std::source_location loc = std::source_location::current()) void throwAddressableError(FString msg, std::source_location loc = std::source_location::current())
{ {
static_assert(std::is_base_of_v<AddressableError, _ErrT>, static_assert(std::is_base_of_v<AddressableError, _ErrT>, "_ErrT must derive from AddressableError");
"_ErrT must derive from AddressableError");
// line, column provide by `currentAAI` // line, column provide by `currentAAI`
_ErrT spError(msg, currentAAI.line, currentAAI.column, loc); _ErrT spError(msg, currentAAI.line, currentAAI.column, loc);
error = std::make_unique<_ErrT>(spError); error = std::make_unique<_ErrT>(spError);
@@ -115,22 +100,15 @@ namespace Fig
template <class _ErrT, typename = UnaddressableError> template <class _ErrT, typename = UnaddressableError>
void throwUnaddressableError(FString msg, std::source_location loc = std::source_location::current()) void throwUnaddressableError(FString msg, std::source_location loc = std::source_location::current())
{ {
static_assert(std::is_base_of_v<AddressableError, _ErrT>, static_assert(std::is_base_of_v<AddressableError, _ErrT>, "_ErrT must derive from AddressableError");
"_ErrT must derive from AddressableError");
_ErrT spError(msg, loc); _ErrT spError(msg, loc);
error = std::make_unique<_ErrT>(spError); error = std::make_unique<_ErrT>(spError);
throw spError; throw spError;
} }
void setCurrentAAI(Ast::AstAddressInfo _aai) void setCurrentAAI(Ast::AstAddressInfo _aai) { currentAAI = std::move(_aai); }
{
currentAAI = std::move(_aai);
}
Ast::AstAddressInfo getCurrentAAI() const Ast::AstAddressInfo getCurrentAAI() const { return currentAAI; }
{
return currentAAI;
}
inline const Token &nextToken() inline const Token &nextToken()
{ {
@@ -143,7 +121,8 @@ namespace Fig
if (int64_t(currentTokenIndex - 1) < int64_t(0)) if (int64_t(currentTokenIndex - 1) < int64_t(0))
// 同下 next注释 // 同下 next注释
{ {
throw std::runtime_error("Internal Error in Parser::rollbackToken, trying to rollback but it's already on the begin"); throw std::runtime_error(
"Internal Error in Parser::rollbackToken, trying to rollback but it's already on the begin");
} }
currentTokenIndex--; currentTokenIndex--;
} }
@@ -152,7 +131,8 @@ namespace Fig
if (int64_t(currentTokenIndex) < (int64_t(tokenPruduced) - 1)) if (int64_t(currentTokenIndex) < (int64_t(tokenPruduced) - 1))
{ {
/* /*
必须两个都显示转换为int64_t.否则负数时会超出范围变成int64_t max, 并且 CTI也需要显示转换否则转换完的pruduced又会被转回去变为 int64_t max 必须两个都显示转换为int64_t.否则负数时会超出范围变成int64_t max, 并且
CTI也需要显示转换否则转换完的pruduced又会被转回去变为 int64_t max
*/ */
currentTokenIndex++; currentTokenIndex++;
setCurrentAAI(Ast::AstAddressInfo{.line = currentToken().line, .column = currentToken().column}); setCurrentAAI(Ast::AstAddressInfo{.line = currentToken().line, .column = currentToken().column});
@@ -184,18 +164,11 @@ namespace Fig
return tok; return tok;
} }
std::pair<Precedence, Precedence> getBindingPower(Ast::Operator op) const std::pair<Precedence, Precedence> &getBindingPower(Ast::Operator op) const { return opPrecedence.at(op); }
{ Precedence getLeftBindingPower(Ast::Operator op) const { return getBindingPower(op).first; }
return opPrecedence.at(op); Precedence getRightBindingPower(Ast::Operator op) const { return getBindingPower(op).second; }
}
Precedence getLeftBindingPower(Ast::Operator op) const Precedence &getUnaryBp(Ast::Operator op) const { return unaryOpPrecedence.at(op); }
{
return getBindingPower(op).first;
}
Precedence getRightBindingPower(Ast::Operator op)
{
return getBindingPower(op).second;
}
// template <class _Tp, class... Args> // template <class _Tp, class... Args>
// std::shared_ptr<_Tp> makeAst(Args &&...args) // std::shared_ptr<_Tp> makeAst(Args &&...args)
@@ -218,7 +191,8 @@ namespace Fig
{ {
throwAddressableError<SyntaxError>(FString(std::format("Expected `{}`, but got `{}`", throwAddressableError<SyntaxError>(FString(std::format("Expected `{}`, but got `{}`",
magic_enum::enum_name(type), magic_enum::enum_name(type),
magic_enum::enum_name(peekToken().getType()))), loc); magic_enum::enum_name(peekToken().getType()))),
loc);
} }
} }
@@ -226,9 +200,11 @@ namespace Fig
{ {
if (currentToken().getType() != type) if (currentToken().getType() != type)
{ {
throwAddressableError<SyntaxError>(FString(std::format("Expected `{}`, but got `{}`", throwAddressableError<SyntaxError>(
FString(std::format("Expected `{}`, but got `{}`",
magic_enum::enum_name(type), magic_enum::enum_name(type),
magic_enum::enum_name(currentToken().getType()))), loc); magic_enum::enum_name(currentToken().getType()))),
loc);
} }
} }
@@ -238,7 +214,8 @@ namespace Fig
{ {
throwAddressableError<SyntaxError>(FString(std::format("Expected `{}`, but got `{}`", throwAddressableError<SyntaxError>(FString(std::format("Expected `{}`, but got `{}`",
expected.toBasicString(), expected.toBasicString(),
magic_enum::enum_name(peekToken().getType()))), loc); magic_enum::enum_name(peekToken().getType()))),
loc);
} }
} }
@@ -246,16 +223,15 @@ namespace Fig
{ {
if (currentToken().getType() != type) if (currentToken().getType() != type)
{ {
throwAddressableError<SyntaxError>(FString(std::format("Expected `{}`, but got `{}`", throwAddressableError<SyntaxError>(
FString(std::format("Expected `{}`, but got `{}`",
expected.toBasicString(), expected.toBasicString(),
magic_enum::enum_name(currentToken().getType()))), loc); magic_enum::enum_name(currentToken().getType()))),
loc);
} }
} }
[[nodiscard]] SemicolonDisabler disableSemicolon() [[nodiscard]] SemicolonDisabler disableSemicolon() { return SemicolonDisabler(this); }
{
return SemicolonDisabler(this);
}
void expectSemicolon() void expectSemicolon()
{ {
@@ -287,14 +263,8 @@ namespace Fig
next(); next();
} }
bool isNext(TokenType type) bool isNext(TokenType type) { return peekToken().getType() == type; }
{ bool isThis(TokenType type) { return currentToken().getType() == type; }
return peekToken().getType() == type;
}
bool isThis(TokenType type)
{
return currentToken().getType() == type;
}
static constexpr FString varDefTypeFollowed = u8"(Followed)"; static constexpr FString varDefTypeFollowed = u8"(Followed)";
@@ -314,7 +284,8 @@ namespace Fig
Ast::VarExpr __parseVarExpr(FString); Ast::VarExpr __parseVarExpr(FString);
Ast::FunctionDef __parseFunctionDef(bool); // entry: current is Token::Identifier (isPublic: Bool) Ast::FunctionDef __parseFunctionDef(bool); // entry: current is Token::Identifier (isPublic: Bool)
Ast::StructDef __parseStructDef(bool); // entry: current is Token::Identifier (struct name) arg(isPublic: bool) Ast::StructDef __parseStructDef(bool); // entry: current is Token::Identifier (struct name) arg(isPublic: bool)
Ast::InterfaceDef __parseInterfaceDef(bool); // entry: current is Token::Identifier (interface name) arg(isPublic: bool) Ast::InterfaceDef
__parseInterfaceDef(bool); // entry: current is Token::Identifier (interface name) arg(isPublic: bool)
Ast::Implement __parseImplement(); // entry: current is `impl` Ast::Implement __parseImplement(); // entry: current is `impl`
Ast::Throw __parseThrow(); // entry: current is `throw` Ast::Throw __parseThrow(); // entry: current is `throw`
@@ -327,14 +298,15 @@ namespace Fig
Ast::ListExpr __parseListExpr(); // entry: current is `[` Ast::ListExpr __parseListExpr(); // entry: current is `[`
Ast::MapExpr __parseMapExpr(); // entry: current is `{` Ast::MapExpr __parseMapExpr(); // entry: current is `{`
Ast::InitExpr __parseInitExpr(FString); // entry: current is `{`, ahead is struct name. arg (struct name : FString) Ast::InitExpr __parseInitExpr(
Ast::Expression); // entry: current is `{`, ahead is struct type exp.
Ast::Expression __parseTupleOrParenExpr(); // entry: current is `(` Ast::Expression __parseTupleOrParenExpr(); // entry: current is `(`
Ast::FunctionLiteralExpr __parseFunctionLiteralExpr(); // entry: current is Token::LParen after Token::Function Ast::FunctionLiteralExpr __parseFunctionLiteralExpr(); // entry: current is Token::LParen after Token::Function
Ast::Import __parseImport(); // entry: current is Token::Import Ast::Import __parseImport(); // entry: current is Token::Import
Ast::Statement __parseStatement(); // entry: (idk) Ast::Statement __parseStatement(bool = true); // entry: (idk)
Ast::Expression parseExpression(Precedence, TokenType = TokenType::Semicolon, TokenType = TokenType::Semicolon); Ast::Expression parseExpression(Precedence, TokenType = TokenType::Semicolon, TokenType = TokenType::Semicolon);
std::vector<Ast::AstBase> parseAll(); std::vector<Ast::AstBase> parseAll();
}; };

29
src/VMValue/VMValue.cpp Normal file
View File

@@ -0,0 +1,29 @@
#include <VMValue/VMValue.hpp>
#include <cassert>
#include <string>
namespace Fig
{
FString Value::toString() const
{
if (static_cast<int>(type) > static_cast<int>(Double))
{
return heap->toString();
}
switch (type)
{
case Null:
return u8"null";
case Bool:
return (b ? u8"true" : u8"false");
case Int:
return FString(std::to_string(i));
case Double:
return FString(std::to_string(d));
default:
assert(false);
}
}
};

91
src/VMValue/VMValue.hpp Normal file
View File

@@ -0,0 +1,91 @@
#pragma once
/*
value system for virtual machine
not Evaluator value
*/
#include <Core/fig_string.hpp>
#include <cstdint>
namespace Fig
{
struct HeapObject;
struct Value
{
struct NullObject {};
enum _Type : uint8_t
{
Null = 0,
Bool,
Int,
Double,
/* Complex types, alloc in heap*/
String,
// Function,
// StructType,
// StructInstance,
// List,
// Map,
// Module,
// InterfaceType
} type;
union
{
NullObject n;
bool b;
int64_t i;
double d;
HeapObject *heap;
};
Value()
{
type = Null;
n = NullObject();
}
Value(bool _b)
{
type = Bool;
b = _b;
}
Value(int64_t _i)
{
type = Int;
i = _i;
}
Value(double _d)
{
type = Double;
d = _d;
}
FString toString() const;
};
struct HeapObject
{
Value::_Type type; // > 3
virtual FString toString() const = 0;
};
struct String : HeapObject
{
FString value;
virtual FString toString() const override
{
return value;
}
};
};

View File

@@ -0,0 +1,43 @@
/*
███████████ █████ █████ ██████████ ███████████ █████ █████████ █████ █████████ ██████ █████ █████████ █████ █████ █████████ █████████ ██████████
░█░░░███░░░█░░███ ░░███ ░░███░░░░░█ ░░███░░░░░░█░░███ ███░░░░░███ ░░███ ███░░░░░███ ░░██████ ░░███ ███░░░░░███░░███ ░░███ ███░░░░░███ ███░░░░░███░░███░░░░░█
░ ░███ ░ ░███ ░███ ░███ █ ░ ░███ █ ░ ░███ ███ ░░░ ░███ ░███ ░███ ░███░███ ░███ ███ ░░░ ░███ ░███ ░███ ░███ ███ ░░░ ░███ █ ░
░███ ░███████████ ░██████ ░███████ ░███ ░███ ░███ ░███████████ ░███░░███░███ ░███ ░███ ░███ ░███████████ ░███ ░██████
░███ ░███░░░░░███ ░███░░█ ░███░░░█ ░███ ░███ █████ ░███ ░███░░░░░███ ░███ ░░██████ ░███ █████ ░███ ░███ ░███░░░░░███ ░███ █████ ░███░░█
░███ ░███ ░███ ░███ ░ █ ░███ ░ ░███ ░░███ ░░███ ░███ █ ░███ ░███ ░███ ░░█████ ░░███ ░░███ ░███ ░███ ░███ ░███ ░░███ ░░███ ░███ ░ █
█████ █████ █████ ██████████ █████ █████ ░░█████████ ███████████ █████ █████ █████ ░░█████ ░░█████████ ░░████████ █████ █████ ░░█████████ ██████████
░░░░░ ░░░░░ ░░░░░ ░░░░░░░░░░ ░░░░░ ░░░░░ ░░░░░░░░░ ░░░░░░░░░░░ ░░░░░ ░░░░░ ░░░░░ ░░░░░ ░░░░░░░░░ ░░░░░░░░ ░░░░░ ░░░░░ ░░░░░░░░░ ░░░░░░░░░░
Copyright (C) 2020-2026 PuqiAR
This software is licensed under the MIT License. See LICENSE for details.
*/
// DO NOT USE CLANG-FORMAT FOR THIS FILE
#include <Bytecode/Bytecode.hpp>
#include <iostream>
int main()
{
using namespace Fig;
std::vector<OpCodeType> src;
{
using enum Bytecode;
src = {
0x21, // LOAD_TRUE
0x23, 0x7f, // LOAD_CON8 0x7f
0x24, 0x12, 0x34, // LOAD_CON16 0x1234
0x25, 0x12, 0x34, 0x56, 0x78, // LOAD_CON32 0x12345678
0x63, 0x12, 0x34, 0x56, 0x78 // JUMP32_IF_TRUE
};
FString r = reverseCompile(src);
std::cout << r.toBasicString() << std::endl;
}
}

View File

@@ -7,7 +7,6 @@ target("Fig")
set_kind("binary") set_kind("binary")
set_languages("c++23") set_languages("c++23")
add_ldflags("-static", {force = true}) add_ldflags("-static", {force = true})
if is_plat("linux") then if is_plat("linux") then
-- Linux: clang + libc++ -- Linux: clang + libc++
@@ -27,15 +26,52 @@ target("Fig")
end end
add_files("src/main.cpp") add_files("src/Evaluator/main.cpp")
add_files("src/Core/warning.cpp") add_files("src/Core/warning.cpp")
add_files("src/Core/runtimeTime.cpp")
add_files("src/Evaluator/evaluator.cpp") add_files("src/Evaluator/evaluator.cpp")
add_files("src/Evaluator/Value/value.cpp")
add_files("src/Lexer/lexer.cpp") add_files("src/Lexer/lexer.cpp")
add_files("src/Parser/parser.cpp") add_files("src/Parser/parser.cpp")
add_files("src/Value/value.cpp")
add_includedirs("src") add_includedirs("src")
add_includedirs("src/Evaluator")
set_warnings("all") set_warnings("all")
add_defines("__FCORE_COMPILE_TIME=\"" .. os.date("%Y-%m-%d %H:%M:%S") .. "\"") add_defines("__FCORE_COMPILE_TIME=\"" .. os.date("%Y-%m-%d %H:%M:%S") .. "\"")
-- -- Bytecode VM target
-- target("Figc")
-- set_kind("binary")
-- set_languages("c++23")
-- add_ldflags("-static", {force = true})
-- if is_plat("linux") then
-- -- Linux: clang + libc++
-- set_toolchains("clang")
-- add_cxxflags("-stdlib=libc++")
-- add_ldflags("-stdlib=libc++")
-- elseif is_plat("windows") then
-- -- 1. CI cross (Linux -> Windows)
-- -- 2. local dev (Windows + llvm-mingw)
-- set_toolchains("mingw") -- llvm-mingw
-- add_ldflags("-Wl,--stack,268435456")
-- -- set_toolchains("clang")
-- -- static lib
-- -- add_ldflags("-target x86_64-w64-mingw32", "-static")
-- -- add_cxxflags("-stdlib=libc++")
-- -- add_ldflags("-stdlib=libc++")
-- end
-- add_includedirs("src/Evaluator")
-- add_files("src/Evaluator/Value/value.cpp")
-- add_files("src/VirtualMachine/main.cpp")
-- add_files("src/Core/warning.cpp")
-- add_files("src/Lexer/lexer.cpp")
-- add_files("src/Parser/parser.cpp")
-- add_includedirs("src")
-- set_warnings("all")
-- add_defines("__FCORE_COMPILE_TIME=\"" .. os.date("%Y-%m-%d %H:%M:%S") .. "\"")