diff --git a/include/value.hpp b/include/value.hpp index 9f6a4b3..258ffd6 100644 --- a/include/value.hpp +++ b/include/value.hpp @@ -14,6 +14,16 @@ namespace Fig { + inline bool isDoubleInteger(ValueType::DoubleClass d) + { + return std::floor(d) == d; + } + inline bool isNumberExceededIntLimit(ValueType::DoubleClass d) + { + static constexpr ValueType::DoubleClass intMaxAsDouble = static_cast(std::numeric_limits::max()); + static constexpr ValueType::DoubleClass intMinAsDouble = static_cast(std::numeric_limits::min()); + return d > intMaxAsDouble || d < intMinAsDouble; + } class Value { public: @@ -194,7 +204,14 @@ namespace Fig if (lhs.isNull() || rhs.isNull()) throw ValueError(FStringView(makeTypeErrorMessage("Cannot add", "+", lhs, rhs))); if (lhs.isNumeric() and rhs.isNumeric()) - return lhs.getNumericValue() + rhs.getNumericValue(); + { + ValueType::DoubleClass result = lhs.getNumericValue() + rhs.getNumericValue(); + if (isDoubleInteger(result) and !isNumberExceededIntLimit(result)) + { + return Value(static_cast(result)); + } + return Value(ValueType::DoubleClass(result)); + } if (lhs.is() && rhs.is()) return Value(ValueType::StringClass(lhs.as().getValue() + rhs.as().getValue())); @@ -206,7 +223,14 @@ namespace Fig if (lhs.isNull() || rhs.isNull()) throw ValueError(FStringView(makeTypeErrorMessage("Cannot subtract", "-", lhs, rhs))); if (lhs.isNumeric() and rhs.isNumeric()) - return lhs.getNumericValue() - rhs.getNumericValue(); + { + ValueType::DoubleClass result = lhs.getNumericValue() - rhs.getNumericValue(); + if (isDoubleInteger(result) and !isNumberExceededIntLimit(result)) + { + return Value(static_cast(result)); + } + return Value(ValueType::DoubleClass(result)); + } throw ValueError(FStringView(makeTypeErrorMessage("Unsupported operation", "-", lhs, rhs))); } @@ -215,7 +239,14 @@ namespace Fig if (lhs.isNull() || rhs.isNull()) throw ValueError(FStringView(makeTypeErrorMessage("Cannot multiply", "*", lhs, rhs))); if (lhs.isNumeric() and rhs.isNumeric()) - return lhs.getNumericValue() * rhs.getNumericValue(); + { + ValueType::DoubleClass result = lhs.getNumericValue() * rhs.getNumericValue(); + if (isDoubleInteger(result) and !isNumberExceededIntLimit(result)) + { + return Value(static_cast(result)); + } + return Value(ValueType::DoubleClass(result)); + } throw ValueError(FStringView(makeTypeErrorMessage("Unsupported operation", "*", lhs, rhs))); } @@ -225,9 +256,14 @@ namespace Fig throw ValueError(FStringView(makeTypeErrorMessage("Cannot divide", "/", lhs, rhs))); if (lhs.isNumeric() and rhs.isNumeric()) { - auto rnv = rhs.getNumericValue(); + ValueType::DoubleClass rnv = rhs.getNumericValue(); if (rnv == 0) throw ValueError(FStringView(makeTypeErrorMessage("Division by zero", "/", lhs, rhs))); - return lhs.getNumericValue() / rnv; + ValueType::DoubleClass result = lhs.getNumericValue() / rnv; + if (isDoubleInteger(result) and !isNumberExceededIntLimit(result)) + { + return Value(static_cast(result)); + } + return Value(ValueType::DoubleClass(result)); } throw ValueError(FStringView(makeTypeErrorMessage("Unsupported operation", "/", lhs, rhs))); } @@ -238,9 +274,14 @@ namespace Fig throw ValueError(FStringView(makeTypeErrorMessage("Cannot modulo", "%", lhs, rhs))); if (lhs.isNumeric() and rhs.isNumeric()) { - auto rnv = rhs.getNumericValue(); - if (rnv == 0) throw ValueError(FStringView(makeTypeErrorMessage("Modulo by zero", "%", lhs, rhs))); - return fmod(lhs.getNumericValue(), rhs.getNumericValue()); + ValueType::DoubleClass rnv = rhs.getNumericValue(); + if (rnv == 0) throw ValueError(FStringView(makeTypeErrorMessage("Modulo by zero", "/", lhs, rhs))); + ValueType::DoubleClass result = fmod(lhs.getNumericValue(), rnv); + if (isDoubleInteger(result) and !isNumberExceededIntLimit(result)) + { + return Value(static_cast(result)); + } + return Value(ValueType::DoubleClass(result)); } throw ValueError(FStringView(makeTypeErrorMessage("Unsupported operation", "%", lhs, rhs))); } @@ -367,6 +408,22 @@ namespace Fig throw ValueError(FStringView(makeTypeErrorMessage("Shift right requires int", ">>", lhs, rhs))); return Value(lhs.as().getValue() >> rhs.as().getValue()); } + + friend Value power(const Value &base, const Value &exp) + { + if (base.isNull() || exp.isNull()) + throw ValueError(FStringView(makeTypeErrorMessage("Cannot exponentiate", "**", base, exp))); + if (base.isNumeric() and exp.isNumeric()) + { + ValueType::DoubleClass result = std::pow(base.getNumericValue(), exp.getNumericValue()); + if (isDoubleInteger(result) and !isNumberExceededIntLimit(result)) + { + return Value(static_cast(result)); + } + return Value(ValueType::DoubleClass(result)); + } + throw ValueError(FStringView(makeTypeErrorMessage("Unsupported operation", "**", base, exp))); + } }; using Any = Value; diff --git a/src/evaluator.cpp b/src/evaluator.cpp index 8cf2337..cd6388a 100644 --- a/src/evaluator.cpp +++ b/src/evaluator.cpp @@ -14,6 +14,7 @@ namespace Fig 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::And: return lhs && rhs; case Operator::Or: return lhs || rhs; @@ -291,7 +292,7 @@ namespace Fig if (expectedType != actualType and expectedType != ValueType::Any) { static constexpr char VariableTypeMismatchErrorName[] = "VariableTypeMismatchError"; - throw EvaluatorError(FStringView(std::format("Variable '{}' expects type '{}', but got type '{}'", varDef->name.toBasicString(), expectedType.toString().toBasicString(), actualType.toString().toBasicString())), currentAddressInfo); + throw EvaluatorError(FStringView(std::format("Variable '{}' expects type '{}', but got type '{}'", varDef->name.toBasicString(), expectedType.toString().toBasicString(), actualType.toString().toBasicString())), varDef->getAAI()); } } } diff --git a/test.fig b/test.fig index 95ba00b..e69de29 100644 --- a/test.fig +++ b/test.fig @@ -1,9 +0,0 @@ -var x = 1; - -func f() { - x = x + 1; -} - -f(); -var print = __fstdout_println; -print(x); \ No newline at end of file