Skip to content

Devilcord/Vex

Repository files navigation

Vex

CI

Vex is a small, dynamically-typed scripting language implemented in C, with its own lexer, recursive-descent parser, and tree-walking interpreter — plus a CLI to run source files, and a Windows installer (Inno Setup) that puts vex on your PATH and associates its file types with the Vex CLI.

vex script.vex        # run a file
vex --version          # print version
vex --help             # usage

File types

Extension Name Purpose
.vex Vex Script A runnable program: vex myprogram.vex
.vh Vex Header File Shared structs/functions, pulled into a script with import "file.vh";

There's no special syntax inside a .vh file — it's ordinary Vex source. .vex vs .vh is purely a naming convention for "this file is meant to be run" vs. "this file is meant to be imported," the same way .c vs .h works in C.

Language features

  • Dynamic typing: nil, bool, number (double), string, array, struct, function
  • Variables: let x = 10;
  • Control flow: if/else, while, for x in <array>, break, continue
  • Functions with closures and recursion: fn add(a, b) { return a + b; }
  • Anonymous functions: let f = fn(x) { return x * 2; };
  • Structs: struct Point { x, y } and literals Point { x: 1, y: 2 }, field access/assignment p.x, p.x = 5;
  • Arrays: [1, 2, 3], indexing a[0], assignment a[0] = 9;, push/pop
  • Operators: + - * / %, comparisons, == !=, && ||, !, unary -
  • Strings: concatenation with +, indexing, upper/lower/split/join
  • Imports: import "mathutils.vh"; pulls a header's top-level struct/fn declarations directly into the importing scope. Paths are resolved relative to the importing file's own directory; a file is only ever imported once even if imported from multiple places.
  • Standard library: print, println, len, type_of, str, num, input, math (sqrt, floor, ceil, abs, pow, min, max, random), arrays (push, pop, range), and file I/O (read_file, write_file, append_file, file_exists)

See examples/demo.vex for a tour of the core language, examples/hello.vex for a minimal starting point, and examples/mathutils.vh + examples/uses_header.vex for the header/import feature.

Project layout

src/            interpreter source (C11, no dependencies besides libc/libm)
  vex.h         shared types (tokens, AST, values, env)
  lexer.c       source text -> tokens
  parser.c      tokens -> AST (recursive descent)
  value.c       runtime value helpers
  env.c         variable scopes / closures
  interpreter.c tree-walking evaluator + standard library
  main.c        CLI entry point
Makefile        builds ./vex (or vex.exe on Windows/MinGW)
examples/       sample .vex scripts and .vh headers
installer/      Inno Setup script + prebuilt vex.exe for packaging

Building

Linux / macOS:

make
./vex examples/demo.vex

Windows, cross-compiled from Linux/macOS with MinGW-w64:

x86_64-w64-mingw32-gcc -O2 -std=c11 -o vex.exe src/*.c -lm

(vex.exe in installer/ was built exactly this way.)

Windows, natively (MSVC or MinGW installed on Windows):

gcc -O2 -std=c11 -o vex.exe src\lexer.c src\parser.c src\value.c src\env.c src\interpreter.c src\main.c -lm

or open a Developer Command Prompt and use cl if you prefer MSVC — the code is portable C11 with no POSIX-only calls besides strdup (already guarded).

Building the Windows installer

Two installer implementations, functionally equivalent - pick whichever toolchain you'd rather use:

  • installer/vex.iss (Inno Setup) - the original. Windows-only to build.
  • installer-nsis/vex.nsi (NSIS) - see installer-nsis/README.md. NSIS has an official Linux build, so this one can (and does, in CI) get built without a Windows runner.

Inno Setup

The installer lives in installer/vex.iss and already expects vex.exe to sit right next to it (it's included, prebuilt via MinGW).

  1. Install Inno Setup (free) on Windows.
  2. If you rebuilt vex.exe, drop the new one into installer/, replacing the old one.
  3. Open installer/vex.iss in the Inno Setup Compiler (or run ISCC vex.iss from a command prompt) and build.
  4. The installer is written to installer/output/VexSetup-1.0.0.exe.

The installer:

  • Installs to Program Files\Vex (or per-user if not run elevated).
  • Has an "Add Vex to the system PATH" task, checked by default, so after installing you can open a new terminal and just run vex myscript.vex from anywhere.
  • Has an "Associate .vex and .vh with Vex" task, checked by default. This is driven by a real .reg file, installer/vex_file_associations.reg: at install time, the [Code] section reads that template, substitutes the actual install path for the INSTALL_PATH placeholder (and, for a per-user install, redirects HKEY_CLASSES_ROOT to HKEY_CURRENT_USER\Software\Classes), writes the patched file to a temp folder, and imports it with reg.exe import. Double-clicking a .vex file then runs it with vex.exe; double-clicking a .vh file opens it in Notepad (headers are meant to be imported, not run directly — you can still run one explicitly with vex file.vh if you want). The same template, with the placeholder left in, ships in {app} for reference or manual re-association.
  • Cleanly removes itself, its PATH entry, and its file associations on uninstall.
  • Ships examples/*.vex, examples/*.vh, and this README alongside the executable.

Known limitations

This is a from-scratch teaching/hobby-scale interpreter, not a production language:

  • No garbage collector — memory used by a running script is freed when the process exits, not incrementally. Fine for scripts; not for long-running daemons.
  • No module/import system — one file per run.
  • Struct instances copy by reference (assigning let b = a; for a struct or array shares the same underlying object, same as arrays/objects in most scripting languages).
  • Numbers are always doubles (no separate int type).

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages