From 8f4fb6965358d8fb70bb239f605d920bb1455c7d Mon Sep 17 00:00:00 2001 From: PuqiAR Date: Mon, 22 Dec 2025 23:19:40 +0800 Subject: [PATCH] =?UTF-8?q?[VER=200.3.2-Hotfix]=20[Feat]=20=E9=9D=A2?= =?UTF-8?q?=E5=AF=B9=E5=AF=B9=E8=B1=A1(struct)=E6=94=AF=E6=8C=81=EF=BC=8C?= =?UTF-8?q?=E5=AE=8C=E6=88=90=E5=AF=B9=E5=85=B6=E5=88=9D=E5=A7=8B=E5=8C=96?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E3=80=82=20[Impl]=20Value=E6=9B=B4=E6=8D=A2?= =?UTF-8?q?=E4=B8=BAObject=EF=BC=8C=E4=B8=94=E7=AE=80=E5=8D=95=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E6=8C=89=E5=80=BC=E5=AD=98=E5=82=A8=EF=BC=8C=E5=A4=8D?= =?UTF-8?q?=E6=9D=82=E7=B1=BB=E5=9E=8B=E4=B8=BAshared=5Fptr=E3=80=82=20[Im?= =?UTF-8?q?pl]=20=E5=85=A8=E5=B1=80=E4=BD=BF=E7=94=A8=20Object=20shared=5F?= =?UTF-8?q?ptr?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/Ast/FunctionCall.hpp | 2 +- include/Ast/ValueExpr.hpp | 4 +- include/Ast/astBase.hpp | 1 + include/AstPrinter.hpp | 2 +- include/Value/BaseValue.hpp | 190 -------------------- include/Value/function.hpp | 8 +- include/Value/structInstance.hpp | 1 - include/Value/structType.hpp | 2 - include/builtins.hpp | 122 ++++++------- include/context.hpp | 22 +-- include/core.hpp | 2 +- include/evaluator.hpp | 22 +-- include/parser.hpp | 2 +- include/value.hpp | 297 +++++++++++++------------------ src/evaluator.cpp | 199 ++++++++++----------- src/parser.cpp | 12 +- test.fig | 21 ++- 17 files changed, 327 insertions(+), 582 deletions(-) delete mode 100644 include/Value/BaseValue.hpp diff --git a/include/Ast/FunctionCall.hpp b/include/Ast/FunctionCall.hpp index 15ce8bf..d6a8a63 100644 --- a/include/Ast/FunctionCall.hpp +++ b/include/Ast/FunctionCall.hpp @@ -14,7 +14,7 @@ namespace Fig::Ast struct FunctionCallArgs final { - std::vector argv; + std::vector argv; size_t getLength() const { return argv.size(); } }; diff --git a/include/Ast/ValueExpr.hpp b/include/Ast/ValueExpr.hpp index 4cb8899..31adf45 100644 --- a/include/Ast/ValueExpr.hpp +++ b/include/Ast/ValueExpr.hpp @@ -9,13 +9,13 @@ namespace Fig::Ast class ValueExprAst final : public ExpressionAst { public: - Object val; + ObjectPtr val; ValueExprAst() { type = AstType::ValueExpr; } - ValueExprAst(Object _val) + ValueExprAst(ObjectPtr _val) { type = AstType::ValueExpr; val = std::move(_val); diff --git a/include/Ast/astBase.hpp b/include/Ast/astBase.hpp index 370be62..056f4c6 100644 --- a/include/Ast/astBase.hpp +++ b/include/Ast/astBase.hpp @@ -290,6 +290,7 @@ namespace Fig::Ast {TokenType::ShiftRight, Operator::ShiftRight}, // 赋值表达式 + {TokenType::Assign, Operator::Assign}, // {TokenType::Walrus, Operator::Walrus}, // 点运算符 {TokenType::Dot, Operator::Dot}, diff --git a/include/AstPrinter.hpp b/include/AstPrinter.hpp index 8927d5b..e7ea357 100644 --- a/include/AstPrinter.hpp +++ b/include/AstPrinter.hpp @@ -99,7 +99,7 @@ private: { printIndent(indent); std::cout << "ValueExpr\n"; - printFString(node->val.toString(), indent + 2); + printFString(node->val->toString(), indent + 2); } void printVarDef(const std::shared_ptr &node, int indent) diff --git a/include/Value/BaseValue.hpp b/include/Value/BaseValue.hpp deleted file mode 100644 index a033a2d..0000000 --- a/include/Value/BaseValue.hpp +++ /dev/null @@ -1,190 +0,0 @@ -#pragma once - -#include -#include - -#include -#include - -namespace Fig -{ - - template - class __ValueWrapper - { - public: - const TypeInfo ti; - std::unique_ptr data; - - __ValueWrapper(const __ValueWrapper &other) : - ti(other.ti) - { - if (other.data) - data = std::make_unique(*other.data); - } - - __ValueWrapper(__ValueWrapper &&other) noexcept - : - ti(other.ti), data(std::move(other.data)) {} - - __ValueWrapper &operator=(const __ValueWrapper &other) - { - if (this != &other) - { - if (other.data) - data = std::make_unique(*other.data); - else - data.reset(); - } - return *this; - } - - __ValueWrapper &operator=(__ValueWrapper &&other) noexcept - { - if (this != &other) - { - data = std::move(other.data); - } - return *this; - } - - const T &getValue() const - { - if (!data) throw std::runtime_error("Accessing null Value data"); - return *data; - } - - virtual size_t getSize() const - { - return sizeof(T); - } - - virtual bool isNull() const - { - return !data; - } - - virtual FString toString() const - { - if (!data) - return FString(std::format("<{} object (null)>", ti.name.toBasicString())); - - return FString(std::format( - "<{} object @{:p}>", - ti.name.toBasicString(), - static_cast(data.get()))); - } - - __ValueWrapper(const TypeInfo &_ti) : - ti(_ti) {} - - __ValueWrapper(const T &x, const TypeInfo &_ti) : - ti(_ti) - { - data = std::make_unique(x); - } - }; - - class Int final : public __ValueWrapper - { - public: - Int(const ValueType::IntClass &x) : - __ValueWrapper(x, ValueType::Int) {} - - Int(const Int &) = default; - Int(Int &&) noexcept = default; - - Int &operator=(const Int &) = default; - Int &operator=(Int &&) noexcept = default; - - bool operator==(const Int &other) const noexcept - { - return getValue() == other.getValue(); - } - bool operator!=(const Int &other) const noexcept - { - return !(*this == other); - } - }; - - class Double final : public __ValueWrapper - { - public: - Double(const ValueType::DoubleClass &x) : - __ValueWrapper(x, ValueType::Double) {} - Double(const Double &) = default; - Double(Double &&) noexcept = default; - - Double &operator=(const Double &) = default; - Double &operator=(Double &&) noexcept = default; - - bool operator==(const Double &other) const noexcept - { - return getValue() == other.getValue(); - } - bool operator!=(const Double &other) const noexcept - { - return !(*this == other); - } - }; - - class Null final : public __ValueWrapper - { - public: - Null() : - __ValueWrapper(ValueType::NullClass{}, ValueType::Null) {} - - Null(const Null &) = default; - Null(Null &&) noexcept = default; - - Null &operator=(const Null &) = default; - Null &operator=(Null &&) noexcept = default; - - bool isNull() const override { return true; } - bool operator==(const Null &) const noexcept { return true; } - bool operator!=(const Null &) const noexcept { return false; } - }; - - class String final : public __ValueWrapper - { - public: - String(const ValueType::StringClass &x) : - __ValueWrapper(x, ValueType::String) {} - String(const String &) = default; - String(String &&) noexcept = default; - - String &operator=(const String &) = default; - String &operator=(String &&) noexcept = default; - - bool operator==(const String &other) const noexcept - { - return getValue() == other.getValue(); - } - bool operator!=(const String &other) const noexcept - { - return !(*this == other); - } - }; - - class Bool final : public __ValueWrapper - { - public: - Bool(const ValueType::BoolClass &x) : - __ValueWrapper(x, ValueType::Bool) {} - - Bool(const Bool &) = default; - Bool(Bool &&) noexcept = default; - - Bool &operator=(const Bool &) = default; - Bool &operator=(Bool &&) noexcept = default; - - bool operator==(const Bool &other) const noexcept - { - return getValue() == other.getValue(); - } - bool operator!=(const Bool &other) const noexcept - { - return !(*this == other); - } - }; -} // namespace Fig diff --git a/include/Value/function.hpp b/include/Value/function.hpp index 7a5f88e..908dd87 100644 --- a/include/Value/function.hpp +++ b/include/Value/function.hpp @@ -20,7 +20,7 @@ namespace Fig Ast::BlockStatement body; bool isBuiltin = false; - std::function &)> builtin; + std::function(const std::vector> &)> builtin; int builtinParamCount = -1; std::shared_ptr closureContext; @@ -38,10 +38,8 @@ namespace Fig { } - Function(std::function &)> fn, int argc) : - id(nextId()), isBuiltin(true), builtin(std::move(fn)), builtinParamCount(argc) - { - } + Function(std::function(const std::vector> &)> fn, int argc) : + id(nextId()), isBuiltin(true), builtin(fn), builtinParamCount(argc) {} // ===== Copy / Move ===== Function(const Function &other) = default; diff --git a/include/Value/structInstance.hpp b/include/Value/structInstance.hpp index fab4baa..8f55ac0 100644 --- a/include/Value/structInstance.hpp +++ b/include/Value/structInstance.hpp @@ -1,6 +1,5 @@ #pragma once -#include #include namespace Fig diff --git a/include/Value/structType.hpp b/include/Value/structType.hpp index 1776857..f831379 100644 --- a/include/Value/structType.hpp +++ b/include/Value/structType.hpp @@ -4,11 +4,9 @@ #include #include -#include #include #include -#include #include namespace Fig diff --git a/include/builtins.hpp b/include/builtins.hpp index e92ac04..4e1442b 100644 --- a/include/builtins.hpp +++ b/include/builtins.hpp @@ -13,13 +13,13 @@ namespace Fig { namespace Builtins { - const std::unordered_map builtinValues = { + const std::unordered_map builtinValues = { {u8"null", Object::getNullInstance()}, - {u8"true", Object(true)}, - {u8"false", Object(false)}, + {u8"true", Object::getTrueInstance()}, + {u8"false", Object::getFalseInstance()}, }; - using BuiltinFunction = std::function &)>; + using BuiltinFunction = std::function &)>; const std::unordered_map builtinFunctionArgCounts = { {u8"__fstdout_print", -1}, // variadic @@ -35,91 +35,91 @@ namespace Fig }; const std::unordered_map builtinFunctions{ - {u8"__fstdout_print", [](const std::vector &args) -> Object { + {u8"__fstdout_print", [](const std::vector &args) -> ObjectPtr { for (auto arg : args) { - std::print("{}", arg.toString().toBasicString()); + std::print("{}", arg->toString().toBasicString()); } - return Object(Int(args.size())); + return std::make_shared(ValueType::IntClass(args.size())); }}, - {u8"__fstdout_println", [](const std::vector &args) -> Object { + {u8"__fstdout_println", [](const std::vector &args) -> ObjectPtr { for (auto arg : args) { - std::print("{}", arg.toString().toBasicString()); + std::print("{}", arg->toString().toBasicString()); } std::print("\n"); - return Object(Int(args.size())); + return std::make_shared(ValueType::IntClass(args.size())); }}, - {u8"__fstdin_read", [](const std::vector &args) -> Object { + {u8"__fstdin_read", [](const std::vector &args) -> ObjectPtr { std::string input; std::cin >> input; - return Object(FString::fromBasicString(input)); + return std::make_shared(FString::fromBasicString(input)); }}, - {u8"__fstdin_readln", [](const std::vector &args) -> Object { + {u8"__fstdin_readln", [](const std::vector &args) -> ObjectPtr { std::string line; std::getline(std::cin, line); - return Object(FString::fromBasicString(line)); + return std::make_shared(FString::fromBasicString(line)); }}, - {u8"__fvalue_type", [](const std::vector &args) -> Object { - return Object(args[0].getTypeInfo().toString()); + {u8"__fvalue_type", [](const std::vector &args) -> ObjectPtr { + return std::make_shared(args[0]->getTypeInfo().toString()); }}, - {u8"__fvalue_int_parse", [](const std::vector &args) -> Object { - FString str = args[0].as().getValue(); + {u8"__fvalue_int_parse", [](const std::vector &args) -> ObjectPtr { + FString str = args[0]->as(); try { ValueType::IntClass val = std::stoi(str.toBasicString()); - return Object(Int(val)); + return std::make_shared(val); } catch (...) { throw RuntimeError(FStringView(std::format("Invalid int string for parsing", str.toBasicString()))); } }}, - {u8"__fvalue_int_from", [](const std::vector &args) -> Object { - Object val = args[0]; - if (val.is()) - { - return Object(Int(static_cast(val.as().getValue()))); - } - else if (val.is()) - { - return Object(Int(val.as().getValue() ? 1 : 0)); - } - else - { - throw RuntimeError(FStringView(std::format("Type '{}' cannot be converted to int", val.getTypeInfo().toString().toBasicString()))); - } + {u8"__fvalue_int_from", [](const std::vector &args) -> ObjectPtr { + ObjectPtr val = args[0]; + if (val->is()) + { + return std::make_shared(static_cast(val->as())); + } + else if (val->is()) + { + return std::make_shared(static_cast(val->as() ? 1 : 0)); + } + else + { + throw RuntimeError(FStringView(std::format("Type '{}' cannot be converted to int", val->getTypeInfo().toString().toBasicString()))); + } }}, - {u8"__fvalue_double_parse", [](const std::vector &args) -> Object { - FString str = args[0].as().getValue(); - try - { - ValueType::DoubleClass val = std::stod(str.toBasicString()); - return Object(Double(val)); - } - catch (...) - { - throw RuntimeError(FStringView(std::format("Invalid double string for parsing", str.toBasicString()))); - } + {u8"__fvalue_double_parse", [](const std::vector &args) -> ObjectPtr { + FString str = args[0]->as(); + try + { + ValueType::DoubleClass val = std::stod(str.toBasicString()); + return std::make_shared(ValueType::DoubleClass(val)); + } + catch (...) + { + throw RuntimeError(FStringView(std::format("Invalid double string for parsing", str.toBasicString()))); + } }}, - {u8"__fvalue_double_from", [](const std::vector &args) -> Object { - Object val = args[0]; - if (val.is()) - { - return Object(Double(static_cast(val.as().getValue()))); - } - else if (val.is()) - { - return Object(Double(val.as().getValue() ? 1.0 : 0.0)); - } - else - { - throw RuntimeError(FStringView(std::format("Type '{}' cannot be converted to double", val.getTypeInfo().toString().toBasicString()))); - } + {u8"__fvalue_double_from", [](const std::vector &args) -> ObjectPtr { + ObjectPtr val = args[0]; + if (val->is()) + { + return std::make_shared(static_cast(val->as())); + } + else if (val->is()) + { + return std::make_shared(ValueType::DoubleClass(val->as() ? 1.0 : 0.0)); + } + else + { + throw RuntimeError(FStringView(std::format("Type '{}' cannot be converted to double", val->getTypeInfo().toString().toBasicString()))); + } }}, - {u8"__fvalue_string_from", [](const std::vector &args) -> Object { - Object val = args[0]; - return Object(val.toString()); + {u8"__fvalue_string_from", [](const std::vector &args) -> ObjectPtr { + ObjectPtr val = args[0]; + return std::make_shared(val->toString()); }}, }; diff --git a/include/context.hpp b/include/context.hpp index cdb8830..f1306cc 100644 --- a/include/context.hpp +++ b/include/context.hpp @@ -15,7 +15,7 @@ namespace Fig private: FString scopeName; std::unordered_map varTypes; - std::unordered_map variables; + std::unordered_map variables; std::unordered_map ams; std::unordered_map functions; @@ -28,7 +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 types, std::unordered_map vars, std::unordered_map _ams) : + Context(const FString &name, std::unordered_map types, std::unordered_map vars, std::unordered_map _ams) : scopeName(std::move(name)), varTypes(std::move(types)), variables(std::move(vars)), ams(std::move(_ams)) {} void setParent(ContextPtr _parent) @@ -46,7 +46,7 @@ namespace Fig return scopeName; } - std::optional get(const FString &name) + std::optional get(const FString &name) { auto it = variables.find(name); if (it != variables.end()) @@ -73,13 +73,13 @@ namespace Fig ContextPtr createCopyWithPublicVariables() { std::unordered_map _varTypes; - std::unordered_map _variables; + std::unordered_map _variables; std::unordered_map _ams; for (const auto &p : this->variables) { if (isVariablePublic(p.first)) { - _variables[p.first] = p.second; + _variables[p.first] = std::make_shared(*p.second); // copy _varTypes[p.first] = varTypes[p.first]; _ams[p.first] = ams[p.first]; } @@ -104,7 +104,7 @@ namespace Fig { throw RuntimeError(FStringView(std::format("Variable '{}' is immutable", name.toBasicString()))); } - variables[name] = value; + variables[name] = std::make_shared(value); } else if (parent != nullptr) { @@ -115,25 +115,25 @@ namespace Fig throw RuntimeError(FStringView(std::format("Variable '{}' not defined", name.toBasicString()))); } } - void def(const FString &name, const TypeInfo &ti, AccessModifier am, const Object &value = Object::getNullInstance()) + void def(const FString &name, const TypeInfo &ti, AccessModifier am, const ObjectPtr &value = Object::getNullInstance()) { if (containsInThisScope(name)) { throw RuntimeError(FStringView(std::format("Variable '{}' already defined in this scope", name.toBasicString()))); } - variables[name] = value; + variables[name] = std::make_shared(*value); varTypes[name] = ti; ams[name] = am; - if (ti == ValueType::Function and value.getTypeInfo() == ValueType::Function) + if (ti == ValueType::Function and value->getTypeInfo() == ValueType::Function) { - auto &fn = value.as(); + auto &fn = value->as(); functions[fn.id] = fn; functionNames[fn.id] = name; } if (ti == ValueType::StructType) { - auto &st = value.as(); + auto &st = value->as(); structTypeNames[st.id] = name; } } diff --git a/include/core.hpp b/include/core.hpp index 8cb3209..037c4a7 100644 --- a/include/core.hpp +++ b/include/core.hpp @@ -4,7 +4,7 @@ #include #include -#define __FCORE_VERSION "0.3.1" +#define __FCORE_VERSION "0.3.2" #if defined(_WIN32) #define __FCORE_PLATFORM "Windows" diff --git a/include/evaluator.hpp b/include/evaluator.hpp index 6d18857..716d02f 100644 --- a/include/evaluator.hpp +++ b/include/evaluator.hpp @@ -30,7 +30,7 @@ namespace Fig }; struct StatementResult { - Object result; + ObjectPtr result; enum class Flow { Normal, @@ -39,16 +39,16 @@ namespace Fig Continue } flow; - StatementResult(Object val, Flow f = Flow::Normal) : + StatementResult(ObjectPtr val, Flow f = Flow::Normal) : result(val), flow(f) { } - static StatementResult normal(Object val = Object::getNullInstance()) + static StatementResult normal(ObjectPtr val = Object::getNullInstance()) { return StatementResult(val, Flow::Normal); } - static StatementResult returnFlow(Object val) + static StatementResult returnFlow(ObjectPtr val) { return StatementResult(val, Flow::Return); } @@ -91,14 +91,14 @@ namespace Fig name, ValueType::Function, AccessModifier::PublicConst, - Object(f)); + std::make_shared(f)); } for (auto &[name, val] : Builtins::builtinValues) { globalContext->def( name, - val.getTypeInfo(), + val->getTypeInfo(), AccessModifier::PublicConst, val); } @@ -107,16 +107,16 @@ namespace Fig std::shared_ptr getCurrentContext() { return currentContext; } std::shared_ptr getGlobalContext() { return globalContext; } - Object __evalOp(Ast::Operator, const Object &, const Object & = Object::getNullInstance()); - Object evalBinary(const Ast::BinaryExpr &); - Object evalUnary(const Ast::UnaryExpr &); + ObjectPtr __evalOp(Ast::Operator, const ObjectPtr &, const ObjectPtr & = Object::getNullInstance()); + ObjectPtr evalBinary(const Ast::BinaryExpr &); + ObjectPtr evalUnary(const Ast::UnaryExpr &); StatementResult evalBlockStatement(const Ast::BlockStatement &, ContextPtr = nullptr); StatementResult evalStatement(const Ast::Statement &); - Object evalFunctionCall(const Function &, const Ast::FunctionArguments &, FString fnName = u8""); + ObjectPtr evalFunctionCall(const Function &, const Ast::FunctionArguments &, FString fnName = u8""); - Object eval(Ast::Expression); + ObjectPtr eval(Ast::Expression); void run(); void printStackTrace() const; }; diff --git a/include/parser.hpp b/include/parser.hpp index a6d5fe0..4bc2914 100644 --- a/include/parser.hpp +++ b/include/parser.hpp @@ -298,7 +298,7 @@ namespace Fig static constexpr FString varDefTypeFollowed = u8"(Followed)"; Ast::VarDef __parseVarDef(bool); // entry: current is keyword `var` or `const` (isConst: Bool) - Object __parseValue(); + ObjectPtr __parseValue(); Ast::ValueExpr __parseValueExpr(); Ast::FunctionParameters __parseFunctionParameters(); // entry: current is Token::LeftParen Ast::BlockStatement __parseBlockStatement(); // entry: current is Token::LeftBrace diff --git a/include/value.hpp b/include/value.hpp index 59b9b58..5012c92 100644 --- a/include/value.hpp +++ b/include/value.hpp @@ -1,11 +1,9 @@ #pragma once -#include -#include #include #include #include - #include +#include #include #include @@ -30,11 +28,11 @@ namespace Fig { public: using VariantType = std::variant< - Null, - Int, - Double, - String, - Bool, + ValueType::NullClass, + ValueType::IntClass, + ValueType::DoubleClass, + ValueType::StringClass, + ValueType::BoolClass, Function, StructType, StructInstance>; @@ -42,62 +40,29 @@ namespace Fig VariantType data; Object() : - data(Null{}) {} - Object(const Null &n) : - data(std::in_place_type, n) {} - Object(const Int &i) : - data(std::in_place_type, i) {} - Object(const Double &d) + data(ValueType::NullClass{}) {} + Object(const ValueType::NullClass &n) : + data(n) {} + Object(const ValueType::IntClass &i) : + data(i) {} + Object(const ValueType::DoubleClass &d) { - ValueType::IntClass casted = static_cast(d.getValue()); - if (casted == d.getValue()) - data.emplace(casted); + ValueType::IntClass casted = static_cast(d); + if (casted == d) + data = casted; else - data.emplace(d); + data = d; } - Object(const String &s) : - data(std::in_place_type, s) {} - Object(const Bool &b) : - data(std::in_place_type, b) {} + Object(const ValueType::StringClass &s) : + data(s) {} + Object(const ValueType::BoolClass &b) : + data(b) {} Object(const Function &f) : - data(std::in_place_type, f) {} + data(f) {} Object(const StructType &s) : - data(std::in_place_type, s) {} + data(s) {} Object(const StructInstance &s) : - data(std::in_place_type, s) {} - - template - || std::is_same_v - || std::is_same_v - || std::is_same_v - || std::is_same_v - || std::is_same_v - || std::is_same_v>> - Object(const T &val) - { - if constexpr (std::is_same_v) - data.emplace(val); - else if constexpr (std::is_same_v) - { - ValueType::IntClass casted = static_cast(val); - if (casted == val) - data.emplace(casted); - else - data.emplace(val); - } - else if constexpr (std::is_same_v) - data.emplace(val); - else if constexpr (std::is_same_v) - data.emplace(val); - else if constexpr (std::is_same_v) - data.emplace(val); - else if constexpr (std::is_same_v) - data.emplace(val); - else if constexpr (std::is_same_v) - data.emplace(val); - } + data(s) {} Object(const Object &) = default; Object(Object &&) noexcept = default; @@ -107,15 +72,15 @@ namespace Fig static Object defaultValue(TypeInfo ti) { if (ti == ValueType::Int) - return Object(Int(0)); + return Object(ValueType::IntClass(0)); else if (ti == ValueType::Double) - return Object(Double(0.0)); + return Object(ValueType::DoubleClass(0.0)); else if (ti == ValueType::String) - return Object(String(u8"")); + return Object(ValueType::StringClass(u8"")); else if (ti == ValueType::Bool) - return Object(Bool(false)); + return Object(ValueType::BoolClass(false)); else - return getNullInstance(); + return *getNullInstance(); } template @@ -136,25 +101,35 @@ namespace Fig return std::get(data); } - static Object getNullInstance() + static std::shared_ptr getNullInstance() { - static Object v(Null{}); - return v; + static std::shared_ptr n = std::make_shared(ValueType::NullClass{}); + return n; + } + static std::shared_ptr getTrueInstance() + { + static std::shared_ptr t = std::make_shared(true); + return t; + } + static std::shared_ptr getFalseInstance() + { + static std::shared_ptr f = std::make_shared(false); + return f; } TypeInfo getTypeInfo() const { return std::visit([](auto &&val) -> TypeInfo { using T = std::decay_t; - if constexpr (std::is_same_v) + if constexpr (std::is_same_v) return ValueType::Null; - else if constexpr (std::is_same_v) + else if constexpr (std::is_same_v) return ValueType::Int; - else if constexpr (std::is_same_v) + else if constexpr (std::is_same_v) return ValueType::Double; - else if constexpr (std::is_same_v) + else if constexpr (std::is_same_v) return ValueType::String; - else if constexpr (std::is_same_v) + else if constexpr (std::is_same_v) return ValueType::Bool; else if constexpr (std::is_same_v) return ValueType::Function; @@ -168,26 +143,26 @@ namespace Fig data); } - bool isNull() const { return is(); } - bool isNumeric() const { return is() || is(); } + bool isNull() const { return is(); } + bool isNumeric() const { return is() || is(); } ValueType::DoubleClass getNumericValue() const { - if (is()) - return static_cast(as().getValue()); - else if (is()) - return as().getValue(); + if (is()) + return static_cast(as()); + else if (is()) + return as(); else throw RuntimeError(u8"getNumericValue: Not a numeric value"); } FString toString() const { - if (is()) return FString(u8"null"); - if (is()) return FString(std::to_string(as().getValue())); - if (is()) return FString(std::to_string(as().getValue())); - if (is()) return as().getValue(); - if (is()) return as().getValue() ? FString(u8"true") : FString(u8"false"); + if (is()) return FString(u8"null"); + if (is()) return FString(std::to_string(as())); + if (is()) return FString(std::to_string(as())); + if (is()) return as(); + if (is()) return as() ? FString(u8"true") : FString(u8"false"); if (is()) return FString(std::format("", as().id, @@ -197,7 +172,7 @@ namespace Fig as().id, static_cast(&as()))); if (is()) - return FString(std::format("", + return FString(std::format("", as().parentId, static_cast(&as()))); return FString(u8""); @@ -220,15 +195,14 @@ namespace Fig throw ValueError(FStringView(makeTypeErrorMessage("Cannot add", "+", lhs, rhs))); if (lhs.isNumeric() && rhs.isNumeric()) { - bool lhsIsInt = lhs.is(); - bool rhsIsInt = rhs.is(); - ValueType::DoubleClass result = lhs.getNumericValue() + rhs.getNumericValue(); - if (lhsIsInt && rhsIsInt && !isNumberExceededIntLimit(result)) + bool bothInt = lhs.is() && rhs.is(); + auto result = lhs.getNumericValue() + rhs.getNumericValue(); + if (bothInt && !isNumberExceededIntLimit(result)) return Object(static_cast(result)); - return Object(ValueType::DoubleClass(result)); + return Object(result); } - if (lhs.is() && rhs.is()) - return Object(ValueType::StringClass(lhs.as().getValue() + rhs.as().getValue())); + if (lhs.is() && rhs.is()) + return Object(FString(lhs.as() + rhs.as())); throw ValueError(FStringView(makeTypeErrorMessage("Unsupported operation", "+", lhs, rhs))); } @@ -238,12 +212,11 @@ namespace Fig throw ValueError(FStringView(makeTypeErrorMessage("Cannot subtract", "-", lhs, rhs))); if (lhs.isNumeric() && rhs.isNumeric()) { - bool lhsIsInt = lhs.is(); - bool rhsIsInt = rhs.is(); - ValueType::DoubleClass result = lhs.getNumericValue() - rhs.getNumericValue(); - if (lhsIsInt && rhsIsInt && !isNumberExceededIntLimit(result)) + bool bothInt = lhs.is() && rhs.is(); + auto result = lhs.getNumericValue() - rhs.getNumericValue(); + if (bothInt && !isNumberExceededIntLimit(result)) return Object(static_cast(result)); - return Object(ValueType::DoubleClass(result)); + return Object(result); } throw ValueError(FStringView(makeTypeErrorMessage("Unsupported operation", "-", lhs, rhs))); } @@ -254,12 +227,11 @@ namespace Fig throw ValueError(FStringView(makeTypeErrorMessage("Cannot multiply", "*", lhs, rhs))); if (lhs.isNumeric() && rhs.isNumeric()) { - bool lhsIsInt = lhs.is(); - bool rhsIsInt = rhs.is(); - ValueType::DoubleClass result = lhs.getNumericValue() * rhs.getNumericValue(); - if (lhsIsInt && rhsIsInt && !isNumberExceededIntLimit(result)) + bool bothInt = lhs.is() && rhs.is(); + auto result = lhs.getNumericValue() * rhs.getNumericValue(); + if (bothInt && !isNumberExceededIntLimit(result)) return Object(static_cast(result)); - return Object(ValueType::DoubleClass(result)); + return Object(result); } throw ValueError(FStringView(makeTypeErrorMessage("Unsupported operation", "*", lhs, rhs))); } @@ -270,15 +242,14 @@ namespace Fig throw ValueError(FStringView(makeTypeErrorMessage("Cannot divide", "/", lhs, rhs))); if (lhs.isNumeric() && rhs.isNumeric()) { - ValueType::DoubleClass rnv = rhs.getNumericValue(); + auto rnv = rhs.getNumericValue(); if (rnv == 0) throw ValueError(FStringView(makeTypeErrorMessage("Division by zero", "/", lhs, rhs))); - ValueType::DoubleClass result = lhs.getNumericValue() / rnv; - bool lhsIsInt = lhs.is(); - bool rhsIsInt = rhs.is(); - if (lhsIsInt && rhsIsInt && !isNumberExceededIntLimit(result)) + bool bothInt = lhs.is() && rhs.is(); + auto result = lhs.getNumericValue() / rnv; + if (bothInt && !isNumberExceededIntLimit(result)) return Object(static_cast(result)); - return Object(ValueType::DoubleClass(result)); + return Object(result); } throw ValueError(FStringView(makeTypeErrorMessage("Unsupported operation", "/", lhs, rhs))); } @@ -289,15 +260,14 @@ namespace Fig throw ValueError(FStringView(makeTypeErrorMessage("Cannot modulo", "%", lhs, rhs))); if (lhs.isNumeric() && rhs.isNumeric()) { - ValueType::DoubleClass rnv = rhs.getNumericValue(); + auto rnv = rhs.getNumericValue(); if (rnv == 0) - throw ValueError(FStringView(makeTypeErrorMessage("Modulo by zero", "%", lhs, rhs))); - ValueType::DoubleClass result = fmod(lhs.getNumericValue(), rnv); - bool lhsIsInt = lhs.is(); - bool rhsIsInt = rhs.is(); - if (lhsIsInt && rhsIsInt && !isNumberExceededIntLimit(result)) + throw ValueError(FStringView(makeTypeErrorMessage("Modulo by zero", "/", lhs, rhs))); + bool bothInt = lhs.is() && rhs.is(); + auto result = std::fmod(lhs.getNumericValue(), rnv); + if (bothInt && !isNumberExceededIntLimit(result)) return Object(static_cast(result)); - return Object(ValueType::DoubleClass(result)); + return Object(result); } throw ValueError(FStringView(makeTypeErrorMessage("Unsupported operation", "%", lhs, rhs))); } @@ -305,123 +275,104 @@ namespace Fig // logic friend Object operator&&(const Object &lhs, const Object &rhs) { - if (!lhs.is() || !rhs.is()) + if (!lhs.is() || !rhs.is()) throw ValueError(FStringView(makeTypeErrorMessage("Logical AND requires bool", "&&", lhs, rhs))); - return Object(lhs.as().getValue() && rhs.as().getValue()); + return Object(lhs.as() && rhs.as()); } friend Object operator||(const Object &lhs, const Object &rhs) { - if (!lhs.is() || !rhs.is()) + if (!lhs.is() || !rhs.is()) throw ValueError(FStringView(makeTypeErrorMessage("Logical OR requires bool", "||", lhs, rhs))); - return Object(lhs.as().getValue() || rhs.as().getValue()); + return Object(lhs.as() || rhs.as()); } friend Object operator!(const Object &v) { - if (!v.is()) + if (!v.is()) throw ValueError(FStringView(std::format("Logical NOT requires bool: '{}'", v.getTypeInfo().name.toBasicString()))); - return Object(!v.as().getValue()); + return Object(!v.as()); } friend Object operator-(const Object &v) { if (v.isNull()) - throw ValueError(FStringView(std::format("Unary minus cannot be applied to null"))); - if (v.is()) - return Object(-v.as().getValue()); - if (v.is()) - return Object(-v.as().getValue()); + throw ValueError(FStringView(u8"Unary minus cannot be applied to null")); + if (v.is()) + return Object(-v.as()); + if (v.is()) + return Object(-v.as()); throw ValueError(FStringView(std::format("Unary minus requires int or double: '{}'", v.getTypeInfo().name.toBasicString()))); } friend Object operator~(const Object &v) { - if (!v.is()) + if (!v.is()) throw ValueError(FStringView(std::format("Bitwise NOT requires int: '{}'", v.getTypeInfo().name.toBasicString()))); - return Object(~v.as().getValue()); - } - - // compare - friend bool operator==(const Object &lhs, const Object &rhs) - { - return lhs.data == rhs.data; - } - - friend bool operator!=(const Object &lhs, const Object &rhs) - { - return !(lhs == rhs); + return Object(~v.as()); } + // comparison + friend bool operator==(const Object &lhs, const Object &rhs) { return lhs.data == rhs.data; } + friend bool operator!=(const Object &lhs, const Object &rhs) { return !(lhs == rhs); } friend bool operator<(const Object &lhs, const Object &rhs) { - if (lhs.isNumeric() && rhs.isNumeric()) - return lhs.getNumericValue() < rhs.getNumericValue(); - if (lhs.is() && rhs.is()) - return lhs.as().getValue() < rhs.as().getValue(); + if (lhs.isNumeric() && rhs.isNumeric()) return lhs.getNumericValue() < rhs.getNumericValue(); + if (lhs.is() && rhs.is()) + return lhs.as() < rhs.as(); throw ValueError(FStringView(makeTypeErrorMessage("Unsupported comparison", "<", lhs, rhs))); } - - friend bool operator<=(const Object &lhs, const Object &rhs) - { - return lhs == rhs || lhs < rhs; - } - + friend bool operator<=(const Object &lhs, const Object &rhs) { return lhs == rhs || lhs < rhs; } friend bool operator>(const Object &lhs, const Object &rhs) { - if (lhs.isNumeric() && rhs.isNumeric()) - return lhs.getNumericValue() > rhs.getNumericValue(); - if (lhs.is() && rhs.is()) - return lhs.as().getValue() > rhs.as().getValue(); + if (lhs.isNumeric() && rhs.isNumeric()) return lhs.getNumericValue() > rhs.getNumericValue(); + if (lhs.is() && rhs.is()) + return lhs.as() > rhs.as(); throw ValueError(FStringView(makeTypeErrorMessage("Unsupported comparison", ">", lhs, rhs))); } - - friend bool operator>=(const Object &lhs, const Object &rhs) - { - return lhs == rhs || lhs > rhs; - } + friend bool operator>=(const Object &lhs, const Object &rhs) { return lhs == rhs || lhs > rhs; } // bitwise friend Object bit_and(const Object &lhs, const Object &rhs) { - if (!lhs.is() || !rhs.is()) + if (!lhs.is() || !rhs.is()) throw ValueError(FStringView(makeTypeErrorMessage("Bitwise AND requires int", "&", lhs, rhs))); - return Object(lhs.as().getValue() & rhs.as().getValue()); + return Object(lhs.as() & rhs.as()); } friend Object bit_or(const Object &lhs, const Object &rhs) { - if (!lhs.is() || !rhs.is()) + if (!lhs.is() || !rhs.is()) throw ValueError(FStringView(makeTypeErrorMessage("Bitwise OR requires int", "|", lhs, rhs))); - return Object(lhs.as().getValue() | rhs.as().getValue()); + return Object(lhs.as() | rhs.as()); } friend Object bit_xor(const Object &lhs, const Object &rhs) { - if (!lhs.is() || !rhs.is()) + if (!lhs.is() || !rhs.is()) throw ValueError(FStringView(makeTypeErrorMessage("Bitwise XOR requires int", "^", lhs, rhs))); - return Object(lhs.as().getValue() ^ rhs.as().getValue()); + return Object(lhs.as() ^ rhs.as()); } friend Object bit_not(const Object &v) { - if (!v.is()) + if (!v.is()) throw ValueError(FStringView(std::format("Bitwise NOT requires int: '{}'", v.getTypeInfo().name.toBasicString()))); - return Object(~v.as().getValue()); + return Object(~v.as()); } friend Object shift_left(const Object &lhs, const Object &rhs) { - if (!lhs.is() || !rhs.is()) + if (!lhs.is() || !rhs.is()) throw ValueError(FStringView(makeTypeErrorMessage("Shift left requires int", "<<", lhs, rhs))); - return Object(lhs.as().getValue() << rhs.as().getValue()); + return Object(lhs.as() << rhs.as()); } friend Object shift_right(const Object &lhs, const Object &rhs) { - if (!lhs.is() || !rhs.is()) + if (!lhs.is() || !rhs.is()) throw ValueError(FStringView(makeTypeErrorMessage("Shift right requires int", ">>", lhs, rhs))); - return Object(lhs.as().getValue() >> rhs.as().getValue()); + return Object(lhs.as() >> rhs.as()); } friend Object power(const Object &base, const Object &exp) @@ -430,16 +381,16 @@ namespace Fig throw ValueError(FStringView(makeTypeErrorMessage("Cannot exponentiate", "**", base, exp))); if (base.isNumeric() && exp.isNumeric()) { - bool baseIsInt = base.is(); - bool expIsInt = exp.is(); - ValueType::DoubleClass result = std::pow(base.getNumericValue(), exp.getNumericValue()); - if (baseIsInt && expIsInt && isDoubleInteger(result) && !isNumberExceededIntLimit(result)) + bool bothInt = base.is() && exp.is(); + auto result = std::pow(base.getNumericValue(), exp.getNumericValue()); + if (bothInt && !isNumberExceededIntLimit(result)) return Object(static_cast(result)); - return Object(ValueType::DoubleClass(result)); + return Object(result); } throw ValueError(FStringView(makeTypeErrorMessage("Unsupported operation", "**", base, exp))); } }; using ObjectPtr = std::shared_ptr; + } // namespace Fig diff --git a/src/evaluator.cpp b/src/evaluator.cpp index 6f5ea29..868d9d2 100644 --- a/src/evaluator.cpp +++ b/src/evaluator.cpp @@ -4,35 +4,41 @@ namespace Fig { - Object Evaluator::__evalOp(Ast::Operator op, const Object &lhs, const Object &rhs) + ObjectPtr Evaluator::__evalOp(Ast::Operator op, const ObjectPtr &lhs, const ObjectPtr &rhs) { using Fig::Ast::Operator; switch (op) { - case Operator::Add: return lhs + rhs; - case Operator::Subtract: return lhs - rhs; - case Operator::Multiply: return lhs * rhs; - case Operator::Divide: return lhs / rhs; - case Operator::Modulo: return lhs % rhs; - case Operator::Power: return power(lhs, rhs); + case Operator::Add: return std::make_shared(*lhs + *rhs); + case Operator::Subtract: return std::make_shared(*lhs - *rhs); + case Operator::Multiply: return std::make_shared((*lhs) * (*rhs)); + case Operator::Divide: return std::make_shared(*lhs / *rhs); + case Operator::Modulo: return std::make_shared(*lhs % *rhs); + case Operator::Power: return std::make_shared(power(*lhs, *rhs)); - case Operator::And: return lhs && rhs; - case Operator::Or: return lhs || rhs; - case Operator::Not: return !lhs; + case Operator::And: return std::make_shared(*lhs && *rhs); + case Operator::Or: return std::make_shared(*lhs || *rhs); + case Operator::Not: return std::make_shared(!*lhs); - case Operator::Equal: return Object(lhs == rhs); - case Operator::NotEqual: return Object(lhs != rhs); - case Operator::Less: return lhs < rhs; - case Operator::LessEqual: return lhs <= rhs; - case Operator::Greater: return lhs > rhs; - case Operator::GreaterEqual: return lhs >= rhs; + case Operator::Equal: return std::make_shared(*lhs == *rhs); + case Operator::NotEqual: return std::make_shared(*lhs != *rhs); + case Operator::Less: return std::make_shared(*lhs < *rhs); + case Operator::LessEqual: return std::make_shared(*lhs <= *rhs); + case Operator::Greater: return std::make_shared(*lhs > *rhs); + case Operator::GreaterEqual: return std::make_shared(*lhs >= *rhs); - case Operator::BitAnd: return bit_and(lhs, rhs); - case Operator::BitOr: return bit_or(lhs, rhs); - case Operator::BitXor: return bit_xor(lhs, rhs); - case Operator::BitNot: return bit_not(lhs); - case Operator::ShiftLeft: return shift_left(lhs, rhs); - case Operator::ShiftRight: return shift_right(lhs, rhs); + case Operator::BitAnd: return std::make_shared(bit_and(*lhs, *rhs)); + case Operator::BitOr: return std::make_shared(bit_or(*lhs, *rhs)); + case Operator::BitXor: return std::make_shared(bit_xor(*lhs, *rhs)); + case Operator::BitNot: return std::make_shared(bit_not(*lhs)); + case Operator::ShiftLeft: return std::make_shared(shift_left(*lhs, *rhs)); + case Operator::ShiftRight: return std::make_shared(shift_right(*lhs, *rhs)); + + case Operator::Assign: + { + *lhs = *rhs; + return Object::getNullInstance(); + } // case Operator::Walrus: { // static constexpr char WalrusErrorName[] = "WalrusError"; @@ -43,19 +49,19 @@ namespace Fig } } - Object Evaluator::evalBinary(const Ast::BinaryExpr &binExp) + ObjectPtr Evaluator::evalBinary(const Ast::BinaryExpr &binExp) { if (binExp->op == Ast::Operator::Dot) { - const Object &lhs = eval(binExp->lexp); - if (!lhs.is()) + const ObjectPtr &lhs = eval(binExp->lexp); + if (!lhs->is()) { static constexpr char AccessOpObjectNotStructError[] = "AccessOpObjectNotStructError"; throw EvaluatorError(FStringView( std::format("Object not a struct")), binExp->lexp->getAAI()); } - const StructInstance &st = lhs.as(); + const StructInstance &st = lhs->as(); Ast::VarExpr varExp; if (!(varExp = std::dynamic_pointer_cast(binExp->rexp))) { @@ -77,44 +83,27 @@ namespace Fig } return *st.localContext->get(member); // safe } - if (binExp->op == Ast::Operator::Assign) - { - Ast::VarExpr varExp; - if (!(varExp = std::dynamic_pointer_cast(binExp->rexp))) - { - static constexpr char AssignToRightValueError[] = "AssignToRightValueError"; - throw EvaluatorError(FStringView( - std::format("Can't assign to right value {}", binExp->lexp->toString().toBasicString())), - binExp->lexp->getAAI()); - } - const FString& varName = varExp->name; - if (!currentContext->contains(varName)) - { - static constexpr char VariableNotFoundErrorName[] = "VariableNotFoundError"; - throw EvaluatorError(FStringView(std::format("Variable '{}' not defined", varName.toBasicString())), currentAddressInfo); - } - } return __evalOp(binExp->op, eval(binExp->lexp), eval(binExp->rexp)); } - Object Evaluator::evalUnary(const Ast::UnaryExpr &unExp) + ObjectPtr Evaluator::evalUnary(const Ast::UnaryExpr &unExp) { using Fig::Ast::Operator; switch (unExp->op) { case Operator::Not: - return !eval(unExp->exp); + return std::make_shared(!*eval(unExp->exp)); case Operator::Subtract: - return -eval(unExp->exp); + return std::make_shared(-*eval(unExp->exp)); case Operator::BitNot: - return bit_not(eval(unExp->exp)); + return std::make_shared(bit_not(*eval(unExp->exp))); default: throw RuntimeError(FStringView(std::format("Unsupported unary operator: {}", magic_enum::enum_name(unExp->op)))); } } - Object Evaluator::evalFunctionCall(const Function &fn, const Ast::FunctionArguments &fnArgs, FString fnName) + ObjectPtr Evaluator::evalFunctionCall(const Function &fn, const Ast::FunctionArguments &fnArgs, FString fnName) { - const Function& fnStruct = fn; + const Function &fnStruct = fn; Ast::FunctionCallArgs evaluatedArgs; if (fnStruct.isBuiltin) { @@ -143,8 +132,8 @@ namespace Fig for (i = 0; i < fnParas.posParas.size(); i++) { TypeInfo expectedType(fnParas.posParas[i].second); // look up type info, if exists a type with the name, use it, else throw - Object argVal = eval(fnArgs.argv[i]); - TypeInfo actualType = argVal.getTypeInfo(); + ObjectPtr argVal = eval(fnArgs.argv[i]); + TypeInfo actualType = argVal->getTypeInfo(); if (expectedType != actualType and expectedType != ValueType::Any) { static constexpr char ArgumentTypeMismatchErrorName[] = "ArgumentTypeMismatchError"; @@ -158,15 +147,15 @@ namespace Fig size_t defParamIndex = i - fnParas.posParas.size(); TypeInfo expectedType = fnParas.defParas[defParamIndex].second.first; - Object defaultVal = eval(fnParas.defParas[defParamIndex].second.second); - if (expectedType != defaultVal.getTypeInfo() and expectedType != ValueType::Any) + ObjectPtr defaultVal = eval(fnParas.defParas[defParamIndex].second.second); + if (expectedType != defaultVal->getTypeInfo() and expectedType != ValueType::Any) { static constexpr char DefaultParameterTypeErrorName[] = "DefaultParameterTypeError"; - throw EvaluatorError(FStringView(std::format("In function '{}', default parameter '{}' has type '{}', which does not match the expected type '{}'", fnName.toBasicString(), fnParas.defParas[defParamIndex].first.toBasicString(), defaultVal.getTypeInfo().toString().toBasicString(), expectedType.toString().toBasicString())), currentAddressInfo); + throw EvaluatorError(FStringView(std::format("In function '{}', default parameter '{}' has type '{}', which does not match the expected type '{}'", fnName.toBasicString(), fnParas.defParas[defParamIndex].first.toBasicString(), defaultVal->getTypeInfo().toString().toBasicString(), expectedType.toString().toBasicString())), currentAddressInfo); } - Object argVal = eval(fnArgs.argv[i]); - TypeInfo actualType = argVal.getTypeInfo(); + ObjectPtr argVal = eval(fnArgs.argv[i]); + TypeInfo actualType = argVal->getTypeInfo(); if (expectedType != actualType and expectedType != ValueType::Any) { static constexpr char ArgumentTypeMismatchErrorName[] = "ArgumentTypeMismatchError"; @@ -178,7 +167,7 @@ namespace Fig for (; i < fnParas.size(); i++) { size_t defParamIndex = i - fnParas.posParas.size(); - Object defaultVal = eval(fnParas.defParas[defParamIndex].second.second); + ObjectPtr defaultVal = eval(fnParas.defParas[defParamIndex].second.second); evaluatedArgs.argv.push_back(defaultVal); } // create new context for function call @@ -206,7 +195,7 @@ namespace Fig currentContext->def(paramName, paramType, argAm, evaluatedArgs.argv[j]); } // execute function body - Object retVal = Object::getNullInstance(); + ObjectPtr retVal = Object::getNullInstance(); for (const auto &stmt : fnStruct.body->stmts) { StatementResult sr = evalStatement(stmt); @@ -217,15 +206,15 @@ namespace Fig } } currentContext = previousContext; - if (fnStruct.retType != retVal.getTypeInfo() and fnStruct.retType != ValueType::Any) + if (fnStruct.retType != retVal->getTypeInfo() and fnStruct.retType != ValueType::Any) { static constexpr char ReturnTypeMismatchErrorName[] = "ReturnTypeMismatchError"; - throw EvaluatorError(FStringView(std::format("Function '{}' expects return type '{}', but got type '{}'", fnName.toBasicString(), fnStruct.retType.toString().toBasicString(), retVal.getTypeInfo().toString().toBasicString())), currentAddressInfo); + throw EvaluatorError(FStringView(std::format("Function '{}' expects return type '{}', but got type '{}'", fnName.toBasicString(), fnStruct.retType.toString().toBasicString(), retVal->getTypeInfo().toString().toBasicString())), currentAddressInfo); } return retVal; } - Object Evaluator::eval(Ast::Expression exp) + ObjectPtr Evaluator::eval(Ast::Expression exp) { using Fig::Ast::AstType; switch (exp->getType()) @@ -255,19 +244,19 @@ namespace Fig case AstType::FunctionCall: { auto fnCall = std::dynamic_pointer_cast(exp); - Object calleeVal = eval(fnCall->callee); + ObjectPtr calleeVal = eval(fnCall->callee); - if (!calleeVal.is()) + if (!calleeVal->is()) { static constexpr char NotAFunctionErrorName[] = "NotAFunctionError"; throw EvaluatorError( FStringView(std::format( "'{}' is not a function or callable", - calleeVal.toString().toBasicString())), + calleeVal->toString().toBasicString())), currentAddressInfo); } - Function fn = calleeVal.as(); + Function fn = calleeVal->as(); FString fnName = u8""; if (auto var = std::dynamic_pointer_cast(fnCall->callee)) @@ -286,20 +275,20 @@ namespace Fig Ast::Statement retSt = std::make_shared(fn->getExprBody()); retSt->setAAI(fn->getExprBody()->getAAI()); body->stmts.push_back(retSt); - return Function( + return std::make_shared(Function( fn->paras, ValueType::Any, body, - currentContext); + currentContext)); } else { Ast::BlockStatement body = fn->getBlockBody(); - return Function( + return std::make_shared(Function( fn->paras, ValueType::Any, body, - currentContext); + currentContext)); } } case AstType::InitExpr: { @@ -309,13 +298,13 @@ namespace Fig static constexpr char StructNotFoundErrorName[] = "StructNotFoundError"; throw EvaluatorError(FStringView(std::format("Structure type '{}' not found", initExpr->structName.toBasicString())), initExpr->getAAI()); } - Object structTypeVal = currentContext->get(initExpr->structName).value(); - if (!structTypeVal.is()) + ObjectPtr structTypeVal = currentContext->get(initExpr->structName).value(); + if (!structTypeVal->is()) { static constexpr char NotAStructTypeErrorName[] = "NotAStructTypeError"; throw EvaluatorError(FStringView(std::format("'{}' is not a structure type", initExpr->structName.toBasicString())), initExpr->getAAI()); } - const StructType &structT = structTypeVal.as(); + const StructType &structT = structTypeVal->as(); ContextPtr defContext = structT.defContext; // definition context // check init args @@ -334,7 +323,7 @@ namespace Fig throw EvaluatorError(FStringView(std::format("Structure '{}' expects {} to {} fields, but {} were provided", initExpr->structName.toBasicString(), minArgs, maxArgs, initExpr->args.size())), initExpr->getAAI()); } - std::vector> evaluatedArgs; + std::vector> evaluatedArgs; for (const auto &[argName, argExpr] : initExpr->args) { evaluatedArgs.push_back({argName, eval(argExpr)}); @@ -363,26 +352,26 @@ namespace Fig ContextPtr previousContext = currentContext; currentContext = defContext; // evaluate default value in definition context - Object defaultVal = eval(field.defaultValue); // it can't be null here + ObjectPtr defaultVal = eval(field.defaultValue); // it can't be null here currentContext = previousContext; // type check - if (expectedType != defaultVal.getTypeInfo() && expectedType != ValueType::Any) + if (expectedType != defaultVal->getTypeInfo() && expectedType != ValueType::Any) { static constexpr char StructFieldTypeMismatchErrorName[] = "StructFieldTypeMismatchError"; - throw EvaluatorError(FStringView(std::format("In structure '{}', field '{}' expects type '{}', but got type '{}'", initExpr->structName.toBasicString(), fieldName.toBasicString(), expectedType.toString().toBasicString(), defaultVal.getTypeInfo().toString().toBasicString())), initExpr->getAAI()); + throw EvaluatorError(FStringView(std::format("In structure '{}', field '{}' expects type '{}', but got type '{}'", initExpr->structName.toBasicString(), fieldName.toBasicString(), expectedType.toString().toBasicString(), defaultVal->getTypeInfo().toString().toBasicString())), initExpr->getAAI()); } instanceCtx->def(fieldName, expectedType, field.am, defaultVal); continue; } - const Object &argVal = evaluatedArgs[i].second; - if (expectedType != argVal.getTypeInfo() && expectedType != ValueType::Any) + const ObjectPtr &argVal = evaluatedArgs[i].second; + if (expectedType != argVal->getTypeInfo() && expectedType != ValueType::Any) { static constexpr char StructFieldTypeMismatchErrorName[] = "StructFieldTypeMismatchError"; - throw EvaluatorError(FStringView(std::format("In structure '{}', field '{}' expects type '{}', but got type '{}'", initExpr->structName.toBasicString(), fieldName.toBasicString(), expectedType.toString().toBasicString(), argVal.getTypeInfo().toString().toBasicString())), initExpr->getAAI()); + throw EvaluatorError(FStringView(std::format("In structure '{}', field '{}' expects type '{}', but got type '{}'", initExpr->structName.toBasicString(), fieldName.toBasicString(), expectedType.toString().toBasicString(), argVal->getTypeInfo().toString().toBasicString())), initExpr->getAAI()); } instanceCtx->def(fieldName, expectedType, field.am, argVal); } @@ -403,32 +392,32 @@ namespace Fig { // use default value ContextPtr previousContext = currentContext; - currentContext = defContext; // evaluate default value in definition context - Object defaultVal = eval(field.defaultValue); // it can't be null here + currentContext = defContext; // evaluate default value in definition context + ObjectPtr defaultVal = eval(field.defaultValue); // it can't be null here currentContext = previousContext; // type check const TypeInfo &expectedType = field.type; - if (expectedType != defaultVal.getTypeInfo() && expectedType != ValueType::Any) + if (expectedType != defaultVal->getTypeInfo() && expectedType != ValueType::Any) { static constexpr char StructFieldTypeMismatchErrorName[] = "StructFieldTypeMismatchError"; - throw EvaluatorError(FStringView(std::format("In structure '{}', field '{}' expects type '{}', but got type '{}'", initExpr->structName.toBasicString(), fieldName.toBasicString(), expectedType.toString().toBasicString(), defaultVal.getTypeInfo().toString().toBasicString())), initExpr->getAAI()); + throw EvaluatorError(FStringView(std::format("In structure '{}', field '{}' expects type '{}', but got type '{}'", initExpr->structName.toBasicString(), fieldName.toBasicString(), expectedType.toString().toBasicString(), defaultVal->getTypeInfo().toString().toBasicString())), initExpr->getAAI()); } instanceCtx->def(fieldName, field.type, field.am, defaultVal); continue; } - const Object &argVal = evaluatedArgs[i].second; - if (field.type != argVal.getTypeInfo() && field.type != ValueType::Any) + const ObjectPtr &argVal = evaluatedArgs[i].second; + if (field.type != argVal->getTypeInfo() && field.type != ValueType::Any) { static constexpr char StructFieldTypeMismatchErrorName[] = "StructFieldTypeMismatchError"; - throw EvaluatorError(FStringView(std::format("In structure '{}', field '{}' expects type '{}', but got type '{}'", initExpr->structName.toBasicString(), fieldName.toBasicString(), field.type.toString().toBasicString(), argVal.getTypeInfo().toString().toBasicString())), initExpr->getAAI()); + throw EvaluatorError(FStringView(std::format("In structure '{}', field '{}' expects type '{}', but got type '{}'", initExpr->structName.toBasicString(), fieldName.toBasicString(), field.type.toString().toBasicString(), argVal->getTypeInfo().toString().toBasicString())), initExpr->getAAI()); } instanceCtx->def(fieldName, field.type, field.am, argVal); } } } - return StructInstance(structT.id, instanceCtx); + return std::make_shared(StructInstance(structT.id, instanceCtx)); } default: throw RuntimeError(FStringView("Unknown expression type:" + std::to_string(static_cast(exp->getType())))); @@ -472,13 +461,13 @@ namespace Fig static constexpr char RedeclarationErrorName[] = "RedeclarationError"; throw EvaluatorError(FStringView(std::format("Variable '{}' already defined in this scope", varDef->name.toBasicString())), currentAddressInfo); } - Object val; + ObjectPtr val; TypeInfo varTypeInfo; if (varDef->typeName == Parser::varDefTypeFollowed) { // has expr val = eval(varDef->expr); - varTypeInfo = val.getTypeInfo(); + varTypeInfo = val->getTypeInfo(); } else if (varDef->expr) { @@ -486,7 +475,7 @@ namespace Fig if (varDef->typeName != ValueType::Any.name) { TypeInfo expectedType(varDef->typeName); - TypeInfo actualType = val.getTypeInfo(); + TypeInfo actualType = val->getTypeInfo(); if (expectedType != actualType and expectedType != ValueType::Any) { static constexpr char VariableTypeMismatchErrorName[] = "VariableTypeMismatchError"; @@ -497,7 +486,7 @@ namespace Fig else if (!varDef->typeName.empty()) { varTypeInfo = TypeInfo(varDef->typeName); // may throw - val = Object::defaultValue(varTypeInfo); + val = std::make_shared(Object::defaultValue(varTypeInfo)); } AccessModifier am = (varDef->isPublic ? (varDef->isConst ? AccessModifier::PublicConst : AccessModifier::Public) : (varDef->isConst ? AccessModifier::Const : AccessModifier::Normal)); currentContext->def(varDef->name, varTypeInfo, am, val); @@ -524,7 +513,7 @@ namespace Fig fnDef->name, ValueType::Function, am, - Object(Function( + std::make_shared(Function( fnDef->paras, TypeInfo(fnDef->retType), fnDef->body, @@ -556,7 +545,7 @@ namespace Fig stDef->name, ValueType::StructType, am, - Object(StructType( + std::make_shared(StructType( defContext, fields))); return StatementResult::normal(); @@ -589,26 +578,26 @@ namespace Fig // }; case AstType::IfSt: { auto ifSt = std::dynamic_pointer_cast(stmt); - Object condVal = eval(ifSt->condition); - if (condVal.getTypeInfo() != ValueType::Bool) + ObjectPtr condVal = eval(ifSt->condition); + if (condVal->getTypeInfo() != ValueType::Bool) { static constexpr char ConditionTypeErrorName[] = "ConditionTypeError"; throw EvaluatorError(FStringView(u8"If condition must be boolean"), currentAddressInfo); } - if (condVal.as().getValue()) + if (condVal->as()) { return evalBlockStatement(ifSt->body); } // else for (const auto &elif : ifSt->elifs) { - Object elifCondVal = eval(elif->condition); - if (elifCondVal.getTypeInfo() != ValueType::Bool) + ObjectPtr elifCondVal = eval(elif->condition); + if (elifCondVal->getTypeInfo() != ValueType::Bool) { static constexpr char ConditionTypeErrorName[] = "ConditionTypeError"; throw EvaluatorError(FStringView(u8"Else-if condition must be boolean"), currentAddressInfo); } - if (elifCondVal.as().getValue()) + if (elifCondVal->as()) { return evalBlockStatement(elif->body); } @@ -623,13 +612,13 @@ namespace Fig auto whileSt = std::dynamic_pointer_cast(stmt); while (true) { - Object condVal = eval(whileSt->condition); - if (condVal.getTypeInfo() != ValueType::Bool) + ObjectPtr condVal = eval(whileSt->condition); + if (condVal->getTypeInfo() != ValueType::Bool) { static constexpr char ConditionTypeErrorName[] = "ConditionTypeError"; throw EvaluatorError(FStringView(u8"While condition must be boolean"), whileSt->condition->getAAI()); } - if (!condVal.as().getValue()) + if (!condVal->as()) { break; } @@ -667,13 +656,13 @@ namespace Fig while (true) // use while loop to simulate for loop, cause we need to check condition type every iteration { - Object condVal = eval(forSt->condition); - if (condVal.getTypeInfo() != ValueType::Bool) + ObjectPtr condVal = eval(forSt->condition); + if (condVal->getTypeInfo() != ValueType::Bool) { static constexpr char ConditionTypeErrorName[] = "ConditionTypeError"; throw EvaluatorError(FStringView(u8"For condition must be boolean"), forSt->condition->getAAI()); } - if (!condVal.as().getValue()) + if (!condVal->as()) { break; } diff --git a/src/parser.cpp b/src/parser.cpp index 2a02120..b3e1ad9 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -78,7 +78,7 @@ namespace Fig return makeAst(isPublic, isConst, name, tiName, exp); } - Object Parser::__parseValue() + ObjectPtr Parser::__parseValue() { FString _val = currentToken().getValue(); if (currentToken().getType() == TokenType::LiteralNumber) @@ -95,7 +95,7 @@ namespace Fig { throwAddressableError(FStringView(u8"Illegal number literal")); } - return Object(d); + return std::make_shared(d); } else { @@ -109,16 +109,16 @@ namespace Fig { throwAddressableError(FStringView(u8"Illegal number literal")); } - return Object(i); + return std::make_shared(i); } } else if (currentToken().getType() == TokenType::LiteralString) { - return Object(_val); + return std::make_shared(_val); } else if (currentToken().getType() == TokenType::LiteralBool) { - return Object((_val == u8"true" ? true : false)); + return std::make_shared((_val == u8"true" ? true : false)); } else if (currentToken().getType() == TokenType::LiteralNull) { @@ -132,7 +132,7 @@ namespace Fig Ast::ValueExpr Parser::__parseValueExpr() { - return Ast::ValueExpr(new Ast::ValueExprAst(__parseValue())); + return makeAst (__parseValue()); } Ast::FunctionParameters Parser::__parseFunctionParameters() { diff --git a/test.fig b/test.fig index ce93635..42b21ec 100644 --- a/test.fig +++ b/test.fig @@ -1,17 +1,16 @@ struct Person { name: String; - age: Int = 10; - - public func getName() - { - return name; - } + age: Int; } -var person = Person{"123"}; +var person := Person{"Fig", 1}; -const print := __fstdout_print; -print(person.name); -person.name = "sb"; -print(person.name); \ No newline at end of file +const print := __fstdout_println; + +print(person.name, " ", person.age); + +person.name = "hello"; +person.age = 114514; + +print(person.name, " ", person.age);