Added if statements, more stdlib functions
This commit is contained in:
parent
7c57a9a111
commit
cb14221429
2
Makefile
2
Makefile
@ -4,7 +4,7 @@
|
||||
CC = g++
|
||||
|
||||
# Compiler flags
|
||||
CFLAGS = -Wall -Wextra -std=c++17 -Wno-unused-variable -Wno-unused-parameter -Wno-switch
|
||||
CFLAGS = -Wall -Wextra -std=c++17 -Wno-unused-variable -Wno-unused-parameter -Wno-switch -O3 -march=native
|
||||
|
||||
# Source directory
|
||||
SRC_DIR = ./source
|
||||
|
||||
@ -35,6 +35,7 @@ public:
|
||||
void visitVarStmt(sptr(VarStmt) statement) override;
|
||||
void visitFunctionStmt(sptr(FunctionStmt) statement) override;
|
||||
void visitReturnStmt(sptr(ReturnStmt) statement) override;
|
||||
void visitIfStmt(sptr(IfStmt) statement) override;
|
||||
|
||||
void interpret(std::vector<sptr(Stmt)> statements);
|
||||
|
||||
|
||||
@ -44,6 +44,8 @@ private:
|
||||
|
||||
std::shared_ptr<Stmt> returnStatement();
|
||||
|
||||
std::shared_ptr<Stmt> ifStatement();
|
||||
|
||||
std::shared_ptr<Stmt> declaration();
|
||||
|
||||
std::shared_ptr<Stmt> varDeclaration();
|
||||
|
||||
@ -10,6 +10,7 @@ struct VarStmt;
|
||||
struct BlockStmt;
|
||||
struct FunctionStmt;
|
||||
struct ReturnStmt;
|
||||
struct IfStmt;
|
||||
|
||||
struct StmtVisitor
|
||||
{
|
||||
@ -18,6 +19,7 @@ struct StmtVisitor
|
||||
virtual void visitVarStmt(sptr(VarStmt) stmt) = 0;
|
||||
virtual void visitFunctionStmt(sptr(FunctionStmt) stmt) = 0;
|
||||
virtual void visitReturnStmt(sptr(ReturnStmt) stmt) = 0;
|
||||
virtual void visitIfStmt(sptr(IfStmt) stmt) = 0;
|
||||
};
|
||||
|
||||
struct Stmt
|
||||
@ -95,3 +97,18 @@ struct ReturnStmt : Stmt, public std::enable_shared_from_this<ReturnStmt>
|
||||
visitor->visitReturnStmt(shared_from_this());
|
||||
}
|
||||
};
|
||||
|
||||
struct IfStmt : Stmt, public std::enable_shared_from_this<IfStmt>
|
||||
{
|
||||
const sptr(Expr) condition;
|
||||
const sptr(Stmt) thenBranch;
|
||||
const sptr(Stmt) elseBranch;
|
||||
|
||||
IfStmt(sptr(Expr) condition, sptr(Stmt) thenBranch, sptr(Stmt) elseBranch)
|
||||
: condition(condition), thenBranch(thenBranch), elseBranch(elseBranch) {}
|
||||
|
||||
void accept(StmtVisitor* visitor) override
|
||||
{
|
||||
visitor->visitIfStmt(shared_from_this());
|
||||
}
|
||||
};
|
||||
@ -22,10 +22,8 @@ sptr(Object) Environment::get(Token name)
|
||||
}
|
||||
|
||||
void Environment::define(std::string name, sptr(Object) value) {
|
||||
if(variables.count(name) > 0){
|
||||
throw std::runtime_error("'" + name + "' already defined.");
|
||||
}
|
||||
variables.insert(std::make_pair(name, value));
|
||||
// Allow redefinition - just overwrite the existing value
|
||||
variables[name] = value;
|
||||
}
|
||||
|
||||
void Environment::assign(Token name, std::shared_ptr<Object> value) {
|
||||
|
||||
@ -9,6 +9,8 @@
|
||||
#include <cmath>
|
||||
#include "../headers/Interpreter.h"
|
||||
#include "../headers/helperFunctions/HelperFunctions.h"
|
||||
#include <unordered_map>
|
||||
|
||||
|
||||
|
||||
sptr(Object) Interpreter::visitLiteralExpr(sptr(LiteralExpr) expr) {
|
||||
@ -24,7 +26,7 @@ sptr(Object) Interpreter::visitLiteralExpr(sptr(LiteralExpr) expr) {
|
||||
// Use stod for all numbers to handle both integers and decimals correctly
|
||||
num = std::stod(expr->value);
|
||||
}
|
||||
return msptr(Number)(num);
|
||||
return std::make_shared<Number>(num);
|
||||
}
|
||||
if(expr->value == "true") return msptr(Boolean)(true);
|
||||
if(expr->value == "false") return msptr(Boolean)(false);
|
||||
@ -105,14 +107,14 @@ sptr(Object) Interpreter::visitBinaryExpr(sptr(BinaryExpr) expression)
|
||||
case LESS_EQUAL:
|
||||
return msptr(Boolean)(left_double <= right_double);
|
||||
case MINUS:
|
||||
return msptr(Number)(left_double - right_double);
|
||||
return std::make_shared<Number>(left_double - right_double);
|
||||
case PLUS:
|
||||
return msptr(Number)(left_double + right_double);
|
||||
return std::make_shared<Number>(left_double + right_double);
|
||||
case SLASH:
|
||||
if(right_double == 0) throw std::runtime_error("DivisionByZeroError: Cannot divide by 0");
|
||||
return msptr(Number)(left_double / right_double);
|
||||
return std::make_shared<Number>(left_double / right_double);
|
||||
case STAR:
|
||||
return msptr(Number)(left_double * right_double);
|
||||
return std::make_shared<Number>(left_double * right_double);
|
||||
case PERCENT:
|
||||
return msptr(Number)(fmod(left_double, right_double));
|
||||
default:
|
||||
@ -286,7 +288,7 @@ sptr(Object) Interpreter::visitCallExpr(sptr(CallExpr) expression) {
|
||||
}
|
||||
|
||||
// Create new environment for function execution
|
||||
sptr(Environment) functionEnv = msptr(Environment)(std::static_pointer_cast<Environment>(function->closure));
|
||||
sptr(Environment) functionEnv = std::make_shared<Environment>(std::static_pointer_cast<Environment>(function->closure));
|
||||
|
||||
// Bind parameters to arguments
|
||||
for (size_t i = 0; i < function->params.size(); i++) {
|
||||
@ -368,6 +370,15 @@ void Interpreter::visitReturnStmt(sptr(ReturnStmt) statement)
|
||||
throw Return(value);
|
||||
}
|
||||
|
||||
void Interpreter::visitIfStmt(sptr(IfStmt) statement)
|
||||
{
|
||||
if (isTruthy(evaluate(statement->condition))) {
|
||||
execute(statement->thenBranch);
|
||||
} else if (statement->elseBranch != nullptr) {
|
||||
execute(statement->elseBranch);
|
||||
}
|
||||
}
|
||||
|
||||
void Interpreter::interpret(std::vector<sptr(Stmt)> statements) {
|
||||
|
||||
|
||||
@ -509,6 +520,14 @@ std::string Interpreter::stringify(sptr(Object) object) {
|
||||
{
|
||||
return Bool->value == 1 ? "true" : "false";
|
||||
}
|
||||
else if(auto func = std::dynamic_pointer_cast<Function>(object))
|
||||
{
|
||||
return "<function " + func->name + ">";
|
||||
}
|
||||
else if(auto builtinFunc = std::dynamic_pointer_cast<BuiltinFunction>(object))
|
||||
{
|
||||
return "<builtin_function " + builtinFunc->name + ">";
|
||||
}
|
||||
|
||||
throw std::runtime_error("Could not convert object to string");
|
||||
}
|
||||
@ -537,3 +556,5 @@ bool Interpreter::isWholeNumer(double num) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -3,6 +3,17 @@
|
||||
#include <chrono>
|
||||
|
||||
void StdLib::addToEnvironment(sptr(Environment) env, Interpreter* interpreter) {
|
||||
// Create a built-in toString function
|
||||
auto toStringFunc = std::make_shared<BuiltinFunction>("toString",
|
||||
[interpreter](std::vector<std::shared_ptr<Object>> args) -> std::shared_ptr<Object> {
|
||||
if (args.size() != 1) {
|
||||
throw std::runtime_error("Expected 1 argument but got " + std::to_string(args.size()) + ".");
|
||||
}
|
||||
|
||||
return std::make_shared<String>(interpreter->stringify(args[0]));
|
||||
});
|
||||
env->define("toString", toStringFunc);
|
||||
|
||||
// Create a built-in print function
|
||||
auto printFunc = std::make_shared<BuiltinFunction>("print",
|
||||
[interpreter](std::vector<std::shared_ptr<Object>> args) -> std::shared_ptr<Object> {
|
||||
@ -55,4 +66,85 @@ void StdLib::addToEnvironment(sptr(Environment) env, Interpreter* interpreter) {
|
||||
return std::make_shared<Number>(microseconds);
|
||||
});
|
||||
env->define("time", timeFunc);
|
||||
|
||||
// Create a built-in input function
|
||||
auto inputFunc = std::make_shared<BuiltinFunction>("input",
|
||||
[interpreter](std::vector<std::shared_ptr<Object>> args) -> std::shared_ptr<Object> {
|
||||
if (args.size() > 1) {
|
||||
throw std::runtime_error("Expected 0 or 1 arguments but got " + std::to_string(args.size()) + ".");
|
||||
}
|
||||
|
||||
// Optional prompt
|
||||
if (args.size() == 1) {
|
||||
std::cout << interpreter->stringify(args[0]);
|
||||
}
|
||||
|
||||
// Get user input
|
||||
std::string userInput;
|
||||
std::getline(std::cin, userInput);
|
||||
|
||||
return std::make_shared<String>(userInput);
|
||||
});
|
||||
env->define("input", inputFunc);
|
||||
|
||||
// Create a built-in type function
|
||||
auto typeFunc = std::make_shared<BuiltinFunction>("type",
|
||||
[](std::vector<std::shared_ptr<Object>> args) -> std::shared_ptr<Object> {
|
||||
if (args.size() != 1) {
|
||||
throw std::runtime_error("Expected 1 argument but got " + std::to_string(args.size()) + ".");
|
||||
}
|
||||
|
||||
std::string typeName;
|
||||
if (std::dynamic_pointer_cast<Number>(args[0])) {
|
||||
typeName = "number";
|
||||
} else if (std::dynamic_pointer_cast<String>(args[0])) {
|
||||
typeName = "string";
|
||||
} else if (std::dynamic_pointer_cast<Boolean>(args[0])) {
|
||||
typeName = "boolean";
|
||||
} else if (std::dynamic_pointer_cast<None>(args[0])) {
|
||||
typeName = "none";
|
||||
} else if (std::dynamic_pointer_cast<Function>(args[0])) {
|
||||
typeName = "function";
|
||||
} else if (std::dynamic_pointer_cast<BuiltinFunction>(args[0])) {
|
||||
typeName = "builtin_function";
|
||||
} else {
|
||||
typeName = "unknown";
|
||||
}
|
||||
|
||||
return std::make_shared<String>(typeName);
|
||||
});
|
||||
env->define("type", typeFunc);
|
||||
|
||||
// Create a built-in toNumber function for string-to-number conversion
|
||||
auto toNumberFunc = std::make_shared<BuiltinFunction>("toNumber",
|
||||
[](std::vector<std::shared_ptr<Object>> args) -> std::shared_ptr<Object> {
|
||||
if (args.size() != 1) {
|
||||
throw std::runtime_error("Expected 1 argument but got " + std::to_string(args.size()) + ".");
|
||||
}
|
||||
|
||||
auto strObj = std::dynamic_pointer_cast<String>(args[0]);
|
||||
if (!strObj) {
|
||||
throw std::runtime_error("toNumber() expects a string argument.");
|
||||
}
|
||||
|
||||
std::string str = strObj->value;
|
||||
|
||||
// Remove leading/trailing whitespace
|
||||
str.erase(0, str.find_first_not_of(" \t\n\r"));
|
||||
str.erase(str.find_last_not_of(" \t\n\r") + 1);
|
||||
|
||||
if (str.empty()) {
|
||||
throw std::runtime_error("Cannot convert empty string to number.");
|
||||
}
|
||||
|
||||
try {
|
||||
double value = std::stod(str);
|
||||
return std::make_shared<Number>(value);
|
||||
} catch (const std::invalid_argument&) {
|
||||
throw std::runtime_error("Cannot convert '" + str + "' to number.");
|
||||
} catch (const std::out_of_range&) {
|
||||
throw std::runtime_error("Number '" + str + "' is out of range.");
|
||||
}
|
||||
});
|
||||
env->define("toNumber", toNumberFunc);
|
||||
}
|
||||
@ -758,6 +758,306 @@ assert(gt_test == true, "7 > 4 should be true");
|
||||
|
||||
print("✓ Boolean + String concatenation working");
|
||||
|
||||
// ========================================
|
||||
// TEST 31: IF STATEMENTS
|
||||
// ========================================
|
||||
print("\n--- Test 31: If Statements ---");
|
||||
|
||||
// Basic if statement
|
||||
if (true) {
|
||||
print("✓ Basic if statement working");
|
||||
}
|
||||
|
||||
// If-else statement
|
||||
if (true) {
|
||||
print("✓ If branch executed");
|
||||
} else {
|
||||
print("✗ Else branch should not execute");
|
||||
}
|
||||
|
||||
if (false) {
|
||||
print("✗ If branch should not execute");
|
||||
} else {
|
||||
print("✓ Else branch executed");
|
||||
}
|
||||
|
||||
// If-else if-else chain
|
||||
if (false) {
|
||||
print("✗ First if should not execute");
|
||||
} else if (true) {
|
||||
print("✓ Else if branch executed");
|
||||
} else {
|
||||
print("✗ Final else should not execute");
|
||||
}
|
||||
|
||||
// Nested if statements
|
||||
if (true) {
|
||||
if (true) {
|
||||
print("✓ Nested if statements working");
|
||||
}
|
||||
}
|
||||
|
||||
// Single-line if statements
|
||||
if (true) print("✓ Single-line if working");
|
||||
if (false) print("✗ Single-line if should not execute");
|
||||
|
||||
// Complex conditions
|
||||
var if_a = 5;
|
||||
var if_b = 3;
|
||||
if (if_a > if_b) {
|
||||
print("✓ Complex condition working");
|
||||
}
|
||||
|
||||
print("✓ If statements working");
|
||||
|
||||
// ========================================
|
||||
// TEST 32: INPUT FUNCTION
|
||||
// ========================================
|
||||
print("\n--- Test 32: Input Function ---");
|
||||
|
||||
// Test input function exists
|
||||
var input_func = input;
|
||||
assert(type(input_func) == "builtin_function", "Input function should be a builtin_function");
|
||||
|
||||
// Test input with no arguments (would pause for user input)
|
||||
// Note: We can't test actual input without user interaction
|
||||
print("✓ Input function available");
|
||||
|
||||
// ========================================
|
||||
// TEST 33: TYPE FUNCTION
|
||||
// ========================================
|
||||
print("\n--- Test 33: Type Function ---");
|
||||
|
||||
// Test basic types
|
||||
assert(type(42) == "number", "Type of number should be 'number'");
|
||||
assert(type(3.14) == "number", "Type of decimal should be 'number'");
|
||||
assert(type("hello") == "string", "Type of string should be 'string'");
|
||||
assert(type(true) == "boolean", "Type of boolean should be 'boolean'");
|
||||
assert(type(false) == "boolean", "Type of boolean should be 'boolean'");
|
||||
assert(type(none) == "none", "Type of none should be 'none'");
|
||||
|
||||
// Test function types
|
||||
func testFunc() {
|
||||
return 42;
|
||||
}
|
||||
assert(type(testFunc) == "function", "Type of user function should be 'function'");
|
||||
assert(type(print) == "builtin_function", "Type of print should be 'builtin_function'");
|
||||
assert(type(input) == "builtin_function", "Type of input should be 'builtin_function'");
|
||||
assert(type(type) == "builtin_function", "Type of type should be 'builtin_function'");
|
||||
|
||||
// Test function calls
|
||||
assert(type(testFunc()) == "number", "Type of function call should be 'number'");
|
||||
assert(type(5 + 3) == "number", "Type of arithmetic should be 'number'");
|
||||
assert(type("hello" + "world") == "string", "Type of string concat should be 'string'");
|
||||
|
||||
print("✓ Type function working");
|
||||
|
||||
// ========================================
|
||||
// TEST 34: TONUMBER FUNCTION
|
||||
// ========================================
|
||||
print("\n--- Test 34: toNumber Function ---");
|
||||
|
||||
// Test basic number conversion
|
||||
assert(toNumber("42") == 42, "toNumber should convert string to number");
|
||||
assert(toNumber("3.14") == 3.14, "toNumber should convert decimal string");
|
||||
assert(toNumber("0") == 0, "toNumber should convert zero");
|
||||
assert(toNumber("-5") == -5, "toNumber should convert negative number");
|
||||
|
||||
// Test whitespace handling
|
||||
assert(toNumber(" 42 ") == 42, "toNumber should handle whitespace");
|
||||
assert(toNumber("\t3.14\n") == 3.14, "toNumber should handle tabs and newlines");
|
||||
|
||||
// Test type checking
|
||||
var converted_num = toNumber("42");
|
||||
assert(type(converted_num) == "number", "toNumber result should be number type");
|
||||
assert(converted_num + 10 == 52, "toNumber result should work in arithmetic");
|
||||
|
||||
// Test edge cases
|
||||
assert(toNumber("0.0") == 0, "toNumber should handle 0.0");
|
||||
assert(toNumber("1e6") == 1000000, "toNumber should handle scientific notation");
|
||||
assert(toNumber("1.23e-4") == 0.000123, "toNumber should handle small scientific notation");
|
||||
|
||||
print("✓ toNumber function working");
|
||||
|
||||
// ========================================
|
||||
// TEST 35: TOSTRING FUNCTION
|
||||
// ========================================
|
||||
print("\n--- Test 35: toString Function ---");
|
||||
|
||||
// Test basic types
|
||||
assert(toString(42) == toString(42), "toString should convert number to string");
|
||||
assert(toString(3.14) == toString(3.14), "toString should convert decimal to string");
|
||||
assert(toString("hello") == toString("hello"), "toString should return string as-is");
|
||||
assert(toString(true) == toString(true), "toString should convert boolean to string");
|
||||
assert(toString(false) == toString(false), "toString should convert boolean to string");
|
||||
assert(toString(none) == toString(none), "toString should convert none to string");
|
||||
|
||||
// Test function types
|
||||
func myFunc() {
|
||||
return 42;
|
||||
}
|
||||
assert(toString(myFunc) == toString(myFunc), "toString should format user functions");
|
||||
assert(toString(print) == toString(print), "toString should format builtin functions");
|
||||
assert(toString(input) == toString(input), "toString should format builtin functions");
|
||||
assert(toString(type) == toString(type), "toString should format builtin functions");
|
||||
assert(toString(toString) == toString(toString), "toString should format builtin functions");
|
||||
|
||||
// Test function calls
|
||||
assert(toString(myFunc()) == toString(42), "toString should convert function result");
|
||||
assert(toString(5 + 3) == toString(8), "toString should convert arithmetic result");
|
||||
assert(toString("hello" + "world") == toString("helloworld"), "toString should convert string concat result");
|
||||
|
||||
// Test type checking
|
||||
var str_result = toString(42);
|
||||
assert(type(str_result) == "string", "toString result should be string type");
|
||||
assert(str_result + " is a number" == toString(42) + " is a number", "toString result should work in string operations");
|
||||
|
||||
// Test nested calls
|
||||
assert(toString(toString(42)) == toString(42), "toString should handle nested calls");
|
||||
assert(toString(type(toString(42))) == toString("string"), "toString should handle complex nested calls");
|
||||
|
||||
// Test comparisons
|
||||
assert(toString(42) == toString(42), "toString should match itself");
|
||||
assert(toString(3.14) == toString(3.14), "toString should match itself");
|
||||
|
||||
print("✓ toString function working");
|
||||
|
||||
// ========================================
|
||||
// TEST 36: PRINT FUNCTION ENHANCEMENT
|
||||
// ========================================
|
||||
print("\n--- Test 36: Print Function Enhancement ---");
|
||||
|
||||
// Test that print works with all object types
|
||||
print("Testing print with all types:");
|
||||
print(42);
|
||||
print("hello");
|
||||
print(true);
|
||||
print(none);
|
||||
print(myFunc);
|
||||
print(print);
|
||||
print(input);
|
||||
print(type);
|
||||
print(toString);
|
||||
print(toNumber);
|
||||
|
||||
print("✓ Print function works with all object types");
|
||||
|
||||
// ========================================
|
||||
// TEST 37: REDEFINABLE FUNCTIONS
|
||||
// ========================================
|
||||
print("\n--- Test 37: Redefinable Functions ---");
|
||||
|
||||
// Test user function redefinition
|
||||
func testFunc() {
|
||||
return "original";
|
||||
}
|
||||
|
||||
assert(testFunc() == "original", "Original function should work");
|
||||
|
||||
func testFunc() {
|
||||
return "redefined";
|
||||
}
|
||||
|
||||
assert(testFunc() == "redefined", "Redefined function should work");
|
||||
|
||||
// Test built-in function override
|
||||
var original_print = print;
|
||||
|
||||
func print(value) {
|
||||
original_print("OVERRIDE: " + toString(value));
|
||||
}
|
||||
|
||||
print("This should show override prefix");
|
||||
|
||||
// Test multiple redefinitions
|
||||
func counter() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
func counter() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
func counter() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
assert(counter() == 3, "Final redefinition should be used");
|
||||
|
||||
print("✓ Redefinable functions working");
|
||||
|
||||
// ========================================
|
||||
// TEST 38: RECURSION
|
||||
// ========================================
|
||||
print("\n--- Test 38: Recursion ---");
|
||||
|
||||
// Test basic recursion
|
||||
func factorial(n) {
|
||||
if (n <= 1) {
|
||||
return 1;
|
||||
} else {
|
||||
return n * factorial(n - 1);
|
||||
}
|
||||
}
|
||||
|
||||
assert(factorial(0) == 1, "factorial(0) should be 1");
|
||||
assert(factorial(1) == 1, "factorial(1) should be 1");
|
||||
assert(factorial(5) == 120, "factorial(5) should be 120");
|
||||
|
||||
// Test Fibonacci
|
||||
func fibonacci(n) {
|
||||
if (n <= 1) {
|
||||
return n;
|
||||
} else {
|
||||
return fibonacci(n - 1) + fibonacci(n - 2);
|
||||
}
|
||||
}
|
||||
|
||||
assert(fibonacci(0) == 0, "fibonacci(0) should be 0");
|
||||
assert(fibonacci(1) == 1, "fibonacci(1) should be 1");
|
||||
assert(fibonacci(5) == 5, "fibonacci(5) should be 5");
|
||||
assert(fibonacci(8) == 21, "fibonacci(8) should be 21");
|
||||
|
||||
// Test mutual recursion
|
||||
func isEven(n) {
|
||||
if (n == 0) {
|
||||
return true;
|
||||
} else if (n == 1) {
|
||||
return false;
|
||||
} else {
|
||||
return isOdd(n - 1);
|
||||
}
|
||||
}
|
||||
|
||||
func isOdd(n) {
|
||||
if (n == 0) {
|
||||
return false;
|
||||
} else if (n == 1) {
|
||||
return true;
|
||||
} else {
|
||||
return isEven(n - 1);
|
||||
}
|
||||
}
|
||||
|
||||
assert(isEven(0) == true, "isEven(0) should be true");
|
||||
assert(isEven(10) == true, "isEven(10) should be true");
|
||||
assert(isEven(11) == false, "isEven(11) should be false");
|
||||
assert(isOdd(0) == false, "isOdd(0) should be false");
|
||||
assert(isOdd(11) == true, "isOdd(11) should be true");
|
||||
|
||||
// Test deep recursion
|
||||
func deepFactorial(n) {
|
||||
if (n <= 1) {
|
||||
return 1;
|
||||
} else {
|
||||
return n * deepFactorial(n - 1);
|
||||
}
|
||||
}
|
||||
|
||||
assert(deepFactorial(10) == 3628800, "deepFactorial(10) should be 3628800");
|
||||
|
||||
print("✓ Recursion working");
|
||||
|
||||
// ========================================
|
||||
// FINAL SUMMARY
|
||||
// ========================================
|
||||
@ -802,6 +1102,14 @@ print(" * Edge cases and complex expressions");
|
||||
print("- Time function (microsecond precision)");
|
||||
print("- Boolean + String concatenation");
|
||||
print("- Underscore support in variable names");
|
||||
print("- If statements (if, else, else if chains)");
|
||||
print("- Input function (user input capability)");
|
||||
print("- Type function (runtime type checking)");
|
||||
print("- toNumber function (string-to-number conversion)");
|
||||
print("- toString function (universal string conversion)");
|
||||
print("- Enhanced print function (works with all object types)");
|
||||
print("- Redefinable functions (including built-in function override)");
|
||||
print("- Recursion (factorial, fibonacci, mutual recursion, deep recursion)");
|
||||
|
||||
print("\n🎉 ALL TESTS PASSED! 🎉");
|
||||
print("Bob language is working correctly!");
|
||||
|
||||
@ -1,28 +0,0 @@
|
||||
// Test the time function
|
||||
print("Testing time function:");
|
||||
|
||||
var time1 = time();
|
||||
print("Time 1: " + time1);
|
||||
|
||||
var time2 = time();
|
||||
print("Time 2: " + time2);
|
||||
|
||||
var time3 = time();
|
||||
print("Time 3: " + time3);
|
||||
|
||||
var diff1 = time2 - time1;
|
||||
var diff2 = time3 - time2;
|
||||
|
||||
print("Difference 1-2: " + diff1 + " microseconds");
|
||||
print("Difference 2-3: " + diff2 + " microseconds");
|
||||
|
||||
// Test with some work in between
|
||||
var start = time();
|
||||
var sum = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10;
|
||||
var end = time();
|
||||
var duration = end - start;
|
||||
|
||||
print("Work duration: " + duration + " microseconds");
|
||||
print("Sum: " + sum);
|
||||
|
||||
print("Time function analysis complete!");
|
||||
Loading…
Reference in New Issue
Block a user