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
- Lexical Structure
- Data Types
- Expressions
- Statements
- Functions
- Scoping and Environments
- 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:
| Keyword | Purpose |
|---|---|
def | Variable declaration |
if | Conditional statement |
else | Alternative branch |
while | Loop statement |
fn | Function literal |
end | Block terminator |
true | Boolean literal |
false | Boolean 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
| Operator | Name | Example |
|---|---|---|
+ | Addition | 5 + 3 |
- | Subtraction | 10 - 4 |
* | Multiplication | 6 * 7 |
/ | Division | 20 / 4 |
Comparison Operators
| Operator | Name | Example |
|---|---|---|
< | Less than | x < 10 |
> | Greater than | x > 5 |
== | Equal to | x == 42 |
!= | Not equal to | x != 0 |
Logical Operators
| Operator | Name | Example |
|---|---|---|
! | Logical NOT | !true |
Note: && (AND) and || (OR) are not yet implemented
Delimiters
| Symbol | Name | Usage |
|---|---|---|
; | Semicolon | Statement terminator |
: | Colon | Block delimiter |
( ) | Parentheses | Grouping, function calls |
, | Comma | Parameter/argument separator |
= | Equals | Assignment |
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):
- Parentheses
( ) - Multiplication
*, Division/ - Addition
+, Subtraction- - 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:
- Its own local variables
- Variables from enclosing scopes
- 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
- Expressions are evaluated left-to-right
- Function arguments are evaluated before the function is called
- The last expression in a block is the block's value
Truthiness
In boolean contexts:
trueis truthyfalseis 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
- README.md - Project overview
- CONTRIBUTING.md - Development guide
- ROADMAP.md - Future plans
For questions or clarifications about this specification, please open an issue on GitHub