[Feat] 模块系统支持,使用 import x.x.x导入
[Fix] Context内部辅助函数修改, getStructName .... [Feat] 增加字符串下标获取操作,和修改字符操作,实现使用了第四点的函数 [Impl] FString添加新方法 getRealChar, realReplace [Fun] 在utf8_iterator中辱骂了C++
This commit is contained in:
27
src/Ast/Statements/ImportSt.hpp
Normal file
27
src/Ast/Statements/ImportSt.hpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <Ast/astBase.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace Fig::Ast
|
||||
{
|
||||
class ImportSt final : public StatementAst
|
||||
{
|
||||
public:
|
||||
std::vector<FString> path;
|
||||
|
||||
ImportSt()
|
||||
{
|
||||
type = AstType::ImportSt;
|
||||
}
|
||||
|
||||
ImportSt(std::vector<FString> _path) :
|
||||
path(std::move(_path))
|
||||
{
|
||||
type = AstType::ImportSt;
|
||||
}
|
||||
};
|
||||
|
||||
using Import = std::shared_ptr<ImportSt>;
|
||||
};
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <Ast/Statements/StructDefSt.hpp>
|
||||
#include <Ast/Statements/IfSt.hpp>
|
||||
#include <Ast/Statements/ImplementSt.hpp>
|
||||
#include <Ast/Statements/ImportSt.hpp>
|
||||
#include <Ast/Statements/FunctionDefSt.hpp>
|
||||
#include <Ast/Statements/ControlSt.hpp>
|
||||
#include <Ast/Statements/ExpressionStmt.hpp>
|
||||
|
||||
@@ -50,12 +50,15 @@ namespace Fig::Ast
|
||||
ElseSt,
|
||||
ElseIfSt,
|
||||
|
||||
VarAssignSt,
|
||||
// VarAssignSt,
|
||||
WhileSt,
|
||||
ForSt,
|
||||
ReturnSt,
|
||||
BreakSt,
|
||||
ContinueSt,
|
||||
|
||||
PackageSt,
|
||||
ImportSt,
|
||||
};
|
||||
|
||||
// static const std::unordered_map<AstType, FString> astTypeToString{
|
||||
|
||||
@@ -28,9 +28,7 @@ namespace Fig
|
||||
Context(const Context &) = default;
|
||||
Context(const FString &name, ContextPtr p = nullptr) :
|
||||
scopeName(name), parent(p) {}
|
||||
Context(const FString &name, std::unordered_map<FString, TypeInfo> types, std::unordered_map<FString, std::shared_ptr<VariableSlot>> vars, std::unordered_map<FString, AccessModifier> _ams) :
|
||||
scopeName(std::move(name)), variables(std::move(vars)) {}
|
||||
|
||||
|
||||
void setParent(ContextPtr _parent)
|
||||
{
|
||||
parent = _parent;
|
||||
@@ -120,7 +118,7 @@ namespace Fig
|
||||
}
|
||||
else if (parent != nullptr)
|
||||
{
|
||||
parent->set(name, value);
|
||||
parent->_update(name, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -191,7 +189,7 @@ namespace Fig
|
||||
}
|
||||
else if (parent)
|
||||
{
|
||||
return parent->getFunctionName(id);
|
||||
return parent->getStructName(id);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
// using String = std::u8string;
|
||||
@@ -12,10 +11,10 @@ namespace Fig
|
||||
{
|
||||
public:
|
||||
using std::u8string_view::u8string_view;
|
||||
|
||||
|
||||
static FStringView fromBasicStringView(std::string_view sv)
|
||||
{
|
||||
return FStringView(reinterpret_cast<const char8_t*>(sv.data()));
|
||||
return FStringView(reinterpret_cast<const char8_t *>(sv.data()));
|
||||
}
|
||||
|
||||
explicit FStringView(std::string_view sv)
|
||||
@@ -39,7 +38,7 @@ namespace Fig
|
||||
public:
|
||||
using std::u8string::u8string;
|
||||
|
||||
FString operator+(const FString& x)
|
||||
FString operator+(const FString &x)
|
||||
{
|
||||
return FString(toBasicString() + x.toBasicString());
|
||||
}
|
||||
@@ -72,7 +71,7 @@ namespace Fig
|
||||
|
||||
static FString fromStringView(FStringView sv)
|
||||
{
|
||||
return FString(reinterpret_cast<const char*> (sv.data()));
|
||||
return FString(reinterpret_cast<const char *>(sv.data()));
|
||||
}
|
||||
|
||||
static FString fromU8String(const std::u8string &str)
|
||||
@@ -93,6 +92,60 @@ namespace Fig
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
FString getRealChar(size_t index)
|
||||
{
|
||||
FString ch;
|
||||
size_t cnt = 0;
|
||||
for (size_t i = 0; i < size();)
|
||||
{
|
||||
uint8_t cplen = 1;
|
||||
if ((at(i) & 0xf8) == 0xf0)
|
||||
cplen = 4;
|
||||
else if ((at(i) & 0xf0) == 0xe0)
|
||||
cplen = 3;
|
||||
else if ((at(i) & 0xe0) == 0xc0)
|
||||
cplen = 2;
|
||||
if (i + cplen > size())
|
||||
cplen = 1;
|
||||
|
||||
if (cnt == index)
|
||||
{
|
||||
ch += substr(i, cplen);
|
||||
}
|
||||
|
||||
i += cplen;
|
||||
++ cnt;
|
||||
}
|
||||
|
||||
return ch;
|
||||
}
|
||||
|
||||
void realReplace(size_t index, const FString &src)
|
||||
{
|
||||
size_t cnt = 0;
|
||||
for (size_t i = 0; i < size();)
|
||||
{
|
||||
uint8_t cplen = 1;
|
||||
if ((at(i) & 0xf8) == 0xf0)
|
||||
cplen = 4;
|
||||
else if ((at(i) & 0xf0) == 0xe0)
|
||||
cplen = 3;
|
||||
else if ((at(i) & 0xe0) == 0xc0)
|
||||
cplen = 2;
|
||||
if (i + cplen > size())
|
||||
cplen = 1;
|
||||
|
||||
if (cnt == index)
|
||||
{
|
||||
*this = FString(substr(0, i)) + src +
|
||||
FString(substr(i + cplen));
|
||||
}
|
||||
|
||||
i += cplen;
|
||||
++cnt;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}; // namespace Fig
|
||||
@@ -107,4 +160,4 @@ namespace std
|
||||
return std::hash<std::u8string>{}(static_cast<const std::u8string &>(s));
|
||||
}
|
||||
};
|
||||
}
|
||||
} // namespace std
|
||||
@@ -8,6 +8,22 @@
|
||||
// fuck
|
||||
// generate by Qwen3-Coder:
|
||||
|
||||
// 2025-12-26
|
||||
/*
|
||||
again: C++ fuck you
|
||||
fuck you
|
||||
fuck you!
|
||||
|
||||
fuck
|
||||
|
||||
C++ IS A PIECE OF SHIT
|
||||
STOP USING C++
|
||||
|
||||
unicodeString = "some unicode points";
|
||||
unicodeString[0] ---> ?????
|
||||
FUCK YOU C++
|
||||
*/
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
class UTF8Char
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
#include <Error/errorLog.hpp>
|
||||
#include <Evaluator/evaluator.hpp>
|
||||
#include <Evaluator/evaluator_error.hpp>
|
||||
#include <Module/builtins.hpp>
|
||||
#include <Context/context.hpp>
|
||||
#include <Utils/utils.hpp>
|
||||
|
||||
#include <Parser/parser.hpp>
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
LvObject Evaluator::evalVarExpr(Ast::VarExpr var, ContextPtr ctx)
|
||||
@@ -22,6 +25,25 @@ namespace Fig
|
||||
LvObject base = evalLv(me->base, ctx);
|
||||
RvObject baseVal = base.get();
|
||||
const FString &member = me->member;
|
||||
if (baseVal->getTypeInfo() == ValueType::Module)
|
||||
{
|
||||
const Module &mod = baseVal->as<Module>();
|
||||
if (mod.ctx->contains(member) && mod.ctx->isVariablePublic(member))
|
||||
{
|
||||
return LvObject(
|
||||
mod.ctx->get(member)
|
||||
);
|
||||
}
|
||||
else {
|
||||
throw EvaluatorError(
|
||||
u8"VariableNotFoundError",
|
||||
std::format(
|
||||
"`{}` has not variable '{}', check if it is public",
|
||||
baseVal->toString().toBasicString(),
|
||||
member.toBasicString()),
|
||||
me->base);
|
||||
}
|
||||
}
|
||||
if (baseVal->hasMemberFunction(member))
|
||||
{
|
||||
return LvObject(std::make_shared<VariableSlot>(
|
||||
@@ -71,10 +93,8 @@ namespace Fig
|
||||
u8"TypeError",
|
||||
std::format(
|
||||
"Type `List` indices must be `Int`, got '{}'",
|
||||
index->getTypeInfo().toString().toBasicString()
|
||||
),
|
||||
ie->index
|
||||
);
|
||||
index->getTypeInfo().toString().toBasicString()),
|
||||
ie->index);
|
||||
}
|
||||
List &list = base.get()->as<List>();
|
||||
ValueType::IntClass indexVal = index->as<ValueType::IntClass>();
|
||||
@@ -85,21 +105,48 @@ namespace Fig
|
||||
std::format(
|
||||
"Index {} out of list `{}` range",
|
||||
indexVal,
|
||||
base.get()->toString().toBasicString()
|
||||
),
|
||||
ie->index
|
||||
);
|
||||
base.get()->toString().toBasicString()),
|
||||
ie->index);
|
||||
}
|
||||
return LvObject(
|
||||
base.get(),
|
||||
indexVal
|
||||
);
|
||||
indexVal,
|
||||
LvObject::Kind::ListElement);
|
||||
}
|
||||
else if (type == ValueType::Map)
|
||||
{
|
||||
return LvObject(
|
||||
base.get(),
|
||||
index
|
||||
index,
|
||||
LvObject::Kind::MapElement);
|
||||
}
|
||||
else if (type == ValueType::String)
|
||||
{
|
||||
if (index->getTypeInfo() != ValueType::Int)
|
||||
{
|
||||
throw EvaluatorError(
|
||||
u8"TypeError",
|
||||
std::format(
|
||||
"Type `String` indices must be `Int`, got '{}'",
|
||||
index->getTypeInfo().toString().toBasicString()),
|
||||
ie->index);
|
||||
}
|
||||
FString &string = base.get()->as<ValueType::StringClass>();
|
||||
ValueType::IntClass indexVal = index->as<ValueType::IntClass>();
|
||||
if (indexVal >= string.length())
|
||||
{
|
||||
throw EvaluatorError(
|
||||
u8"IndexOutOfRangeError",
|
||||
std::format(
|
||||
"Index {} out of string `{}` range",
|
||||
indexVal,
|
||||
base.get()->toString().toBasicString()),
|
||||
ie->index);
|
||||
}
|
||||
return LvObject(
|
||||
base.get(),
|
||||
indexVal,
|
||||
LvObject::Kind::StringElement
|
||||
);
|
||||
}
|
||||
else
|
||||
@@ -111,7 +158,6 @@ namespace Fig
|
||||
base.declaredType().toString().toBasicString()),
|
||||
ie->base);
|
||||
}
|
||||
|
||||
}
|
||||
LvObject Evaluator::evalLv(Ast::Expression exp, ContextPtr ctx)
|
||||
{
|
||||
@@ -322,9 +368,13 @@ namespace Fig
|
||||
Ast::FunctionParameters fnParas = fnStruct.paras;
|
||||
if (fnArgs.getLength() < fnParas.posParas.size() || fnArgs.getLength() > fnParas.size())
|
||||
{
|
||||
throw EvaluatorError(
|
||||
u8"ArgumentMismatchError",
|
||||
std::format("Function '{}' expects {} to {} arguments, but {} were provided", fnName.toBasicString(), fnParas.posParas.size(), fnParas.size(), fnArgs.getLength()), fnArgs.argv.back());
|
||||
throw RuntimeError(FString(
|
||||
std::format(
|
||||
"Function '{}' expects {} to {} arguments, but {} were provided",
|
||||
fnName.toBasicString(),
|
||||
fnParas.posParas.size(),
|
||||
fnParas.size(),
|
||||
fnArgs.getLength())));
|
||||
}
|
||||
|
||||
// positional parameters type check
|
||||
@@ -484,8 +534,15 @@ namespace Fig
|
||||
}
|
||||
const Function &fn = fnObj->as<Function>();
|
||||
size_t fnId = fn.id;
|
||||
const auto &fnNameOpt = ctx->getFunctionName(fnId);
|
||||
// const auto &fnNameOpt = ctx->getFunctionName(fnId);
|
||||
// const FString &fnName = (fnNameOpt ? *fnNameOpt : u8"<anonymous>");
|
||||
|
||||
auto fnNameOpt = ctx->getFunctionName(fnId);
|
||||
if (!fnNameOpt && fn.closureContext)
|
||||
fnNameOpt = fn.closureContext->getFunctionName(fnId);
|
||||
|
||||
const FString &fnName = (fnNameOpt ? *fnNameOpt : u8"<anonymous>");
|
||||
|
||||
return evalFunctionCall(fn, fnCall->arg, fnName, ctx);
|
||||
}
|
||||
case AstType::FunctionLiteralExpr: {
|
||||
@@ -722,7 +779,7 @@ namespace Fig
|
||||
}
|
||||
return std::make_shared<Object>(std::move(map));
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
@@ -745,6 +802,11 @@ namespace Fig
|
||||
using enum Ast::AstType;
|
||||
switch (stmt->getType())
|
||||
{
|
||||
case ImportSt: {
|
||||
auto i = std::dynamic_pointer_cast<Ast::ImportSt>(stmt);
|
||||
assert(i != nullptr);
|
||||
return evalImportSt(i, ctx);
|
||||
}
|
||||
case VarDefSt: {
|
||||
auto varDef = std::dynamic_pointer_cast<Ast::VarDefAst>(stmt);
|
||||
assert(varDef != nullptr);
|
||||
@@ -1067,6 +1129,189 @@ namespace Fig
|
||||
magic_enum::enum_name(stmt->getType()))));
|
||||
}
|
||||
}
|
||||
|
||||
std::filesystem::path Evaluator::resolveModulePath(const std::vector<FString> &pathVec)
|
||||
{
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
static const std::vector<fs::path> defaultLibraryPath{
|
||||
"Library",
|
||||
"Library/fpm"};
|
||||
|
||||
std::vector<fs::path> pathToFind(defaultLibraryPath);
|
||||
pathToFind.insert(
|
||||
pathToFind.begin(),
|
||||
fs::path(
|
||||
this->sourcePath.toBasicString())
|
||||
.parent_path()); // first search module at the source file path
|
||||
|
||||
fs::path path;
|
||||
|
||||
/*
|
||||
Example:
|
||||
import comp.config;
|
||||
*/
|
||||
|
||||
const FString &modPathStrTop = pathVec.at(0);
|
||||
fs::path modPath;
|
||||
|
||||
bool found = false;
|
||||
for (auto &parentFolder : pathToFind)
|
||||
{
|
||||
modPath = parentFolder / FString(modPathStrTop + u8".fig").toBasicString();
|
||||
if (fs::exists(modPath))
|
||||
{
|
||||
path = modPath;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
modPath = parentFolder / modPathStrTop.toBasicString();
|
||||
if (fs::is_directory(modPath)) // comp is a directory
|
||||
{
|
||||
modPath = modPath / FString(modPathStrTop + u8".fig").toBasicString();
|
||||
/*
|
||||
if module name is a directory, we require [module name].fig at the directory
|
||||
*/
|
||||
if (!fs::exists(modPath))
|
||||
{
|
||||
throw RuntimeError(FString(
|
||||
std::format(
|
||||
"requires module file, {}\\{}",
|
||||
modPathStrTop.toBasicString(),
|
||||
FString(modPathStrTop + u8".fig").toBasicString())));
|
||||
}
|
||||
found = true;
|
||||
path = modPath;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
throw RuntimeError(
|
||||
FString(std::format(
|
||||
"Could not find module `{}`",
|
||||
modPathStrTop.toBasicString())));
|
||||
|
||||
bool found2 = false;
|
||||
|
||||
for (size_t i = 1; i < pathVec.size(); ++i) // has next module
|
||||
{
|
||||
const FString &next = pathVec.at(i);
|
||||
modPath = modPath.parent_path(); // get the folder
|
||||
modPath = modPath / FString(next + u8".fig").toBasicString();
|
||||
if (fs::exists(modPath))
|
||||
{
|
||||
if (i != pathVec.size() - 1)
|
||||
throw RuntimeError(FString(
|
||||
std::format(
|
||||
"expects {} as parent directory and find next module, but got a file",
|
||||
next.toBasicString())));
|
||||
// it's the last module
|
||||
found2 = true;
|
||||
path = modPath;
|
||||
break;
|
||||
}
|
||||
// `next` is a folder
|
||||
modPath = modPath.parent_path() / next.toBasicString();
|
||||
if (!fs::exists(modPath))
|
||||
throw RuntimeError(FString(
|
||||
std::format("Could not find module `{}`", next.toBasicString())));
|
||||
}
|
||||
|
||||
if (!found2 && !fs::exists(modPath))
|
||||
throw RuntimeError(FString(
|
||||
std::format("Could not find module `{}`", pathVec.end()->toBasicString())));
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
ContextPtr Evaluator::loadModule(const std::filesystem::path &path)
|
||||
{
|
||||
std::ifstream file(path);
|
||||
assert(file.is_open());
|
||||
|
||||
std::string source((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
|
||||
file.close();
|
||||
|
||||
Lexer lexer((FString(source)));
|
||||
Parser parser(lexer);
|
||||
std::vector<Ast::AstBase> asts;
|
||||
|
||||
std::vector<FString> sourceLines = Utils::splitSource(FString(source));
|
||||
|
||||
try
|
||||
{
|
||||
asts = parser.parseAll();
|
||||
}
|
||||
catch (const AddressableError &e)
|
||||
{
|
||||
ErrorLog::logAddressableError(e, sourcePath, sourceLines);
|
||||
}
|
||||
catch (const UnaddressableError &e)
|
||||
{
|
||||
ErrorLog::logUnaddressableError(e);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
std::cerr << "uncaught exception of: " << e.what() << '\n';
|
||||
}
|
||||
|
||||
Evaluator evaluator;
|
||||
evaluator.SetSourcePath(FString(path.string()));
|
||||
|
||||
ContextPtr modctx = std::make_shared<Context>(
|
||||
FString(std::format("<Module at {}>", path.string())),
|
||||
nullptr);
|
||||
|
||||
evaluator.SetGlobalContext(modctx);
|
||||
evaluator.RegisterBuiltins();
|
||||
|
||||
try
|
||||
{
|
||||
evaluator.Run(asts);
|
||||
}
|
||||
catch (std::exception &e)
|
||||
{
|
||||
std::cerr << "load module failed" << '\n';
|
||||
throw e;
|
||||
}
|
||||
|
||||
return evaluator.global;
|
||||
}
|
||||
|
||||
StatementResult Evaluator::evalImportSt(Ast::Import i, ContextPtr ctx)
|
||||
{
|
||||
const std::vector<FString> &pathVec = i->path;
|
||||
auto path = resolveModulePath(pathVec);
|
||||
ContextPtr modCtx = loadModule(path);
|
||||
|
||||
const FString &modName = pathVec.at(pathVec.size() - 1);
|
||||
|
||||
// std::cerr << modName.toBasicString() << '\n'; DEBUG
|
||||
|
||||
if (ctx->containsInThisScope(modName))
|
||||
{
|
||||
throw EvaluatorError(
|
||||
u8"RedeclarationError",
|
||||
std::format(
|
||||
"{} has already been declared.",
|
||||
modName.toBasicString()),
|
||||
i);
|
||||
}
|
||||
ctx->def(
|
||||
modName,
|
||||
ValueType::Module,
|
||||
AccessModifier::PublicConst,
|
||||
std::make_shared<Object>(
|
||||
Module(
|
||||
modName,
|
||||
modCtx)));
|
||||
return StatementResult::normal();
|
||||
}
|
||||
|
||||
StatementResult Evaluator::Run(std::vector<Ast::AstBase> asts)
|
||||
{
|
||||
using Ast::AstType;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <Error/error.hpp>
|
||||
#include <Module/builtins.hpp>
|
||||
#include <Value/LvObject.hpp>
|
||||
#include <filesystem>
|
||||
|
||||
|
||||
namespace Fig
|
||||
@@ -52,6 +53,12 @@ namespace Fig
|
||||
private:
|
||||
ContextPtr global;
|
||||
public:
|
||||
FString sourcePath;
|
||||
|
||||
void SetSourcePath(const FString &sp)
|
||||
{
|
||||
sourcePath = sp;
|
||||
}
|
||||
|
||||
void SetGlobalContext(ContextPtr ctx)
|
||||
{
|
||||
@@ -110,8 +117,13 @@ namespace Fig
|
||||
StatementResult evalBlockStatement(Ast::BlockStatement, ContextPtr); // block
|
||||
StatementResult evalStatement(Ast::Statement, ContextPtr); // statement
|
||||
|
||||
std::filesystem::path resolveModulePath(const std::vector<FString> &);
|
||||
ContextPtr loadModule(const std::filesystem::path &);
|
||||
|
||||
StatementResult evalImportSt(Ast::Import, ContextPtr);
|
||||
|
||||
StatementResult Run(std::vector<Ast::AstBase>); // Entry
|
||||
|
||||
|
||||
void printStackTrace();
|
||||
};
|
||||
}; // namespace Fig
|
||||
9
src/Module/Library/std/io/io.fig
Normal file
9
src/Module/Library/std/io/io.fig
Normal file
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
Official Module `std.io`
|
||||
Library/std/io/io.fig
|
||||
*/
|
||||
|
||||
public func print(value) -> Null
|
||||
{
|
||||
__fstdout_print(value);
|
||||
}
|
||||
6
src/Module/Library/std/std.fig
Normal file
6
src/Module/Library/std/std.fig
Normal file
@@ -0,0 +1,6 @@
|
||||
/*
|
||||
Official Module `std`
|
||||
Library/std/std.fig
|
||||
*/
|
||||
|
||||
import io; // link std io
|
||||
@@ -1,47 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <Core/fig_string.hpp>
|
||||
#include <Value/value.hpp>
|
||||
#include <Context/context.hpp>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
// class Module
|
||||
// {
|
||||
// public:
|
||||
// const FString name;
|
||||
// const FString spec;
|
||||
// const FString path;
|
||||
|
||||
// std::shared_ptr<Context> context; // module-level context
|
||||
|
||||
// /*
|
||||
|
||||
// import module -> automatically create a module context and call function `init` if exists
|
||||
// all global functions, variables, structs, etc will be stored in module context
|
||||
// then module context will be linked to the current context
|
||||
|
||||
// */
|
||||
// Module(const FString &moduleName, const FString &moduleSpec, const FString &modulePath) :
|
||||
// name(moduleName), spec(moduleSpec), path(modulePath)
|
||||
// {
|
||||
// context = std::make_shared<Context>(FString(std::format("<Module {}>", name.toBasicString())), nullptr);
|
||||
// }
|
||||
|
||||
// bool hasSymbol(const FString &symbolName)
|
||||
// {
|
||||
// return context->contains(symbolName);
|
||||
// }
|
||||
// Object getSymbol(const FString &symbolName)
|
||||
// {
|
||||
// auto valOpt = context->get(symbolName);
|
||||
// if (!valOpt.has_value())
|
||||
// {
|
||||
// throw RuntimeError(FStringView(std::format("Symbol '{}' not found in module '{}'", symbolName.toBasicString(), name.toBasicString())));
|
||||
// }
|
||||
// return valOpt.value();
|
||||
// }
|
||||
// };
|
||||
};
|
||||
@@ -132,7 +132,7 @@ namespace Fig
|
||||
|
||||
Ast::ValueExpr Parser::__parseValueExpr()
|
||||
{
|
||||
return makeAst<Ast::ValueExprAst> (__parseValue());
|
||||
return makeAst<Ast::ValueExprAst>(__parseValue());
|
||||
}
|
||||
Ast::FunctionParameters Parser::__parseFunctionParameters()
|
||||
{
|
||||
@@ -350,7 +350,11 @@ namespace Fig
|
||||
{
|
||||
Ast::Statement stmt;
|
||||
if (isThis(TokenType::EndOfFile)) { return makeAst<Ast::EofStmt>(); }
|
||||
if (isThis(TokenType::Public))
|
||||
else if (isThis(TokenType::Import))
|
||||
{
|
||||
stmt = __parseImport();
|
||||
}
|
||||
else if (isThis(TokenType::Public))
|
||||
{
|
||||
next(); // consume `public`
|
||||
if (isThis(TokenType::Variable) || isThis(TokenType::Const))
|
||||
@@ -708,8 +712,7 @@ namespace Fig
|
||||
{
|
||||
throwAddressableError<SyntaxError>(FString(
|
||||
std::format("Expect `,` or `}}` in struct initialization expression, got {}",
|
||||
currentToken().toString().toBasicString())
|
||||
));
|
||||
currentToken().toString().toBasicString())));
|
||||
}
|
||||
}
|
||||
expect(TokenType::RightBrace);
|
||||
@@ -782,6 +785,33 @@ namespace Fig
|
||||
return makeAst<Ast::FunctionLiteralExprAst>(params, __parseBlockStatement());
|
||||
}
|
||||
|
||||
Ast::Import Parser::__parseImport()
|
||||
{
|
||||
next(); // consume `import`
|
||||
std::vector<FString> path;
|
||||
while (true)
|
||||
{
|
||||
expect(TokenType::Identifier, u8"package name");
|
||||
path.push_back(currentToken().getValue());
|
||||
next(); // consume package name
|
||||
if (isThis(TokenType::Semicolon))
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (isThis(TokenType::Dot))
|
||||
{
|
||||
next(); // consume `.`
|
||||
}
|
||||
else
|
||||
{
|
||||
throw SyntaxError();
|
||||
}
|
||||
}
|
||||
expect(TokenType::Semicolon);
|
||||
next(); // consume `;`
|
||||
return makeAst<Ast::ImportSt>(path);
|
||||
}
|
||||
|
||||
Ast::Expression Parser::parseExpression(Precedence bp, TokenType stop, TokenType stop2)
|
||||
{
|
||||
Ast::Expression lhs;
|
||||
@@ -921,10 +951,17 @@ namespace Fig
|
||||
return output;
|
||||
}
|
||||
|
||||
// TODO: Package/Module Import Support
|
||||
while (!isEOF())
|
||||
{
|
||||
pushNode(__parseStatement());
|
||||
auto stmt = __parseStatement();
|
||||
if (!output.empty() && stmt->getType() == Ast::AstType::PackageSt)
|
||||
{
|
||||
throw SyntaxError(
|
||||
u8"Package must be at the beginning of the file",
|
||||
currentAAI.line,
|
||||
currentAAI.column);
|
||||
}
|
||||
pushNode(stmt);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
@@ -325,6 +325,8 @@ namespace Fig
|
||||
Ast::Expression __parseTupleOrParenExpr(); // entry: current is `(`
|
||||
|
||||
Ast::FunctionLiteralExpr __parseFunctionLiteralExpr(); // entry: current is Token::LParen after Token::Function
|
||||
|
||||
Ast::Import __parseImport(); // entry: current is Token::Import
|
||||
|
||||
Ast::Statement __parseStatement(); // entry: (idk)
|
||||
Ast::Expression parseExpression(Precedence, TokenType = TokenType::Semicolon, TokenType = TokenType::Semicolon);
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace Fig
|
||||
Identifier,
|
||||
|
||||
/* Keywords */
|
||||
Package, // package
|
||||
And, // and
|
||||
Or, // or
|
||||
Not, // not
|
||||
@@ -48,7 +49,7 @@ namespace Fig
|
||||
LiteralNumber, // number (int,float...)
|
||||
LiteralString, // FString
|
||||
LiteralBool, // bool (true/false)
|
||||
LiteralNull, // null (Null的唯一实例)
|
||||
LiteralNull, // null (Null unique instance)
|
||||
|
||||
/* Punct */
|
||||
Plus, // +
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include <Lexer/lexer.hpp>
|
||||
#include <Core/fig_string.hpp>
|
||||
#include <string>
|
||||
#include <locale>
|
||||
@@ -9,6 +10,32 @@
|
||||
|
||||
namespace Fig::Utils
|
||||
{
|
||||
|
||||
inline std::vector<FString> splitSource(FString source)
|
||||
{
|
||||
UTF8Iterator it(source);
|
||||
std::vector<FString> lines;
|
||||
FString currentLine;
|
||||
while (!it.isEnd())
|
||||
{
|
||||
UTF8Char c = *it;
|
||||
if (c == U'\n')
|
||||
{
|
||||
lines.push_back(currentLine);
|
||||
currentLine = FString(u8"");
|
||||
}
|
||||
else
|
||||
{
|
||||
currentLine += c.getString();
|
||||
}
|
||||
++it;
|
||||
}
|
||||
if (!currentLine.empty())
|
||||
{
|
||||
lines.push_back(currentLine);
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
inline std::u32string utf8ToUtf32(const FString &s)
|
||||
{
|
||||
std::u32string result;
|
||||
|
||||
@@ -12,12 +12,13 @@ namespace Fig
|
||||
{
|
||||
Variable,
|
||||
ListElement,
|
||||
MapElement
|
||||
MapElement,
|
||||
StringElement,
|
||||
} kind;
|
||||
std::shared_ptr<VariableSlot> slot;
|
||||
|
||||
ObjectPtr listOrMap = nullptr;
|
||||
size_t listIndex;
|
||||
ObjectPtr value = nullptr;
|
||||
size_t numIndex;
|
||||
|
||||
ObjectPtr mapIndex;
|
||||
|
||||
@@ -26,20 +27,18 @@ namespace Fig
|
||||
{
|
||||
kind = Kind::Variable;
|
||||
}
|
||||
LvObject(ObjectPtr _v, size_t _index) :
|
||||
listOrMap(_v), listIndex(_index)
|
||||
LvObject(ObjectPtr _v, size_t _index, Kind _kind) :
|
||||
value(_v), numIndex(_index)
|
||||
{
|
||||
assert(_v->getTypeInfo() == ValueType::List);
|
||||
kind = Kind::ListElement;
|
||||
kind = _kind;
|
||||
}
|
||||
LvObject(ObjectPtr _v, ObjectPtr _index) :
|
||||
listOrMap(_v), mapIndex(_index)
|
||||
LvObject(ObjectPtr _v, ObjectPtr _index, Kind _kind) :
|
||||
value(_v), mapIndex(_index)
|
||||
{
|
||||
assert(_v->getTypeInfo() == ValueType::Map);
|
||||
kind = Kind::MapElement;
|
||||
kind = _kind;
|
||||
}
|
||||
|
||||
const ObjectPtr &get() const
|
||||
ObjectPtr get() const
|
||||
{
|
||||
if (kind == Kind::Variable)
|
||||
{
|
||||
@@ -48,20 +47,30 @@ namespace Fig
|
||||
}
|
||||
else if (kind == Kind::ListElement)
|
||||
{
|
||||
List &list = listOrMap->as<List>();
|
||||
if (listIndex >= list.size())
|
||||
List &list = value->as<List>();
|
||||
if (numIndex >= list.size())
|
||||
throw RuntimeError(FString(
|
||||
std::format("Index {} out of range", listIndex)));
|
||||
return list.at(listIndex);
|
||||
std::format("Index {} out of range {}", numIndex, value->toString().toBasicString())));
|
||||
return list.at(numIndex);
|
||||
}
|
||||
else // map
|
||||
else if (kind == Kind::MapElement) // map
|
||||
{
|
||||
Map &map = listOrMap->as<Map>();
|
||||
Map &map = value->as<Map>();
|
||||
if (!map.contains(mapIndex))
|
||||
throw RuntimeError(FString(
|
||||
std::format("Key {} not found", mapIndex->toString().toBasicString())));
|
||||
return map.at(mapIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
// string
|
||||
FString &string = value->as<ValueType::StringClass>();
|
||||
if (numIndex >= string.length())
|
||||
throw RuntimeError(FString(
|
||||
std::format("Index {} out of range {}", numIndex, value->toString().toBasicString())));
|
||||
|
||||
return std::make_shared<Object>(string.getRealChar(numIndex));
|
||||
}
|
||||
}
|
||||
|
||||
void set(const ObjectPtr &v)
|
||||
@@ -87,17 +96,35 @@ namespace Fig
|
||||
}
|
||||
else if (kind == Kind::ListElement)
|
||||
{
|
||||
List &list = listOrMap->as<List>();
|
||||
if (listIndex >= list.size())
|
||||
List &list = value->as<List>();
|
||||
if (numIndex >= list.size())
|
||||
throw RuntimeError(FString(
|
||||
std::format("Index {} out of range", listIndex)));
|
||||
list[listIndex] = v;
|
||||
std::format("Index {} out of range", numIndex)));
|
||||
list[numIndex] = v;
|
||||
}
|
||||
else // map
|
||||
else if (kind == Kind::MapElement) // map
|
||||
{
|
||||
Map &map = listOrMap->as<Map>();
|
||||
Map &map = value->as<Map>();
|
||||
map[mapIndex] = v;
|
||||
}
|
||||
else if (kind == Kind::StringElement)
|
||||
{
|
||||
FString &string = value->as<ValueType::StringClass>();
|
||||
if (numIndex >= string.length())
|
||||
throw RuntimeError(FString(
|
||||
std::format("Index {} out of range {}", numIndex, value->toString().toBasicString())));
|
||||
|
||||
if (v->getTypeInfo() != ValueType::String)
|
||||
throw RuntimeError(FString(
|
||||
std::format("Could not assign {} to sub string", v->toString().toBasicString())
|
||||
));
|
||||
const FString &strReplace = v->as<ValueType::StringClass>();
|
||||
if (strReplace.length() > 1)
|
||||
throw RuntimeError(FString(
|
||||
std::format("Could not assign {} to sub string, expects length 1", v->toString().toBasicString())
|
||||
));
|
||||
string.realReplace(numIndex, strReplace);
|
||||
}
|
||||
}
|
||||
|
||||
FString name() const { return resolve(slot)->name; }
|
||||
@@ -111,4 +138,4 @@ namespace Fig
|
||||
return s;
|
||||
}
|
||||
};
|
||||
}
|
||||
} // namespace Fig
|
||||
@@ -67,6 +67,7 @@ namespace Fig
|
||||
extern const TypeInfo StructInstance;
|
||||
extern const TypeInfo List;
|
||||
extern const TypeInfo Map;
|
||||
extern const TypeInfo Module;
|
||||
// extern const TypeInfo Tuple;
|
||||
|
||||
using IntClass = int64_t;
|
||||
|
||||
27
src/Value/module.hpp
Normal file
27
src/Value/module.hpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <Core/fig_string.hpp>
|
||||
|
||||
#include <Context/context_forward.hpp>
|
||||
|
||||
namespace Fig
|
||||
{
|
||||
struct Module
|
||||
{
|
||||
FString name;
|
||||
ContextPtr ctx;
|
||||
|
||||
Module() = default;
|
||||
|
||||
Module(FString n, ContextPtr c) :
|
||||
name(std::move(n)),
|
||||
ctx(std::move(c))
|
||||
{
|
||||
}
|
||||
|
||||
bool operator==(const Module &o) const noexcept
|
||||
{
|
||||
return name == o.name;
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -80,5 +80,5 @@ namespace Fig
|
||||
const TypeInfo ValueType::StructInstance(FString(u8"StructInstance"), true); // id: 9
|
||||
const TypeInfo ValueType::List(FString(u8"List"), true); // id: 10
|
||||
const TypeInfo ValueType::Map(FString(u8"Map"), true); // id: 11
|
||||
// const TypeInfo ValueType::Tuple(FString(u8"Tuple"), true); // id: 12
|
||||
const TypeInfo ValueType::Module(FString(u8"Module"), true); // id: 12
|
||||
} // namespace Fig
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <Value/structInstance.hpp>
|
||||
#include <Value/Type.hpp>
|
||||
#include <Value/valueError.hpp>
|
||||
#include <Value/module.hpp>
|
||||
|
||||
#include <variant>
|
||||
#include <cmath>
|
||||
@@ -58,7 +59,8 @@ namespace Fig
|
||||
StructType,
|
||||
StructInstance,
|
||||
List,
|
||||
Map>;
|
||||
Map,
|
||||
Module>;
|
||||
|
||||
std::unordered_map<TypeInfo,
|
||||
std::unordered_map<FString,
|
||||
@@ -134,6 +136,7 @@ namespace Fig
|
||||
map.contains(index));
|
||||
}},
|
||||
}},
|
||||
{ValueType::Module, {}}
|
||||
};
|
||||
std::unordered_map<TypeInfo, std::unordered_map<FString, int>, TypeInfoHash> memberTypeFunctionsParas{
|
||||
{ValueType::Null, {}},
|
||||
@@ -151,6 +154,7 @@ namespace Fig
|
||||
{u8"get", 1},
|
||||
{u8"contains", 1},
|
||||
}},
|
||||
{ValueType::Module, {}}
|
||||
|
||||
};
|
||||
bool hasMemberFunction(const FString &name) const
|
||||
@@ -190,6 +194,8 @@ namespace Fig
|
||||
data(l) {}
|
||||
Object(const Map &m) :
|
||||
data(m) {}
|
||||
Object(const Module &m) :
|
||||
data(m) {}
|
||||
|
||||
Object(const Object &) = default;
|
||||
Object(Object &&) noexcept = default;
|
||||
@@ -283,6 +289,9 @@ namespace Fig
|
||||
else if constexpr (std::is_same_v<T, Map>)
|
||||
return ValueType::Map;
|
||||
|
||||
else if constexpr (std::is_same_v<T, Module>)
|
||||
return ValueType::Module;
|
||||
|
||||
else
|
||||
return ValueType::Any;
|
||||
},
|
||||
@@ -357,6 +366,12 @@ namespace Fig
|
||||
output += u8"}";
|
||||
return output;
|
||||
}
|
||||
if (is<Module>())
|
||||
{
|
||||
return FString(std::format(
|
||||
"<Module at {:p}>",
|
||||
static_cast<const void *>(&as<Module>())));
|
||||
}
|
||||
return FString(u8"<error>");
|
||||
}
|
||||
|
||||
@@ -576,7 +591,6 @@ namespace Fig
|
||||
using ObjectPtr = std::shared_ptr<Object>;
|
||||
using RvObject = ObjectPtr;
|
||||
|
||||
|
||||
inline bool operator==(const ValueKey &l, const ValueKey &r)
|
||||
{
|
||||
return *l.value == *r.value;
|
||||
|
||||
31
src/main.cpp
31
src/main.cpp
@@ -36,36 +36,12 @@ This software is licensed under the MIT License. See LICENSE.txt for details.
|
||||
#include <Parser/parser.hpp>
|
||||
#include <Evaluator/evaluator.hpp>
|
||||
#include <Utils/AstPrinter.hpp>
|
||||
#include <Utils/utils.hpp>
|
||||
#include <Error/errorLog.hpp>
|
||||
|
||||
static size_t addressableErrorCount = 0;
|
||||
static size_t unaddressableErrorCount = 0;
|
||||
|
||||
std::vector<FString> splitSource(FString source)
|
||||
{
|
||||
UTF8Iterator it(source);
|
||||
std::vector<FString> lines;
|
||||
FString currentLine;
|
||||
while (!it.isEnd())
|
||||
{
|
||||
UTF8Char c = *it;
|
||||
if (c == U'\n')
|
||||
{
|
||||
lines.push_back(currentLine);
|
||||
currentLine = FString(u8"");
|
||||
}
|
||||
else
|
||||
{
|
||||
currentLine += c.getString();
|
||||
}
|
||||
++it;
|
||||
}
|
||||
if (!currentLine.empty())
|
||||
{
|
||||
lines.push_back(currentLine);
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
@@ -119,7 +95,7 @@ int main(int argc, char **argv)
|
||||
Fig::Parser parser(lexer);
|
||||
std::vector<Fig::Ast::AstBase> asts;
|
||||
|
||||
std::vector<FString> sourceLines = splitSource(Fig::FString(source));
|
||||
std::vector<FString> sourceLines = Fig::Utils::splitSource(Fig::FString(source));
|
||||
|
||||
try
|
||||
{
|
||||
@@ -151,8 +127,11 @@ int main(int argc, char **argv)
|
||||
// }
|
||||
|
||||
Fig::Evaluator evaluator;
|
||||
|
||||
evaluator.SetSourcePath(sourcePath);
|
||||
evaluator.CreateGlobalContext();
|
||||
evaluator.RegisterBuiltins();
|
||||
|
||||
try
|
||||
{
|
||||
evaluator.Run(asts);
|
||||
|
||||
Reference in New Issue
Block a user