FunnyLang
FunnyLang
Note: This language is heavily inspired by Porth by Tsoding.
FunnyLang is a simple, stack-based, interpreted language implemented in Python. It uses postfix (Reverse Polish) notation for operations and supports variables, conditionals, loops, and function definitions.
Table of Contents
Overview
FunnyLang is a postfix, stack-oriented language. Instead of writing a + b, you push a and b onto the stack, then apply the operator +. You can define functions, variables, and control flow structures such as if, else, while, etc. The language is intended to be minimalistic yet expressive enough for small scripting tasks.
Features
- Stack-based operations: Push operands onto the stack and then apply operations.
- Control flow:
if ... end,else, andwhile ... endconstructs. - Functions: Define named functions with
func <name> ... end. - Variables: Declare variables with
var <name>and assign with@. - Standard library: Common operations like
print,true,false, basic arithmetic definitions, etc.
Project Structure
.
├── funny.py # Main interpreter
├── lexer.py # Tokenizes .funny files
├── keywords.py # Enumeration of keywords and helper functions
├── funny.bat # Batch script for Windows to run .funny files
└── Libraries
└── std.funny # Standard library of helpful functions
└── useless.funny # Useless functions that you might never need
Installation & Requirements
- Python 3.x
No external libraries are required beyond standard Python. Just clone or download this repository, and you can run funny.py directly.
How to Run FunnyLang
You can run a FunnyLang program in two ways:
- Directly with Python:
python funny.py path/to/program.funny
- Using the provided batch file (Windows):
funny.bat path\to\program.funny
This will pause after execution so you can see the output.
Language Basics
Stack-Based Execution
FunnyLang works with a stack. Every time you write a literal (number or string), it is pushed onto the stack. Operators then act on the top elements of the stack.
- PUSH: Numbers and quoted strings (e.g.,
5,"Hello") are automatically pushed. - Arithmetic (
+,-,*,/,%): Pops the top two items from the stack, applies the operation, and pushes the result back. - dump (.): Pops the top of the stack and prints it as a number without a newline.
- write: Pops the top of the stack and prints it as string/text without a newline.
- dup: Duplicates the top element of the stack.
Operators
Below is a table of key operators in FunnyLang:
| Operator/Keyword | Description |
|---|---|
+
|
Add the top two numbers on the stack. |
-
|
Subtract the top of the stack from the second top. |
*
|
Multiply the top two numbers. |
/
|
Divide the second top by the top. |
%
|
Modulo (second top mod top). |
. (dot)
|
Print the top of the stack (as a number), no newline. |
write
|
Print the top of the stack as text, no newline. |
dup
|
Duplicate the top of the stack. |
pop
|
Pop the top element from the stack. |
: (roll)
|
Rotate the top element under the next one. |
attach
|
Attach/import another .funny file.
|
input
|
Prompt user input and push it onto the stack. |
Variables
Variables are declared with var <name>:
var myVar
This defines myVar in the current environment with a default value of 0.
To get the value of a variable, just write its name:
myVar
It pushes the current value of myVar onto the stack.
To set a variable, push the new value first, then push the variable name (as a string), and finally use @:
42 "myVar" @
This sets myVar to 42.
Functions
Define a function with:
func <functionName>
... function body ...
end
Call it simply by writing its name:
<functionName>
That will execute all instructions in the function body.
Conditionals
FunnyLang provides if, else, and end for conditionals. The structure is:
<condition> if
... code if true ...
else
... code if false ...
end
- The
<condition>is expected to be a number on the stack (non-zero is true, zero is false). - The
elsepart is optional.
Example:
5 10 > if "5 is greater than 10" write else "5 is not greater than 10" write end
Loops
Use while and end for loops. The pattern is:
<condition> while
... code ...
end
The loop will keep running as long as the condition on the top of the stack is non-zero. Typically, you update that condition inside the loop.
Example:
var counter
10 "counter" @ // set counter to 10
1 while // 1 is just there to get the while started
pop // pop the condition check so it doesn't clutter the stack
counter // push current value of counter
1 - // subtract 1
"counter" @ // set new value to counter
"Looping!\n" write
counter 0 >
end
Attachments (Imports)
Use attach to include another .funny file:
"./Libraries/std.funny" attach
This merges the functions from std.funny into the current environment. You can then call those functions directly.
Standard Library (std.funny)
Within ./Libraries/std.funny, you'll find a collection of basic helper functions:
print– Prints the top of the stack along with a newline.false– Pushes0.true– Pushes1.add / sub / mult / div– Aliases for+,-,*,/.roll– Alias for:.square– Squares the top of the stack.double– Doubles the top of the stack.odd– Tests if top of stack is odd (pushes1or0).even– Tests if top of stack is even (pushes1or0).set– Alias for@(set variable).pow– Raises a number to a given exponent (handles negative exponents as well).
These functions serve as building blocks for more complex FunnyLang programs.
Example Program
Create a file called example.funny with the following content:
// example.funny
"./Libraries/std.funny" attach // load standard library
func main
5 6 add // 5 + 6
print // print result
"Hello, FunnyLang!" print
end
Then run:
python funny.py example.funny
or on Windows:
funny.bat example.funny
You should see:
11 Hello, FunnyLang!
Interpreters
Github Python Interpreter: FunnyLang