forked from PuqiAR/Fig-TreeWalker
Compare commits
12 Commits
v0.3.7-alp
...
v0.4.1-alp
| Author | SHA1 | Date | |
|---|---|---|---|
| 21641f888e | |||
| def69e031f | |||
| 009a70fc64 | |||
| e01b4e9849 | |||
| da262a4cf1 | |||
| f76e28ee8d | |||
| a324cf17f6 | |||
| caf058dd55 | |||
| 9e3f17711f | |||
| d398d457b5 | |||
| ccf80536b3 | |||
| 13fdbec0c4 |
@@ -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
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
#define __FCORE_VERSION "0.3.7-alpha"
|
#define __FCORE_VERSION "0.4.1-alpha"
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#define __FCORE_PLATFORM "Windows"
|
#define __FCORE_PLATFORM "Windows"
|
||||||
|
|||||||
21
src/Core/executablePath.hpp
Normal file
21
src/Core/executablePath.hpp
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <libloaderapi.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Fig
|
||||||
|
{
|
||||||
|
inline std::filesystem::path getExecutablePath()
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
wchar_t buffer[MAX_PATH];
|
||||||
|
GetModuleFileNameW(nullptr, buffer, MAX_PATH);
|
||||||
|
return std::filesystem::path(buffer);
|
||||||
|
#else
|
||||||
|
return std::filesystem::canonical("/proc/self/exe");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}; // namespace Fig
|
||||||
18
src/Core/runtimeTime.cpp
Normal file
18
src/Core/runtimeTime.cpp
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#include <Core/runtimeTime.hpp>
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
namespace Fig::Time
|
||||||
|
{
|
||||||
|
Clock::time_point start_time;
|
||||||
|
void init()
|
||||||
|
{
|
||||||
|
static bool flag = false;
|
||||||
|
if (flag)
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
start_time = Clock::now();
|
||||||
|
flag = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
10
src/Core/runtimeTime.hpp
Normal file
10
src/Core/runtimeTime.hpp
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
namespace Fig::Time
|
||||||
|
{
|
||||||
|
using Clock = std::chrono::steady_clock;
|
||||||
|
extern Clock::time_point start_time; // since process start
|
||||||
|
void init();
|
||||||
|
};
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <format>
|
#include <format>
|
||||||
#include <source_location>
|
#include <source_location>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
@@ -16,8 +17,10 @@ namespace Fig
|
|||||||
explicit AddressableError(FString _msg,
|
explicit AddressableError(FString _msg,
|
||||||
size_t _line,
|
size_t _line,
|
||||||
size_t _column,
|
size_t _column,
|
||||||
|
FString _sourcePath,
|
||||||
|
std::vector<FString> _sourceLines,
|
||||||
std::source_location loc = std::source_location::current()) :
|
std::source_location loc = std::source_location::current()) :
|
||||||
src_loc(loc), line(_line), column(_column)
|
src_loc(loc), line(_line), column(_column), sourcePath(std::move(_sourcePath)), sourceLines(std::move(_sourceLines))
|
||||||
{
|
{
|
||||||
message = _msg;
|
message = _msg;
|
||||||
}
|
}
|
||||||
@@ -33,9 +36,11 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
std::source_location src_loc;
|
std::source_location src_loc;
|
||||||
|
|
||||||
size_t getLine() const { return line; }
|
virtual size_t getLine() const { return line; }
|
||||||
size_t getColumn() const { return column; }
|
virtual size_t getColumn() const { return column; }
|
||||||
FString getMessage() const { return message; }
|
FString getMessage() const { return message; }
|
||||||
|
FString getSourcePath() const { return sourcePath; }
|
||||||
|
std::vector<FString> getSourceLines() const { return sourceLines; }
|
||||||
|
|
||||||
virtual FString getErrorType() const
|
virtual FString getErrorType() const
|
||||||
{
|
{
|
||||||
@@ -45,6 +50,9 @@ namespace Fig
|
|||||||
protected:
|
protected:
|
||||||
size_t line, column;
|
size_t line, column;
|
||||||
FString message;
|
FString message;
|
||||||
|
|
||||||
|
FString sourcePath;
|
||||||
|
std::vector<FString> sourceLines;
|
||||||
};
|
};
|
||||||
|
|
||||||
class UnaddressableError : public std::exception
|
class UnaddressableError : public std::exception
|
||||||
@@ -84,14 +92,6 @@ namespace Fig
|
|||||||
public:
|
public:
|
||||||
using AddressableError::AddressableError;
|
using AddressableError::AddressableError;
|
||||||
|
|
||||||
explicit SyntaxError(FString _msg,
|
|
||||||
size_t _line,
|
|
||||||
size_t _column,
|
|
||||||
std::source_location loc = std::source_location::current()) :
|
|
||||||
AddressableError(_msg, _line, _column, loc)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual FString toString() const override
|
virtual FString toString() const override
|
||||||
{
|
{
|
||||||
std::string msg = std::format("[SyntaxError] {} in [{}] {}", this->message.toBasicString(), this->src_loc.file_name(), this->src_loc.function_name());
|
std::string msg = std::format("[SyntaxError] {} in [{}] {}", this->message.toBasicString(), this->src_loc.file_name(), this->src_loc.function_name());
|
||||||
|
|||||||
@@ -98,8 +98,11 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void logAddressableError(const AddressableError &err, FString fileName, std::vector<FString> sourceLines)
|
inline void logAddressableError(const AddressableError &err)
|
||||||
{
|
{
|
||||||
|
const FString &fileName = err.getSourcePath();
|
||||||
|
const std::vector<FString> &sourceLines = err.getSourceLines();
|
||||||
|
|
||||||
std::print("\n");
|
std::print("\n");
|
||||||
namespace TC = TerminalColors;
|
namespace TC = TerminalColors;
|
||||||
coloredPrint(TC::LightWhite, "An error occurred! ");
|
coloredPrint(TC::LightWhite, "An error occurred! ");
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
@@ -68,7 +74,7 @@ namespace Fig
|
|||||||
AccessModifier::PublicConst),
|
AccessModifier::PublicConst),
|
||||||
ctx); // fake l-value
|
ctx); // fake l-value
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx->hasMethodImplemented(baseVal->getTypeInfo(), member))
|
if (ctx->hasMethodImplemented(baseVal->getTypeInfo(), member))
|
||||||
{
|
{
|
||||||
// builtin type implementation!
|
// builtin type implementation!
|
||||||
@@ -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,11 +318,34 @@ 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>();
|
||||||
bin->lexp);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
case Operator::BitAnd: {
|
case Operator::BitAnd: {
|
||||||
@@ -605,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);
|
||||||
}
|
}
|
||||||
@@ -633,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;
|
||||||
@@ -658,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;
|
||||||
@@ -688,7 +720,7 @@ 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);
|
||||||
LvObject structeLv = evalLv(initExpr->structe, ctx);
|
LvObject structeLv = evalLv(initExpr->structe, ctx);
|
||||||
ObjectPtr structTypeVal = structeLv.get();
|
ObjectPtr structTypeVal = structeLv.get();
|
||||||
const FString &structName = structeLv.name();
|
const FString &structName = structeLv.name();
|
||||||
@@ -952,22 +984,47 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
instanceCtx->merge(*structT.defContext);
|
// instanceCtx->merge(*structT.defContext);
|
||||||
for (auto &[id, fn] : instanceCtx->getFunctions())
|
// for (auto &[id, fn] : instanceCtx->getFunctions())
|
||||||
|
// {
|
||||||
|
// instanceCtx->_update(*instanceCtx->getFunctionName(id),
|
||||||
|
// std::make_shared<Object>(Function(fn.paras,
|
||||||
|
// fn.retType,
|
||||||
|
// fn.body,
|
||||||
|
// instanceCtx) // change its closureContext to
|
||||||
|
// // struct instance's context
|
||||||
|
// ));
|
||||||
|
// }
|
||||||
|
|
||||||
|
ContextPtr stDefCtx = structT.defContext;
|
||||||
|
|
||||||
|
// load struct method
|
||||||
|
for (auto &[id, fn] : stDefCtx->getFunctions())
|
||||||
{
|
{
|
||||||
instanceCtx->_update(*instanceCtx->getFunctionName(id),
|
auto funcNameOpt = stDefCtx->getFunctionName(id);
|
||||||
std::make_shared<Object>(Function(fn.paras,
|
assert(funcNameOpt.has_value());
|
||||||
fn.retType,
|
|
||||||
fn.body,
|
const FString &funcName = *funcNameOpt;
|
||||||
instanceCtx) // change its closureContext to
|
auto funcSlot = stDefCtx->get(funcName);
|
||||||
// struct instance's context
|
|
||||||
));
|
instanceCtx->def(
|
||||||
|
funcName,
|
||||||
|
ValueType::Function,
|
||||||
|
funcSlot->am,
|
||||||
|
std::make_shared<Object>(Function(
|
||||||
|
fn.paras,
|
||||||
|
fn.retType,
|
||||||
|
fn.body,
|
||||||
|
instanceCtx
|
||||||
|
))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::make_shared<Object>(StructInstance(structT.type, instanceCtx));
|
return std::make_shared<Object>(StructInstance(structT.type, instanceCtx));
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
@@ -976,7 +1033,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;
|
||||||
@@ -984,9 +1041,11 @@ 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)
|
||||||
{
|
{
|
||||||
@@ -1004,12 +1063,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))
|
||||||
@@ -1050,7 +1109,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;
|
||||||
@@ -1070,7 +1129,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))
|
||||||
@@ -1122,7 +1181,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;
|
||||||
@@ -1143,7 +1202,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);
|
||||||
@@ -1287,7 +1346,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)
|
||||||
{
|
{
|
||||||
@@ -1314,7 +1373,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);
|
||||||
@@ -1337,7 +1396,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
|
||||||
@@ -1378,7 +1437,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>(
|
||||||
@@ -1417,7 +1476,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);
|
||||||
@@ -1429,7 +1488,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
|
||||||
@@ -1440,11 +1499,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();
|
||||||
}
|
}
|
||||||
@@ -1452,17 +1513,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));
|
||||||
@@ -1481,6 +1544,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
|
||||||
@@ -1574,28 +1645,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;
|
||||||
}
|
}
|
||||||
@@ -1617,8 +1690,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)));
|
||||||
@@ -1632,14 +1706,14 @@ namespace Fig
|
|||||||
for (auto &ast : asts)
|
for (auto &ast : asts)
|
||||||
{
|
{
|
||||||
Ast::Expression exp;
|
Ast::Expression exp;
|
||||||
if ((exp = std::dynamic_pointer_cast<Ast::ExpressionAst>(ast)))
|
if ((exp = std::dynamic_pointer_cast<Ast::ExpressionAst>(ast))) // 保持 dynamic_pointer_cast !
|
||||||
{
|
{
|
||||||
sr = StatementResult::normal(eval(exp, global));
|
sr = StatementResult::normal(eval(exp, global));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// statement
|
// statement
|
||||||
Ast::Statement stmt = std::dynamic_pointer_cast<Ast::StatementAst>(ast);
|
Ast::Statement stmt = std::static_pointer_cast<Ast::StatementAst>(ast);
|
||||||
assert(stmt != nullptr);
|
assert(stmt != nullptr);
|
||||||
sr = evalStatement(stmt, global);
|
sr = evalStatement(stmt, global);
|
||||||
if (sr.isError())
|
if (sr.isError())
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "Ast/Statements/ImplementSt.hpp"
|
#include <Ast/Statements/ImplementSt.hpp>
|
||||||
#include "Ast/Statements/InterfaceDefSt.hpp"
|
#include <Ast/Statements/InterfaceDefSt.hpp>
|
||||||
#include "Value/Type.hpp"
|
#include <Value/Type.hpp>
|
||||||
#include <Ast/ast.hpp>
|
#include <Ast/ast.hpp>
|
||||||
|
|
||||||
#include <Context/context.hpp>
|
#include <Context/context.hpp>
|
||||||
@@ -63,12 +63,18 @@ namespace Fig
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
FString sourcePath;
|
FString sourcePath;
|
||||||
|
std::vector<FString> sourceLines;
|
||||||
|
|
||||||
void SetSourcePath(const FString &sp)
|
void SetSourcePath(const FString &sp)
|
||||||
{
|
{
|
||||||
sourcePath = sp;
|
sourcePath = sp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetSourceLines(const std::vector<FString> &sl)
|
||||||
|
{
|
||||||
|
sourceLines = sl;
|
||||||
|
}
|
||||||
|
|
||||||
void SetGlobalContext(ContextPtr ctx)
|
void SetGlobalContext(ContextPtr ctx)
|
||||||
{
|
{
|
||||||
assert(ctx != nullptr);
|
assert(ctx != nullptr);
|
||||||
|
|||||||
@@ -10,7 +10,10 @@ namespace Fig
|
|||||||
public:
|
public:
|
||||||
FString typeName;
|
FString typeName;
|
||||||
using AddressableError::AddressableError;
|
using AddressableError::AddressableError;
|
||||||
EvaluatorError(FString _typeName, FString msg, Ast::AstBase ast, std::source_location loc = std::source_location::current())
|
EvaluatorError(FString _typeName,
|
||||||
|
FString msg,
|
||||||
|
Ast::AstBase ast,
|
||||||
|
std::source_location loc = std::source_location::current())
|
||||||
{
|
{
|
||||||
message = msg;
|
message = msg;
|
||||||
line = ast->getAAI().line;
|
line = ast->getAAI().line;
|
||||||
@@ -20,8 +23,13 @@ namespace Fig
|
|||||||
|
|
||||||
typeName = std::move(_typeName);
|
typeName = std::move(_typeName);
|
||||||
|
|
||||||
|
sourcePath = *ast->getAAI().sourcePath;
|
||||||
|
sourceLines = *ast->getAAI().sourceLines;
|
||||||
}
|
}
|
||||||
EvaluatorError(FString _typeName, std::string_view msg, Ast::AstBase ast, std::source_location loc = std::source_location::current())
|
EvaluatorError(FString _typeName,
|
||||||
|
std::string_view msg,
|
||||||
|
Ast::AstBase ast,
|
||||||
|
std::source_location loc = std::source_location::current())
|
||||||
{
|
{
|
||||||
message = FString::fromBasicString(std::string(msg.data()));
|
message = FString::fromBasicString(std::string(msg.data()));
|
||||||
line = ast->getAAI().line;
|
line = ast->getAAI().line;
|
||||||
@@ -30,13 +38,11 @@ namespace Fig
|
|||||||
src_loc = std::move(loc);
|
src_loc = std::move(loc);
|
||||||
|
|
||||||
typeName = std::move(_typeName);
|
typeName = std::move(_typeName);
|
||||||
|
|
||||||
|
sourcePath = *ast->getAAI().sourcePath;
|
||||||
|
sourceLines = *ast->getAAI().sourceLines;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual FString getErrorType() const override
|
virtual FString getErrorType() const override { return typeName; }
|
||||||
{
|
|
||||||
return typeName;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
};
|
}; // namespace Fig
|
||||||
@@ -28,7 +28,7 @@ This software is licensed under the MIT License. See LICENSE.txt for details.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <Utils/argparse/argparse.hpp>
|
#include <Utils/argparse/argparse.hpp>
|
||||||
#include <print>
|
// #include <print>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
#include <Core/core.hpp>
|
#include <Core/core.hpp>
|
||||||
@@ -38,6 +38,7 @@ This software is licensed under the MIT License. See LICENSE.txt for details.
|
|||||||
#include <Utils/AstPrinter.hpp>
|
#include <Utils/AstPrinter.hpp>
|
||||||
#include <Utils/utils.hpp>
|
#include <Utils/utils.hpp>
|
||||||
#include <Error/errorLog.hpp>
|
#include <Error/errorLog.hpp>
|
||||||
|
#include <Core/runtimeTime.hpp>
|
||||||
|
|
||||||
static size_t addressableErrorCount = 0;
|
static size_t addressableErrorCount = 0;
|
||||||
static size_t unaddressableErrorCount = 0;
|
static size_t unaddressableErrorCount = 0;
|
||||||
@@ -45,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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,10 @@
|
|||||||
#include <iostream> // debug
|
#include <iostream> // debug
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef SourceInfo
|
||||||
|
#define SourceInfo(ptr) (ptr->sourcePath), (ptr->sourceLines)
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Fig
|
namespace Fig
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -163,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();
|
||||||
@@ -200,12 +204,11 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
error = SyntaxError(FString(
|
error = SyntaxError(FString(std::format("Unsupported escape character: {}",
|
||||||
std::format(
|
FString(ec.getString()).toBasicString())),
|
||||||
"Unsupported escape character: {}",
|
|
||||||
FString(ec.getString()).toBasicString())),
|
|
||||||
this->line,
|
this->line,
|
||||||
it.column());
|
it.column(),
|
||||||
|
SourceInfo(this));
|
||||||
return IllegalTok;
|
return IllegalTok;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -217,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);
|
||||||
@@ -244,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);
|
||||||
@@ -275,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();
|
||||||
@@ -317,12 +320,11 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
error = SyntaxError(FString(
|
error = SyntaxError(FString(std::format("Unsupported escape character: {}",
|
||||||
std::format(
|
FString(ec.getString()).toBasicString())),
|
||||||
"Unsupported escape character: {}",
|
|
||||||
FString(ec.getString()).toBasicString())),
|
|
||||||
this->line,
|
this->line,
|
||||||
it.column());
|
it.column(),
|
||||||
|
SourceInfo(this));
|
||||||
return IllegalTok;
|
return IllegalTok;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -334,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);
|
||||||
@@ -378,8 +380,10 @@ namespace Fig
|
|||||||
|
|
||||||
if (numStr.ends_with(U'e'))
|
if (numStr.ends_with(U'e'))
|
||||||
{
|
{
|
||||||
error = SyntaxError(
|
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
||||||
FString(std::format("Illegal number literal: {}", numStr.toBasicString())), this->line, it.column());
|
this->line,
|
||||||
|
it.column(),
|
||||||
|
SourceInfo(this));
|
||||||
return IllegalTok;
|
return IllegalTok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,8 +399,10 @@ namespace Fig
|
|||||||
|
|
||||||
if (!hasDigit)
|
if (!hasDigit)
|
||||||
{
|
{
|
||||||
error = SyntaxError(
|
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
||||||
FString(std::format("Illegal number literal: {}", numStr.toBasicString())), this->line, it.column());
|
this->line,
|
||||||
|
it.column(),
|
||||||
|
SourceInfo(this));
|
||||||
return IllegalTok;
|
return IllegalTok;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -407,14 +413,16 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
||||||
this->line,
|
this->line,
|
||||||
it.column());
|
it.column(),
|
||||||
|
SourceInfo(this));
|
||||||
return IllegalTok;
|
return IllegalTok;
|
||||||
}
|
}
|
||||||
if (ePos + 1 >= numStr.length())
|
if (ePos + 1 >= numStr.length())
|
||||||
{
|
{
|
||||||
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
||||||
this->line,
|
this->line,
|
||||||
it.column());
|
it.column(),
|
||||||
|
SourceInfo(this));
|
||||||
return IllegalTok;
|
return IllegalTok;
|
||||||
}
|
}
|
||||||
bool hasDigitAfterE = false;
|
bool hasDigitAfterE = false;
|
||||||
@@ -427,7 +435,8 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
||||||
this->line,
|
this->line,
|
||||||
it.column());
|
it.column(),
|
||||||
|
SourceInfo(this));
|
||||||
return IllegalTok;
|
return IllegalTok;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@@ -438,7 +447,8 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
||||||
this->line,
|
this->line,
|
||||||
it.column());
|
it.column(),
|
||||||
|
SourceInfo(this));
|
||||||
return IllegalTok;
|
return IllegalTok;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -447,7 +457,8 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
error = SyntaxError(FString(std::format("Illegal number literal: {}", numStr.toBasicString())),
|
||||||
this->line,
|
this->line,
|
||||||
it.column());
|
it.column(),
|
||||||
|
SourceInfo(this));
|
||||||
return IllegalTok;
|
return IllegalTok;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -472,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;
|
||||||
}
|
}
|
||||||
@@ -500,9 +512,10 @@ 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;
|
||||||
}
|
}
|
||||||
@@ -562,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;
|
||||||
}
|
}
|
||||||
@@ -633,9 +647,11 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
error = SyntaxError(FString(
|
error =
|
||||||
std::format("Cannot tokenize char: '{}'", FString(ch.getString()).toBasicString())),
|
SyntaxError(FString(std::format("Cannot tokenize char: '{}'", FString(ch.getString()).toBasicString())),
|
||||||
this->line, it.column());
|
this->line,
|
||||||
|
it.column(),
|
||||||
|
SourceInfo(this));
|
||||||
if (hasNext())
|
if (hasNext())
|
||||||
{
|
{
|
||||||
next();
|
next();
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ namespace Fig
|
|||||||
SyntaxError error;
|
SyntaxError error;
|
||||||
UTF8Iterator it;
|
UTF8Iterator it;
|
||||||
|
|
||||||
|
FString sourcePath;
|
||||||
|
std::vector<FString> sourceLines;
|
||||||
|
|
||||||
std::vector<Warning> warnings;
|
std::vector<Warning> warnings;
|
||||||
|
|
||||||
size_t last_line, last_column, column = 1;
|
size_t last_line, last_column, column = 1;
|
||||||
@@ -60,8 +63,8 @@ namespace Fig
|
|||||||
static const std::unordered_map<FString, TokenType> symbol_map;
|
static const std::unordered_map<FString, TokenType> symbol_map;
|
||||||
static const std::unordered_map<FString, TokenType> keyword_map;
|
static const std::unordered_map<FString, TokenType> keyword_map;
|
||||||
|
|
||||||
inline Lexer(const FString &_source) :
|
inline Lexer(const FString &_source, const FString &_sourcePath, const std::vector<FString> &_sourceLines) :
|
||||||
source(_source), it(source)
|
source(_source), it(source), sourcePath(_sourcePath), sourceLines(_sourceLines)
|
||||||
{
|
{
|
||||||
line = 1;
|
line = 1;
|
||||||
}
|
}
|
||||||
|
|||||||
51
src/Module/Library/std/time/time.fig
Normal file
51
src/Module/Library/std/time/time.fig
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
Official Module `time`
|
||||||
|
Library/time/time.fig
|
||||||
|
|
||||||
|
Copyright © 2026 PuqiAR. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import _builtins; // provides __ftime_now_ns (int64_t)
|
||||||
|
|
||||||
|
|
||||||
|
public struct Time
|
||||||
|
{
|
||||||
|
ns: Int; // int64_t, private
|
||||||
|
|
||||||
|
public func toNanos() -> Int
|
||||||
|
{
|
||||||
|
return ns;
|
||||||
|
}
|
||||||
|
|
||||||
|
public func toMicros() -> Int
|
||||||
|
{
|
||||||
|
return __fvalue_int_from(ns / 1000); // convert double to int
|
||||||
|
}
|
||||||
|
|
||||||
|
public func toMillis() -> Double
|
||||||
|
{
|
||||||
|
return ns / 1000 / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
public func toSeconds() -> Double
|
||||||
|
{
|
||||||
|
return ns / 1000 / 1000 / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
public func since(other: Time) -> Int
|
||||||
|
{
|
||||||
|
const time_ns := other.toNanos();
|
||||||
|
const result := ns - time_ns;
|
||||||
|
if result < 0
|
||||||
|
{
|
||||||
|
throw "time has been reversed! 😢";
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
// TODO: support `-` operator when Fig supports overload
|
||||||
|
}
|
||||||
|
|
||||||
|
public func now() -> Time
|
||||||
|
{
|
||||||
|
return Time{__ftime_now_ns()};
|
||||||
|
}
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Ast/Statements/InterfaceDefSt.hpp"
|
#include <Ast/Statements/InterfaceDefSt.hpp>
|
||||||
#include "Ast/functionParameters.hpp"
|
#include <Ast/functionParameters.hpp>
|
||||||
#include <Core/fig_string.hpp>
|
#include <Core/fig_string.hpp>
|
||||||
#include <Value/value.hpp>
|
#include <Value/value.hpp>
|
||||||
|
#include <Core/runtimeTime.hpp>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@@ -65,6 +67,7 @@ namespace Fig
|
|||||||
{u8"__fvalue_double_parse", 1},
|
{u8"__fvalue_double_parse", 1},
|
||||||
{u8"__fvalue_double_from", 1},
|
{u8"__fvalue_double_from", 1},
|
||||||
{u8"__fvalue_string_from", 1},
|
{u8"__fvalue_string_from", 1},
|
||||||
|
{u8"__ftime_now_ns", 0},
|
||||||
/* math start */
|
/* math start */
|
||||||
{u8"__fmath_acos", 1},
|
{u8"__fmath_acos", 1},
|
||||||
{u8"__fmath_acosh", 1},
|
{u8"__fmath_acosh", 1},
|
||||||
@@ -194,6 +197,15 @@ namespace Fig
|
|||||||
ObjectPtr val = args[0];
|
ObjectPtr val = args[0];
|
||||||
return std::make_shared<Object>(val->toStringIO());
|
return std::make_shared<Object>(val->toStringIO());
|
||||||
}},
|
}},
|
||||||
|
{u8"__ftime_now_ns",
|
||||||
|
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||||
|
// returns nanoseconds
|
||||||
|
using namespace Fig::Time;
|
||||||
|
auto now = Clock::now();
|
||||||
|
return std::make_shared<Object>(static_cast<ValueType::IntClass>(
|
||||||
|
std::chrono::duration_cast<std::chrono::nanoseconds>(now - start_time).count()));
|
||||||
|
}},
|
||||||
|
|
||||||
/* math start */
|
/* math start */
|
||||||
{u8"__fmath_acos",
|
{u8"__fmath_acos",
|
||||||
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
[](const std::vector<ObjectPtr> &args) -> ObjectPtr {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ namespace Fig
|
|||||||
// 逻辑
|
// 逻辑
|
||||||
{Ast::Operator::And, {5, 6}},
|
{Ast::Operator::And, {5, 6}},
|
||||||
{Ast::Operator::Or, {4, 5}},
|
{Ast::Operator::Or, {4, 5}},
|
||||||
{Ast::Operator::Not, {30, 31}}, // 一元
|
// {Ast::Operator::Not, {30, 31}}, // 一元
|
||||||
|
|
||||||
// 比较
|
// 比较
|
||||||
{Ast::Operator::Equal, {7, 8}},
|
{Ast::Operator::Equal, {7, 8}},
|
||||||
@@ -37,7 +37,7 @@ namespace Fig
|
|||||||
{Ast::Operator::BitAnd, {6, 7}},
|
{Ast::Operator::BitAnd, {6, 7}},
|
||||||
{Ast::Operator::BitOr, {4, 5}},
|
{Ast::Operator::BitOr, {4, 5}},
|
||||||
{Ast::Operator::BitXor, {5, 6}},
|
{Ast::Operator::BitXor, {5, 6}},
|
||||||
{Ast::Operator::BitNot, {30, 31}}, // 一元
|
// {Ast::Operator::BitNot, {30, 31}}, // 一元
|
||||||
{Ast::Operator::ShiftLeft, {15, 16}},
|
{Ast::Operator::ShiftLeft, {15, 16}},
|
||||||
{Ast::Operator::ShiftRight, {15, 16}},
|
{Ast::Operator::ShiftRight, {15, 16}},
|
||||||
|
|
||||||
@@ -214,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);
|
||||||
@@ -433,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);
|
||||||
@@ -480,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -556,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);
|
||||||
@@ -592,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))
|
||||||
@@ -677,11 +679,7 @@ namespace Fig
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw SyntaxError(
|
throwAddressableError<SyntaxError>(u8"invalid syntax", currentAAI.line, currentAAI.column);
|
||||||
u8"invalid syntax",
|
|
||||||
currentAAI.line,
|
|
||||||
currentAAI.column
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return stmt;
|
return stmt;
|
||||||
}
|
}
|
||||||
@@ -1207,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 = makeAst<Ast::BinaryExprAst>(lhs, op, parseExpression(bp, stop, stop2));
|
lhs = makeAst<Ast::BinaryExprAst>(lhs, op, parseExpression(rbp, stop, stop2));
|
||||||
}
|
}
|
||||||
|
|
||||||
return lhs;
|
return lhs;
|
||||||
@@ -1231,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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#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>
|
||||||
@@ -22,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;
|
||||||
|
|
||||||
@@ -72,7 +76,11 @@ namespace Fig
|
|||||||
static const std::unordered_map<Ast::Operator, std::pair<Precedence, Precedence>> opPrecedence;
|
static const std::unordered_map<Ast::Operator, std::pair<Precedence, Precedence>> opPrecedence;
|
||||||
static const std::unordered_map<Ast::Operator, Precedence> unaryOpPrecedence;
|
static const std::unordered_map<Ast::Operator, Precedence> unaryOpPrecedence;
|
||||||
|
|
||||||
Parser(const Lexer &_lexer) : 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 { return error.get(); }
|
AddressableError *getError() const { return error.get(); }
|
||||||
|
|
||||||
@@ -83,7 +91,7 @@ namespace Fig
|
|||||||
std::source_location loc = std::source_location::current())
|
std::source_location loc = std::source_location::current())
|
||||||
{
|
{
|
||||||
static_assert(std::is_base_of_v<AddressableError, _ErrT>, "_ErrT must derive from AddressableError");
|
static_assert(std::is_base_of_v<AddressableError, _ErrT>, "_ErrT must derive from AddressableError");
|
||||||
_ErrT spError(msg, line, column, loc);
|
_ErrT spError(msg, line, column, *sourcePathPtr, *sourceLinesPtr, loc);
|
||||||
error = std::make_unique<_ErrT>(spError);
|
error = std::make_unique<_ErrT>(spError);
|
||||||
throw spError;
|
throw spError;
|
||||||
}
|
}
|
||||||
@@ -92,7 +100,7 @@ namespace Fig
|
|||||||
{
|
{
|
||||||
static_assert(std::is_base_of_v<AddressableError, _ErrT>, "_ErrT must derive from AddressableError");
|
static_assert(std::is_base_of_v<AddressableError, _ErrT>, "_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;
|
||||||
}
|
}
|
||||||
@@ -135,7 +143,10 @@ namespace Fig
|
|||||||
CTI也需要显示转换,否则转换完的pruduced又会被转回去,变为 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;
|
||||||
@@ -143,7 +154,11 @@ namespace Fig
|
|||||||
tokenPruduced++;
|
tokenPruduced++;
|
||||||
if (tok == IllegalTok) throw lexer.getError();
|
if (tok == IllegalTok) throw lexer.getError();
|
||||||
currentTokenIndex = tokenPruduced - 1;
|
currentTokenIndex = tokenPruduced - 1;
|
||||||
setCurrentAAI(Ast::AstAddressInfo{.line = tok.line, .column = tok.column});
|
setCurrentAAI(Ast::AstAddressInfo{.line = tok.line,
|
||||||
|
.column = tok.column,
|
||||||
|
.sourcePath = sourcePathPtr,
|
||||||
|
.sourceLines = sourceLinesPtr});
|
||||||
|
|
||||||
previousTokens.push_back(tok);
|
previousTokens.push_back(tok);
|
||||||
}
|
}
|
||||||
inline const Token ¤tToken()
|
inline const Token ¤tToken()
|
||||||
@@ -298,9 +313,8 @@ 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(
|
Ast::InitExpr __parseInitExpr(Ast::Expression); // entry: current is `{`, ahead is struct type exp.
|
||||||
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
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ target("Fig")
|
|||||||
|
|
||||||
add_files("src/Evaluator/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/Evaluator/Value/value.cpp")
|
||||||
add_files("src/Lexer/lexer.cpp")
|
add_files("src/Lexer/lexer.cpp")
|
||||||
|
|||||||
Reference in New Issue
Block a user