7 Commits

Author SHA1 Message Date
9e3f17711f [VER] 0.4.0-alpha
All checks were successful
Release Build / build-windows-x64 (push) Successful in 54s
Release Build / build-linux-x64 (push) Successful in 1m21s
[Fix] 修复恶性Bug: Parser: parseExpression没有正确解析二元表达式,没有用到 right binding power的问题,表现在生成类似 a * b * c时,结果为 a * (b * c) 的Bug
[Impl][Fix] 修复跨文件(如import)报错信息错误的问题,现在Ast跟踪保存文件信息,报错统一从Error父类获取
[...] 忘了,好困不管了
2026-01-19 04:13:55 +08:00
d398d457b5 [VER] v0.3.9-alpha
All checks were successful
Release Build / build-windows-x64 (push) Successful in 1m0s
Release Build / build-linux-x64 (push) Successful in 1m2s
[Feat] is 操作符现在可以直接判断内置数据类型, 如 10 is Int
[Fix] evalMemberExpr的lhs可以为右值,修复原来限制为左值的BUG,如调用一个函数返回结果为struct且访问member触发此bug
[Impl] 可更换的std::dynamic_pointer_cast更换为static版本,更快!
[Feat] 增加标准库 std.time,以及用到的builtin: __ftime_now_ns,但目前 Time类有点BUG
[...] 剩下的忘了
2026-01-15 17:51:01 +08:00
ccf80536b3 [Fix] 蠢蛋clang!
All checks were successful
Release Build / build-windows-x64 (push) Successful in 47s
Release Build / build-linux-x64 (push) Successful in 58s
2026-01-14 21:35:48 +08:00
13fdbec0c4 [VER] v0.3.8-alpha
Some checks failed
Release Build / build-linux-x64 (push) Failing after 18s
Release Build / build-windows-x64 (push) Successful in 46s
[Impl][Fix] 更改resolveModulePath实现,使用绝对路径查找内置库
2026-01-14 21:31:11 +08:00
99e00492f5 删除蠢蛋注释
All checks were successful
Release Build / build-windows-x64 (push) Successful in 46s
Release Build / build-linux-x64 (push) Successful in 59s
2026-01-14 17:37:27 +08:00
310d79acc5 我忘记改版本号了
Some checks failed
Release Build / build-windows-x64 (push) Failing after 48s
Release Build / build-linux-x64 (push) Successful in 58s
2026-01-14 17:34:24 +08:00
e28921ae02 [VER] 0.3.7-alpha
[Fix] 修复科学表达式数字解析的问题(Lexer引起) 由 Satklomi发现,感谢
[Feat] 增加Compiler相关定义,将开发BytecodeVM
[Tip] Evaluator进入Bug fix阶段,新功能延缓开发。转向VM
2026-01-14 17:28:38 +08:00
41 changed files with 1083 additions and 401 deletions

View File

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

View File

@@ -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
View File

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

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

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

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

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

View File

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

View File

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

View File

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

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

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

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

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

View File

@@ -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());

View File

@@ -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! ");

View File

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

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
#include <Ast/Statements/ErrorFlow.hpp> #include <Ast/Statements/ErrorFlow.hpp>
#include "Value/VariableSlot.hpp" #include <Value/VariableSlot.hpp>
#include <Value/value.hpp> #include <Value/value.hpp>
#include <Ast/AccessModifier.hpp> #include <Ast/AccessModifier.hpp>
#include <Ast/Statements/ImplementSt.hpp> #include <Ast/Statements/ImplementSt.hpp>
@@ -17,10 +17,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())

View File

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

View File

@@ -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

View File

@@ -28,7 +28,7 @@ This software is licensed under the MIT License. See LICENSE.txt for details.
*/ */
#include <Utils/argparse/argparse.hpp> #include <Utils/argparse/argparse.hpp>
#include <print> // #include <print>
#include <fstream> #include <fstream>
#include <Core/core.hpp> #include <Core/core.hpp>
@@ -38,6 +38,7 @@ This software is licensed under the MIT License. See LICENSE.txt for details.
#include <Utils/AstPrinter.hpp> #include <Utils/AstPrinter.hpp>
#include <Utils/utils.hpp> #include <Utils/utils.hpp>
#include <Error/errorLog.hpp> #include <Error/errorLog.hpp>
#include <Core/runtimeTime.hpp>
static size_t addressableErrorCount = 0; static size_t addressableErrorCount = 0;
static size_t unaddressableErrorCount = 0; static size_t unaddressableErrorCount = 0;
@@ -45,6 +46,10 @@ 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")
@@ -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;
} }

View File

@@ -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();

View File

@@ -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;
} }

View File

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

View File

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

View File

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

View File

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

View File

@@ -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);
} }

View File

@@ -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 &currentToken() inline const Token &currentToken()
@@ -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
View File

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

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

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

View File

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

View File

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