diff --git a/src/Core/core.hpp b/src/Core/core.hpp index 566a779..79d6f5d 100644 --- a/src/Core/core.hpp +++ b/src/Core/core.hpp @@ -4,7 +4,7 @@ #include #include -#define __FCORE_VERSION "0.3.8-alpha" +#define __FCORE_VERSION "0.3.9-alpha" #if defined(_WIN32) #define __FCORE_PLATFORM "Windows" diff --git a/src/Core/runtimeTime.cpp b/src/Core/runtimeTime.cpp new file mode 100644 index 0000000..25b766b --- /dev/null +++ b/src/Core/runtimeTime.cpp @@ -0,0 +1,18 @@ +#include + +#include + +namespace Fig::Time +{ + Clock::time_point start_time; + void init() + { + static bool flag = false; + if (flag) + { + assert(false); + } + start_time = Clock::now(); + flag = true; + } +}; \ No newline at end of file diff --git a/src/Core/runtimeTime.hpp b/src/Core/runtimeTime.hpp new file mode 100644 index 0000000..0a69530 --- /dev/null +++ b/src/Core/runtimeTime.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include + +namespace Fig::Time +{ + using Clock = std::chrono::steady_clock; + extern Clock::time_point start_time; // since process start + void init(); +}; \ No newline at end of file diff --git a/src/Evaluator/Value/Type.hpp b/src/Evaluator/Value/Type.hpp index 95ba57e..b8ace30 100644 --- a/src/Evaluator/Value/Type.hpp +++ b/src/Evaluator/Value/Type.hpp @@ -2,6 +2,7 @@ #include +#include #include #include @@ -75,6 +76,28 @@ namespace Fig using BoolClass = bool; using NullClass = std::monostate; using StringClass = FString; + + static const std::unordered_set 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 Fig diff --git a/src/Evaluator/evaluator.cpp b/src/Evaluator/evaluator.cpp index ac13992..51d5c21 100644 --- a/src/Evaluator/evaluator.cpp +++ b/src/Evaluator/evaluator.cpp @@ -22,6 +22,7 @@ #include #include #include +#include namespace Fig { @@ -40,8 +41,8 @@ namespace Fig } LvObject Evaluator::evalMemberExpr(Ast::MemberExpr me, ContextPtr ctx) { - LvObject base = evalLv(me->base, ctx); - RvObject baseVal = base.get(); + // LvObject base = evalLv(me->base, ctx); + RvObject baseVal = eval(me->base, ctx); const FString &member = me->member; if (baseVal->getTypeInfo() == ValueType::Module) { @@ -194,25 +195,26 @@ namespace Fig switch (exp->getType()) { case AstType::VarExpr: { - Ast::VarExpr var = std::dynamic_pointer_cast(exp); + Ast::VarExpr var = std::static_pointer_cast(exp); assert(var != nullptr); return evalVarExpr(var, ctx); } case AstType::MemberExpr: { - Ast::MemberExpr me = std::dynamic_pointer_cast(exp); + Ast::MemberExpr me = std::static_pointer_cast(exp); assert(me != nullptr); return evalMemberExpr(me, ctx); } case AstType::IndexExpr: { - Ast::IndexExpr ie = std::dynamic_pointer_cast(exp); + Ast::IndexExpr ie = std::static_pointer_cast(exp); assert(ie != nullptr); return evalIndexExpr(ie, ctx); } default: { - throw EvaluatorError( - u8"TypeError", - std::format("Expression '{}' doesn't refer to a lvalue", exp->typeName().toBasicString()), - exp); + // throw EvaluatorError( + // u8"TypeError", + // std::format("Expression '{}' doesn't refer to a lvalue", exp->typeName().toBasicString()), + // exp); + } } } @@ -298,6 +300,9 @@ namespace Fig ObjectPtr lhs = eval(lexp, ctx); ObjectPtr rhs = eval(rexp, ctx); + const TypeInfo &lhsType = lhs->getTypeInfo(); + const TypeInfo &rhsType = rhs->getTypeInfo(); + if (lhs->is() && rhs->is()) { const StructInstance &si = lhs->as(); @@ -310,10 +315,37 @@ namespace Fig const InterfaceType &it = rhs->as(); return std::make_shared(implements(si.parentType, it.type, ctx)); } + + if (ValueType::isTypeBuiltin(lhsType) && rhsType == ValueType::StructType) + { + const StructType &st = rhs->as(); + 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("Operator `is` requires an struct instance on left-hand side, got '{}'", - lhs->getTypeInfo().toString().toBasicString()), + std::format("Unsupported operator `is` for '{}' && '{}'", + lhsType.toString().toBasicString(), + rhsType.toString().toBasicString()), bin->lexp); } @@ -606,27 +638,27 @@ namespace Fig switch (type) { case AstType::ValueExpr: { - auto val = std::dynamic_pointer_cast(exp); + auto val = std::static_pointer_cast(exp); assert(val != nullptr); return val->val; } case AstType::VarExpr: { - auto varExpr = std::dynamic_pointer_cast(exp); + auto varExpr = std::static_pointer_cast(exp); assert(varExpr != nullptr); return evalVarExpr(varExpr, ctx).get(); // LvObject -> RvObject } case AstType::BinaryExpr: { - auto bin = std::dynamic_pointer_cast(exp); + auto bin = std::static_pointer_cast(exp); assert(bin != nullptr); return evalBinary(bin, ctx); } case AstType::UnaryExpr: { - auto un = std::dynamic_pointer_cast(exp); + auto un = std::static_pointer_cast(exp); assert(un != nullptr); return evalUnary(un, ctx); } case AstType::TernaryExpr: { - auto te = std::dynamic_pointer_cast(exp); + auto te = std::static_pointer_cast(exp); assert(te != nullptr); return evalTernary(te, ctx); } @@ -634,7 +666,7 @@ namespace Fig case AstType::IndexExpr: return evalLv(exp, ctx).get(); case AstType::FunctionCall: { - auto fnCall = std::dynamic_pointer_cast(exp); + auto fnCall = std::static_pointer_cast(exp); assert(fnCall != nullptr); Ast::Expression callee = fnCall->callee; @@ -659,7 +691,7 @@ namespace Fig return evalFunctionCall(fn, fnCall->arg, fnName, ctx); } case AstType::FunctionLiteralExpr: { - auto fnLiteral = std::dynamic_pointer_cast(exp); + auto fnLiteral = std::static_pointer_cast(exp); assert(fnLiteral != nullptr); Ast::BlockStatement body = nullptr; @@ -689,7 +721,7 @@ namespace Fig return std::make_shared(std::move(fn)); } case AstType::InitExpr: { - auto initExpr = std::dynamic_pointer_cast(exp); + auto initExpr = std::static_pointer_cast(exp); LvObject structeLv = evalLv(initExpr->structe, ctx); ObjectPtr structTypeVal = structeLv.get(); const FString &structName = structeLv.name(); @@ -968,7 +1000,7 @@ namespace Fig } case AstType::ListExpr: { - auto lstExpr = std::dynamic_pointer_cast(exp); + auto lstExpr = std::static_pointer_cast(exp); assert(lstExpr != nullptr); List list; @@ -977,7 +1009,7 @@ namespace Fig } case AstType::MapExpr: { - auto mapExpr = std::dynamic_pointer_cast(exp); + auto mapExpr = std::static_pointer_cast(exp); assert(mapExpr != nullptr); Map map; @@ -985,7 +1017,12 @@ namespace Fig return std::make_shared(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 } @@ -1005,12 +1042,12 @@ namespace Fig switch (stmt->getType()) { case ImportSt: { - auto i = std::dynamic_pointer_cast(stmt); + auto i = std::static_pointer_cast(stmt); assert(i != nullptr); return evalImportSt(i, ctx); } case VarDefSt: { - auto varDef = std::dynamic_pointer_cast(stmt); + auto varDef = std::static_pointer_cast(stmt); assert(varDef != nullptr); if (ctx->containsInThisScope(varDef->name)) @@ -1051,7 +1088,7 @@ namespace Fig } case FunctionDefSt: { - auto fnDef = std::dynamic_pointer_cast(stmt); + auto fnDef = std::static_pointer_cast(stmt); assert(fnDef != nullptr); const FString &fnName = fnDef->name; @@ -1071,7 +1108,7 @@ namespace Fig } case StructSt: { - auto stDef = std::dynamic_pointer_cast(stmt); + auto stDef = std::static_pointer_cast(stmt); assert(stDef != nullptr); if (ctx->containsInThisScope(stDef->name)) @@ -1123,7 +1160,7 @@ namespace Fig } case InterfaceDefSt: { - auto ifd = std::dynamic_pointer_cast(stmt); + auto ifd = std::static_pointer_cast(stmt); assert(ifd != nullptr); const FString &interfaceName = ifd->name; @@ -1144,7 +1181,7 @@ namespace Fig } case ImplementSt: { - auto ip = std::dynamic_pointer_cast(stmt); + auto ip = std::static_pointer_cast(stmt); assert(ip != nullptr); TypeInfo structType(ip->structName); @@ -1288,7 +1325,7 @@ namespace Fig } case IfSt: { - auto ifSt = std::dynamic_pointer_cast(stmt); + auto ifSt = std::static_pointer_cast(stmt); ObjectPtr condVal = eval(ifSt->condition, ctx); if (condVal->getTypeInfo() != ValueType::Bool) { @@ -1315,7 +1352,7 @@ namespace Fig return StatementResult::normal(); }; case WhileSt: { - auto whileSt = std::dynamic_pointer_cast(stmt); + auto whileSt = std::static_pointer_cast(stmt); while (true) { ObjectPtr condVal = eval(whileSt->condition, ctx); @@ -1338,7 +1375,7 @@ namespace Fig return StatementResult::normal(); }; case ForSt: { - auto forSt = std::dynamic_pointer_cast(stmt); + auto forSt = std::static_pointer_cast(stmt); ContextPtr loopContext = std::make_shared( FString(std::format("", forSt->getAAI().line, forSt->getAAI().column)), ctx); // for loop has its own context @@ -1379,7 +1416,7 @@ namespace Fig } case TrySt: { - auto tryst = std::dynamic_pointer_cast(stmt); + auto tryst = std::static_pointer_cast(stmt); assert(tryst != nullptr); ContextPtr tryCtx = std::make_shared( @@ -1418,7 +1455,7 @@ namespace Fig } case ThrowSt: { - auto ts = std::dynamic_pointer_cast(stmt); + auto ts = std::static_pointer_cast(stmt); assert(ts != nullptr); ObjectPtr value = eval(ts->value, ctx); @@ -1430,7 +1467,7 @@ namespace Fig } case ReturnSt: { - auto returnSt = std::dynamic_pointer_cast(stmt); + auto returnSt = std::static_pointer_cast(stmt); assert(returnSt != nullptr); ObjectPtr returnValue = Object::getNullInstance(); // default is null @@ -1463,7 +1500,7 @@ namespace Fig } case ExpressionStmt: { - auto exprStmt = std::dynamic_pointer_cast(stmt); + auto exprStmt = std::static_pointer_cast(stmt); assert(exprStmt != nullptr); return StatementResult::normal(eval(exprStmt->exp, ctx)); @@ -1641,14 +1678,14 @@ namespace Fig for (auto &ast : asts) { Ast::Expression exp; - if ((exp = std::dynamic_pointer_cast(ast))) + if ((exp = std::dynamic_pointer_cast(ast))) // 保持 dynamic_pointer_cast ! { sr = StatementResult::normal(eval(exp, global)); } else { // statement - Ast::Statement stmt = std::dynamic_pointer_cast(ast); + Ast::Statement stmt = std::static_pointer_cast(ast); assert(stmt != nullptr); sr = evalStatement(stmt, global); if (sr.isError()) diff --git a/src/Evaluator/main.cpp b/src/Evaluator/main.cpp index 7913512..8836b86 100644 --- a/src/Evaluator/main.cpp +++ b/src/Evaluator/main.cpp @@ -28,7 +28,7 @@ This software is licensed under the MIT License. See LICENSE.txt for details. */ #include -#include +// #include #include #include @@ -38,6 +38,7 @@ This software is licensed under the MIT License. See LICENSE.txt for details. #include #include #include +#include static size_t addressableErrorCount = 0; static size_t unaddressableErrorCount = 0; @@ -45,6 +46,10 @@ static size_t unaddressableErrorCount = 0; 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()); program.add_argument("source") .help("source file to be interpreted") diff --git a/src/Module/Library/std/time/time.fig b/src/Module/Library/std/time/time.fig new file mode 100644 index 0000000..c0704c1 --- /dev/null +++ b/src/Module/Library/std/time/time.fig @@ -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()}; +} \ No newline at end of file diff --git a/src/Module/builtins.hpp b/src/Module/builtins.hpp index 91189fc..aad22a0 100644 --- a/src/Module/builtins.hpp +++ b/src/Module/builtins.hpp @@ -1,10 +1,12 @@ #pragma once -#include "Ast/Statements/InterfaceDefSt.hpp" -#include "Ast/functionParameters.hpp" +#include +#include #include #include +#include +#include #include #include #include @@ -65,6 +67,7 @@ namespace Fig {u8"__fvalue_double_parse", 1}, {u8"__fvalue_double_from", 1}, {u8"__fvalue_string_from", 1}, + {u8"__ftime_now_ns", 0}, /* math start */ {u8"__fmath_acos", 1}, {u8"__fmath_acosh", 1}, @@ -194,6 +197,15 @@ namespace Fig ObjectPtr val = args[0]; return std::make_shared(val->toStringIO()); }}, + {u8"__ftime_now_ns", + [](const std::vector &args) -> ObjectPtr { + // returns nanoseconds + using namespace Fig::Time; + auto now = Clock::now(); + return std::make_shared(static_cast( + std::chrono::duration_cast(now - start_time).count())); + }}, + /* math start */ {u8"__fmath_acos", [](const std::vector &args) -> ObjectPtr { diff --git a/src/Parser/parser.cpp b/src/Parser/parser.cpp index 55bf396..6d27777 100644 --- a/src/Parser/parser.cpp +++ b/src/Parser/parser.cpp @@ -592,6 +592,7 @@ namespace Fig } else if (isThis(TokenType::Struct)) { + next(); stmt = __parseStructDef(true); } else if (isThis(TokenType::Interface)) diff --git a/xmake.lua b/xmake.lua index eb473ca..aa6daef 100644 --- a/xmake.lua +++ b/xmake.lua @@ -28,6 +28,7 @@ target("Fig") add_files("src/Evaluator/main.cpp") add_files("src/Core/warning.cpp") + add_files("src/Core/runtimeTime.cpp") add_files("src/Evaluator/evaluator.cpp") add_files("src/Evaluator/Value/value.cpp") add_files("src/Lexer/lexer.cpp")