1 Commits

Author SHA1 Message Date
d398d457b5 [VER] v0.3.9-alpha
[Feat] is 操作符现在可以直接判断内置数据类型, 如 10 is Int
[Fix] evalMemberExpr的lhs可以为右值,修复原来限制为左值的BUG,如调用一个函数返回结果为struct且访问member触发此bug
[Impl] 可更换的std::dynamic_pointer_cast更换为static版本,更快!
[Feat] 增加标准库 std.time,以及用到的builtin: __ftime_now_ns,但目前 Time类有点BUG
[...] 剩下的忘了
2026-01-15 17:51:01 +08:00
10 changed files with 199 additions and 41 deletions

View File

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

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

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

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

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

View File

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

View File

@@ -22,6 +22,7 @@
#include <filesystem> #include <filesystem>
#include <fstream> #include <fstream>
#include <memory> #include <memory>
#include <unordered_map>
namespace Fig namespace Fig
{ {
@@ -40,8 +41,8 @@ namespace Fig
} }
LvObject Evaluator::evalMemberExpr(Ast::MemberExpr me, ContextPtr ctx) LvObject Evaluator::evalMemberExpr(Ast::MemberExpr me, ContextPtr ctx)
{ {
LvObject base = evalLv(me->base, ctx); // LvObject base = evalLv(me->base, ctx);
RvObject baseVal = base.get(); RvObject baseVal = eval(me->base, ctx);
const FString &member = me->member; const FString &member = me->member;
if (baseVal->getTypeInfo() == ValueType::Module) if (baseVal->getTypeInfo() == ValueType::Module)
{ {
@@ -194,25 +195,26 @@ namespace Fig
switch (exp->getType()) switch (exp->getType())
{ {
case AstType::VarExpr: { case AstType::VarExpr: {
Ast::VarExpr var = std::dynamic_pointer_cast<Ast::VarExprAst>(exp); Ast::VarExpr var = std::static_pointer_cast<Ast::VarExprAst>(exp);
assert(var != nullptr); assert(var != nullptr);
return evalVarExpr(var, ctx); return evalVarExpr(var, ctx);
} }
case AstType::MemberExpr: { case AstType::MemberExpr: {
Ast::MemberExpr me = std::dynamic_pointer_cast<Ast::MemberExprAst>(exp); Ast::MemberExpr me = std::static_pointer_cast<Ast::MemberExprAst>(exp);
assert(me != nullptr); assert(me != nullptr);
return evalMemberExpr(me, ctx); return evalMemberExpr(me, ctx);
} }
case AstType::IndexExpr: { case AstType::IndexExpr: {
Ast::IndexExpr ie = std::dynamic_pointer_cast<Ast::IndexExprAst>(exp); Ast::IndexExpr ie = std::static_pointer_cast<Ast::IndexExprAst>(exp);
assert(ie != nullptr); assert(ie != nullptr);
return evalIndexExpr(ie, ctx); return evalIndexExpr(ie, ctx);
} }
default: { default: {
throw EvaluatorError( // throw EvaluatorError(
u8"TypeError", // u8"TypeError",
std::format("Expression '{}' doesn't refer to a lvalue", exp->typeName().toBasicString()), // std::format("Expression '{}' doesn't refer to a lvalue", exp->typeName().toBasicString()),
exp); // exp);
} }
} }
} }
@@ -298,6 +300,9 @@ namespace Fig
ObjectPtr lhs = eval(lexp, ctx); ObjectPtr lhs = eval(lexp, ctx);
ObjectPtr rhs = eval(rexp, ctx); ObjectPtr rhs = eval(rexp, ctx);
const TypeInfo &lhsType = lhs->getTypeInfo();
const TypeInfo &rhsType = rhs->getTypeInfo();
if (lhs->is<StructInstance>() && rhs->is<StructType>()) if (lhs->is<StructInstance>() && rhs->is<StructType>())
{ {
const StructInstance &si = lhs->as<StructInstance>(); const StructInstance &si = lhs->as<StructInstance>();
@@ -310,10 +315,37 @@ namespace Fig
const InterfaceType &it = rhs->as<InterfaceType>(); const InterfaceType &it = rhs->as<InterfaceType>();
return std::make_shared<Object>(implements(si.parentType, it.type, ctx)); return std::make_shared<Object>(implements(si.parentType, it.type, ctx));
} }
if (ValueType::isTypeBuiltin(lhsType) && rhsType == ValueType::StructType)
{
const StructType &st = rhs->as<StructType>();
const TypeInfo &type = st.type;
/*
如果是内置类型(e.g. Int, String)
那么 eval出来String这个字出来的是StructType
而出来的StructType.type就不会是一个独立的TypeInfo,而是内置的ValueType::String
依次我们可以判断内置类型
e.g:
"123" is String
L OP R
其中 L 类型为 String
而 R 类型为 StructType (builtins.hpp) 中注册
拿到 R 的 StructType, 其中的 type 为 String
*/
if (lhs->getTypeInfo() == type)
{
return Object::getTrueInstance();
}
return Object::getFalseInstance();
}
throw EvaluatorError( throw EvaluatorError(
u8"TypeError", u8"TypeError",
std::format("Operator `is` requires an struct instance on left-hand side, got '{}'", std::format("Unsupported operator `is` for '{}' && '{}'",
lhs->getTypeInfo().toString().toBasicString()), lhsType.toString().toBasicString(),
rhsType.toString().toBasicString()),
bin->lexp); bin->lexp);
} }
@@ -606,27 +638,27 @@ namespace Fig
switch (type) switch (type)
{ {
case AstType::ValueExpr: { case AstType::ValueExpr: {
auto val = std::dynamic_pointer_cast<Ast::ValueExprAst>(exp); auto val = std::static_pointer_cast<Ast::ValueExprAst>(exp);
assert(val != nullptr); assert(val != nullptr);
return val->val; return val->val;
} }
case AstType::VarExpr: { case AstType::VarExpr: {
auto varExpr = std::dynamic_pointer_cast<Ast::VarExprAst>(exp); auto varExpr = std::static_pointer_cast<Ast::VarExprAst>(exp);
assert(varExpr != nullptr); assert(varExpr != nullptr);
return evalVarExpr(varExpr, ctx).get(); // LvObject -> RvObject return evalVarExpr(varExpr, ctx).get(); // LvObject -> RvObject
} }
case AstType::BinaryExpr: { case AstType::BinaryExpr: {
auto bin = std::dynamic_pointer_cast<Ast::BinaryExprAst>(exp); auto bin = std::static_pointer_cast<Ast::BinaryExprAst>(exp);
assert(bin != nullptr); assert(bin != nullptr);
return evalBinary(bin, ctx); return evalBinary(bin, ctx);
} }
case AstType::UnaryExpr: { case AstType::UnaryExpr: {
auto un = std::dynamic_pointer_cast<Ast::UnaryExprAst>(exp); auto un = std::static_pointer_cast<Ast::UnaryExprAst>(exp);
assert(un != nullptr); assert(un != nullptr);
return evalUnary(un, ctx); return evalUnary(un, ctx);
} }
case AstType::TernaryExpr: { case AstType::TernaryExpr: {
auto te = std::dynamic_pointer_cast<Ast::TernaryExprAst>(exp); auto te = std::static_pointer_cast<Ast::TernaryExprAst>(exp);
assert(te != nullptr); assert(te != nullptr);
return evalTernary(te, ctx); return evalTernary(te, ctx);
} }
@@ -634,7 +666,7 @@ namespace Fig
case AstType::IndexExpr: return evalLv(exp, ctx).get(); case AstType::IndexExpr: return evalLv(exp, ctx).get();
case AstType::FunctionCall: { case AstType::FunctionCall: {
auto fnCall = std::dynamic_pointer_cast<Ast::FunctionCallExpr>(exp); auto fnCall = std::static_pointer_cast<Ast::FunctionCallExpr>(exp);
assert(fnCall != nullptr); assert(fnCall != nullptr);
Ast::Expression callee = fnCall->callee; Ast::Expression callee = fnCall->callee;
@@ -659,7 +691,7 @@ namespace Fig
return evalFunctionCall(fn, fnCall->arg, fnName, ctx); return evalFunctionCall(fn, fnCall->arg, fnName, ctx);
} }
case AstType::FunctionLiteralExpr: { case AstType::FunctionLiteralExpr: {
auto fnLiteral = std::dynamic_pointer_cast<Ast::FunctionLiteralExprAst>(exp); auto fnLiteral = std::static_pointer_cast<Ast::FunctionLiteralExprAst>(exp);
assert(fnLiteral != nullptr); assert(fnLiteral != nullptr);
Ast::BlockStatement body = nullptr; Ast::BlockStatement body = nullptr;
@@ -689,7 +721,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();
@@ -968,7 +1000,7 @@ namespace Fig
} }
case AstType::ListExpr: { case AstType::ListExpr: {
auto lstExpr = std::dynamic_pointer_cast<Ast::ListExprAst>(exp); auto lstExpr = std::static_pointer_cast<Ast::ListExprAst>(exp);
assert(lstExpr != nullptr); assert(lstExpr != nullptr);
List list; List list;
@@ -977,7 +1009,7 @@ namespace Fig
} }
case AstType::MapExpr: { case AstType::MapExpr: {
auto mapExpr = std::dynamic_pointer_cast<Ast::MapExprAst>(exp); auto mapExpr = std::static_pointer_cast<Ast::MapExprAst>(exp);
assert(mapExpr != nullptr); assert(mapExpr != nullptr);
Map map; Map map;
@@ -985,7 +1017,12 @@ namespace Fig
return std::make_shared<Object>(std::move(map)); return std::make_shared<Object>(std::move(map));
} }
default: assert(false); default:
{
throw RuntimeError(FString(
std::format("err type of expr: {}", magic_enum::enum_name(type))
));
}
} }
return Object::getNullInstance(); // ignore warning return Object::getNullInstance(); // ignore warning
} }
@@ -1005,12 +1042,12 @@ namespace Fig
switch (stmt->getType()) switch (stmt->getType())
{ {
case ImportSt: { case ImportSt: {
auto i = std::dynamic_pointer_cast<Ast::ImportSt>(stmt); auto i = std::static_pointer_cast<Ast::ImportSt>(stmt);
assert(i != nullptr); assert(i != nullptr);
return evalImportSt(i, ctx); return evalImportSt(i, ctx);
} }
case VarDefSt: { case VarDefSt: {
auto varDef = std::dynamic_pointer_cast<Ast::VarDefAst>(stmt); auto varDef = std::static_pointer_cast<Ast::VarDefAst>(stmt);
assert(varDef != nullptr); assert(varDef != nullptr);
if (ctx->containsInThisScope(varDef->name)) if (ctx->containsInThisScope(varDef->name))
@@ -1051,7 +1088,7 @@ namespace Fig
} }
case FunctionDefSt: { case FunctionDefSt: {
auto fnDef = std::dynamic_pointer_cast<Ast::FunctionDefSt>(stmt); auto fnDef = std::static_pointer_cast<Ast::FunctionDefSt>(stmt);
assert(fnDef != nullptr); assert(fnDef != nullptr);
const FString &fnName = fnDef->name; const FString &fnName = fnDef->name;
@@ -1071,7 +1108,7 @@ namespace Fig
} }
case StructSt: { case StructSt: {
auto stDef = std::dynamic_pointer_cast<Ast::StructDefSt>(stmt); auto stDef = std::static_pointer_cast<Ast::StructDefSt>(stmt);
assert(stDef != nullptr); assert(stDef != nullptr);
if (ctx->containsInThisScope(stDef->name)) if (ctx->containsInThisScope(stDef->name))
@@ -1123,7 +1160,7 @@ namespace Fig
} }
case InterfaceDefSt: { case InterfaceDefSt: {
auto ifd = std::dynamic_pointer_cast<Ast::InterfaceDefAst>(stmt); auto ifd = std::static_pointer_cast<Ast::InterfaceDefAst>(stmt);
assert(ifd != nullptr); assert(ifd != nullptr);
const FString &interfaceName = ifd->name; const FString &interfaceName = ifd->name;
@@ -1144,7 +1181,7 @@ namespace Fig
} }
case ImplementSt: { case ImplementSt: {
auto ip = std::dynamic_pointer_cast<Ast::ImplementAst>(stmt); auto ip = std::static_pointer_cast<Ast::ImplementAst>(stmt);
assert(ip != nullptr); assert(ip != nullptr);
TypeInfo structType(ip->structName); TypeInfo structType(ip->structName);
@@ -1288,7 +1325,7 @@ namespace Fig
} }
case IfSt: { case IfSt: {
auto ifSt = std::dynamic_pointer_cast<Ast::IfSt>(stmt); auto ifSt = std::static_pointer_cast<Ast::IfSt>(stmt);
ObjectPtr condVal = eval(ifSt->condition, ctx); ObjectPtr condVal = eval(ifSt->condition, ctx);
if (condVal->getTypeInfo() != ValueType::Bool) if (condVal->getTypeInfo() != ValueType::Bool)
{ {
@@ -1315,7 +1352,7 @@ namespace Fig
return StatementResult::normal(); return StatementResult::normal();
}; };
case WhileSt: { case WhileSt: {
auto whileSt = std::dynamic_pointer_cast<Ast::WhileSt>(stmt); auto whileSt = std::static_pointer_cast<Ast::WhileSt>(stmt);
while (true) while (true)
{ {
ObjectPtr condVal = eval(whileSt->condition, ctx); ObjectPtr condVal = eval(whileSt->condition, ctx);
@@ -1338,7 +1375,7 @@ namespace Fig
return StatementResult::normal(); return StatementResult::normal();
}; };
case ForSt: { case ForSt: {
auto forSt = std::dynamic_pointer_cast<Ast::ForSt>(stmt); auto forSt = std::static_pointer_cast<Ast::ForSt>(stmt);
ContextPtr loopContext = std::make_shared<Context>( ContextPtr loopContext = std::make_shared<Context>(
FString(std::format("<For {}:{}>", forSt->getAAI().line, forSt->getAAI().column)), FString(std::format("<For {}:{}>", forSt->getAAI().line, forSt->getAAI().column)),
ctx); // for loop has its own context ctx); // for loop has its own context
@@ -1379,7 +1416,7 @@ namespace Fig
} }
case TrySt: { case TrySt: {
auto tryst = std::dynamic_pointer_cast<Ast::TrySt>(stmt); auto tryst = std::static_pointer_cast<Ast::TrySt>(stmt);
assert(tryst != nullptr); assert(tryst != nullptr);
ContextPtr tryCtx = std::make_shared<Context>( ContextPtr tryCtx = std::make_shared<Context>(
@@ -1418,7 +1455,7 @@ namespace Fig
} }
case ThrowSt: { case ThrowSt: {
auto ts = std::dynamic_pointer_cast<Ast::ThrowSt>(stmt); auto ts = std::static_pointer_cast<Ast::ThrowSt>(stmt);
assert(ts != nullptr); assert(ts != nullptr);
ObjectPtr value = eval(ts->value, ctx); ObjectPtr value = eval(ts->value, ctx);
@@ -1430,7 +1467,7 @@ namespace Fig
} }
case ReturnSt: { case ReturnSt: {
auto returnSt = std::dynamic_pointer_cast<Ast::ReturnSt>(stmt); auto returnSt = std::static_pointer_cast<Ast::ReturnSt>(stmt);
assert(returnSt != nullptr); assert(returnSt != nullptr);
ObjectPtr returnValue = Object::getNullInstance(); // default is null ObjectPtr returnValue = Object::getNullInstance(); // default is null
@@ -1463,7 +1500,7 @@ namespace Fig
} }
case ExpressionStmt: { case ExpressionStmt: {
auto exprStmt = std::dynamic_pointer_cast<Ast::ExpressionStmtAst>(stmt); auto exprStmt = std::static_pointer_cast<Ast::ExpressionStmtAst>(stmt);
assert(exprStmt != nullptr); assert(exprStmt != nullptr);
return StatementResult::normal(eval(exprStmt->exp, ctx)); return StatementResult::normal(eval(exprStmt->exp, ctx));
@@ -1641,14 +1678,14 @@ namespace Fig
for (auto &ast : asts) for (auto &ast : asts)
{ {
Ast::Expression exp; Ast::Expression exp;
if ((exp = std::dynamic_pointer_cast<Ast::ExpressionAst>(ast))) if ((exp = std::dynamic_pointer_cast<Ast::ExpressionAst>(ast))) // 保持 dynamic_pointer_cast !
{ {
sr = StatementResult::normal(eval(exp, global)); sr = StatementResult::normal(eval(exp, global));
} }
else else
{ {
// statement // statement
Ast::Statement stmt = std::dynamic_pointer_cast<Ast::StatementAst>(ast); Ast::Statement stmt = std::static_pointer_cast<Ast::StatementAst>(ast);
assert(stmt != nullptr); assert(stmt != nullptr);
sr = evalStatement(stmt, global); sr = evalStatement(stmt, global);
if (sr.isError()) if (sr.isError())

View File

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

View File

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

View File

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

View File

@@ -592,6 +592,7 @@ namespace Fig
} }
else if (isThis(TokenType::Struct)) else if (isThis(TokenType::Struct))
{ {
next();
stmt = __parseStructDef(true); stmt = __parseStructDef(true);
} }
else if (isThis(TokenType::Interface)) else if (isThis(TokenType::Interface))

View File

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