Skip to main content

The GladLang Interpreter

Project description

GladLang

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.

GladLang source files use the .glad file extension.

Lines of code

This is the full overview of the GladLang language, its features, and how to run the interpreter.

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, PLUS).
  • 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 Context and SymbolTable for managing variable scope, context (for tracebacks), and closures.
  • Values: Defines the language's internal data types (Number, String, List, Dict, Function, Class, Instance).
  • Interpreter: The core engine that walks the AST. It uses a "Zero-Copy" architecture with Dependency Injection for high-performance execution and low memory overhead.
  • 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), Strings, Lists, Dictionaries, Booleans, and Null.
  • Variables: Dynamic variable assignment with LET.
  • Advanced Assignments:
    • Destructuring: Unpack lists in assignments (LET [x, y] = [1, 2]) and loops (FOR [x, y] IN points).
    • Slicing: Access sub-lists or substrings easily (list[0:3]).
  • String Manipulation:
    • Interpolation: JavaScript-style template strings (`Hello ${name}`).
    • Multi-line Strings: Triple-quoted strings ("""...""") for large text blocks.
  • Comprehensions:
    • List Comprehensions: Supports nesting ([x+y FOR x IN A FOR y IN B]).
    • Dictionary Comprehensions: Create dicts programmatically ({k: v FOR k IN list}).
  • Dictionaries: Key-value data structures ({'key': 'value'}).
  • Control Flow:
    • Full support for IF / ELSE IF, SWITCH / CASE.
    • Universal Iteration: FOR loops over Lists, Strings (chars), and Dictionaries (keys).
  • Functions: First-class citizens, Closures, Recursion, Named/Anonymous support, and Overloading (by argument count).
  • Object-Oriented: Full OOP support with CLASS, INHERITS, Access Modifiers, and Method/Constructor Overloading.
  • Static Members: Java-style STATIC fields, methods, and constants (STATIC FINAL).
  • Operators: Ternary Operator (condition ? true : false) for concise conditional logic.
  • OOP Safety: Runtime checks for circular inheritance, LSP violations, and secure encapsulation.
  • Error Management: Gracefully handle errors with TRY, CATCH, and FINALLY.
  • Constants: Declare immutable values using FINAL, fully protected from shadowing..
  • Built-ins: PRINT, INPUT, STR, INT, FLOAT, BOOL, LEN.
  • Error Handling: Robust, user-friendly runtime error reporting with full tracebacks.
  • Advanced Math: Compound assignments (+=, *=), Power (**), Modulo (%), and automatic float division.
  • Rich Comparisons: Chained comparisons (1 < x < 10) and Identity checks (is).
  • Flexible Logic: Support for and / or (case-insensitive).

Getting Started

There are several ways to install and run GladLang.

1. Installation

Option A: Install via Pip (Recommended)

If you just want to use the language, install it via pip:

pip install gladlang

Option B: 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

Once installed, you can use the global gladlang command.

Interactive Shell (REPL)

Run the interpreter without arguments to start the shell:

gladlang

Running a Script

Pass a file path to execute a script:

gladlang "tests/test.glad"

3. Running Without Installation (Source)

You can run the interpreter directly from the source code without installing it via pip:

python run.py "tests/test.glad"

4. Building the Executable

You can build a standalone executable (no Python required) using PyInstaller:

pip install pyinstaller
pyinstaller run.py --paths src -F --name gladlang --icon=favicon.ico

This will create a single-file executable at dist/gladlang (or gladlang.exe on Windows).

Adding to PATH (Optional): To run the standalone executable from anywhere:

  • Windows: Move it to a folder and add that folder to your System PATH variables.
  • Mac/Linux: Move it to /usr/local/bin: sudo mv dist/gladlang /usr/local/bin/

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

Variables are assigned using the LET keyword. You can also unpack lists directly into variables using Destructuring.

# Immutable Constants
FINAL PI = 3.14159

# Variable Assignment
LET a = 10
LET b = "Hello"
LET my_list = [a, b, 123]

# Destructuring Assignment
LET point = [10, 20]
LET [x, y] = point

PRINT x # 10
PRINT y # 20

Numbers

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

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"
PRINT "Hello"[1]          # "e"

# Escapes (work in "..." and `...`)
PRINT "Line 1\nLine 2"
PRINT `Column 1\tColumn 2`

# Interpolation (Template Strings)
LET name = "Glad"
PRINT `Welcome back, ${name}!`
PRINT `5 + 10 = ${5 + 10}`

Lists, Slicing & Comprehensions

Lists are ordered collections. You can access elements, slice them, or create new lists dynamically using comprehensions.

LET nums = [0, 1, 2, 3, 4, 5]

# Indexing & Assignment
PRINT nums[1]        # 1
LET nums[1] = 100

# Slicing [start:end]
PRINT nums[0:3]      # [0, 1, 2]
PRINT nums[3:]       # [3, 4, 5]

# List Comprehension
LET squares = [n ** 2 FOR n IN nums]
PRINT squares        # [0, 1, 4, 9, 16, 25]

# Nested List Comprehension
LET pairs = [[x, y] FOR x IN [1, 2] FOR y IN [3, 4]]
# Result: [[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
}

PRINT 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} 
PRINT 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
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."

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.


3. Operators

Math Operations

GladLang supports standard arithmetic plus advanced operators like Modulo, Floor Division, and Power.

LET sum = 10 + 5    # 15
LET diff = 20 - 8   # 12
LET prod = 5 * 4    # 20
LET quot = 100 / 2  # 50.0 (Always Float)

PRINT 2 ** 3      # Power: 8
PRINT 10 // 3     # Floor Division: 3
PRINT 10 % 3      # Modulo: 1

# Standard precedence rules apply
PRINT 2 + 3 * 4   # 14
PRINT 1 + 2 * 3   # 7
PRINT (1 + 2) * 3 # 9

Compound Assignments

GladLang supports syntactic sugar for updating variables in place.

LET score = 10

score += 5   # score is now 15
score -= 2   # score is now 13
score *= 2   # score is now 26
score /= 2   # score is now 13.0
score %= 5   # score is now 3.0

Bitwise Operators

Perform binary manipulation on integers.

LET a = 5  # Binary 101
LET b = 3  # Binary 011

PRINT a & b   # 1 (AND)
PRINT a | b   # 7 (OR)
PRINT a ^ b   # 6 (XOR)
PRINT ~a      # -6 (NOT)
PRINT 1 << 2  # 4 (Left Shift)
PRINT 8 >> 2  # 2 (Right Shift)

# Compound Assignment
LET x = 1
x <<= 2       # x is now 4

Comparisons & Logic

You can compare values, chain comparisons for ranges, and check object identity.

# Equality & Inequality
PRINT 1 == 1      # True
PRINT 1 != 2      # True

# Chained Comparisons (Ranges)
LET age = 25
IF 18 <= age < 30 THEN
  PRINT "Young Adult"
ENDIF

PRINT (10 < 20) AND (10 != 5) # 1 (True)

# Identity ('is' checks if variables refer to the same object)
LET a = [1, 2]
LET b = a
PRINT b is a      # True
PRINT b == [1, 2] # True (Values match)

# Boolean Operators (case-insensitive)
IF a and b THEN
  PRINT "Both exist"
ENDIF

Conditional (Ternary) Operator

A concise way to write IF...ELSE statements in a single line. It supports nesting and arbitrary expressions.

LET age = 20
LET type = age >= 18 ? "Adult" : "Minor"
PRINT type # "Adult"

# Nested Ternary
LET score = 85
LET grade = score > 90 ? "A" : score > 80 ? "B" : "C"
PRINT grade # "B"

Increment / Decrement

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

4. Control Flow

IF Statements

Uses IF...THEN...ENDIF syntax.

IF x > 10 THEN
    PRINT "Large"
ELSE IF x > 5 THEN
    PRINT "Medium"
ELSE
    PRINT "Small"
ENDIF

Switch Statements

Use SWITCH to match a value against multiple possibilities. It supports single values, comma-separated lists for multiple matches, and expressions.

LET status = 200

SWITCH status
    CASE 200:
        PRINT "OK"
    CASE 404, 500:
        PRINT "Error"
    DEFAULT:
        PRINT "Unknown Status"
ENDSWITCH

WHILE Loops

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

FOR Loops

Iterates over the elements of a list.

LET my_list = ["apple", "banana", "cherry"]
FOR item IN my_list
  PRINT "Item: " + item
ENDFOR

# Iterate over Strings (Characters)
FOR char IN "Hi"
  PRINT char 
ENDFOR

# Iterate over Dictionaries (Keys)
LET data = {"x": 10, "y": 20}
FOR key IN data
  PRINT key + ": " + data[key]
ENDFOR

# Loop Destructuring (Unpacking)
LET points = [[1, 2], [3, 4]]
FOR [x, y] IN points
  PRINT "x: " + x + ", y: " + y
ENDFOR

BREAK and CONTINUE are supported in both WHILE and FOR loops.


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)
PRINT sum # 15

Anonymous Functions

Functions can be defined without a name, perfect for assigning to variables.

LET double = DEF(x)
  RETURN x * 2
ENDDEF

PRINT 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")
PRINT 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

PRINT fib(7) # 13

Function Overloading

You can define multiple functions with the same name, as long as they accept a different number of arguments (arity).

DEF add(a, b)
  RETURN a + b
ENDDEF

DEF add(a, b, c)
  RETURN a + b + c
ENDDEF

PRINT add(10, 20)     # Calls 2-arg version: 30
PRINT add(10, 20, 30) # Calls 3-arg version: 60

6. Object-Oriented Programming (OOP)

Classes and Instantiation

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
  ENDDEF
  
  DEF increment(SELF)
    SELF.count = SELF.count + 1
  ENDDEF
  
  DEF get_count(SELF)
    RETURN SELF.count
  ENDDEF
ENDCLASS

The SELF Keyword

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

Inheritance

Use the INHERITS keyword. Methods can be overridden, but GladLang enforces strict visibility rules (LSP) and prevents circular inheritance loops.

CLASS Pet
  DEF init(SELF, name)
    SELF.name = name
  ENDDEF
  
  DEF speak(SELF)
    PRINT SELF.name + " makes a generic pet sound."
  ENDDEF
ENDCLASS

CLASS Dog INHERITS Pet
  # Override the 'speak' method
  DEF speak(SELF)
    PRINT SELF.name + " says: Woof!"
  ENDDEF
ENDCLASS

LET my_dog = NEW Dog("Buddy")
my_dog.speak() # "Buddy says: Woof!"

Method & Constructor Overloading

Classes support overloading for both regular methods and the init constructor. This allows for flexible object creation (e.g., Copy Constructors).

CLASS Vector
  # Default Constructor
  DEF init(SELF)
    SELF.x = 0
    SELF.y = 0
  ENDDEF

  # Overloaded Constructor
  DEF init(SELF, x, y)
    SELF.x = x
    SELF.y = y
  ENDDEF
  
  # Copy Constructor
  DEF init(SELF, other)
    SELF.x = other.x
    SELF.y = other.y
  ENDDEF
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 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'
  ENDDEF
  
  DEF speak(SELF)
    PRINT "(Generic pet sound)"
  ENDDEF
ENDCLASS

CLASS Cat INHERITS Pet
  DEF speak(SELF)
    PRINT "Meow!"
  ENDDEF
ENDCLASS

LET my_cat = NEW Cat("Whiskers")
my_cat.introduce()
# Prints:
# I am a pet and I say:
# Meow!

Access Modifiers

You can control the visibility of methods and attributes using PUBLIC, PRIVATE, and PROTECTED.

  • Encapsulation: Private attributes are name-mangled to prevent collisions.
  • Singleton Support: Constructors (init) can be private to force factory usage.
CLASS SecureData
  DEF init(SELF, data)
    PRIVATE SELF.data = data
  ENDDEF

  PUBLIC DEF get_data(SELF)
    RETURN SELF.data
  ENDDEF
ENDCLASS

# External access to 'data' will raise a Runtime Error.

Static Members

GladLang supports Java-style static fields and methods. These belong to the class itself rather than instances.

  • Static Fields: Shared across all instances.
  • Static Constants: STATIC FINAL creates class-level constants.
  • Static Privacy: STATIC PRIVATE fields are only visible within the class.
CLASS Config
  # A constant shared by everyone
  STATIC FINAL MAX_USERS = 100

  # A private static variable
  STATIC PRIVATE LET internal_count = 0

  STATIC PUBLIC DEF increment()
    Config.internal_count = Config.internal_count + 1
    RETURN Config.internal_count
  ENDDEF
ENDCLASS

# Access directly via the Class name
PRINT Config.MAX_USERS      # 100
PRINT Config.increment()    # 1

7. Built-in Functions

  • 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 (TRUE or FALSE).
  • LEN(value): Returns the length of a String, List, Dict, or Number. Alias: LENGTH().

Error Handling

You can handle runtime errors gracefully or throw your own exceptions.

TRY
    # Attempt dangerous code
    LET result = 10 / 0
    PRINT result
CATCH error
    # Handle the error
    PRINT "Caught an error: " + error
FINALLY
    # Always runs
    PRINT "Cleanup complete."
ENDTRY

# Manually throwing errors
IF age < 0 THEN
    THROW "Age cannot be negative!"
ENDIF

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

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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

gladlang-0.1.7.tar.gz (44.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

gladlang-0.1.7-py3-none-any.whl (37.3 kB view details)

Uploaded Python 3

File details

Details for the file gladlang-0.1.7.tar.gz.

File metadata

  • Download URL: gladlang-0.1.7.tar.gz
  • Upload date:
  • Size: 44.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.0

File hashes

Hashes for gladlang-0.1.7.tar.gz
Algorithm Hash digest
SHA256 076485bfaf0ada4d98ec3f2d4ce51df18c4118609280d2e88f29b02d8f90eeef
MD5 846680ceaf94df4754d87630a46be9b8
BLAKE2b-256 3ac94b1447add429b7aeab5884e08b6441493d534125d49ecea8fb4f3d290b3e

See more details on using hashes here.

File details

Details for the file gladlang-0.1.7-py3-none-any.whl.

File metadata

  • Download URL: gladlang-0.1.7-py3-none-any.whl
  • Upload date:
  • Size: 37.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.0

File hashes

Hashes for gladlang-0.1.7-py3-none-any.whl
Algorithm Hash digest
SHA256 2646af7712420c42cc9f3e41d479b559a896a8a3720a5fe9ac50479cf1e8d3a7
MD5 f468cece2fa532396b4f51a497d879f9
BLAKE2b-256 4e5ff240fca956f9afb55ce5f4ce9549990af827eb16a070394f69cfa8315fe5

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page