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.

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:

  1. Double Quotes: Standard strings.
  2. Triple Quotes: Multi-line strings that preserve formatting.
  3. 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 (TRUE or FALSE).
  • 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 %5d are 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). Requires start < 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, returns default when given, otherwise NULL.
  • READ_FILE(path): Reads a UTF-8 text file as a String, with no newline translation.
  • WRITE_FILE(path, text, append): Writes text as UTF-8, replacing the file. If the optional append is 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 IMPORT line runs — see tests/modules/circular_a.glad and circular_b.glad for a working example.

Path Rules & Security

  • Import paths must be relative (e.g. "./..." or "../..."), must end in .glad and 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_FILE and LIST_DIR refuse symbolic links anywhere in a path, accept files up to 10 MB, and only touch regular files. Set the environment variable GLADLANG_DISABLE_FILE_ACCESS=1 to turn them off, and GLADLANG_DISABLE_ENV_ACCESS=1 to turn off ENV.
  • 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 use NEW Calculator().

Notes:

  • EXPORT is 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.