Changelog

All notable changes to VDX, by version.

v0.1.4

2026-07-02
  • Optimized math.min() and math.max() to single-pass (track min/max and float flag in one loop instead of two)
  • math module expanded with 14 new functions: isPrime, primes, primeCount, sort, sortDesc, count, lcm, sum, mean, comb, hypot, lerp, e, tau
  • math.primes(n) uses Sieve of Eratosthenes for fast prime generation
  • math.isPrime(n) uses 6k±1 trial division — O(√n)
  • graph module expanded with 4 new functions: area, grid, color, legend
  • graph.area(xs, ys) — area chart with filled region below the line
  • graph.grid(bool) — toggle dashed grid lines on/off
  • graph.color(name) — set plot color (named colors or hex strings)
  • graph.legend(labels) — add a legend box with color swatches
  • All chart types (scatter, line, bar, hist) now respect graph.color() instead of hardcoded steelblue

v0.1.3

2026-06-30
  • Fixed for-in loops lacking loop safety protection — iterations are now timed and blocked if they exceed 2000ms, matching while and C-style for loop behavior
  • @unsafe annotation now correctly applies to for-in loops to bypass loop safety protection
  • math module expanded with 16 new functions: log, log2, log10, exp, cbrt, asin, acos, atan, atan2, degrees, radians, gcd, sign, clamp, factorial, fibonacci
  • math.fibonacci(n) uses fast doubling algorithm — O(log n) instead of O(n)

v0.1.2

2026-06-30
  • Fixed bare method calls losing object field mutations when break or continue is thrown inside a method
  • Fixed graph.bar() drawing bars from vMin instead of the zero line for mixed positive/negative values
  • Fixed Value::toString not escaping inner quotes in strings inside arrays and dicts
  • Fixed graph module escXml not escaping control characters — now escapes all control chars as numeric XML entities
  • Fixed graph module PlotState being shared across threads — changed to thread_local
  • Fixed lexer not handling \r and \0 escape sequences in string literals
  • Fixed math.floor(), math.ceil(), math.round() causing undefined behavior on very large float values — now checks bounds
  • Fixed graph.show() using tmpnam_s with a TOCTOU race condition — now uses std::filesystem::temp_directory_path() with random filename

v0.1.1

2026-06-30
  • Fixed for-in iterating over a copy of the array instead of the live array — modifications during iteration are now reflected
  • Fixed DotCallExpr method calls losing object field mutations when break or continue is thrown inside a method
  • Fixed graph.bar() rendering incorrectly with all-negative values — now computes proper axis range from data
  • Fixed integer overflow in ++/-- operators not being detected — now throws runtime error matching +/-/* checks
  • Fixed empty dict literal {} causing a parse error — now correctly produces an empty dictionary

v0.1.0

2026-06-29
  • this system overhaul — this now returns the actual object instead of doing scope lookup, fixing param/field shadowing bugs
  • Fixed this.field = value parse error — this field assignment now works inside methods
  • Fixed this.method() parse error — this method calls now work inside methods
  • Fixed method-to-method calls losing object context — calling a bare method name from within another method now properly pushes object fields as scope
  • Fixed new re-executing side-effect statements (e.g. print) on every instantiation — only let field initializers are executed now
  • Fixed class executing non-function statements at declaration time — now only registers methods
  • Fixed nested imports not being processed — imported files' own import statements are now resolved recursively
  • Fixed math.random(min, max) rejecting min == max — now returns min instead of erroring
  • C++ quality: noexcept on simple getters, const correctness on isVarConst and isTruthy
  • graph module — new plotting and data visualization module (SVG vector graphics output): graph.scatter(), graph.line(), graph.bar(), graph.hist(), graph.title(), graph.xlabel(), graph.ylabel(), graph.save(path), graph.show()

v0.0.15

2026-06-28
  • class{} wrapper is no longer mandatory — top-level statements (print, let, fn, if, while, for, etc.) can now be written directly without a class wrapper
  • Top-level function declarations are now supported: fn add(a, b) { ... } at file scope
  • Top-level functions are importable: imported files can export plain functions (not just class methods)
  • Added recommendation warning: when a VDX file has no class declaration, a tip is printed to stderr suggesting class{} for better organization
  • class{} is now recommended but optional — existing code with classes continues to work unchanged
  • Fixed math.round() returning FLOAT instead of INT for float inputs — now returns INT like math.floor() and math.ceil()
  • Fixed math.random(max) being exclusive (0 to max-1) — now inclusive (0 to max) for consistency with math.random(min, max)
  • Fixed return/break/continue at top level (outside function/loop) causing crash — now handled gracefully
  • Fixed return/break/continue in class body (outside functions) causing crash — now handled gracefully
  • Fixed return/break/continue during object construction (new) causing crash — now handled gracefully
  • Fixed scope leak in execClass on exception — scope is now properly popped on all exit paths
  • Fixed scope leak in execNew on exception — scope is now properly popped on all exit paths

v0.0.14

2026-06-28
  • Fixed scope leak on return inside if blocks, while, for, and for-in loops
  • Fixed math module never being registered at startup
  • Fixed module function dispatch for math.sqrt() etc. — now checks moduleFunctions before object lookup
  • Module constants like math.pi now work via DotExpr with 0 args
  • Fixed std::stoi/std::stod throwing uncaught std::out_of_range on out-of-range literals
  • Fixed undefined behavior: isdigit/isalpha/isalnum in lexer now receive unsigned char cast
  • Fixed const variables modifiable via push(), pop(), arr[i]=, obj.f=, and ++/--
  • Fixed break/continue escaping method call boundaries via DotCallExpr
  • Fixed duplicate function names across classes — methods now namespaced as ClassName::funcName
  • Fixed math.floor() and math.ceil() returning FLOAT instead of INT
  • Fixed duplicate class names silently overwriting each other — now throws error
  • Added unary minus/plus operator support: let x = -5;, 5 - -3 now parse correctly
  • Fixed static module registration flag breaking multiple Interpreter instances
  • Fixed math functions silently accepting non-numeric arguments — now throws type error

v0.0.13

2026-06-27
  • Fixed continue in while and for loops corrupting the scope stack (double popScope)
  • Fixed loop safety check logic: now correctly flags iterations taking >2s instead of <2s
  • Fixed break/continue escaping function call boundaries into outer loops
  • Fixed import crashing with unhandled exception when file doesn't exist (now gives clean error)
  • Fixed signed integer overflow causing undefined behavior in +, -, * — now throws runtime error
  • Fixed duplicate function names across classes silently overwriting each other — now throws error
  • Fixed new capturing temporary variables (e.g. loop counters) as object fields — only captures let declarations
  • Added func as alias for fn keyword: func add(a, b) { ... }
  • Added ++/-- syntax in for-loop update: for (let i = 0; i < 10; i++) { ... }
  • Added math module to CMake build (was missing — dead code)
  • Fixed math module function signatures to match interpreter's ModuleFunc type
  • Added #include for portable isdigit/isalpha usage in lexer and main
  • Added compiler warnings (/W4 on MSVC, -Wall -Wextra -Wpedantic on GCC/Clang)
  • Replaced std::rand() with std::mt19937 for better random number quality
  • Replaced hardcoded PI with M_PI from
  • Replaced std::endl with \n in print to avoid unnecessary flush
  • Refactored repetitive try/catch in if/elif/else into execBlock helper
  • Improved extractLine robustness: searches for "at line " instead of just "line "
  • Removed pointless pushScope/popScope in execImport

v0.0.12

2026-06-15
  • Added dictionary/map type: let user = {"name": "Alice", "age": 30};
  • Dictionary access: user["name"] returns the value for a key
  • Dictionary assignment: user["city"] = "Paris"; adds or updates keys
  • Dictionary length: len(user) returns number of key-value pairs
  • Added fs module with file I/O: fs.readFile(path) and fs.writeFile(path, content)
  • Added array type annotations: let nums: int[] = [1, 2, 3];
  • Added dict type annotation: let user: dict = {"name": "Bob"};

v0.0.11

2026-06-15
  • Added import statement: import other VDX files with import "filename.vdx";
  • Imported files provide access to their classes and functions
  • Circular import protection prevents infinite loops
  • Added type(value) built-in: returns type name as string ("int", "float", "string", "bool", "array", "object", "void")
  • Added input() built-in: read user input from stdin
  • Added input(prompt) variant: print prompt then read input
  • Added pop(arr) built-in: remove and return last element from array
  • Extended len(obj): now works with objects, returning number of fields
  • len() now supports arrays, strings, and objects

v0.0.10

2026-06-08
  • Added modulo operator % for game calculations (e.g., x % 2, playerIndex % teamSize)
  • Added increment ++ and decrement -- operators
  • Prefix form: ++x and --x (returns new value)
  • Postfix form: x++ and x-- (returns old value)
  • MSI installer now properly adds vdx to system PATH

v0.0.9

2026-06-08
  • Added break statement for exiting loops early
  • Added continue statement for skipping to next loop iteration
  • Added const keyword for declaring immutable constants
  • Constants support type annotations: const PI: float = 3.14;
  • Added math module with 12+ functions: sqrt, pow, abs, sin, cos, tan, floor, ceil, round, min, max, random, pi
  • Interpreter tracks const variables to prevent reassignment
  • Loop control statements work with while, for, and for-in loops
  • Break/continue exceptions properly propagate through function calls

v0.0.8

2026-03-23
  • Added float type: float literals with decimal point (e.g., 3.14, 5.0)
  • Added true / false boolean literals
  • Added optional type annotations on let: let x: int = 5;, let pi: float = 3.14;
  • Runtime type checking: annotated variables are validated at assignment
  • Mixed int/float arithmetic: operations auto-promote to float when either operand is float
  • Added new keyword for object instantiation: let obj = new ClassName();
  • Dot field access: obj.field reads a field from an object
  • Dot field assignment: obj.field = value; sets a field on an object
  • Dot method calls: obj.method(args) calls a method with access to object fields
  • Objects print as
  • Added C-style for loop: for (let i = 0; i < n; i = i + 1) { ... }
  • Added for-in loop over arrays: for (item in arr) { ... }
  • @unsafe now also works with for loops
  • Float truthiness: 0.0 is falsy, non-zero is truthy
  • Object truthiness: objects are truthy

v0.0.7

2026-03-22
  • Added arrays / lists: let arr = [1, 2, 3];
  • Array index access: arr[0]
  • Array index assignment: arr[0] = 5;
  • String index access: str[0] returns single character
  • Built-in len(): returns length of arrays and strings
  • Built-in push(arr, value): appends a value to an array
  • Array printing: print(arr) outputs [1, 2, 3]
  • Array truthiness: non-empty arrays are truthy, empty arrays are falsy
  • Improved error reporting: errors now display file name, line number, and surrounding source lines

v0.0.6

2026-03-22
  • Added loop safety protection: while loops that iterate faster than 2 seconds are blocked
  • Added @unsafe annotation: place before while to bypass loop speed protection
  • Added SVG icon (assets/icon.svg)
  • Added Windows MSI installer support via CMake CPack + WiX
  • Installer adds vdx to system PATH
  • Added .vdx file association in installer
  • Added LICENSE.txt (MIT)
  • Website v0.1.0: main page, download page, documentation pages

v0.0.5

2026-03-22
  • Added while loop: while (condition) { body }
  • Added block scoping: variables declared inside { } blocks are local
  • Added wait(ms) statement to pause execution
  • Added variable reassignment: name = expr;

v0.0.4

2026-03-22
  • Added this keyword for accessing class-scope variables
  • Added if / elif / else control flow
  • Inline expression evaluation in print()
  • Truthiness rules: int != 0, non-empty string, bool value, void = false

v0.0.3

2026-03-22
  • Added fn keyword for function declarations with parameters
  • Added return statement for function return values
  • Function calls as expressions
  • Operators: +, -, *, /, ==, !=, <, >, <=, >=
  • String concatenation with +
  • Operator precedence and parenthesized expressions
  • Division by zero runtime error
  • Two-pass class execution (register functions first, then run statements)

v0.0.2

2026-03-22
  • Added let keyword for variable declarations
  • Variables support string and integer values
  • Variables can be used in print() arguments
  • Added expression system (string literals, integer literals, identifiers)

v0.0.1

2026-03-22
  • Initial release
  • Lexer with support for strings, integers, identifiers, keywords, symbols
  • Parser for class declarations and print() statements
  • Tree-walking interpreter
  • class keyword: declare named classes with a body
  • print(): output string literals to stdout
  • Line comments (//)