Mico
Mico ("Monkey" in catalan). Monkey language implementation done with C++. https://interpreterbook.com/
Install / Use
/learn @newenclave/MicoREADME
Mico
<a href="https://scan.coverity.com/projects/newenclave-mico"> <img alt="Coverity Scan Build Status" src="https://img.shields.io/coverity/scan/13291.svg"/> </a>Monkey :monkey: the language interpreter implementation done with C++. https://interpreterbook.com/
- There is no compiler implementation here. Sorry. But I dont have a piece of time for this :(
- Feel free to ask me anything.
- Now I'm a more experienced and would rewrite this code completely :)
- thanks Thorsten Ball :)
- https://monkeylang.org/

Requirements
- C++ compiler (c++11 or later)
- The book https://interpreterbook.com/. If you have not read it yet.
Table of Contents
Compile
Mico is a header-only project. Well you need just compile mico.cpp
github $ git clone https://github.com/newenclave/mico.git
github $ cd mico
mico $ git submodule update --init etool
mico $ g++ -std=c++11 mico.cpp -O2 -Iinclude -Ietool/include -Wall -o mico
Or clang
mico $ clang++ -O2 mico.cpp -std=c++11 -Iinclude -Ietool/include -Wall -o mico
Or MS SDK compiler. It should be called from the "Visual Studio Command Prompt" for example
mico> cl /I include /I etool/include mico.cpp
mico> link /OUT:"mico.exe" mico.obj
Or just use Visual Studio (at least version 12)
Thats all.
Monkey and Mico
"Mico" is an implementation but of course it has some difference. For now I'm pretty sure that Mico can run the major part of Monkey's code.
View
Mico supports: integers, floats, chars, strings, arrays, tables, functions, modules, intervals
let int = 1_000_000 // int is an integer
let f = 0.1e-3 // f is a float `0.0001`
let s = "This is a string" // string
let t = { "x": 0, "y": 0, "z": 0 } // table (or Hash)
let a = [1, 2, 3, 4, 5, 6, [0, 0, 0]] // array (that contains another array)
let fun = fn(a, b){ (a - b) * (a + b) } // function
let mod = module { let var1 = 1; let var2 = 2 } // module
let ival = 1..100 // interval
let c = '🐒' // character
Identifiers
Identifiers can use unicode symbols
let кирилица = "Кирилица"
let españa = "Spain"
let 中國 = 12312
let العربية
= {1: 中國}
io.puts(кирилица)
io.puts(españa)
io.puts(中國)
io.puts(العربية
[1])
// Кирилица
// Spain
// 12312
// 12312
Token position
Every token has its position.
let test_val = someUnknownCall()
error: [1:15] Identifier not found 'someUnknownCall'
Numbers
Numbers can contain a gap symbol _. The symbol can be included both in integers and in floats.
let int = 1_000_000 // 1000000
let hex = 0xAAA_BBB // 11185083
let bin = 0b1111_0000_1111_0000 // 61680
let ter = 0t22_11_22_11 // 6232
let oct = 0_777_111_222_333 // 68604470491
let flt = 10.1000_0002 // 10.10000002
Strings
let s = "string"
io.puts(s[1])
// `t`
let s = "中國"
io.puts(s, " ", len(s), " ", s[0])
// `中國 2 中`
Yes. It supports the unicode. Not completely of course. I've written a small utf8 parser and I think it's enough for this toy language. And for Windows it uses native API for encoding.
Raw strings
Raw strings are just arrays of bytes
let s = r"string"
io.puts(s[1])
// 116
let s = r"中國"
io.puts(s, " ", len(s), " ", s[0])
// 中國 6 228
Unlike strings raw strings know nothing about the unicode. And that is why string 中國 has length 2 and the
lenght of the raw string is 6.
Slices
Slice is a part of an array or a string. Slice holds the object (string or array) and an interval [left..right].
The slice can be created with index operator []. Interval includes only its left side (i.e. the intervals are left closed, right open).
Full container interval can be created with the interval cont[0..len(cont)] or cont[0..-1] (see "Negative index" above)
let str = "This is a string"
let this = str[0..4]
io.puts(this)
// shows `This`
Arrays slices
let arr = [0,1,2,3,4,5,6,7,8,9]
let s = arr[0..3]
for i in s { io.put( i, " " ) } // shows `0 1 2`
Slice can change its direction. If the left part of the interval is greater then right, interval changes its direction.
let arr = [0,1,2,3,4,5,6,7,8,9]
let s = arr[8..2]
for i in s { io.put( i, " " ) } // shows `7 6 5 4 3 2`
Of cource it's only valid when an element is accessed by index
let str = "Hello, world!"
let s = str[len(str)..0]
for i in s { io.put( i ) } // shows `!dlrow ,olleH`
/// but!
io.puts(s) // Hello, world!
Slices are not copyes!
Slice can be also created from another slice.
let arr = [0,1,2,3,4,5,6,7,8,9]
let s = arr[1..10] // s is a slice[1,2,3,4,5,6,7,8,9]
let t = s[2..5] // t is a slice[3, 4, 5]
for i in t { io.put( i, " " ) } // shows `3 4 5`
Negative index
Elements of arrays or strings can be obtained by negative index. -1 means the last element of the array/string
let arr = [0,1,2,3,4,5,6,7,8,9]
io.puts(arr[-1]) // 9
io.puts(arr[-2]) // 8
let s = "中國"
io.puts(s[-2]) // 中
Slices also can be created by adding a negative index
let str = "Hello, world!Äáç¶"
let sym = str[-5..-1]
let hello = str[0..-5]
io.puts(sym) // Äáç¶
io.puts(hello) // Hello, world!
Mutability
By-default all values set by let statement are inmutable. For making a variable, that can change its value use var statement.
Every variable is a real variable and can be changed by assignmet operator =.
var a = [1, 2, 3, 4, 6]
var b = 1
let d = 77.77 // `d` is constant
b = 10 // ok
c = 100 // oops; error: [1:0] Identifier not found: 'c'
d = 88.88 // oops; error: [1:2] Invalid left value for ASSIGN d
let fun = fn( ) {
let a = 100 // here `a` shadows the variable `a` from the global scope
b = 0.0 // here `b` is from the global scope
}
fun( )
mut keyword
All objects are also constats. It can be changed by keyword mut. It makes sense for arrays and tables.
let a = [1,2,3,4]
a[0] = 1000
// error: [2:5] Invalid left value for ASSIGN a[0]
// as far as the object is const
let a = mut [1,2,3,4]
a[0] = 1000 // ok
io.puts(a[0]) // shows `1000`
const keyword
The const keyword can make an object constant.
let a = mut [1,2,3,4]
a[0] = 1000 // ok
let a = const a // set const
a[0] = 1000
// error: [1:5] Invalid left value for ASSIGN a[0]
The keywords mut and const always make a copy of the object if the mutablity of the object is different.
let a = mut [1,2,3,4]
let a = mut a // returns `a` without changes
let a = const a // makes a copy of `a`
The operator is a right arm operator.
var a = [1, 2, 3, 4, 5]
a[0] = a[1] = a[2] = a[3] = a[4] = 0
// a == [0, 0, 0, 0, 0]
The let statement makes constants objects
let a = [1, 2, 3, 4, 5]
a[0] = a[1] = a[2] = a[3] = a[4] = 0
// error: [2:9] Invalid left value for ASSIGN a[0]
Intervals
Intervals are pairs of values. Values can be integers, floats, strings or boolean. Operator .. creates an interval.
For now there are not a lot of operations with intervals.
let float = 1.0..100.0
let int = 1..100
let bool = false..true
let strings = "a".."z"
for in
The operator makes a for-loop. It's an expression and always returns its value as the result. There are several types of the operator.
Simple counter loop. Accepts an integer or a float as a value and makes a loop that is repeated value times
for i in 10 {
io.put(i, " ")
}
io.puts( )
This code shows 0 1 2 3 4 5 6 7 8 9.
The operator can have a step value that can change loop's increment and even make it negative
for i in 10, 2 {
io.put(i, " ")
}
io.puts( )
// 0 2 4 6 8
for i in -7, -0.7 {
io.put(i, " ")
}
io.puts( )
// 0 -0.7 -1.4 -2.1 -2.8 -3.5 -4.2 -4.9 -5.6 -6.3
An interval loop acccepts a numeric (float or integer) interval and
Related Skills
node-connect
343.3kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
92.1kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
343.3kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
343.3kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。
