GladLang is 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.
This is the full overview of the GladLang language, its features, and how to run the interpreter.
- About The Language
- Key Features
- Getting Started
- Language Tour (Syntax Reference)
- Error Handling
- Running Tests
- License
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 (
lexer.py): A tokenizer that scans source code and converts it into a stream of tokens (e.g.,NUMBER,STRING,IDENTIFIER,KEYWORD,PLUS). - Parser (
parser.py): A parser that takes the token stream and builds an Abstract Syntax Tree (AST), representing the code's structure. - AST Nodes (
nodes.py): A comprehensive set of nodes that define every syntactic structure in the language (e.g.,BinOpNode,IfNode,FunDefNode,ClassNode). - Runtime (
runtime.py): Defines theContextandSymbolTablefor managing variable scope, context (for tracebacks), and closures. - Values (
values.py): Defines the language's internal data types (Number,String,List,Function,Class,Instance). - Interpreter (
interpreter.py): The core engine that walks the AST and executes the program by visiting each node. - Entry Point (
gladlang.py): The main file that ties everything together. It handles command-line arguments, runs files, and starts the interactive shell.
GladLang supports a rich, modern feature set:
- Data Types: Numbers (int/float), Strings, Lists, Booleans, and Null.
- Variables: Dynamic variable assignment with the
LETkeyword. - Operators: Full set of arithmetic (
+,-,*,/,^), comparison (==,!=,<,>), and logical (AND,OR,NOT) operators. - Control Flow:
IF...THEN...ENDIF,WHILE...ENDWHILE, andFOR...IN...ENDFORloops. - Flow Control:
BREAKandCONTINUEkeywords for loops. - Functions:
- First-class citizens (can be passed as arguments and stored in variables).
- Support for named and anonymous functions.
- Closures: Functions capture their parent's scope.
- Recursive function calls.
- Object-Oriented Programming:
CLASS...ENDCLASSsyntax.NEWkeyword for instantiation.SELFkeyword for instance context.INHERITSkeyword for class inheritance.- Method overriding and polymorphism.
- Advanced Operators: Pre- and post-increment/decrement (
++i,i--). - List Manipulation: Index access (
my_list[0]), index assignment (my_list[0] = 10), and concatenation (list1 + list2). - Built-ins:
PRINT,INPUT,STR,INT,FLOAT, andBOOL. - Error Handling: Robust, user-friendly runtime error reporting with full tracebacks.
You can execute any .glad file by passing it as an argument to gladlang.py.
python gladlang.py "test.glad"Output:
--- OOP & Inheritance Tester ---
--- Creating a Pet ---
A new pet is born!
Sammy makes a generic pet sound.
--- Creating a Dog ---
A new pet is born!
Buddy says: Woof!
Buddy wags its tail.
Run the interpreter without any arguments to start the interactive Read-Eval-Print Loop (REPL) shell.
python gladlang.pyShell:
Welcome to GladLang (v0.1.0)
Type 'exit' or 'quit' to close the shell.
--------------------------------------------------
GladLang > PRINT "Hello, " + "World!"
Hello, World!
0
GladLang > LET a = 10 * (2 + 3)
0
GladLang > PRINT a
50
0
GladLang > exit
You can build a standalone executable using PyInstaller:
pyinstaller gladlang.py -F --icon=favicon.icoThis will create a single-file executable at dist/gladlang.
You can then add it to your system PATH so it can be run globally as "gladlang" from anywhere.
-
Move or copy the executable to a folder of your choice, for example:
move dist\gladlang.exe "C:\Programs\GladLang"
-
Add that folder to your system PATH:
- Press Win + R, type
sysdm.cpl, press Enter. - Go to Advanced
$\rightarrow$ Environment Variables. - Under System variables, select Path
$\rightarrow$ Edit$\rightarrow$ New. - Add the full path (e.g.,
C:\Programs\GladLang).
- Press Win + R, type
-
Open a new terminal and test:
gladlang "test_recursion.glad"
- Move the executable to
/usr/local/bin(or another directory in your PATH):sudo mv dist/gladlang /usr/local/bin/
- Make sure it's executable:
sudo chmod +x /usr/local/bin/gladlang
- Test it anywhere:
gladlang "test_recursion.glad"
Now you can run GladLang from any folder without prefixing ./dist/.
Here is a guide to the GladLang syntax, with examples from the tests/ directory.
Comments start with # and last for the entire line.
# This is a comment.
LET a = 10 # This is an inline comment
Variables are assigned using the LET keyword.
LET a = 10
LET b = "Hello"
LET my_list = [a, b, 123]
Numbers can be integers or floats. All standard arithmetic operations are supported.
LET math_result = (1 + 2) * 3 # 9
LET float_result = 10 / 4 # 2.5
Strings are defined with double quotes and support escape characters. They can be concatenated with +.
LET newline = "Hello\nWorld"
LET quoted = "She said, \"This is cool!\""
PRINT "Hello, " + "GladLang"
Lists are ordered collections of any type. They support indexing, assignment, and concatenation.
LET my_list = [1, "hello", 2 * 3, TRUE]
PRINT my_list[1] # Access: "hello"
LET my_list[1] = "world" # Assign
PRINT my_list[1] # "world"
LET other_list = my_list + [FALSE, 100]
Booleans are TRUE and FALSE. They are the result of comparisons and logical operations.
LET t = TRUE
LET f = FALSE
PRINT t AND f # 0 (False)
PRINT t OR f # 1 (True)
PRINT 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."
The NULL keyword represents a null or "nothing" value. It is falsy and prints as 0. Functions with no RETURN statement implicitly return NULL.
^ (power), *, / (division), +, -. Standard operator precedence is respected.
PRINT 1 + 2 * 3 # 7
PRINT (1 + 2) * 3 # 9
- Comparison:
==,!=,<,>,<=,>= - Logical:
AND,OR,NOT
PRINT (10 < 20) AND (10 != 5) # 1 (True)
Supports C-style pre- and post-increment/decrement operators on variables and list elements.
LET i = 5
PRINT i++ # 5
PRINT i # 6
PRINT ++i # 7
PRINT i # 7
LET my_list = [10, 20]
PRINT my_list[1]++ # 20
PRINT my_list[1] # 21
Uses IF...THEN...ENDIF syntax.
LET num = -5
IF num < 0 THEN
PRINT "It is negative."
ENDIF
Loops while a condition is TRUE.
LET i = 3
WHILE i > 0
PRINT "i = " + i
LET i = i - 1
ENDWHILE
# Prints:
# i = 3
# i = 2
# i = 1
Iterates over the elements of a list.
LET my_list = ["apple", "banana", "cherry"]
FOR item IN my_list
PRINT "Item: " + item
ENDFOR
BREAK and CONTINUE are supported in both WHILE and FOR loops.
Defined with DEF...ENDEF. Arguments are passed by value. RETURN sends a value back.
DEF add(a, b)
RETURN a + b
ENDEF
LET sum = add(10, 5)
PRINT sum # 15
Functions can be defined without a name, perfect for assigning to variables.
LET double = DEF(x)
RETURN x * 2
ENDEF
PRINT double(5) # 10
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 + "!"
ENDEF
RETURN greeter_func
ENDEF
LET say_hello = create_greeter("Hello")
PRINT say_hello("Alex") # "Hello, Alex!"
Functions can call themselves.
DEF fib(n)
IF n <= 1 THEN
RETURN n
ENDIF
RETURN fib(n - 1) + fib(n - 2)
ENDEF
PRINT fib(7) # 13
Use CLASS...ENDCLASS to define classes and NEW to create instances. The constructor is init.
CLASS Counter
DEF init(self)
SELF.count = 0 # 'SELF' is the instance
ENDEF
DEF increment(self)
SELF.count = SELF.count + 1
ENDEF
DEF get_count(self)
RETURN SELF.count
ENDEF
ENDCLASS
SELF is the mandatory first argument for all methods and is used to access instance attributes and methods.
LET c = NEW Counter()
c.increment()
PRINT c.get_count() # 1
Use the INHERITS keyword. Methods can be overridden by the child class.
CLASS Pet
DEF init(self, name)
SELF.name = name
ENDEF
DEF speak(self)
PRINT SELF.name + " makes a generic pet sound."
ENDEF
ENDCLASS
CLASS Dog INHERITS Pet
# Override the 'speak' method
DEF speak(self)
PRINT SELF.name + " says: Woof!"
ENDEF
ENDCLASS
LET my_dog = NEW Dog("Buddy")
my_dog.speak() # "Buddy says: Woof!"
When a base class method calls another method on SELF, it will correctly use the child's overridden version.
CLASS Pet
DEF introduce(self)
PRINT "I am a pet and I say:"
SELF.speak() # This will call the child's 'speak'
ENDEF
DEF speak(self)
PRINT "(Generic pet sound)"
ENDEF
ENDCLASS
CLASS Cat INHERITS Pet
DEF speak(self)
PRINT "Meow!"
ENDEF
ENDCLASS
LET my_cat = NEW Cat("Whiskers")
my_cat.introduce()
# Prints:
# I am a pet and I say:
# Meow!
PRINT(value): Prints a value to the console.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).
GladLang features detailed error handling and prints full tracebacks for runtime errors, making debugging easy.
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
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:
python gladlang.py "test_closures.glad"
python gladlang.py "test_lists.glad"
python gladlang.py "test_polymorphism.glad"
or
gladlang "test_closures.glad"
gladlang "test_lists.glad"
gladlang "test_polymorphism.glad"You can use this under the MIT License. See LICENSE for more details.