forked from PuqiAR/Fig-TreeWalker
Compare commits
10 Commits
dev-build
...
v0.4.0-alp
| Author | SHA1 | Date | |
|---|---|---|---|
| 9e3f17711f | |||
| d398d457b5 | |||
| ccf80536b3 | |||
| 13fdbec0c4 | |||
| 99e00492f5 | |||
| 310d79acc5 | |||
| e28921ae02 | |||
| 1ccc63419d | |||
| 3b5e99242f | |||
| 85bdab5db3 |
@@ -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版本发布完成!"
|
||||||
@@ -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'])
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,6 +100,8 @@ namespace Fig::Ast
|
|||||||
struct AstAddressInfo
|
struct AstAddressInfo
|
||||||
{
|
{
|
||||||
size_t line, column;
|
size_t line, column;
|
||||||
|
std::shared_ptr<FString> sourcePath;
|
||||||
|
std::shared_ptr<std::vector<FString>> sourceLines;
|
||||||
};
|
};
|
||||||
|
|
||||||
class _AstBase
|
class _AstBase
|
||||||
@@ -238,9 +240,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
125
src/Bytecode/Bytecode.hpp
Normal 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
21
src/Compiler/Compiler.cpp
Normal 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
32
src/Compiler/Compiler.hpp
Normal 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
|
||||||
@@ -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.4.0-alpha"
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#define __FCORE_PLATFORM "Windows"
|
#define __FCORE_PLATFORM "Windows"
|
||||||
|
|||||||
21
src/Core/executablePath.hpp
Normal file
21
src/Core/executablePath.hpp
Normal 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
|
||||||
@@ -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
18
src/Core/runtimeTime.cpp
Normal 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
10
src/Core/runtimeTime.hpp
Normal 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();
|
||||||
|
};
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <format>
|
#include <format>
|
||||||
#include <source_location>
|
#include <source_location>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
@@ -16,8 +17,10 @@ namespace Fig
|
|||||||
explicit AddressableError(FString _msg,
|
explicit AddressableError(FString _msg,
|
||||||
size_t _line,
|
size_t _line,
|
||||||
size_t _column,
|
size_t _column,
|
||||||
|
FString _sourcePath,
|
||||||
|
std::vector<FString> _sourceLines,
|
||||||
std::source_location loc = std::source_location::current()) :
|
std::source_location loc = std::source_location::current()) :
|
||||||
src_loc(loc), line(_line), column(_column)
|
src_loc(loc), line(_line), column(_column), sourcePath(std::move(_sourcePath)), sourceLines(std::move(_sourceLines))
|
||||||
{
|
{
|
||||||
message = _msg;
|
message = _msg;
|
||||||
}
|
}
|
||||||
@@ -33,9 +36,11 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
std::source_location src_loc;
|
std::source_location src_loc;
|
||||||
|
|
||||||
size_t getLine() const { return line; }
|
virtual size_t getLine() const { return line; }
|
||||||
size_t getColumn() const { return column; }
|
virtual size_t getColumn() const { return column; }
|
||||||
FString getMessage() const { return message; }
|
FString getMessage() const { return message; }
|
||||||
|
FString getSourcePath() const { return sourcePath; }
|
||||||
|
std::vector<FString> getSourceLines() const { return sourceLines; }
|
||||||
|
|
||||||
virtual FString getErrorType() const
|
virtual FString getErrorType() const
|
||||||
{
|
{
|
||||||
@@ -45,6 +50,9 @@ namespace Fig
|
|||||||
protected:
|
protected:
|
||||||
size_t line, column;
|
size_t line, column;
|
||||||
FString message;
|
FString message;
|
||||||
|
|
||||||
|
FString sourcePath;
|
||||||
|
std::vector<FString> sourceLines;
|
||||||
};
|
};
|
||||||
|
|
||||||
class UnaddressableError : public std::exception
|
class UnaddressableError : public std::exception
|
||||||
@@ -84,14 +92,6 @@ namespace Fig
|
|||||||
public:
|
public:
|
||||||
using AddressableError::AddressableError;
|
using AddressableError::AddressableError;
|
||||||
|
|
||||||
explicit SyntaxError(FString _msg,
|
|
||||||
size_t _line,
|
|
||||||
size_t _column,
|
|
||||||
std::source_location loc = std::source_location::current()) :
|
|
||||||
AddressableError(_msg, _line, _column, loc)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual FString toString() const override
|
virtual FString toString() const override
|
||||||
{
|
{
|
||||||
std::string msg = std::format("[SyntaxError] {} in [{}] {}", this->message.toBasicString(), this->src_loc.file_name(), this->src_loc.function_name());
|
std::string msg = std::format("[SyntaxError] {} in [{}] {}", this->message.toBasicString(), this->src_loc.file_name(), this->src_loc.function_name());
|
||||||
|
|||||||
@@ -98,8 +98,11 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void logAddressableError(const AddressableError &err, FString fileName, std::vector<FString> sourceLines)
|
inline void logAddressableError(const AddressableError &err)
|
||||||
{
|
{
|
||||||
|
const FString &fileName = err.getSourcePath();
|
||||||
|
const std::vector<FString> &sourceLines = err.getSourceLines();
|
||||||
|
|
||||||
std::print("\n");
|
std::print("\n");
|
||||||
namespace TC = TerminalColors;
|
namespace TC = TerminalColors;
|
||||||
coloredPrint(TC::LightWhite, "An error occurred! ");
|
coloredPrint(TC::LightWhite, "An error occurred! ");
|
||||||
|
|||||||
@@ -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";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -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)));
|
||||||
@@ -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,16 @@
|
|||||||
#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>
|
||||||
|
|
||||||
|
#ifndef SourceInfo
|
||||||
|
#define SourceInfo(ptr) (ptr->sourcePath), (ptr->sourceLines)
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
@@ -39,8 +45,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,17 +199,17 @@ 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);
|
||||||
}
|
}
|
||||||
@@ -297,6 +303,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 +318,33 @@ 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));
|
||||||
}
|
}
|
||||||
throw EvaluatorError(
|
|
||||||
u8"TypeError",
|
if (ValueType::isTypeBuiltin(lhsType) && rhsType == ValueType::StructType)
|
||||||
std::format("Operator `is` requires an struct instance on left-hand side, got '{}'",
|
{
|
||||||
lhs->getTypeInfo().toString().toBasicString()),
|
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(u8"TypeError",
|
||||||
|
std::format("Unsupported operator `is` for '{}' && '{}'",
|
||||||
|
lhsType.toString().toBasicString(),
|
||||||
|
rhsType.toString().toBasicString()),
|
||||||
bin->lexp);
|
bin->lexp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -573,6 +605,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 +637,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 +665,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 +690,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 +720,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 +749,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 +857,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 +870,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 +902,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 +919,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 +940,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 +958,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 +974,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 +999,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 +1008,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 +1016,12 @@ 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 +1038,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 +1084,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 +1104,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 +1156,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 +1177,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 +1321,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 +1348,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 +1371,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 +1412,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 +1451,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 +1463,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
|
||||||
@@ -1439,11 +1474,13 @@ namespace Fig
|
|||||||
case BreakSt: {
|
case BreakSt: {
|
||||||
if (!ctx->parent)
|
if (!ctx->parent)
|
||||||
{
|
{
|
||||||
throw EvaluatorError(u8"BreakOutsideLoopError", u8"`break` statement outside loop", stmt);
|
throw EvaluatorError(
|
||||||
|
u8"BreakOutsideLoopError", u8"`break` statement outside loop", stmt);
|
||||||
}
|
}
|
||||||
if (!ctx->isInLoopContext())
|
if (!ctx->isInLoopContext())
|
||||||
{
|
{
|
||||||
throw EvaluatorError(u8"BreakOutsideLoopError", u8"`break` statement outside loop", stmt);
|
throw EvaluatorError(
|
||||||
|
u8"BreakOutsideLoopError", u8"`break` statement outside loop", stmt);
|
||||||
}
|
}
|
||||||
return StatementResult::breakFlow();
|
return StatementResult::breakFlow();
|
||||||
}
|
}
|
||||||
@@ -1451,17 +1488,19 @@ namespace Fig
|
|||||||
case ContinueSt: {
|
case ContinueSt: {
|
||||||
if (!ctx->parent)
|
if (!ctx->parent)
|
||||||
{
|
{
|
||||||
throw EvaluatorError(u8"ContinueOutsideLoopError", u8"`continue` statement outside loop", stmt);
|
throw EvaluatorError(
|
||||||
|
u8"ContinueOutsideLoopError", u8"`continue` statement outside loop", stmt);
|
||||||
}
|
}
|
||||||
if (!ctx->isInLoopContext())
|
if (!ctx->isInLoopContext())
|
||||||
{
|
{
|
||||||
throw EvaluatorError(u8"ContinueOutsideLoopError", u8"`continue` statement outside loop", stmt);
|
throw EvaluatorError(
|
||||||
|
u8"ContinueOutsideLoopError", u8"`continue` statement outside loop", stmt);
|
||||||
}
|
}
|
||||||
return StatementResult::continueFlow();
|
return StatementResult::continueFlow();
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
@@ -1573,28 +1620,30 @@ namespace Fig
|
|||||||
|
|
||||||
ContextPtr Evaluator::loadModule(const std::filesystem::path &path)
|
ContextPtr Evaluator::loadModule(const std::filesystem::path &path)
|
||||||
{
|
{
|
||||||
|
FString modSourcePath(path.string());
|
||||||
std::ifstream file(path);
|
std::ifstream file(path);
|
||||||
assert(file.is_open());
|
assert(file.is_open());
|
||||||
|
|
||||||
std::string source((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
|
std::string source((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
|
||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
Lexer lexer((FString(source)));
|
std::vector<FString> modSourceLines = Utils::splitSource(FString(source));
|
||||||
Parser parser(lexer);
|
|
||||||
std::vector<Ast::AstBase> asts;
|
|
||||||
|
|
||||||
std::vector<FString> sourceLines = Utils::splitSource(FString(source));
|
Lexer lexer((FString(source)), modSourcePath, modSourceLines);
|
||||||
|
Parser parser(lexer, modSourcePath, modSourceLines);
|
||||||
|
std::vector<Ast::AstBase> asts;
|
||||||
|
|
||||||
asts = parser.parseAll();
|
asts = parser.parseAll();
|
||||||
|
|
||||||
Evaluator evaluator;
|
Evaluator evaluator;
|
||||||
evaluator.SetSourcePath(FString(path.string()));
|
evaluator.SetSourcePath(modSourcePath);
|
||||||
|
evaluator.SetSourceLines(modSourceLines);
|
||||||
|
|
||||||
ContextPtr modctx = std::make_shared<Context>(FString(std::format("<Module at {}>", path.string())), nullptr);
|
ContextPtr modctx = std::make_shared<Context>(FString(std::format("<Module at {}>", path.string())), nullptr);
|
||||||
|
|
||||||
evaluator.SetGlobalContext(modctx);
|
evaluator.SetGlobalContext(modctx);
|
||||||
evaluator.RegisterBuiltinsValue();
|
evaluator.RegisterBuiltinsValue();
|
||||||
evaluator.Run(asts);
|
evaluator.Run(asts); // error upward pass-by, log outside, we have already keep info in evaluator error
|
||||||
|
|
||||||
return evaluator.global;
|
return evaluator.global;
|
||||||
}
|
}
|
||||||
@@ -1616,8 +1665,9 @@ namespace Fig
|
|||||||
|
|
||||||
if (ctx->containsInThisScope(modName))
|
if (ctx->containsInThisScope(modName))
|
||||||
{
|
{
|
||||||
throw EvaluatorError(
|
throw EvaluatorError(u8"RedeclarationError",
|
||||||
u8"RedeclarationError", std::format("{} has already been declared.", modName.toBasicString()), i);
|
std::format("{} has already been declared.", modName.toBasicString()),
|
||||||
|
i);
|
||||||
}
|
}
|
||||||
ctx->def(
|
ctx->def(
|
||||||
modName, ValueType::Module, AccessModifier::PublicConst, std::make_shared<Object>(Module(modName, modCtx)));
|
modName, ValueType::Module, AccessModifier::PublicConst, std::make_shared<Object>(Module(modName, modCtx)));
|
||||||
@@ -1631,14 +1681,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())
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "Ast/Statements/ImplementSt.hpp"
|
#include <Ast/Statements/ImplementSt.hpp>
|
||||||
#include "Ast/Statements/InterfaceDefSt.hpp"
|
#include <Ast/Statements/InterfaceDefSt.hpp>
|
||||||
#include "Value/Type.hpp"
|
#include <Value/Type.hpp>
|
||||||
#include <Ast/ast.hpp>
|
#include <Ast/ast.hpp>
|
||||||
|
|
||||||
#include <Context/context.hpp>
|
#include <Context/context.hpp>
|
||||||
@@ -63,12 +63,18 @@ namespace Fig
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
FString sourcePath;
|
FString sourcePath;
|
||||||
|
std::vector<FString> sourceLines;
|
||||||
|
|
||||||
void SetSourcePath(const FString &sp)
|
void SetSourcePath(const FString &sp)
|
||||||
{
|
{
|
||||||
sourcePath = sp;
|
sourcePath = sp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetSourceLines(const std::vector<FString> &sl)
|
||||||
|
{
|
||||||
|
sourceLines = sl;
|
||||||
|
}
|
||||||
|
|
||||||
void SetGlobalContext(ContextPtr ctx)
|
void SetGlobalContext(ContextPtr ctx)
|
||||||
{
|
{
|
||||||
assert(ctx != nullptr);
|
assert(ctx != nullptr);
|
||||||
|
|||||||
@@ -10,7 +10,10 @@ namespace Fig
|
|||||||
public:
|
public:
|
||||||
FString typeName;
|
FString typeName;
|
||||||
using AddressableError::AddressableError;
|
using AddressableError::AddressableError;
|
||||||
EvaluatorError(FString _typeName, FString msg, Ast::AstBase ast, std::source_location loc = std::source_location::current())
|
EvaluatorError(FString _typeName,
|
||||||
|
FString msg,
|
||||||
|
Ast::AstBase ast,
|
||||||
|
std::source_location loc = std::source_location::current())
|
||||||
{
|
{
|
||||||
message = msg;
|
message = msg;
|
||||||
line = ast->getAAI().line;
|
line = ast->getAAI().line;
|
||||||
@@ -20,8 +23,13 @@ namespace Fig
|
|||||||
|
|
||||||
typeName = std::move(_typeName);
|
typeName = std::move(_typeName);
|
||||||
|
|
||||||
|
sourcePath = *ast->getAAI().sourcePath;
|
||||||
|
sourceLines = *ast->getAAI().sourceLines;
|
||||||
}
|
}
|
||||||
EvaluatorError(FString _typeName, std::string_view msg, Ast::AstBase ast, std::source_location loc = std::source_location::current())
|
EvaluatorError(FString _typeName,
|
||||||
|
std::string_view msg,
|
||||||
|
Ast::AstBase ast,
|
||||||
|
std::source_location loc = std::source_location::current())
|
||||||
{
|
{
|
||||||
message = FString::fromBasicString(std::string(msg.data()));
|
message = FString::fromBasicString(std::string(msg.data()));
|
||||||
line = ast->getAAI().line;
|
line = ast->getAAI().line;
|
||||||
@@ -30,13 +38,11 @@ namespace Fig
|
|||||||
src_loc = std::move(loc);
|
src_loc = std::move(loc);
|
||||||
|
|
||||||
typeName = std::move(_typeName);
|
typeName = std::move(_typeName);
|
||||||
|
|
||||||
|
sourcePath = *ast->getAAI().sourcePath;
|
||||||
|
sourceLines = *ast->getAAI().sourceLines;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual FString getErrorType() const override
|
virtual FString getErrorType() const override { return typeName; }
|
||||||
{
|
|
||||||
return typeName;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
};
|
}; // namespace Fig
|
||||||
@@ -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())
|
||||||
{
|
{
|
||||||
@@ -84,7 +89,9 @@ int main(int argc, char **argv)
|
|||||||
std::string source((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
|
std::string source((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
|
||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
Fig::Lexer lexer((Fig::FString(source)));
|
std::vector<FString> sourceLines = Fig::Utils::splitSource(Fig::FString(source));
|
||||||
|
|
||||||
|
Fig::Lexer lexer((Fig::FString(source)), sourcePath, sourceLines);
|
||||||
|
|
||||||
// Token tok;
|
// Token tok;
|
||||||
// while ((tok = lexer.nextToken()).getType() != TokenType::EndOfFile)
|
// while ((tok = lexer.nextToken()).getType() != TokenType::EndOfFile)
|
||||||
@@ -92,11 +99,9 @@ int main(int argc, char **argv)
|
|||||||
// std::println("{}", tok.toString().toBasicString());
|
// std::println("{}", tok.toString().toBasicString());
|
||||||
// }
|
// }
|
||||||
|
|
||||||
Fig::Parser parser(lexer);
|
Fig::Parser parser(lexer, sourcePath, sourceLines);
|
||||||
std::vector<Fig::Ast::AstBase> asts;
|
std::vector<Fig::Ast::AstBase> asts;
|
||||||
|
|
||||||
std::vector<FString> sourceLines = Fig::Utils::splitSource(Fig::FString(source));
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
asts = parser.parseAll();
|
asts = parser.parseAll();
|
||||||
@@ -104,7 +109,7 @@ int main(int argc, char **argv)
|
|||||||
catch (const Fig::AddressableError &e)
|
catch (const Fig::AddressableError &e)
|
||||||
{
|
{
|
||||||
addressableErrorCount++;
|
addressableErrorCount++;
|
||||||
ErrorLog::logAddressableError(e, sourcePath, sourceLines);
|
ErrorLog::logAddressableError(e);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
catch (const Fig::UnaddressableError &e)
|
catch (const Fig::UnaddressableError &e)
|
||||||
@@ -129,6 +134,7 @@ int main(int argc, char **argv)
|
|||||||
Fig::Evaluator evaluator;
|
Fig::Evaluator evaluator;
|
||||||
|
|
||||||
evaluator.SetSourcePath(sourcePath);
|
evaluator.SetSourcePath(sourcePath);
|
||||||
|
evaluator.SetSourceLines(sourceLines);
|
||||||
evaluator.CreateGlobalContext();
|
evaluator.CreateGlobalContext();
|
||||||
evaluator.RegisterBuiltinsValue();
|
evaluator.RegisterBuiltinsValue();
|
||||||
|
|
||||||
@@ -139,7 +145,7 @@ int main(int argc, char **argv)
|
|||||||
catch (const Fig::AddressableError &e)
|
catch (const Fig::AddressableError &e)
|
||||||
{
|
{
|
||||||
addressableErrorCount++;
|
addressableErrorCount++;
|
||||||
ErrorLog::logAddressableError(e, sourcePath, sourceLines);
|
ErrorLog::logAddressableError(e);
|
||||||
evaluator.printStackTrace();
|
evaluator.printStackTrace();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,14 @@
|
|||||||
#include <Core/fig_string.hpp>
|
#include <Core/fig_string.hpp>
|
||||||
#include <Utils/utils.hpp>
|
#include <Utils/utils.hpp>
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#include <iostream> // debug
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SourceInfo
|
||||||
|
#define SourceInfo(ptr) (ptr->sourcePath), (ptr->sourceLines)
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -159,7 +167,7 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
if (it.isEnd())
|
if (it.isEnd())
|
||||||
{
|
{
|
||||||
error = SyntaxError(u8"Unterminated FString", this->line, it.column());
|
error = SyntaxError(u8"Unterminated FString", this->line, it.column(), SourceInfo(this));
|
||||||
return IllegalTok;
|
return IllegalTok;
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
@@ -196,12 +204,11 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
error = SyntaxError(FString(
|
error = SyntaxError(FString(std::format("Unsupported escape character: {}",
|
||||||
std::format(
|
|
||||||
"Unsupported escape character: {}",
|
|
||||||
FString(ec.getString()).toBasicString())),
|
FString(ec.getString()).toBasicString())),
|
||||||
this->line,
|
this->line,
|
||||||
it.column());
|
it.column(),
|
||||||
|
SourceInfo(this));
|
||||||
return IllegalTok;
|
return IllegalTok;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -213,7 +220,7 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
if (unterminated)
|
if (unterminated)
|
||||||
{
|
{
|
||||||
error = SyntaxError(u8"Unterminated FString", this->line, str_start_col);
|
error = SyntaxError(u8"Unterminated FString", this->line, str_start_col, SourceInfo(this));
|
||||||
return IllegalTok;
|
return IllegalTok;
|
||||||
}
|
}
|
||||||
return Token(str, TokenType::LiteralString);
|
return Token(str, TokenType::LiteralString);
|
||||||
@@ -240,7 +247,7 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
if (unterminated)
|
if (unterminated)
|
||||||
{
|
{
|
||||||
error = SyntaxError(u8"Unterminated FString", this->line, str_start_col);
|
error = SyntaxError(u8"Unterminated FString", this->line, str_start_col, SourceInfo(this));
|
||||||
return IllegalTok;
|
return IllegalTok;
|
||||||
}
|
}
|
||||||
return Token(str, TokenType::LiteralString);
|
return Token(str, TokenType::LiteralString);
|
||||||
@@ -271,7 +278,7 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
if (it.isEnd())
|
if (it.isEnd())
|
||||||
{
|
{
|
||||||
error = SyntaxError(u8"Unterminated FString", this->line, it.column());
|
error = SyntaxError(u8"Unterminated FString", this->line, it.column(), SourceInfo(this));
|
||||||
return IllegalTok;
|
return IllegalTok;
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
@@ -313,12 +320,11 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
error = SyntaxError(FString(
|
error = SyntaxError(FString(std::format("Unsupported escape character: {}",
|
||||||
std::format(
|
|
||||||
"Unsupported escape character: {}",
|
|
||||||
FString(ec.getString()).toBasicString())),
|
FString(ec.getString()).toBasicString())),
|
||||||
this->line,
|
this->line,
|
||||||
it.column());
|
it.column(),
|
||||||
|
SourceInfo(this));
|
||||||
return IllegalTok;
|
return IllegalTok;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -330,7 +336,7 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
if (unterminated)
|
if (unterminated)
|
||||||
{
|
{
|
||||||
error = SyntaxError(u8"Unterminated FString", this->line, str_start_col);
|
error = SyntaxError(u8"Unterminated FString", this->line, str_start_col, SourceInfo(this));
|
||||||
return IllegalTok;
|
return IllegalTok;
|
||||||
}
|
}
|
||||||
return Token(str, TokenType::LiteralString);
|
return Token(str, TokenType::LiteralString);
|
||||||
@@ -339,21 +345,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 +376,93 @@ 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(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
||||||
std::format("Ellegal number literal: {}", numStr.toBasicString())),
|
this->line,
|
||||||
this->line, it.column());
|
it.column(),
|
||||||
|
SourceInfo(this));
|
||||||
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(),
|
||||||
|
SourceInfo(this));
|
||||||
|
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(),
|
||||||
|
SourceInfo(this));
|
||||||
|
return IllegalTok;
|
||||||
|
}
|
||||||
|
if (ePos + 1 >= numStr.length())
|
||||||
|
{
|
||||||
|
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
||||||
|
this->line,
|
||||||
|
it.column(),
|
||||||
|
SourceInfo(this));
|
||||||
|
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(),
|
||||||
|
SourceInfo(this));
|
||||||
|
return IllegalTok;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c.isDigit()) { hasDigitAfterE = true; }
|
||||||
|
else
|
||||||
|
{
|
||||||
|
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
||||||
|
this->line,
|
||||||
|
it.column(),
|
||||||
|
SourceInfo(this));
|
||||||
|
return IllegalTok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasDigitAfterE)
|
||||||
|
{
|
||||||
|
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
||||||
|
this->line,
|
||||||
|
it.column(),
|
||||||
|
SourceInfo(this));
|
||||||
|
return IllegalTok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Token(numStr, TokenType::LiteralNumber);
|
return Token(numStr, TokenType::LiteralNumber);
|
||||||
}
|
}
|
||||||
Token Lexer::scanSymbol()
|
Token Lexer::scanSymbol()
|
||||||
@@ -400,9 +483,10 @@ namespace Fig
|
|||||||
|
|
||||||
if (!startsWith(sym))
|
if (!startsWith(sym))
|
||||||
{
|
{
|
||||||
error = SyntaxError(
|
error = SyntaxError(FString(std::format("No such operator: {}", sym.toBasicString())),
|
||||||
FString(std::format("No such operator: {}", sym.toBasicString())),
|
this->line,
|
||||||
this->line, it.column());
|
it.column(),
|
||||||
|
SourceInfo(this));
|
||||||
next();
|
next();
|
||||||
return IllegalTok;
|
return IllegalTok;
|
||||||
}
|
}
|
||||||
@@ -428,13 +512,14 @@ namespace Fig
|
|||||||
|
|
||||||
if (!symbol_map.contains(sym))
|
if (!symbol_map.contains(sym))
|
||||||
{
|
{
|
||||||
error = SyntaxError(
|
error = SyntaxError(FString(std::format("No such operator: {}", sym.toBasicString())),
|
||||||
FString(std::format("No such operator: {}", sym.toBasicString())),
|
this->line,
|
||||||
this->line, it.column());
|
it.column(),
|
||||||
|
SourceInfo(this));
|
||||||
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));
|
||||||
}
|
}
|
||||||
@@ -490,7 +575,8 @@ namespace Fig
|
|||||||
|
|
||||||
if (!terminated)
|
if (!terminated)
|
||||||
{
|
{
|
||||||
error = SyntaxError(FString(u8"Unterminated multiline comment"), this->line, it.column());
|
error =
|
||||||
|
SyntaxError(FString(u8"Unterminated multiline comment"), this->line, it.column(), SourceInfo(this));
|
||||||
next();
|
next();
|
||||||
return IllegalTok;
|
return IllegalTok;
|
||||||
}
|
}
|
||||||
@@ -522,13 +608,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();
|
||||||
@@ -561,9 +647,11 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
error = SyntaxError(FString(
|
error =
|
||||||
std::format("Cannot tokenize char: '{}'", FString(ch.getString()).toBasicString())),
|
SyntaxError(FString(std::format("Cannot tokenize char: '{}'", FString(ch.getString()).toBasicString())),
|
||||||
this->line, it.column());
|
this->line,
|
||||||
|
it.column(),
|
||||||
|
SourceInfo(this));
|
||||||
if (hasNext())
|
if (hasNext())
|
||||||
{
|
{
|
||||||
next();
|
next();
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ namespace Fig
|
|||||||
SyntaxError error;
|
SyntaxError error;
|
||||||
UTF8Iterator it;
|
UTF8Iterator it;
|
||||||
|
|
||||||
|
FString sourcePath;
|
||||||
|
std::vector<FString> sourceLines;
|
||||||
|
|
||||||
std::vector<Warning> warnings;
|
std::vector<Warning> warnings;
|
||||||
|
|
||||||
size_t last_line, last_column, column = 1;
|
size_t last_line, last_column, column = 1;
|
||||||
@@ -60,8 +63,8 @@ namespace Fig
|
|||||||
static const std::unordered_map<FString, TokenType> symbol_map;
|
static const std::unordered_map<FString, TokenType> symbol_map;
|
||||||
static const std::unordered_map<FString, TokenType> keyword_map;
|
static const std::unordered_map<FString, TokenType> keyword_map;
|
||||||
|
|
||||||
inline Lexer(const FString &_source) :
|
inline Lexer(const FString &_source, const FString &_sourcePath, const std::vector<FString> &_sourceLines) :
|
||||||
source(_source), it(source)
|
source(_source), it(source), sourcePath(_sourcePath), sourceLines(_sourceLines)
|
||||||
{
|
{
|
||||||
line = 1;
|
line = 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
{
|
{
|
||||||
@@ -97,15 +120,16 @@ public func formatByListArgs(objects) -> Any
|
|||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
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
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
51
src/Module/Library/std/time/time.fig
Normal file
51
src/Module/Library/std/time/time.fig
Normal 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 been reversed! 😢";
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
// TODO: support `-` operator when Fig supports overload
|
||||||
|
}
|
||||||
|
|
||||||
|
public func now() -> Time
|
||||||
|
{
|
||||||
|
return Time{__ftime_now_ns()};
|
||||||
|
}
|
||||||
@@ -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 {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ namespace Fig
|
|||||||
// 逻辑
|
// 逻辑
|
||||||
{Ast::Operator::And, {5, 6}},
|
{Ast::Operator::And, {5, 6}},
|
||||||
{Ast::Operator::Or, {4, 5}},
|
{Ast::Operator::Or, {4, 5}},
|
||||||
{Ast::Operator::Not, {30, 31}}, // 一元
|
// {Ast::Operator::Not, {30, 31}}, // 一元
|
||||||
|
|
||||||
// 比较
|
// 比较
|
||||||
{Ast::Operator::Equal, {7, 8}},
|
{Ast::Operator::Equal, {7, 8}},
|
||||||
@@ -37,7 +37,7 @@ namespace Fig
|
|||||||
{Ast::Operator::BitAnd, {6, 7}},
|
{Ast::Operator::BitAnd, {6, 7}},
|
||||||
{Ast::Operator::BitOr, {4, 5}},
|
{Ast::Operator::BitOr, {4, 5}},
|
||||||
{Ast::Operator::BitXor, {5, 6}},
|
{Ast::Operator::BitXor, {5, 6}},
|
||||||
{Ast::Operator::BitNot, {30, 31}}, // 一元
|
// {Ast::Operator::BitNot, {30, 31}}, // 一元
|
||||||
{Ast::Operator::ShiftLeft, {15, 16}},
|
{Ast::Operator::ShiftLeft, {15, 16}},
|
||||||
{Ast::Operator::ShiftRight, {15, 16}},
|
{Ast::Operator::ShiftRight, {15, 16}},
|
||||||
|
|
||||||
@@ -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);
|
||||||
@@ -206,7 +214,7 @@ namespace Fig
|
|||||||
variaPara = pname;
|
variaPara = pname;
|
||||||
next(); // skip `...`
|
next(); // skip `...`
|
||||||
if (!isThis(TokenType::RightParen))
|
if (!isThis(TokenType::RightParen))
|
||||||
throw SyntaxError(
|
throwAddressableError<SyntaxError>(
|
||||||
u8"Expects right paren, variable parameter function can only have one parameter",
|
u8"Expects right paren, variable parameter function can only have one parameter",
|
||||||
currentAAI.line,
|
currentAAI.line,
|
||||||
currentAAI.column);
|
currentAAI.column);
|
||||||
@@ -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,
|
||||||
@@ -426,7 +433,7 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw SyntaxError(FString(u8"Invalid syntax"), currentAAI.line, currentAAI.column);
|
throwAddressableError<SyntaxError>(FString(u8"Invalid syntax"), currentAAI.line, currentAAI.column);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return makeAst<Ast::InterfaceDefAst>(interfaceName, methods, isPublic);
|
return makeAst<Ast::InterfaceDefAst>(interfaceName, methods, isPublic);
|
||||||
@@ -473,7 +480,7 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw SyntaxError(FString(u8"Invalid syntax"), currentAAI.line, currentAAI.column);
|
throwAddressableError<SyntaxError>(FString(u8"Invalid syntax"), currentAAI.line, currentAAI.column);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -549,7 +556,8 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
if (finallyBlock != nullptr)
|
if (finallyBlock != nullptr)
|
||||||
{
|
{
|
||||||
throw SyntaxError(u8"Duplicate try finally-block", currentAAI.line, currentAAI.column);
|
throwAddressableError<SyntaxError>(
|
||||||
|
u8"Duplicate try finally-block", currentAAI.line, currentAAI.column);
|
||||||
}
|
}
|
||||||
next(); // consume `finally`
|
next(); // consume `finally`
|
||||||
expect(TokenType::LeftBrace);
|
expect(TokenType::LeftBrace);
|
||||||
@@ -563,7 +571,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 +593,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 +670,17 @@ 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
|
||||||
|
{
|
||||||
|
throwAddressableError<SyntaxError>(u8"invalid syntax", currentAAI.line, currentAAI.column);
|
||||||
|
}
|
||||||
return stmt;
|
return stmt;
|
||||||
}
|
}
|
||||||
Ast::BlockStatement Parser::__parseBlockStatement()
|
Ast::BlockStatement Parser::__parseBlockStatement()
|
||||||
@@ -700,7 +713,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 +736,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 +789,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 +803,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 +921,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 +932,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 +992,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 +1082,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 +1131,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 +1158,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 +1182,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 +1194,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);
|
||||||
@@ -1192,11 +1205,11 @@ namespace Fig
|
|||||||
if (!isTokenOp(tok)) break;
|
if (!isTokenOp(tok)) break;
|
||||||
|
|
||||||
op = Ast::TokenToOp.at(tok.getType());
|
op = Ast::TokenToOp.at(tok.getType());
|
||||||
Precedence lbp = getLeftBindingPower(op);
|
auto [lbp, rbp] = getBindingPower(op);
|
||||||
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(rbp, stop, stop2));
|
||||||
}
|
}
|
||||||
|
|
||||||
return lhs;
|
return lhs;
|
||||||
@@ -1216,10 +1229,8 @@ namespace Fig
|
|||||||
auto stmt = __parseStatement();
|
auto stmt = __parseStatement();
|
||||||
if (!output.empty() && stmt->getType() == Ast::AstType::PackageSt)
|
if (!output.empty() && stmt->getType() == Ast::AstType::PackageSt)
|
||||||
{
|
{
|
||||||
throw SyntaxError(
|
throwAddressableError<SyntaxError>(
|
||||||
u8"Package must be at the beginning of the file",
|
u8"Package must be at the beginning of the file", currentAAI.line, currentAAI.column);
|
||||||
currentAAI.line,
|
|
||||||
currentAAI.column);
|
|
||||||
}
|
}
|
||||||
pushNode(stmt);
|
pushNode(stmt);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
#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>
|
||||||
#include <Error/error.hpp>
|
#include <Error/error.hpp>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <print>
|
#include <print>
|
||||||
#include <source_location>
|
#include <source_location>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
@@ -21,6 +23,9 @@ namespace Fig
|
|||||||
std::vector<Ast::AstBase> output;
|
std::vector<Ast::AstBase> output;
|
||||||
std::vector<Token> previousTokens;
|
std::vector<Token> previousTokens;
|
||||||
|
|
||||||
|
std::shared_ptr<FString> sourcePathPtr;
|
||||||
|
std::shared_ptr<std::vector<FString>> sourceLinesPtr;
|
||||||
|
|
||||||
size_t tokenPruduced = 0;
|
size_t tokenPruduced = 0;
|
||||||
size_t currentTokenIndex = 0;
|
size_t currentTokenIndex = 0;
|
||||||
|
|
||||||
@@ -38,15 +43,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 +63,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,32 +74,33 @@ 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)
|
|
||||||
|
Parser(const Lexer &_lexer, FString _sourcePath, std::vector<FString> _sourceLines) : lexer(_lexer)
|
||||||
{
|
{
|
||||||
|
sourcePathPtr = std::make_shared<FString>(_sourcePath);
|
||||||
|
sourceLinesPtr = std::make_shared<std::vector<FString>>(_sourceLines);
|
||||||
}
|
}
|
||||||
|
|
||||||
AddressableError* getError() const
|
AddressableError *getError() const { return error.get(); }
|
||||||
{
|
|
||||||
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, *sourcePathPtr, *sourceLinesPtr, loc);
|
||||||
_ErrT spError(msg, line, column, loc);
|
|
||||||
error = std::make_unique<_ErrT>(spError);
|
error = std::make_unique<_ErrT>(spError);
|
||||||
throw spError;
|
throw spError;
|
||||||
}
|
}
|
||||||
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, *sourcePathPtr, *sourceLinesPtr, loc);
|
||||||
error = std::make_unique<_ErrT>(spError);
|
error = std::make_unique<_ErrT>(spError);
|
||||||
throw spError;
|
throw spError;
|
||||||
}
|
}
|
||||||
@@ -115,22 +108,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 +129,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,10 +139,14 @@ 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,
|
||||||
|
.sourcePath = sourcePathPtr,
|
||||||
|
.sourceLines = sourceLinesPtr});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isEOF()) return;
|
if (isEOF()) return;
|
||||||
@@ -163,7 +154,11 @@ namespace Fig
|
|||||||
tokenPruduced++;
|
tokenPruduced++;
|
||||||
if (tok == IllegalTok) throw lexer.getError();
|
if (tok == IllegalTok) throw lexer.getError();
|
||||||
currentTokenIndex = tokenPruduced - 1;
|
currentTokenIndex = tokenPruduced - 1;
|
||||||
setCurrentAAI(Ast::AstAddressInfo{.line = tok.line, .column = tok.column});
|
setCurrentAAI(Ast::AstAddressInfo{.line = tok.line,
|
||||||
|
.column = tok.column,
|
||||||
|
.sourcePath = sourcePathPtr,
|
||||||
|
.sourceLines = sourceLinesPtr});
|
||||||
|
|
||||||
previousTokens.push_back(tok);
|
previousTokens.push_back(tok);
|
||||||
}
|
}
|
||||||
inline const Token ¤tToken()
|
inline const Token ¤tToken()
|
||||||
@@ -184,18 +179,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 +206,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 +215,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 +229,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 +238,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 +278,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 +299,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 +313,14 @@ 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
29
src/VMValue/VMValue.cpp
Normal 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
91
src/VMValue/VMValue.hpp
Normal 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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
43
src/VirtualMachine/main.cpp
Normal file
43
src/VirtualMachine/main.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
42
xmake.lua
42
xmake.lua
@@ -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") .. "\"")
|
||||||
|
|||||||
Reference in New Issue
Block a user