diff --git a/docs/changeblog.html b/docs/changeblog.html index 4dc6dcf..715c956 100644 --- a/docs/changeblog.html +++ b/docs/changeblog.html @@ -35,6 +35,7 @@ @@ -59,6 +58,7 @@

Available Modules

@@ -87,6 +87,34 @@

📦 Module System

+
+

Importing Modules

+

Learn how to import and use standard library modules in your Gem programs.

+ +

Basic Import Syntax

+
+
# Import math module
+require "math";
+
+# Import HTTP module
+require "http";
+
+# Use imported modules
+int sum = Math.add(10, 5);
+hash response = Http.get("https://api.example.com");
+
+ +

Module Availability

+
+

📦 Standard Library Modules

+ +
+
+

Math Module

The Math module provides mathematical operations and utility functions.

@@ -351,223 +379,78 @@

📡 HTTP Status Codes

-
-

Core Functions

-

These functions are available without any imports and provide essential I/O operations.

+
+

Time Module

+

The Time module provides basic time-related functionality including current time access, sleep operations, and function timing.

-

Output Functions

+

Importing the Time Module

-
# Print with newline
-puts "Hello, World!";                # Prints: Hello, World!\n
-puts 42;                             # Prints: 42
-puts true;                           # Prints: true
-puts false;                          # Prints: false
+
require "time";
-

Core Functions Reference

+

Current Time

-
# Complete core functions API
-puts(any value) void                 # Print value with newline
+
# Get current time as floating-point timestamp
+puts "Current timestamp: #{Time.now()}";
-
-
-

Importing Modules

-

Learn how to import and use standard library modules in your Gem programs.

- -

Basic Import Syntax

+

Sleep Operations

-
# Import math module
-require "math";
-
-# Import HTTP module
-require "http";
-
-# Use imported modules
-int sum = Math.add(10, 5);
-hash response = Http.get("https://api.example.com");
+
# Sleep for a specified number of milliseconds
+puts "Starting operation...";
+Time.sleep(2000);  # Sleep for 2 seconds (2000 milliseconds)
+puts "Operation completed after delay";
-

Multiple Imports

+

Function Timing

-
# Import multiple modules
-require "math";
-require "http";
-
-def fetchAndCalculate() void
-    # Make HTTP request
-    hash response = Http.get("https://api.example.com/numbers");
-    
-    if (response["success"] as bool)
-        # Use math operations on the response
-        int result = Math.multiply(10, 5);
-        puts "Calculation result: " + result;
-    end
-end
-
- -

Module Availability

-
-

📦 Standard Library Modules

-
    -
  • "math" - Mathematical operations
  • -
  • "http" - HTTP client functionality
  • -
-
-
- -
-

Usage Examples

-

Practical examples showing how to use the standard library.

- -

Mathematical Calculation Example

-
-
require "math";
-
-def calculateStats(int a, int b, int c) void
-    # Basic statistics
-    int sum = Math.add(Math.add(a, b), c);
-    int min = Math.min(Math.min(a, b), c);
-    int max = Math.max(Math.max(a, b), c);
-    
-    # Calculate average (integer division)
-    int average = Math.divide(sum, 3);
-    
-    # Calculate range
-    int range = Math.subtract(max, min);
-    
-    # Display results
-    puts "Sum: " + sum;
-    puts "Average: " + average;
-    puts "Min: " + min;
-    puts "Max: " + max;
-    puts "Range: " + range;
+                            
# Measure execution time of a function
+def slowOperation() void
+    Time.sleep(1000);  # Sleep for 1 second (1000 milliseconds)
+    puts "Slow operation completed";
 end
 
-# Usage
-calculateStats(10, 20, 30);
+# Measure function execution +Time.measure(slowOperation);
-

HTTP API Client Example

+

Timeout Operations

-
require "http";
-
-def fetchUserData(string userId) void
-    # Prepare headers
-    hash headers = {};
-    headers["Authorization"] = "Bearer your-api-token";
-    headers["Content-Type"] = "application/json";
-    
-    # Make GET request
-    string url = "https://api.example.com/users/" + userId;
-    hash response = Http.get(url, headers);
-    
-    # Handle response
-    bool success = response["success"] as bool;
-    int status = response["status"] as int;
-    
-    if (success)
-        puts "User data retrieved successfully!";
-        puts "Status: " + status;
-        puts "Response: " + (response["body"] as string);
-        puts "Response time: " + (response["response_time"] as int) + " microseconds";
-    else
-        puts "Failed to fetch user data";
-        puts "Status code: " + status;
-    end
+                            
# Attempt to run function with timeout
+def quickOperation() void
+    puts "Quick operation";
 end
 
-def createUser(string name, string email) void
-    # Prepare user data
-    hash userData = {};
-    userData["name"] = name;
-    userData["email"] = email;
-    userData["active"] = "true";
-    
-    # Prepare headers
-    hash headers = {};
-    headers["Content-Type"] = "application/json";
-    headers["Authorization"] = "Bearer your-api-token";
-    
-    # Make POST request
-    hash response = Http.post("https://api.example.com/users", userData, headers);
-    
-    # Handle response
-    if (response["success"] as bool)
-        puts "User created successfully!";
-        puts "Response: " + (response["body"] as string);
-    else
-        puts "Failed to create user";
-        puts "Status: " + (response["status"] as int);
-    end
+def slowOperation() void
+    Time.sleep(5000);  # Sleep for 5 seconds (5000 milliseconds)
+    puts "This takes too long";
 end
 
-# Usage examples
-fetchUserData("123");
-createUser("Alice Johnson", "alice@example.com");
+Time.timeout(quickOperation, 2); # 2 second timeout +Time.timeout(slowOperation, 2); # 2 second timeout
-

Combined Math and HTTP Example

+

Practical Time Examples

-
require "math";
-require "http";
-
-def calculateAndSubmit(int a, int b) void
-    # Perform calculations
-    int sum = Math.add(a, b);
-    int product = Math.multiply(a, b);
-    int power = Math.power(a, 2);
-    
-    puts "Calculations completed:";
-    puts "Sum: " + sum;
-    puts "Product: " + product;
-    puts "A squared: " + power;
-    
-    # Prepare data for submission
-    hash calculationData = {};
-    calculationData["input_a"] = "" + a;
-    calculationData["input_b"] = "" + b;
-    calculationData["sum"] = "" + sum;
-    calculationData["product"] = "" + product;
-    calculationData["power"] = "" + power;
-    
-    # Submit results via HTTP
-    hash headers = {};
-    headers["Content-Type"] = "application/json";
-    
-    hash response = Http.post("https://api.example.com/calculations", calculationData, headers);
-    
-    if (response["success"] as bool)
-        puts "Results submitted successfully!";
-        puts "Server response: " + (response["body"] as string);
-    else
-        puts "Failed to submit results";
-    end
+                            
# Simple timing and sleep operations
+def timedWork() void
+    puts "Starting work...";
+    Time.sleep(1500);  # 1.5 seconds of work
+    puts "Work completed";
 end
 
-# Usage
-calculateAndSubmit(10, 5);
-
- -

String Processing Example

-
-
# Basic string operations using built-in concatenation
-def createGreeting(string name) string
-    return "Hello, #{name}!";
-end
-
-def createBanner(string message) string
-    string border = "===================";
-    string spacedMessage = " #{message} ";
-    return "#{border}#{spacedMessage}#{border}";
-end
-
-# Usage
-string greeting = createGreeting("Alice");
-puts greeting;
-
-string banner = createBanner("WELCOME");
-puts banner;
+# Measure the work +puts "Timing work operation:"; +Time.measure(timedWork); + +# Multiple sleep operations +puts "Sleep sequence:"; +Time.sleep(500); # 0.5 seconds +puts "Step 1 complete"; +Time.sleep(1000); # 1.0 seconds +puts "Step 2 complete"; +Time.sleep(750); # 0.75 seconds +puts "All steps complete";
diff --git a/nullable_test.gem b/nullable_test.gem new file mode 100644 index 0000000..10b35fa --- /dev/null +++ b/nullable_test.gem @@ -0,0 +1 @@ +require "time"; int start = Time.now(); int? elapsed = Time.elapsed(start); puts elapsed; diff --git a/src/vm.c b/src/vm.c index c33351a..4448420 100644 --- a/src/vm.c +++ b/src/vm.c @@ -9,6 +9,7 @@ //< Strings vm-include-string //> Calls and Functions vm-include-time #include +#include //< Calls and Functions vm-include-time #include #include @@ -1208,6 +1209,59 @@ static Value httpDeleteWithOptionsNative(int argCount, Value* args) { return OBJ_VAL(responseHash); } +//> TIME Native Functions + +// Returns the current Unix epoch time (seconds since 1970-01-01T00:00:00 UTC). +// Includes microsecond precision. +static Value epochClockNative(int argCount, Value* args) { + struct timeval tv; + gettimeofday(&tv, NULL); + const double now = (double)tv.tv_sec + (double)tv.tv_usec / CLOCKS_PER_SEC; + return NUMBER_VAL(now); +} + +//< For using sleep functions +#if _WIN32 +#include +// Windows Sleep takes milliseconds +#define sleep_ms(ms) Sleep((DWORD)(ms)); +#else +#include +// Unix usleep takes nanoseconds +#define sleep_ms(ms) usleep((useconds_t)ms * 1e3); +#endif +//> + +// Set execution to sleep for a specified number of milliseconds. +static Value sleepNative(int argCount, Value* args) { + if (argCount != 1) { + runtimeError("sleep() takes 1 argument: time (in milliseconds)"); + return NIL_VAL; + } + + if (!IS_NUMBER(args[0])) { + runtimeError("sleep() first argument must be a positive time int"); + return NIL_VAL; + } + + const double milliseconds = AS_NUMBER(args[0]); + + if (milliseconds < 0) { + runtimeError("sleep() first argument must be a positive number"); + return NIL_VAL; + } + + if (milliseconds > UINT_MAX) { + runtimeError("sleep() first argument must not be bigger than 4294967295U"); + return NIL_VAL; + } + + sleep_ms(milliseconds); + + return NIL_VAL; +} +//< TIME Native Functions + void initVM() { #if FAST_STACK_ENABLED // Fast stack is pre-allocated, just reset the pointer @@ -1253,6 +1307,11 @@ void initVM() { defineNative("httpPutWithOptions", httpPutWithOptionsNative); defineNative("httpDeleteWithOptions", httpDeleteWithOptionsNative); //< HTTP Native Functions define + //> TIME Native Functions define + defineNative("epochClock", epochClockNative); + defineNative("sleepMs", sleepNative); + //< TIME Native Functions define + //> Initialize Compiler Tables initCompilerTables(); //< Initialize Compiler Tables diff --git a/stl/time.gem b/stl/time.gem new file mode 100644 index 0000000..9bea2ee --- /dev/null +++ b/stl/time.gem @@ -0,0 +1,97 @@ +module Time + def now() int + return epochClock(); + end + + def elapsed(int since) int? + int current = Time.now(); + # should raise an error instead of returning int? + if (since > current) + return nil; + end + return current - since; + end + + def sleep(int seconds) void + sleepMs(seconds); + end + + def measure(func f) int? + int start = Time.now(); + f(); + return Time.elapsed(start); + end + + def timeout(func f, int maxSeconds) bool + return Time.measure(f) <= maxSeconds; + end +end + +class Duration + def init(int milliseconds) void + if (milliseconds < 0) + this.milliseconds = 0; + return; + end + this.milliseconds = milliseconds; + end + + # ACCESSORS + def as_millis() int + return this.milliseconds; + end + + def as_seconds() int + return this.milliseconds / 1000; + end + + def as_minutes() int + return this.as_seconds() / 60; + end + + # OPERATIONS + def add(obj other) obj + if (other.milliseconds) + return Duration(this.milliseconds + other.milliseconds); + else + return this; + end + end + + def sub(obj other) obj + if (other.milliseconds) + if (this.milliseconds - other.milliseconds < 0) + return Duration(0) + else + return Duration(this.milliseconds - other.milliseconds); + end + else + return this; + end + end + + def mul(int factor) obj + return Duration(this.milliseconds * factor); + end + + def div(int divisor) obj + return Duration(this.milliseconds / divisor); + end + + # Comparisons + def gt(obj other) bool + return this.milliseconds > other.milliseconds; + end + + def lt(obj other) bool + return this.milliseconds < other.milliseconds; + end + + def eq(obj other) bool + return this.milliseconds == other.milliseconds; + end + + def to_string() string + return this.as_seconds().to_string() + "s"; + end +end diff --git a/version.conf b/version.conf index 7031fac..4313778 100644 --- a/version.conf +++ b/version.conf @@ -2,8 +2,8 @@ # This is the single source of truth for version information VERSION_MAJOR=1 -VERSION_MINOR=2 -VERSION_PATCH=2 +VERSION_MINOR=3 +VERSION_PATCH=0 VERSION_SUFFIX= # Derived version strings (automatically calculated)