SkillAgentSearch skills...

Monkey

An interpreted language written in Go

Install / Use

/learn @skx/Monkey
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Go Report Card license Release

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".)
  • 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.
  • 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.
  • 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.
  • 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.
  • Added the eval function.
    • 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 match
    • if ( 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 foreach statement.
  • Added printf and sprintf primitives, which work as you would expect.
    • printf( "%d %s", 3, "Steve" );
  • Added support for switch statements, with block-based case expressions.
    • No bugs due to C-style "fall-through".
  • Add support for explicit null usage:
    • 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
View on GitHub
GitHub Stars301
CategoryDevelopment
Updated14h ago
Forks38

Languages

Go

Security Score

100/100

Audited on Mar 30, 2026

No findings