GladLang
A dynamic, interpreted, object-oriented programming language
This is a full interpreter built from scratch in Python, complete with a lexer, parser and runtime environment. It supports modern programming features like closures, classes, inheritance and robust error handling.
Table of Contents
Key Features
GladLang supports a rich, modern feature set:
Data Types
Numbers (Int/Float/Hex/Octal/Binary), Strings, Lists, Dictionaries, Booleans, Null and Enums.
Variables
Dynamic assignment with LET. Supports Destructuring.
String Power
Interpolation (Template Strings) and Multi-line strings.
List Manipulation
Indexing, Slicing, Nested List Comp and Dict Comprehensions.
Operators
Arithmetic, Logical, Bitwise and Ternary Operators.
Control Flow
IF, SWITCH, WHILE and Iterator/C-Style FOR loops.
Functions
First-class citizens, Closures, Recursion and Overloading (by argument count).
Object-Oriented Programming
Classes, Multiple Inheritance (MRO), SUPER delegation, polymorphism, Static Members and Encapsulation (Public/Private/Protected).
Advanced Operators
Pre- and post-increment/decrement operators.
Advanced Math
Compound assignments (+=, *=), Power and Modulo support.
Enums
Fully encapsulated, immutable ENUM types with auto-incrementing values and class visibility.
Built-ins
PRINTLN, INPUT, STR, INT, FLOAT, BOOL, LEN, TIME, RANDOM, DELAY, EPRINT, CLEAR, INSERT, POP, DELETE, ORD, CHR, GETATTR, SETATTR, ATTRS, EXIT, ENV, READ_FILE, WRITE_FILE, DELETE_FILE, LIST_DIR.
Error Handling
Robust, user-friendly runtime error reporting with full tracebacks.
Memory & Logic Safety
Atomic Locking for constants, Iteration Scoping for loops, full Short-Circuit Evaluation and Resource Limits on collections, strings, recursion and list repetition (1,000,000 elements).
Getting Started
1. Installation
Option A: Install via Pip (Recommended)
pip install gladlang
Option B: Use from Releases
Pre-built binaries for Windows, Linux, and macOS are available on the GitHub Releases page.
Option C: Install from Source (For Developers)
If you want to modify the codebase, clone the repository and install it in editable mode:
git clone --depth 1 https://github.com/gladw-in/gladlang.git cd gladlang pip install -e .
2. Usage
Interactive Shell:
gladlang
Running a Script:
gladlang "tests/test.glad"
Inline Execution:
gladlang "PRINTLN 10 + 5"
Passing Arguments to INPUT():
gladlang "script.glad" arg1 arg2
Help & Version:
gladlang --help gladlang --version
3. Running Without Installation
If running from source without pip, use the helper script:
python run.py "tests/test.glad"
Language Tour (Syntax Reference)
Here is a guide to the GladLang syntax, with examples from the tests/ directory.
1. Comments
Comments start with # and last for the entire line.
# This is a comment. LET a = 10 # This is an inline comment
2. Variables and Data Types
Variables & Constants
Use LET for mutable variables and FINAL for constants.
LET a = 10 LET b = "Hello" a = 20 # Allowed FINAL PI = 3.14 # PI = 3.15 # Error: Cannot reassign constant
Destructuring Assignment
You can unpack lists directly into variables.
LET point = [10, 20] LET [x, y] = point
Numbers
Numbers can be integers, floats, or Hex/Octal/Binary literals.
LET math_result = (1 + 2) * 3 # 9 LET float_result = 10 / 4 # 2.5 LET hex = 0xFF # 255 LET oct = 0o77 # 63 LET bin = 0b101 # 5 LET big = 1_000_000 # 1000000 (underscores allowed) LET sci = 6.022e23 # scientific notation
Strings
Strings can be defined in three ways:
- Double Quotes: Standard strings.
- Triple Quotes: Multi-line strings that preserve formatting.
- Backticks: Template strings supporting interpolation.
# Standard LET s = "Hello\nWorld" # Multi-line LET menu = """ 1. Start 2. Settings 3. Exit """ # Indexing LET char = "GladLang"[0] # "G" PRINTLN "Hello"[1] # "e" # Escapes (work in "..." and `...`) PRINTLN "Line 1\nLine 2" PRINTLN `Column 1\tColumn 2` PRINTLN "Quote: \"Hi\" and backslash: \\" PRINTLN "Unicode: \u0041" # Unicode: A PRINTLN `Escaped: \` and \${not_interpolated}` # Interpolation (Template Strings) LET name = "User" PRINTLN `Welcome back, ${name}!` PRINTLN `5 + 10 = ${5 + 10}`
Lists, Slicing & Comprehensions
Lists are ordered collections. You can access elements, slice them, or create new lists dynamically.
LET nums = [0, 1, 2, 3, 4, 5] # Indexing & Assignment PRINTLN nums[1] # 1 LET copy = [0, 1, 2] LET copy[1] = 100 PRINTLN copy # [0, 100, 2] # Slicing [start:end] PRINTLN nums[0:3] # [0, 1, 2] PRINTLN nums[3:] # [3, 4, 5] PRINTLN nums[-2:] # [4, 5] (negative indexes work) PRINTLN nums[:-1] # [0, 1, 2, 3, 4] PRINTLN "Hello World"[0:5] # Hello (strings slice too) # List Comprehension LET squares = [n ** 2 FOR n IN nums] PRINTLN squares # [0, 1, 4, 9, 16, 25] # Nested Comprehension LET pairs = [[x, y] FOR x IN [1, 2] FOR y IN [3, 4]] PRINTLN pairs # [[1, 3], [1, 4], [2, 3], [2, 4]]
Dictionaries
Dictionaries are key-value pairs enclosed in {}. Keys must be Strings or Numbers.
LET person = { "name": "Glad", "age": 25, "is_admin": TRUE } PRINTLN person["name"] # Access: "Glad" LET person["age"] = 26 # Modify LET person["city"] = "NYC" # Add new key # Dictionary Comprehension LET keys = ["a", "b", "c"] LET d = {k: 0 FOR k IN keys} PRINTLN d # {"a": 0, "b": 0, "c": 0}
Booleans
Booleans are TRUE and FALSE. They are the result of comparisons and logical operations.
LET t = TRUE LET f = FALSE PRINTLN t AND f # 0 (False) PRINTLN t OR f # 1 (True) PRINTLN NOT t # 0 (False)
Truthiness: 0, 0.0, "", NULL, FALSE, empty lists [] and empty dicts {} are "falsy." All other values (including non-empty strings, non-zero numbers, non-empty lists and dicts, functions and classes) are "truthy."
Null
The NULL keyword represents a null or "nothing" value. It is falsy and prints as null. Functions with no RETURN statement implicitly return NULL.
Important: NULL is a distinct value representing "nothing". It is not numerically equal to 0 (e.g., NULL == 0 → FALSE). For identity checks, use the IS operator (NULL IS NULL → TRUE; NULL IS 0 → FALSE).
Enums
GladLang supports strict, immutable ENUM types. Enums can be zero-indexed implicitly, or you can assign explicit values. They also support comma-separated cases.
# Basic Enum (Implicit 0-indexing) ENUM Colors RED GREEN BLUE ENDENUM PRINTLN Colors.RED.value # 0 PRINTLN Colors.GREEN.value # 1 # Explicit & Auto-Incrementing ENUM HTTPStatus OK = 200 NOT_FOUND = 404 CUSTOM_ERROR # Implicitly becomes 405 ENDENUM # Comma-Separated ENUM Days MON, TUE, WED, THU, FRI ENDENUM
3. Operators
Math Operations
Standard arithmetic plus Power (**), Floor Division (//) and Modulo (%).
Standard division / always returns a Float.
PRINTLN 2 ** 3 # Power: 8 PRINTLN 10 // 3 # Floor Division: 3 PRINTLN 10 % 3 # Modulo: 1 PRINTLN 100 / 2 # 50.0 (Float)
Compound Assignments
Update variables in place using syntactic sugar.
LET score = 10 score += 5 # 15 score -= 2 # 13 score *= 2 # 26 score /= 2 # 13.0 score %= 5 # 3.0
Bitwise Operators
Perform binary manipulation on integers.
All bitwise operations are performed on signed 32‑bit integers (two's complement).
LET a = 5 # 101 LET b = 3 # 011 PRINTLN a & b # 1 (AND) PRINTLN a | b # 7 (OR) PRINTLN a ^ b # 6 (XOR) PRINTLN ~a # -6 (bitwise NOT) PRINTLN 1 << 2 # 4 (Left Shift) PRINTLN 8 >> 2 # 2 (Right Shift) # Compound Assignment LET x = 1 x <<= 2 # x is now 4
Comparisons, Logic & Type Checking
Compare values, check object identity and perform runtime type checking.
# Equality & Inequality PRINTLN 1 == 1 # True PRINTLN 1 != 2 # True # Chained Comparisons IF 18 <= age < 30 THEN PRINTLN "Young Adult" ENDIF # Identity Check ('IS') LET a = [1, 2] LET b = a PRINTLN b IS a # True # Type Checking ('INSTANCEOF') CLASS Animal ENDCLASS CLASS Dog INHERITS Animal ENDCLASS LET d = NEW Dog() PRINTLN d INSTANCEOF Dog # 1 (True) PRINTLN d INSTANCEOF Animal # 1 (True) # Built-in types: Number, String, List, Dict, Enum, Function, Object PRINTLN 5 INSTANCEOF Number # 1 (True) PRINTLN "hi" INSTANCEOF List # 0 (False)
Increment / Decrement
Supports C-style pre- and post-increment/decrement.
LET i = 5 PRINTLN i++ # 5 PRINTLN i # 6 PRINTLN ++i # 7 PRINTLN i # 7 LET my_list = [10, 20] PRINTLN my_list[1]++ # 20 PRINTLN my_list[1] # 21
Ternary Operator
Concise conditional logic.
LET age = 20 LET type = age >= 18 ? "Adult" : "Minor" PRINTLN type # "Adult" # Nested Ternary LET score = 85 LET grade = score > 90 ? "A" : score > 80 ? "B" : "C" PRINTLN grade # "B"
4. Control Flow
IF / ELSE IF / ELSE
Supports complex conditional logic.
LET score = 85 IF score > 90 THEN PRINTLN "Excellent" ELSE IF score > 50 THEN PRINTLN "Pass" ELSE PRINTLN "Fail" ENDIF
Switch Statements
Use SWITCH for multi-way branching. It supports values, lists and expressions.
LET status = 200 SWITCH status CASE 200: PRINTLN "OK" CASE 404, 500: PRINTLN "Error" DEFAULT: PRINTLN "Unknown" ENDSWITCH
WHILE Loops
Loops while a condition is TRUE.
LET i = 3 WHILE i > 0 PRINTLN "i = " + i i = i - 1 ENDWHILE # Prints: # i = 3 # i = 2 # i = 1
FOR Loops
GladLang supports both modern collection iterators and classic C-style loops. Both feature Iteration-Level Scoping.
# 1. Collection Iterator (List, String, Dict) FOR item IN [1, 2, 3] PRINTLN item ENDFOR # 2. Loop over Dictionary (Iterate Keys Safely) LET data = {"a": 1, "b": 2} FOR key IN data LET val = data[key] PRINTLN `${key}: ${val}` ENDFOR # 3. Loop Destructuring (Unpacking) LET points = [[1, 2], [3, 4]] FOR [x, y] IN points PRINTLN `x: ${x}, y: ${y}` ENDFOR # 4. C-Style FOR Loop # Recreates a fresh body context on every iteration FOR (LET i = 0; i < 5; i++) PRINTLN `Iteration: ${i}` ENDFOR
BREAK and CONTINUE are supported in all loop types.
5. Functions
Named Functions
Defined with FUNC...ENDFUNC. Arguments are passed by value. RETURN sends a value back.
FUNC add(a, b) RETURN a + b ENDFUNC LET sum = add(10, 5) PRINTLN sum # 15
Function Overloading
Define multiple functions with the same name but different argument counts.
FUNC add(a, b) RETURN a + b ENDFUNC FUNC add(a, b, c) RETURN a + b + c ENDFUNC
Anonymous Functions
Functions can be defined without a name, perfect for assigning to variables.
LET double = FUNC(x) RETURN x * 2 ENDFUNC PRINTLN double(5) # 10
Closures
Functions capture variables from their parent scope.
FUNC create_greeter(greeting) FUNC greeter_func(name) # 'greeting' is "closed over" from the parent RETURN greeting + ", " + name + "!" ENDFUNC RETURN greeter_func ENDFUNC LET say_hello = create_greeter("Hello") PRINTLN say_hello("Alex") # "Hello, Alex!"
Recursion
Functions can call themselves.
FUNC fib(n) IF n <= 1 THEN RETURN n ENDIF RETURN fib(n - 1) + fib(n - 2) ENDFUNC PRINTLN fib(7) # 13
6. Object-Oriented Programming (OOP)
Classes and Instantiation
Use CLASS...ENDCLASS to define classes. The constructor is a method named exactly after the class (which supports Overloading).
CLASS Counter FUNC Counter() THIS.count = 0 # 'THIS' is the instance ENDFUNC FUNC increment() THIS.count = THIS.count + 1 ENDFUNC FUNC get_count() RETURN THIS.count ENDFUNC ENDCLASS
The THIS Keyword
THIS is used to access instance attributes and methods. It is automatically available inside all non-static methods; you do not need to pass it as an argument.
LET c = NEW Counter() c.increment() PRINTLN c.get_count() # 1
Inheritance & The SUPER Keyword
Use the INHERITS keyword. You can seamlessly call parent constructors and overridden methods using SUPER. GladLang enforces strict visibility rules (LSP) and prevents circular inheritance loops.
CLASS Pet FUNC Pet(name) THIS.name = name ENDFUNC FUNC speak() RETURN "makes a generic pet sound." ENDFUNC ENDCLASS CLASS Dog INHERITS Pet FUNC Dog(name) SUPER(name) # Auto-delegates to parent ENDFUNC FUNC speak() PRINTLN THIS.name + " says: Woof, and " + SUPER.speak() ENDFUNC ENDCLASS LET my_dog = NEW Dog("Buddy") my_dog.speak() # "Buddy says: Woof, and makes a generic pet sound."
Multiple Inheritance & MRO
GladLang supports multiple and hybrid inheritance (solving the Diamond Problem). When inheriting from multiple classes, GladLang establishes a Method Resolution Order (MRO) that prioritizes parents from left to right. To bypass the default SUPER() MRO, call parent constructors or methods directly using the Class name.
CLASS Animal FUNC Animal() PRINTLN("Animal Constructor") ENDFUNC FUNC speak() RETURN "Generic Sound" ENDFUNC ENDCLASS CLASS Human FUNC Human() PRINTLN("Human Constructor") ENDFUNC FUNC speak() RETURN "Hello" ENDFUNC ENDCLASS CLASS Dog INHERITS Animal, Human FUNC Dog() # STYLE 1: Explicit calls bypass default MRO Animal.Animal() Human.Human() # STYLE 2: SUPER() follows MRO (calls Animal first) SUPER() ENDFUNC FUNC speak() RETURN "Woof! " + SUPER.speak() + " " + Human.speak() ENDFUNC ENDCLASS # Expected speak(): Woof! Generic Sound Hello
Method & Constructor Overloading
Classes support overloading for both regular methods and constructors. This allows for flexible object creation (e.g., Copy Constructors).
CLASS Vector # Default Constructor FUNC Vector() THIS.x = 0 THIS.y = 0 ENDFUNC # Overloaded Constructor FUNC Vector(x, y) THIS.x = x THIS.y = y ENDFUNC # Copy Constructor FUNC Vector(other) THIS.x = other.x THIS.y = other.y ENDFUNC ENDCLASS LET v1 = NEW Vector() # [0, 0] LET v2 = NEW Vector(10, 20) # [10, 20] LET v3 = NEW Vector(v2) # [10, 20] (Copy of v2)
Polymorphism
When a base class method calls another method on THIS, it will correctly use the child's overridden version.
CLASS Pet FUNC Pet(name) THIS.name = name ENDFUNC FUNC introduce() PRINTLN "I am a pet and I say:" THIS.speak() ENDFUNC FUNC speak() PRINTLN "(Generic pet sound)" ENDFUNC ENDCLASS CLASS Cat INHERITS Pet FUNC speak() PRINTLN "Meow!" ENDFUNC ENDCLASS LET my_cat = NEW Cat("Whiskers") my_cat.introduce() # Prints: # I am a pet and I say: # Meow!
Access Modifiers
Control visibility with PUBLIC, PRIVATE and PROTECTED. Private members are name-mangled for safety.
- Encapsulation: Private attributes are name-mangled to prevent collisions.
- Singleton Support: Constructors can be private to force factory usage.
CLASS Secure FUNC Secure() PRIVATE THIS.secret = "Hidden" ENDFUNC PUBLIC FUNC get_secret() RETURN THIS.secret ENDFUNC ENDCLASS
Static Members
GladLang supports Java-style static fields and methods using STATIC.
CLASS Config # A constant shared by everyone STATIC FINAL MAX_USERS = 100 # A private static variable STATIC PRIVATE LET internal_count = 0 STATIC PUBLIC FUNC increment() Config.internal_count = Config.internal_count + 1 RETURN Config.internal_count ENDFUNC ENDCLASS # Access directly via the Class name PRINTLN Config.MAX_USERS # 100 PRINTLN Config.increment() # 1
7. Built-in Functions
PRINTLN(value): Prints a value to the console with a new line.PRINT(value): Prints a value to the console without a new line.INPUT(): Reads a line of text from the user as a String.STR(value): Casts a value to a String.INT(value): Casts a String or Float to an Integer.FLOAT(value): Casts a String or Integer to a Float.BOOL(value): Casts a value to its Boolean representation (TRUEorFALSE).LEN(value): Returns the length of a String, List, or Dict. Alias:LENGTH().PRINTF(format, ...): Prints formatted text. Supports%s(string),%d(integer),%f(float, with optional precision such as%.2f) and%%(literal percent). Width specifiers such as%5dare not supported. Extra arguments are ignored.TIME(): Returns the current time as a float (seconds since epoch).TIME_SECONDS(): Returns the current time as an integer (seconds since epoch).TIME_MILLIS(): Returns the current time as an integer (milliseconds since epoch).TIME_NANOS(): Returns the current time as an integer (nanoseconds since epoch).RANDOM(): Returns a cryptographically secure random 32‑bit integer.RANDOM_FLOAT(): Returns a cryptographically secure float in the range[0.0, 1.0).RANDOM_RANGE(start, stop): Returns a cryptographically secure integer in[start, stop)(stop excluded). Requiresstart < stop.DELAY(seconds): Pauses execution for the given number of seconds. Only finite, non‑negative numbers up to 60 are accepted; anything larger raises a runtime error.EPRINT(value): Prints a value followed by a new line to standard error.CLEAR(): Clears the terminal screen and scrollback, like cls or clear. It does nothing when output is redirected to a file or pipe, or when TERM is dumb. On Windows it needs a console with ANSI support (Windows 10 or later).INSERT(list, index, value): Inserts value into a list in place, so every reference to the list sees the change. index runs from 0 to LEN(list) (inserting at LEN(list) appends); negative indexes count from the end. Returns NULL.POP(list, index): Removes and returns an element in place. index is optional and defaults to -1 (the last element). Popping from an empty list is an error.DELETE(dict, key): Removes key from a dict in place and returns its value. A missing key is an error.ORD(char): Returns the Unicode code point of a one‑character String.CHR(code): Returns the one‑character String for a Unicode code point (0 to 1114111, surrogates excluded).GETATTR(target, name): Reads a member by name from an Instance, Class, or Enum, exactly like target.name. PRIVATE and PROTECTED rules apply to the code that calls GETATTR.SETATTR(target, name, value): Assigns a member by name, exactly like target.name = value (FINAL and visibility rules apply). Returns the assigned value.ATTRS(target): Returns a List of the member names the caller can read, in declaration order: instance fields, then static members, then methods (constructors are not listed). For an Enum it lists the cases.EXIT(code): Ends the program immediately with exit code code (0 to 255, default 0). It cannot be caught by TRY/CATCH, and FINALLY blocks do not run.ENV(name, default): Returns an environment variable as a String. If it is not set, returnsdefaultwhen given, otherwiseNULL.READ_FILE(path): Reads a UTF-8 text file as a String, with no newline translation.WRITE_FILE(path, text, append): Writestextas UTF-8, replacing the file. If the optionalappendis truthy, the text is added to the end instead. The file is created if missing; its folder must already exist.DELETE_FILE(path): Deletes a file.LIST_DIR(path): Returns a sorted List of the entry names in a directory.
8. Modules
GladLang scripts can be split across files using EXPORT and IMPORT. This allows you to organise your code into reusable modules and share functions, constants and classes between files.
Exporting
EXPORT marks a top-level LET, FUNC, CLASS, or ENUM declaration as visible to other files. It is only valid at the top level of a file that is itself loaded via IMPORT (i.e. not in the entry script and not inside a function, class, loop, or conditional).
# math_module.glad EXPORT LET PI = 3.14159 EXPORT FUNC add(a, b) RETURN a + b ENDFUNC EXPORT CLASS Calculator FUNC add(a, b) RETURN a + b ENDFUNC ENDCLASS EXPORT ENUM Light RED GREEN ENDENUM
An export can also be given a different public name than its local one, via a trailing AS alias. Because the declaration keyword (FUNC/CLASS/ENUM) owns everything up through its own closing ENDFUNC/ENDCLASS/ENDENUM, the alias goes after that, not inline with the signature.
EXPORT LET internal_pi = 3.14159 AS PI EXPORT FUNC internal_add(a, b) RETURN a + b ENDFUNC AS add EXPORT ENUM InternalLight RED GREEN ENDENUM AS Light
Only the alias is visible to importers — the original local name (internal_pi, internal_add above) is not itself exported.
Importing
IMPORT loads a module (by a path relative to the importing file) and binds its exports into the current scope. Three forms are supported:
# Named imports, optionally comma-separated IMPORT PI, add, Calculator FROM "./math_module.glad" # Aliased import (AS) IMPORT PI AS Pi FROM "./math_module.glad" # Namespace import: everything under one identifier IMPORT * AS math FROM "./math_module.glad" PRINTLN math.PI PRINTLN math.add(1, 2)
Re-Exporting with Aliases
A name can also be declared normally first and exported afterward, via a standalone EXPORT statement that takes an existing local name rather than a fresh declaration. This form is the only way to export a FINAL (an ENUM can also be exported directly with EXPORT ENUM) and it is the way to give an already-declared name a different public name, using AS alias.
Multiple names can be exported in one statement, comma-separated, and each entry can carry its own alias or none at all.
LET internal_greeting = "hello" FUNC internal_shout(text) RETURN text + "!!!" ENDFUNC FINAL internal_max = 100 ENUM InternalStatus ACTIVE INACTIVE ENDENUM # Single alias per statement EXPORT internal_greeting AS greeting # Comma-separated list, each entry with its own alias EXPORT internal_shout AS shout, internal_max AS MAX # Enum re-exported under a shorter public name EXPORT InternalStatus AS Status
On the importing side, only the alias is visible — greeting, shout, MAX, Status. The original local names are not exported.
IMPORT greeting, shout, MAX, Status FROM "./greetings.glad" PRINTLN greeting # "hello" PRINTLN shout("hey") # "hey!!!" PRINTLN MAX # 100 PRINTLN Status.ACTIVE.value # 0
Circular Imports & Caching
- Each module is loaded and executed once per run; subsequent imports of the same path are served from an in-memory cache.
- Circular imports (A imports B, B imports A) are supported as long as the names each side needs from the other are exported before the circular
IMPORTline runs — seetests/modules/circular_a.gladandcircular_b.gladfor a working example.
Path Rules & Security
- Import paths must be relative (e.g.
"./..."or"../..."), must end in.gladand are resolved against the directory of the file doing the importing. - Paths may not escape the project's module root (the entry script's directory, by default). In the REPL or when running via piped stdin (
gladlang < script.glad), there is no script file path to anchor against, so the module root falls back to the current working directory instead. READ_FILE,WRITE_FILE,DELETE_FILEandLIST_DIRrefuse symbolic links anywhere in a path, accept files up to 10 MB, and only touch regular files. Set the environment variableGLADLANG_DISABLE_FILE_ACCESS=1to turn them off, andGLADLANG_DISABLE_ENV_ACCESS=1to turn offENV.- Use forward slashes in import paths on every platform, including Windows — a backslash inside a string literal is parsed as an escape sequence, so
"modules\math.glad"will not resolve as a path separator. NEW math.Calculator()(constructing directly off a namespace import) is not supported; import the class by name instead (IMPORT Calculator FROM ...) and useNEW Calculator().
Notes:
EXPORTis disabled in the interactive REPL's top-level prompt (it is still usable inside modules imported from the REPL).- Files are read with a size limit (1 MB) and must be valid UTF-8.
Error Handling
GladLang provides robust error handling using TRY, CATCH, FINALLY and THROW.
Try / Catch Block
TRY LET x = 10 / 0 CATCH error PRINTLN "Caught error: " + error FINALLY PRINTLN "Cleanup" ENDTRY
Manual Throw
TRY LET age = -1 IF age < 0 THEN THROW "Age cannot be negative" ENDIF CATCH e PRINTLN e # prints only "Age cannot be negative" ENDTRY
Runtime Tracebacks
When errors are not caught, GladLang prints full tracebacks:
Example: Name Error (test_name_error.glad)
Traceback (most recent call last): File test_name_error.glad, line 6, in <program> Runtime Error: 'b' is not defined
Example: Type Error (test_type_error.glad with input "5")
Traceback (most recent call last): File test_type_error.glad, line 6, in <program> Runtime Error: Illegal operation
Example: Argument Error (test_arg_error.glad)
Traceback (most recent call last): File test_arg_error.glad, line 8, in <program> File test_arg_error.glad, line 8, in add Runtime Error: Incorrect argument count for 'add'. Expected 2, got 3
Running Tests
The tests/ directory contains a comprehensive suite of .glad files to test every feature of the language. You can run any test by executing it with the interpreter:
gladlang "test_closures.glad" gladlang "test_lists.glad" gladlang "test_polymorphism.glad"
License
You can use this under the MIT License. See LICENSE for more details.