MonkeyScript Language Specification

January 19, 2026 ยท View on GitHub

Version: 0.1.0
Last Updated: January 2026

This document provides a complete technical specification of the MonkeyScript programming language

Table of Contents

  1. Lexical Structure
  2. Data Types
  3. Expressions
  4. Statements
  5. Functions
  6. Scoping and Environments
  7. Grammar Reference

Lexical Structure

Comments

Currently, MonkeyScript does not support comments, this is planned for a future release

Whitespace

Whitespace (spaces, tabs, newlines) is used to separate tokens but is otherwise ignored, you do not need to follow indentation like you do on Python

def x=5;        # Valid
def x = 5;      # Also valid (preferred for readability)

Keywords

Reserved words that cannot be used as identifiers:

KeywordPurpose
defVariable declaration
ifConditional statement
elseAlternative branch
whileLoop statement
fnFunction literal
endBlock terminator
trueBoolean literal
falseBoolean literal

Identifiers

Identifiers are names for variables and functions

Syntax:

  • Must start with a letter (a-z, A-Z)
  • Can contain letters and digits (0-9)
  • Case-sensitive

Valid identifiers:

x
myVariable
counter2
calculateSum

Invalid identifiers:

2fast        # Cannot start with digit
my-var       # Hyphens not allowed
if           # Reserved keyword

Literals

Number Literals

Currently, only integer literals are supported.

0
42
123456

Note: Floating-point numbers are not yet supported.

Boolean Literals

true
false
True    # Also recognized
False   # Also recognized

Operators

Arithmetic Operators

OperatorNameExample
+Addition5 + 3
-Subtraction10 - 4
*Multiplication6 * 7
/Division20 / 4

Comparison Operators

OperatorNameExample
<Less thanx < 10
>Greater thanx > 5
==Equal tox == 42
!=Not equal tox != 0

Logical Operators

OperatorNameExample
!Logical NOT!true

Note: && (AND) and || (OR) are not yet implemented

Delimiters

SymbolNameUsage
;SemicolonStatement terminator
:ColonBlock delimiter
( )ParenthesesGrouping, function calls
,CommaParameter/argument separator
=EqualsAssignment

Data Types

Number

Represents integer values

def age = 25;
def year = 2026;

Operations: Addition, subtraction, multiplication, division, comparisons

Boolean

Represents logical values

def isActive = true;
def hasError = false;

Operations: Logical NOT (!), comparisons

Function

Functions are first-class values and can be stored in variables

def add = fn(a, b): 
    a + b; 
end;

Expressions

Expressions evaluate to a value

Primary Expressions

Literals

42          # Number literal
true        # Boolean literal

Identifiers

myVariable  # Variable reference

Grouped Expressions

(5 + 3) * 2

Binary Expressions

Arithmetic and comparison operations between two values.

# Arithmetic
5 + 3
10 - 2
4 * 6
20 / 5

# Comparison
x > 10
y < 5
a == b
c != d

Precedence (highest to lowest):

  1. Parentheses ( )
  2. Multiplication *, Division /
  3. Addition +, Subtraction -
  4. Comparison <, >, ==, !=

Note: Currently, multiplication and division have the same precedence as addition and subtraction due to the parser implementation.-

Call Expressions

Invoke a function with arguments.

add(5, 3)
factorial(10)
makeCounter()

Function Literals

Anonymous function definitions

fn(x, y): x + y; end
fn(): 42; end
fn(n): n * n; end

Statements

Statements perform actions but do not produce values

Expression Statements

Any expression can be used as a statement.

5 + 3;
factorial(10);

Variable Declaration

Declare and initialize a variable with def

Syntax:

def identifier = expression;

Examples:

def x = 5;
def sum = 10 + 20;
def greeting = myFunction();

Important: Variables cannot be reassigned. Each def creates a new binding in the current scope

def x = 5;
def x = 10;  # Creates new binding, shadows previous x

If Statement

Conditional execution based on a boolean expression.

Syntax:

if condition:
    statements
end;

With else:

if condition:
    statements
else:
    statements
end;

Examples:

if x > 10:
    def result = 1;
end;

if isValid:
    def message = 1;
else:
    def message = 0;
end;

While Statement

Repeat execution while a condition is true

Syntax:

while condition:
    statements
end;

Example:

def i = 0;
while i < 5:
    def i = i + 1;
end;

Block Statements

Blocks are sequences of statements within control structures

if x > 0:
    def a = 1;
    def b = 2;
    def c = a + b;
end;

Functions

Function Definitions

Functions are defined using fn keyword and assigned to variables.

Syntax:

def functionName = fn(param1, param2, ...):
    statements
end;

Example:

def add = fn(a, b):
    a + b;
end;

Parameters

  • Zero or more parameters separated by commas
  • Parameters are identifiers
  • No type annotations
def noParams = fn(): 42; end;
def oneParam = fn(x): x * 2; end;
def twoParams = fn(a, b): a + b; end;

Return Values

The last expression in a function body is implicitly returned

def square = fn(x):
    x;  # This value is returned
end;

Function Calls

Syntax:

functionName(arg1, arg2, ...)

Examples:

add(5, 3);
factorial(10);
greet();

Closures

Functions capture their surrounding environment (lexical scoping)

def makeCounter = fn():
    def count = 0;
    fn():
        def count = count + 1;
        count;
    end;
end;

def counter = makeCounter();
counter();  # Returns 1
counter();  # Returns 2
counter();  # Returns 3

Higher-Order Functions

Functions can accept other functions as arguments and return functions.

def apply = fn(f, x):
    f(x);
end;

def double = fn(n): n * 2; end;

apply(double, 5);  # Returns 10

Scoping and Environments

Lexical Scoping

Variables are resolved based on where they are defined in the source code

def x = 10;

def outer = fn():
    def x = 20;
    def inner = fn():
        x;  # Refers to x = 20 from outer
    end;
    inner();
end;

outer();  # Returns 20

Variable Shadowing

Inner scopes can shadow variables from outer scopes

def x = 5;

if true:
    def x = 10;  # Shadows outer x
    x;           # Returns 10
end;

x;  # Returns 5 (original x)

Scope Chain

Each function creates a new environment that has access to:

  1. Its own local variables
  2. Variables from enclosing scopes
  3. Variables from the global scope
def global = 100;

def outer = fn():
    def middle = 50;
    
    def inner = fn():
        def local = 25;
        global + middle + local;  # Can access all three
    end;
    
    inner();
end;

Grammar Reference

This section provides a formal grammar in Extended Backus-Naur Form (EBNF)

Lexical Grammar

digit       = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
letter      = "a" | ... | "z" | "A" | ... | "Z" ;
number      = digit { digit } ;
identifier  = letter { letter | digit } ;

Syntactic Grammar

program     = { statement } ;

statement   = declaration
            | if-statement
            | while-statement
            | expr-statement ;

declaration = "def" identifier "=" expression ";" ;

if-statement = "if" expression ":"
                   { statement }
               [ "else" ":"
                   { statement } ]
               "end" ";" ;

while-statement = "while" expression ":"
                      { statement }
                  "end" ";" ;

expr-statement = expression ";" ;

expression  = term { ("+" | "-") term } ;

term        = call ;

call        = primary [ "(" [ arguments ] ")" ] ;

primary     = number
            | boolean
            | identifier
            | function-literal
            | "(" expression ")" ;

function-literal = "fn" "(" [ parameters ] ")" ":"
                       { statement }
                   "end" ;

parameters  = identifier { "," identifier } ;

arguments   = expression { "," expression } ;

boolean     = "true" | "false" | "True" | "False" ;

Note: This grammar is simplified and does not fully capture operator precedence for multiplication and division


Evaluation Semantics

Order of Evaluation

  1. Expressions are evaluated left-to-right
  2. Function arguments are evaluated before the function is called
  3. The last expression in a block is the block's value

Truthiness

In boolean contexts:

  • true is truthy
  • false is falsy
  • Note: Currently, only boolean values can be used in conditions

Type Coercion

MonkeyScript does not perform automatic type coercion. Operations on incompatible types will result in runtime errors


Error Handling

Lexical Errors

Thrown when encountering unexpected characters:

Error: unk char: @

Parse Errors

Thrown when syntax is incorrect:

Error: expected ';' after statement
Error: expected ')' to close grouped expression
Error: expected 'end' to close if statement

Runtime Errors

Thrown during execution (implementation-dependent)


Examples

Factorial Function

def factorial = fn(n):
    if n < 2:
        1;
    else:
        n * factorial(n - 1);
    end;
end;

factorial(5);

Counter with Closure

def makeCounter = fn():
    def count = 0;
    fn():
        def count = count + 1;
        count;
    end;
end;

def counter = makeCounter();
counter();
counter();
counter();

Fibonacci Sequence

def fib = fn(n):
    if n < 2:
        n;
    else:
        fib(n - 1) + fib(n - 2);
    end;
end;

fib(10);

Higher-Order Function

def twice = fn(f, x):
    f(f(x));
end;

def addOne = fn(n): n + 1; end;

twice(addOne, 5);  # Returns 7

Future Language Features

See ROADMAP.md for planned additions including:

  • String literals and operations
  • Arrays and hash maps
  • More operators (modulo, logical AND/OR)
  • Break and continue statements
  • Return statements
  • Comments
  • And more :) !

Conformance

This specification describes MonkeyScript version 0.1.0. Implementations should strive to match this behavior exactly. Any deviations should be documented


References


For questions or clarifications about this specification, please open an issue on GitHub