Monkey
An interpreted language written in Go
Install / Use
/learn @skx/MonkeyREADME
- Monkey
- 1. Installation
- 1.1 Usage
- 2 Syntax
- 2.1 Definitions
- 2.2 Arithmetic operations
- 2.3 Builtin containers
- 2.4 Builtin functions
- 2.5 Functions
- 2.6 If-else statements
- 2.7 Switch statements
- 2.8 For-loop statements
- 2.9 Comments
- 2.10 Postfix Operators
- 2.11 Command Execution
- 2.12 Regular Expressions
- 2.13 File I/O
- 2.14 File Operations
- 3. Object Methods
- Github Setup
- Fuzz Testing
Monkey
This repository contains an interpreter for the "Monkey" programming language, as described in Write an Interpreter in Go.
My changes
The interpreter in this repository has been significantly extended from the starting point:
- Added single-line & multi-line comments.
- Added postfix operators (
i++,i--). - Allow accessing individual characters of a string via the index-operator.
- Added a driver to read from STDIN, or a named file, rather than a REPL.
- This allows executing the examples easily (for example "
./monkey examples/hello.mon".)
- This allows executing the examples easily (for example "
- Added a collection of standard-library functions.
- Including file input/output, type-discovery, string, and math functions.
- Added a new way to define functions, via
function. - Added the general-purpose comparision functions
<=&>=. - Allow string comparisons via
==,!=,<=, &>=. - Allow comparisions to be complex:
if ( a >= 'a' && a <= 'z' ) ..if ( a || b ) ..
- Allow assignments without
let.- This also allows operators such as "
+=", "-=", "*=", & "/=" to work.
- This also allows operators such as "
- Added command-line handling, so that scripts can read their own arguments.
- Added global-constants available by default
- For example
PI,E,STDIN,STDOUT, &STDERR.
- For example
- Most scripts will continue running in the face of errors.
- To correct/detect "obvious" errors add
pragma("strict");to your script, which will cause the interpreter to show a suitable error-message and terminate.
- To correct/detect "obvious" errors add
- Function arguments may have defaults. For example:
function greet( name = "World" ) { puts("Hello, " + name + "\n"); }
- Moved parts of the standard-library to 100% pure monkey, rather than implementing it in go.
- See data/stdlib.mon for the implementation.
- See also the notes on object-based methods.
- Added the
evalfunction.- Which allows executing monkey-code from a string.
- Improved error-reporting from the parser.
- It will now show the line-number of failures (where possible).
- Added support for regular expressions, both literally and via
matchif ( name ~= /steve/i ) { puts( "Hello Steve\n"); }
- Added support for ternary expressions.
- Added support for creating arrays of consecutive integers via the range operator (
1..10). - Added the ability to iterate over the contents of arrays, hashes, and strings via the
foreachstatement. - Added
printfandsprintfprimitives, which work as you would expect.printf( "%d %s", 3, "Steve" );
- Added support for
switchstatements, with block-basedcaseexpressions.- No bugs due to C-style "fall-through".
- Add support for explicit
nullusage:a = null; if ( a == null ) { .. }
See Also
If you enjoyed this repository you might find the related ones interesting:
- A tutorial-lead approach to implementing a FORTH interpreter:
- https://github.com/skx/foth
- A simple TCL-like interpreter:
- https://github.com/skx/critical
- A BASIC interpreter:
- https://github.com/skx/gobasic
- An embedded scripting language, based upon the same Monkey core
- This follows the second book, but large parts of the code were replaced with different implementations, and things were extended a lot.
- https://github.com/skx/evalfilter
Finally I put together a couple of "complex" compilers, which convert input into AMD64 assembly language:
- A mathematical compiler
- https://github.com/skx/math-compiler
- A brainfuck compiler:
- https://github.com/skx/bfcc
1. Installation
Due to the embedded standard-library implementation, which is implemented in monkey, you'll need to compile this project with go version 1.16beta1 or higher.
You can install from source like so:
git clone https://github.com/skx/monkey
cd monkey
go install
Binary Releases
Alternatively you could install a binary-release, from the release page.
If you're an emacs user might also wish to install the monkey.el file, which provides syntax highlighting for monkey-scripts.
1.1 Usage
To execute a monkey-script simply pass the name to the interpreter:
$ monkey ./example/hello.mon
Scripts can be made executable by adding a suitable shebang line:
$ cat hello.mon
#!/usr/bin/env monkey
puts( "Hello, world!\n" );
Execution then works as you would expect:
$ chmod 755 hello.mon
$ ./hello.mon
Hello, world!
If no script-name is passed to the interpreter it will read from STDIN and execute that instead, allowing simple tests to be made.
2 Syntax
NOTE: Example-programs can be found beneath examples/ which demonstrate these things, as well as parts of the standard-library.
2.1 Definitions
Variables are defined using the let keyword, with each line ending with ;.
let a = 3;
let b = 1.2;
Variables may be integers, floats, strings, or arrays/hashes (which are discussed later).
Some variables are defined by default, for example:
puts( PI ); // Outputs: 3.14159..
puts( E ); // Outputs: 2.71828..
Variables may be updated without the need for let, for example this works
as you would expect:
let world = "Earth";
world = "world";
puts( "Hello, " + world + "!\n");
If you're not running with pragma("strict"); you can also declare and
use variables without the need for let, but that should be avoided as
typos will cause much confusion!
name = "Steve";
puts( "Hello, " + name + "\n");
2.2 Arithmetic operations
monkey supports all the basic arithmetic operation of int and float types.
The int type is represented by int64 and float type is represented by float64.
let a = 3;
let b = 1.2;
puts( a + b ); // Outputs: 4.2
puts( a - b ); // Outputs: 1.8
puts( a * b ); // Outputs: 3.6
puts( a / b ); // Outputs: 2.5
puts( 2 ** 3 ) ; // Outputs: 8
Here ** is used to raise the first number to the power of the second.
When operating with integers the modulus operator is available too, via %.
2.3 Builtin containers
monkey contains two builtin containers: array and hash.
2.3.1 Arrays
An array is a list which organizes items by linear sequence. Arrays can hold multiple types.
let a = [1, 2.3, "array"];
let b = [false, true, "Hello World", 3, 3.13];
Adding to an array is done via the push function:
let a = push(a, "another");
You can iterate over the contents of an array like so:
let i = 0;
for( i < len(a) ) {
puts( "Array index ", i, " contains ", a[i], "\n");
i++
}
With the definition we included that produces this output:
Array index 0 contains 1
Array index 1 contains 2.3
Array index 2 contains array
Array index 3 contains another
As a helper you may define an array of consecutive integers via the range operator (..):
let a = 1..10;
2.3.2 Hashes
A hash is a key/value container, but note that keys may only be of type boolean, int and string.
let a = {"name":"monkey",
true:1,
7:"seven"};
puts(a); // Outputs: {name: monkey, true: 1, 7: seven}
puts(a["name"]); // Outputs: monkey
Updating a hash is done via the set function, but note that this returns
an updated hash - rather than changing in-place:
let b = set(a, 8, "eight");
puts(b); // Outputs: {name: monkey, true: 1, 7: seven, 8: eight}
You can iterate over the keys in a hash via the keys function, or delete
keys via delete (again these functions returns an updated value rather than
changing it in-place).
Hash functions are demonstrated in the examples/hash.mon sample.
2.4 Builtin functions
The core primitives are:
delete- Deletes a hash-key.
int- convert the given float/string to an integer.
keys- Return the keys of the specified array.
len- Yield the length of builtin containers.
match- Regular-expression matching.
pragma- Allow the run-time environment to be controlled.
- We currently sup
