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
About The Language
GladLang is an interpreter for a custom scripting language. It was built as a complete system, demonstrating the core components of a programming language:
- Lexer: A tokenizer that scans source code and converts it into a stream of tokens (e.g.,
NUMBER,STRING,IDENTIFIER,KEYWORD). - Parser: A parser that takes the token stream and builds an Abstract Syntax Tree (AST), representing the code's structure.
- AST Nodes: A comprehensive set of nodes that define every syntactic structure in the language (e.g.,
BinOpNode,IfNode,FunDefNode,ClassNode). - Runtime: Defines the
ContextandSymbolTablefor managing variable scope, context (for tracebacks), and closures. - Values: Defines the language's internal data types (
Number,String,List,Function,Class,Instance). - Interpreter: The core engine that walks the AST. It uses a Deep-Copy architecture for containers (List, Dict) and Class instances to ensure full state isolation and memory safety.
- Entry Point: The main file that ties everything together. It handles command-line arguments, runs files, and starts the interactive shell.
Key Features
GladLang supports a rich, modern feature set:
Data Types
Numbers (Int/Float/Hex/Octal), 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, inheritance, 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, PRINT, INPUT, STR, INT, FLOAT, and BOOL.
Error Handling
Robust, user-friendly runtime error reporting with full tracebacks.
Memory & Logic Safety
Atomic Locking for constants, Iteration Scoping for loops, and full Short-Circuit Evaluation.
Getting Started
1. Installation
Option A: Install via Pip (Recommended)
pip install gladlang
Option B: Install from Source
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"
3. Running Without Installation
If running from source without pip, use the helper script:
python run.py "tests/test.glad"
4. Building the Executable
Build a standalone executable using PyInstaller:
pip install pyinstaller pyinstaller run.py --paths src -F --name gladlang --icon=favicon.ico
This creates an executable in dist/.
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 bin = 0b101 # 5
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 """ # Interpolation (Template Strings) LET name = "User" PRINTLN `Welcome back, ${name}!` PRINTLN `5 + 10 = ${5 + 10}`
Lists & Slicing
Lists are ordered collections. You can access elements, slice them, or create new lists dynamically.
LET nums = [0, 1, 2, 3, 4, 5] # Slicing [start:end] PRINTLN nums[0:3] # [0, 1, 2] PRINTLN nums[3:] # [3, 4, 5] # 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 list1 FOR y IN list2]
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 d = {k: 0 FOR k IN keys}
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, and FALSE are "falsy." All other values (including non-empty strings, non-zero numbers, lists, functions, and classes) are "truthy."
Null
The NULL keyword represents a null or "nothing" value. It is falsy and prints as 0. Functions with no RETURN statement implicitly return NULL.
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 # 0 # Explicit & Auto-Incrementing ENUM HTTPStatus OK = 200 NOT_FOUND = 404 CUSTOM_ERROR # Implicitly becomes 405 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 # 30 score -= 5 # 25
Bitwise Operators
Perform binary manipulation on integers.
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 (NOT) PRINTLN 1 << 2 # 4 (Left Shift)
Comparisons, Logic & Type Checking
Compare values, check object identity, and perform runtime type checking.
# 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 Dog ENDCLASS LET d = NEW Dog() PRINTLN d INSTANCEOF Dog # 1 (True)
Increment / Decrement
Supports C-style pre- and post-increment/decrement.
LET i = 5 PRINTLN i++ # 5 PRINTLN ++i # 7
Ternary Operator
Concise conditional logic.
LET age = 20 LET type = age >= 18 ? "Adult" : "Minor" PRINTLN type # "Adult"
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 with Destructuring FOR [key, val] IN {"a": 1, "b": 2} PRINTLN key + ": " + val ENDFOR # 3. 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 DEF...ENDDEF. Arguments are passed by value. RETURN sends a value back.
DEF add(a, b) RETURN a + b ENDDEF LET sum = add(10, 5) PRINTLN sum # 15
Function Overloading
Define multiple functions with the same name but different argument counts.
DEF add(a, b) RETURN a + b ENDDEF DEF add(a, b, c) RETURN a + b + c ENDDEF
Anonymous Functions
Functions can be defined without a name, perfect for assigning to variables.
LET double = DEF(x) RETURN x * 2 ENDDEF PRINTLN double(5) # 10
Closures
Functions capture variables from their parent scope.
DEF create_greeter(greeting) DEF greeter_func(name) # 'greeting' is "closed over" from the parent RETURN greeting + ", " + name + "!" ENDDEF RETURN greeter_func ENDDEF LET say_hello = create_greeter("Hello") PRINTLN say_hello("Alex") # "Hello, Alex!"
Recursion
Functions can call themselves.
DEF fib(n) IF n <= 1 THEN RETURN n ENDIF RETURN fib(n - 1) + fib(n - 2) ENDDEF 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 DEF Counter() THIS.count = 0 # 'THIS' is the instance ENDDEF DEF increment() THIS.count = THIS.count + 1 ENDDEF DEF get_count() RETURN THIS.count ENDDEF 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.
CLASS Pet DEF Pet(name) THIS.name = name ENDDEF DEF speak() RETURN "makes a generic pet sound." ENDDEF ENDCLASS CLASS Dog INHERITS Pet DEF Dog(name) SUPER(name) # Auto-delegates to parent ENDDEF DEF speak() PRINTLN THIS.name + " says: Woof! and " + SUPER.speak() ENDDEF 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 inheritance, solving the Diamond Problem with strict left-to-right Method Resolution Order (MRO).
CLASS Dog INHERITS Animal, Human DEF Dog() # Explicit calls bypass default MRO Animal.Animal() Human.Human() SUPER() # Calls Animal (First in MRO) ENDDEF ENDCLASS
Polymorphism
When a base class method calls another method on THIS, it will correctly use the child's overridden version.
CLASS Pet DEF Pet(name) THIS.name = name ENDDEF DEF introduce() PRINTLN "I am a pet and I say:" THIS.speak() ENDDEF DEF speak() PRINTLN "(Generic pet sound)" ENDDEF ENDCLASS CLASS Cat INHERITS Pet DEF speak() PRINTLN "Meow!" ENDDEF 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.
CLASS Secure DEF Secure() PRIVATE THIS.secret = "Hidden" ENDDEF PUBLIC DEF get_secret() RETURN THIS.secret ENDDEF ENDCLASS
Static Members
GladLang supports Java-style static fields and methods using STATIC.
CLASS Config STATIC FINAL MAX_USERS = 100 STATIC PUBLIC DEF get_max() RETURN Config.MAX_USERS ENDDEF ENDCLASS PRINTLN Config.get_max() # 100
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, Dict, or Number. Alias:LENGTH().
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
IF age < 0 THEN THROW "Age cannot be negative" ENDIF
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 7, in <program> File test_arg_error.glad, line 4, 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.