Methan0l Reference Documentation

Introduction

Methan0l is an embeddable general-purpose multi-paradigm interpreted programming language.

Every Methan0l program is a unit - a scoped block of expressions that can return a value.

Expressions can be either separated by a newline character, semicolon or just a space:

foo = 2; bar = 5

/* Valid too */
calc = foo * bar bar += 123

%% calc

Evaluation and Execution

There are no statements in Methan0l because almost everything yields a value upon evaluation. However, there are two ways expressions can be used: they can be either evaluated or executed.

Evaluation of an expression yields a value, while execution doesn’t yield anything and leaves a side effect instead.

Top-level expressions are executed by the interpreter while expressions that are used as parts of other expressions get evaluated for the result to be used in the parent expression.

Execution and evaluation are equivalent for almost all expressions, except for:

Unit definition

{
    do_something()
}

If a unit definition expression is used inside another expression, it just evaluates to a unit object, while if it’s used as a top-level expression, it’s evaluated to a unit and the result is immediately executed).

Identifier expression

some_variable

When used as a top-level expression, identifier is resolved and if it’s bound to a unit, the unit will get executed. If it’s bound to an unevaluated expression, it will get evaluated as a result.

Data Types

All methan0l variables are 3 pointers wide (24 bytes on 64-bit machines) regardless of their type.

Primitives & Heap-stored Types

There are two categories of types in Methan0l:

Because of this, copying of values is also separated into two types:

Type References

Types can be referenced by name using the following expression: (TypeName). Type reference expressions yield numeric type ids, which can be used for type checking (for example, via the val is: type_expr operator), type assertions (obj require: ClassName), or for comparison with another objects’ type ids, which can be obtained via the typeid: obj operator.

Built-in Data Types

All types listed in this section are “magic” built-in non-class types.

Primitive Types

Nil

Represents absence of value.
This is the value type of nil reserved identifier as well as the return type of a non-returning function.

Integer

64-bit integral type.
Supports hex (0x123) and binary (0b0110101) literal formats. Digits of numbers can be delimited with spaces for readability (e.g. x = 1 000 000)

Float

64-bit floating point type.

Boolean

Logical type. Can have values true or false.

Character

Character type. Literal format: 'c', escape sequences are supported: '\n', …

Reference

Points at another value and is always evaluated to it.
Doesn’t have a type id. To check whether value is a reference, use the is_reference: expr operator.
References must always be assigned to variables and returned from functions explicitly (by using the **expr operator), otherwise even if expr evaluates to a reference, it will be unwrapped into a copy of the referenced value.

Heap-stored Types

Callables

Unit

An expression block that may or may not return a value. Can be defined via the {...} syntax. Units can also be assigned to variables and invoked the same way as functions.

Function

Function type. For definition syntax, see the functions section.

User-defined Types

Object

Represents an object of some class (or an anonymous class). Doesn’t have a type id.
Objects are created via the new: Class(...) operator. Copying rules don’t apply to them, so to create a full copy of an object, objcopy: expr operator must be used.

Fallback

Represents an object of an unknown native type.
Used for interfacing with modules and objects of native classes bound to the interpreter.

Unevaluated Expressions

Expression

Value type returned by the noeval: expr operator. When evaluated, evaluates the underlying expression.

Standard Classes

String

String class. Escape sequences are supported inside literals (e.g. "a, b \n c\td").

List

Array-like container class.
Can be defined via the [...] operator (e.g. list = [1, 2, 3]), or by invoking the constructor: list = new: List().

Set

A container class without duplicate elements.
Can be defined by passing a list to the constructor: new: Set(list_obj).

Map

Associative key-value container class.
Can be defined via the @[key1 => value1, key2 => value2, ...] syntax or by invoking the constructor: map = new: Map().

For more detailed infornation on usage of container types, see the container types section.

Variables

Variables are dynamically-typed and are associated with identifiers.
In methan0l (almost) anything can be assigned to a variable, including functions, units (headless functions) and even unevaluated expressions. In terms of visibility variables are divided into two categories: local and global.

Visibility Scopes

All variables in Methan0l are implicitly local.
This means that for any regular unit (a function or a plain unit) any variable defined outside of its scope is global while variables defined inside of its scope are local.
Weak units (loops, conditional / try-catch expressions, lambdas) have a different visibility rule: all variables from parent scopes up to the first regular unit are local and all the other ones are global.

Local Variables

Local variables can be accessed just by referencing their names:

{
    x = 123
    foo(x) /* Access local variable x */
}

There’s also a way to define an explicitly local variable inside of the current scope.
var: name - creates a local variable name and returns a reference to it.
Even though multiple variables with the same name inside nested scopes can be created this way, the # prefix will be referring only to the first outer variable with the given name effectively shadowing all the other ones.


Example:

<% "Explicit local variables"
{
    x = 123
    if (x == 123) ? {
        <% $"Outer `x`: {}" x
        var: x = "foo"
        <% $"Explicitly local `x`: {}" x
    }
    <% $"Outer `x` is unchanged: {}\n" x
    
    <% "Variable shadowing"
    -> {
        var: x = "Local 1"
        -> {
            var: x = "Local 2"
            <% $"`x`s visible from here: [local: {}], [global: {}]" x, #x
        }
    }
}

Output:

Explicit local variables
Outer `x`: 123
Explicitly local `x`: foo
Outer `x` is unchanged: 123

Variable shadowing
`x`s visible from here: [local: Local 2], [global: Local 1]

Global Variables

Global variables can be accessed either by using the # prefix before the variable name:

x = "global value"
f = func: () {
    x = "local value"
    foo(#x) /* Access x from the outer scope */
}

Or by importing them into the current scope by reference via the global operator:

global: var1, var2, ...
var1.foo()

Global variables can also be captured inside function parameter list definitions after all arguments (similar to default argument definition):

f = func: x, y, %glob1, %glob2, ... {
    glob1 = x + y; /* Modifies the global `glob1` by reference */
}

Class Visibility Rules

As for classes, object fields can be accessed using this reference from within the method definition bodies.
All the other visibility rules are applied without changes.

Example:

<% "Class visibility scopes"
{
    some_global_var = "Very important"
    
    class: SomeClass {
        foo
        bar
        
        construct => method: a, b {
            this.foo = a
            this.bar = b
        }
        
        do_stuff => method: ()
            <% $"foo = `{}`, bar = `{}`, accessing a global variable: `{}`" this.foo, this.bar, #some_global_var
    }
    
    obj = new: SomeClass("text", "more text")
    obj.do_stuff()
}
<% ""

Output:

Class visibility scopes
foo = `text`, bar = `more text`, accessing a global variable: `Very important`

Function Invocation Rules

Scope visibility rules don’t apply to invocation expressions (e.g. foo()).
If function being called doesn’t exist in the current scope, an additional lookup will be performed until it’s found. If it’s not defined even in the global scope, an exception will be thrown.

Reserved Identifiers

Methan0l has a number of reserved identifiers:

Comments

There’s only one type of comments supported:

/* Comment text */

Operators

Most Methan0l operators have traditional behavior that doesn’t differ from any other language.
Operator expressions can also be grouped using ( ).

Operator Precedence

The higher the precedence level is, the tighter the operators are bound to their operands.

Pecedence Operators
1 noeval
2 <%, %%, %>
3 +=, -=, *=, /=, …
4 =, <-, :=
5 ::
6 e1 ? e2 : e3
7 ||
8 &&
9 |
10 ^
11 &
12 ==, !=
13 >, <, <=, >=
14 >>, <<
15 +, -
16 *, /, %
17 -, !, ~ (prefix)
18 ++, -- (prefix)
19 Postfix
20 ., @
21 []
22 ()
23 ++, -- (postfix)
24 var

Assignment Operators

Copy Assignment

dest_expr = expr

This effectively creates a full copy of the expr’s Value. This means that for heap-stored types a new object containing the copy of the expr’s Value is created.
Copy assignment is evaluated right-to-left.

Move Assignment

dest_expr <- expr

Creates a temporary partial copy of expr, removes it from the data table (if expr is an idfr) and assigns the partial copy to dest_idfr.
Move assignment is evaluated left-to-right.

Type-keeping Assignment

dest_expr := expr

Evaluates expr and converts it to the dest_expr’s type before assigning to it.
Type-keeping assignment is evaluated right-to-left.

Input / Output Operators

Input Operator

%> expr

Gets a value from stdin, deduces its type and assigns it to the specified variable / reference.

Input can also be read as a String using read_line([String prompt]) function.

Output Operators

Arithmetic Operators

If at least one operand of the expression is Float, the result is promoted to Float (except for bitwise operators and % – only Integers are supported, no implicit conversion is performed).

Binary:
+, -, *, /, %
+=, -=, *=, /=, %=
&, |, ^, >>, <<
&=, |=, ^=, >>=, <<=

Unary:
++, -- (both prefix and postfix)
-, ~ (prefix)

String Operators

String Formatter

String formatter can be used in one of two ways:

Formatter syntax:

Each format cell {...} can contain the following modifiers:

  1. None at all (this will just be replaced by the next argument from the argument list). 0.5. Argument index (optional): n. Must be specified before any other modifiers.

Other modifiers can be used in no particular order.

  1. Preferred width: %n.
  2. Alignment (left by default): -l for left / -r for right / -c for center.
  3. Floating point precision: .n.

Comparison Operators

==, !=, >, >=, <, <=

Equals operator == works for every type (including Units – in their case expression lists are compared), while all others are implemented only for numeric types.

Logical Operators

Binary:
&&, ||, ^^

Unary:
!

Return Operator

Return operator stops the execution of a Unit and returns the result of the provided expression’s evaluation.

Prefix:

Postfix:

Reference Operator

Get a reference to the Value associated with identifier:
**idfr

Example:

foo = 123
ref = **foo
/* Now <foo> and <ref> point at the same Value */

%% ++ref    <-- Outputs 124


Note: To assign a reference to a variable it’s always required to use the ** operator before the expression being assigned, even if it evaluates to a reference. Otherwise, a copy of the value behind the reference will be assigned. Example:

f = func: x -> x *= 10 /* Explicit `**` is required only when assigning  */
foo = 123

bar = f(**foo)
/* `bar` is now an Int variable = 1230
 * (f() call evaluated to a copy instead of reference),
 * `foo` is now = 1230 */

baz = **f(**foo)
/* `baz` is now a Reference to `foo` = 12300,
 * so any subsequent changes to `baz` will modify
 * the value of `foo` */

Conditional (Ternary) Operator

condition ? expr_then : expr_else

The condition is converted to Boolean and if true, the Then expression is evaluated and returned; otherwise – the Else expression result is returned.

Range Expression

start..end[..step]

Evaluates to a Range object (an IntRange or a FloatRange depending on start, end and step value types) that implements the Iterable interface. Ranges are end-exclusive.
Can be used for:

If-Else Expression

If-else expression in Methan0l uses the same syntax as ternary operator, but with if and else keywords used before the conditions and in between the then and else branches:

/* if-else */
if (condition) ? {
    expr1
    ...
} else: {
    else_expr1
    ...
}

/* if only */
if (condition) ? {
    expr1
    ...
}

/* if-elseif-...-else */
if (condition1) ? {
    expr1
    ...
} else: if (condition2) ? {
    elseif_expr1
    ...
} else: {
    else_expr1
    ...
}

Loops

There are 3 types of loops in Methan0l. As with any other block expression, braces can be omitted for single expression loops.

For Loop

for (i = 0, i < 10, ++i) {
    ...
}

While Loop

while (i < 10) {
    ...
    ++i
}

For-each Loop

Allows to iterate over any object, which class implements Iterable.

for (as_elem, iterable) {
    ...
}

Break Expression

You can interrupt a loop via the break expression:

return: break

Try-catch Expression

During a program’s execution exceptions may be thrown either by the interpreter itself or native modules or by using the die(expr) function, where expr can be of any type and can be caught inside of a try-catch expression:

try {
    ...
} catch: name {
    ...
}

Units

There are 2 types of units: regular and weak. The difference between them lies in scope visibility and execution termination rules.

Regular Units

Regular unit is a strongly scoped block of expressions (see visibility scopes section).
When a return expression is executed, regular unit stops its execution and yields the value being returned as its evaluation result.

Function bodies are regular units.

Regular units can be defined using the following syntax:

unit = {
    expr
    expr
    ...
}

If assigned to an identifier, a unit then can be called either using identifier expression’s execution syntax (returned value will be discarded in this case):

unit    /* <-- calls the unit defined above */

or using the function invocation syntax:

result = unit() /* <-- unit's return will be captured, if exists */

Weak Units

Weak units are weakly-scoped expression blocks and can access identifiers from the scopes above the current one up to the first regular unit without using the # prefix or importing references.

Return from a weak unit also causes all subsequent weak units stop their execution and carry the returned value up to the first regular unit, causing it stop its execution and yield the carried value as its return value.

Loops, if-else expressions and lambdas are weak units.

Weak unit definition syntax:

-> {
    expr1
    expr2
    ...
}

Box Units

Box unit preserves its data table after the execution and is executed automatically on definition. Fields inside it can then be accessed by using the . operator.

Modules loaded via the load(path) function or the import: path operator are box units.

Box unit definition syntax:

module = box {
    some_field = "Blah blah blah"
    foo = func @(x) {
        x.pow(2)!
    }
}

<% module.foo(5)    /* Prints 25 */
<% module.some_field    /* Prints contents of the field */


Any non-persistent unit can also be converted to box unit using make_box(Unit) function.

Box units as well as non-persistent ones can also be imported into the current scope:

module.import()

This effectively executes all expressions of module in the current scope.

Pseudo-function Invocation

Units can also be invoked with a single Unit argument (Init Block). Init block will be executed before the Unit being invoked and the resulting data table (which stores all identifiers local to unit) will be shared between them.

This syntax can be used to “inject” identifiers into a unit when calling it, for example:

ratio = {
    if (b == 0) ? "inf"!
    return: (a / b) * 100.0
}

<% "a is " :: ratio({a = 3; b = 10}) :: "% of b"

Functions

Functions accept a list of values and return some value (or nil when no return occurs).

Function Definition Syntax

foo = func (arg1, arg2, arg3 => def_value, ...) {
    ...
}


Or:

foo = func: arg1, arg2, arg3 => def_value, ... {
    ...
}


If function’s body contains only one expression, { & } braces can be omitted:

foo = func: x
    do_stuff(x)

Implicit Return Short Form

foo = func: x, y -> x + y

Here the expression after the -> token is wrapped in a return expression, so its result will be returned from the function without needing to explicitly use the return operator.

Multi-expression Short Form

In this case no return expression is generated automatically.

bar = func: () -> a = 123, b = 456, out = a * b, out!

Lambdas

Can be defined by using @: or f: function prefix instead of func::

foo = @: x
    do_stuff(x)

Or:

foo = f: x
    return: x.pow(2)

Lambdas can also be used with implicit return and multi-expression short form of function body definition. However, they can’t use the parenthesized argument definition form (only when a lambda accepts no arguments: foo = f: () -> do_something()).

The key difference between lambdas and regular functions is that lambdas’ bodies are weak units, which means that it’s possible to access variables from their parent scopes without using global access syntax:

glob = "foo bar"
lambda = @: x
    glob[] = x

lambda(" baz") /* Appends " baz" to the global variable `glob` */

Documenting Functions

When documenting Methan0l functions or methods, the following notation style should be used:

Return type

Argument List

Inherited Methods

When documenting methods inherited from a superclass or provided by an interface, use the following notation:

superclass_method(arg) -> Class @ SuperClass

Calling Functions

Functions can be called using invocation syntax:

result = foo(expr1, expr2, ...)


Functions can also be called by using pseudo-method syntax when the first argument is a built-in non-class type:

value.func(arg1, arg2, ...)

The expression above is internally rewritten as func(value, arg1, arg2, ...) when value is a primitive type, for example:

42.sqrt()

Unevaluated Expressions

Can be created by using the following syntax:

foo = noeval: expr

In this case expr won’t be evaluated until the evaluation of foo. When foo gets evaluated or executed, a new temporary value containing expr’s evaluation result is created and used in place of foo while foo’s contents remain unevaluated.

Example:

x = noeval: y * 2
y = 2

/* Equivalent to x = 2 + 2 * 2 */
<% "Result: " :: (x += y)


Classes

Even though Methan0l is not a pure OOP language, it supports classes with inheritance, interfaces and operator overloading.

Class definition syntax:

class: ClassName {
    ...
}

Class member (field, method, static method) definition follows the key-value syntax:

member => ...

Fields

Fields can be initialized via the syntax mentioned above or defined just by mentioning their name in the class body:

class: ClassName {
    field1, field2
    field3 => 123
}

Methods

Methods can be defined using the function definition syntax, but with method keyword instead of func:

class: ClassName {
    ...

    foo => method: arg1, arg2 {
        <% "ClassName@foo()"
        this.field1 = arg1
        this.field2 = arg2
    }
}

Methods or fields of an object can be accessed by using the . operator:

foo = obj.field
obj.some_method(arg1, arg2, ...)

Methods can also be static. Static methods are independent from any particular object and can be called on the class itself using the @ token instead of . (e.g. ClassName@static_method(...)):

class: ClassName {
    ...

    static_method => func: x {
        <% $"Static method arg: {}" x
    }
}

To distinguish static methods from non-static ones, the func keyword can be used instead of method when defining them.

Constructor

Constructors are defined by defining a special method named construct.

Each class can only have one constructor.

Contructor definition syntax:

class: ClassName {
    ...

    construct => method: arg1, arg2, arg3 {
        this.field1 = arg1 + arg2 + arg3
        this.field2 = "stuff"
    }
}

Object construction syntax:

obj = new: ClassName(arg1, arg2, arg3)

Inheritance

Methan0l classes can only inherit from one superclass at a time and implement multiple interfaces.

Constructor is inherited along with all other superclass methods.

Inheritance syntax:

class: Derived base: ClassName {
    ...
}

Method Overriding

To override a superclass method, just re-define it. The parent version of the method can be called using the static invocation syntax with this reference passed explicitly:

class: Derived base: ClassName {
    ...

    foo => method: arg1, arg2 {
        ClassName@method(this, arg1, arg2)
        <% "Derived@foo()"
    }
}

Operator Overloading

To overload an operator, specify its name as a string literal and then define it as a method:

class: Foo {
    ...
    
    "+" => method: rhs {
        return: new: Foo()
    }

    "*=" => method: rhs {
        <% "Overloaded compound assignment"
        return: this
    }
}

Index Operator Overloading

All of index operator subtypes can be overloaded for user-defined classes. Overload names should be quoted.

Copying Objects

Objects can be copied using copy: obj operator.

Anonymous Objects

Methan0l supports anonymous objects which can be used to pass around multiple named values.

Anonymous objects can also work as prototypes: when used in the RHS of the new operator, a deep copy of the object is created and then its constructor (if defined) is invoked (e.g. new_anon_obj = new: anon_obj(123), where anon_obj is an anonymous object with defined constructor).
Methods defined inside anonymous objects (including constructor) must have an explicit this argument in their parameter list.
Generally, defining methods inside such objects is a huge overhead as they are stored inside the object’s data table and are copied along with new objects when used inside of new or copy operator.

Example of anonymous object usage:

{
    obj = new: @[
        x => 123
        y => "some text"

        some_func => func: x
            return: x * 10

        foo => method: this, n
            return: this.x * n
    ]

    <% "obj.x = " :: obj.x
    <% "Anonymous object method call: " :: obj.foo(2)

    /* For now there's no other way to do this */
    <% "Regular function: " :: obj.get_method("some_func")(42)
}

Output:

obj.x = 123
Anonymous object method call: 246
Regular function: 420

Reflection

Get class’s unique id: class_id(). Can be invoked as a static method or as a method of an object:

obj = Class.new(a, b, c)
obj.class_id() == Class@class_id()
/* ^^ Evaluates to true ^^ */

Get all fields / methods of a class:

Class@get_fields() -> List
Class@get_methods() -> List

These methods return lists of class’ field / method names.
Specific fields can then be accessed from this class’ instance by name using the Class@get_field(name) -> Value method, e.g:

obj = new: SomeClass(42)
fields = SomeClass@get_fields()
<% $"Some field of `obj`: {}" obj.get_field(fields[0])

Specific methods can be invoked by name via the Class@get_method(name) static method:

methods = SomeClass@get_methods()
SomeClass@get_method(methods[0])(obj, arg1, arg2)

Path Prefixes

The following special prefixes can be used at the beginning of path strings everywhere in Methan0l:

For example: "$:/modules/ncurses" becomes: "/opt/methan0l/modules/ncurses".

Built-in Interfaces

Iterable

Interface Iterable requires classes implementing it to define a single method iterator(), which should return an object implementing the Iterator interface.
Iterable also provides a number of useful transformation methods:

Iterable also provides some built-in accumulative methods (specializations of Iterable@map(Function)):

Iterator

This interface describes an abstract iterator to be returned by the Iterable@iterator() method.

Methods:

Collection

Inherits: Iterable

This interface describes a collection of elements, such as a list or a set.

Methods:

Collection also provides the following methods:

Operator overloads:

AbstractMap

Inherits: Iterable

This interface describes an abstract key-value container.

Methods:

MapEntry

A special utility interface designed to be used for iterating over maps.

Methods:

Range

Implements: Iterable

This interface describes an abstract range in form [start, start + step, start + step * 2, ..., end].

Methods:

Built-in Classes

Container Classes

Pair

Represents a pair of values.

Constructor:

new: Pair(a, b)

Methods:

List

Implements: Collection

List definition syntax:

list = [expr, expr, expr, ...]

Methods:

Operator overloads:

Set

Implements: Collection

Set definition syntax:

set = new: Set(List)

Methods:

Operator overloads:

String

Implements: Collection

String definition syntax:

str = "some text"
str = new: String()
str = new: String(other_string)

Methods:

Operator overloads:

Map

Implements: AbstractMap

Map definition syntax:

map = @[
    key1 => val1
    key2 => val2
    ...
]

Or:

map = new: Map()

Methods:

Implements all methods declared by the AbstractMap interface along with:

Operator overloads:

Iterable Classes

Mapping

A class of objects produced by the Iterable@map(Function) -> Mapping method.
Maps an Iterable into another Iterable by applying the supplied function to it.

Methods:

Filter

A class of objects produced by the Iterable@filter(Function) -> Filter method.
Maps an Iterable into another Iterable by discarding elements that do not satisfy the supplied predicate.

Methods:

IntRange / FloatRange

A class of objects produced by the range built-in function and the range expression.
Represents an arbitrary numeric sequence.

Methods:


Utility Classes

File

Constructor:

file = new: File(path_str)

Methods:

Read / Write Operations:

Miscellaneous:

Static Methods:

Properties:


! All File methods (that don’t modify the state of the object) can be invoked statically by specifying the path for invoked operation as the first argument, for example:

File@exists("./foo/bar.txt")

Random

Constructor:

rnd = new: Random([Int seed])

If seed is not specified, a random one will be used.

Methods:

RNG Seeding:

Random Integer:

Random Float:

Random Boolean:


Modules

Module API (Legacy)

The current module architecture is deprecated.

Modules should use the Library loading and initialization mechanism.

Modules are just shared libraries that define a special function void init_methan0l_module(mtl::ExprEvaluator*) to be able to hook up to the interpreter instance.
This function can be defined using the INIT_MODULE macro that is a part of the methan0l module API (defined in the methan0l.h header in the root source directory).
Modules can optionally define an initialization function via the LOAD_MODULE {...} macro.
Alternatively, functions can be bound to the interpreter even without the LOAD_MODULE entry point by using the FUNCTION(name) macro inside of the source file, where name is a name of an already declared function.
C++ classes can also be bound to methan0l classes via the NativeClass<...> helper or directly using the ClassBinder<...> class.

You can see an example of module API usage (including ClassBinder) in modules/test.

Loading Modules

Load a Methan0l source file or a native module as a Box Unit:

load(path_str_expr)

Loaded module can be assigned to a variable and its contents can be accessed via the . operator, as with regular Box Units:

sys = load("system")
<% sys.exec("ls -a")

Modules can also be imported into the current scope after loading:

sys = load("system")
sys.import()

Or imported in-place via the import operator:

import: "system"
import: "test"

<% sys.exec("ls -a")
test()

Module Path Resolution

Module paths are resolved in the following steps:

  1. If supplied path exists
  1. If supplied path does not exist
  1. If supplied path is relative and does not exist


Core Library

Input / Output Operators & Functions [LibIO]

Input operator:
%> idfr

String input function:
read_line([prompt]) – read string from stdin and return it. The optional prompt argument will be converted to string and printed to the stdout before requesting user input, if supplied.

Output operators:
<% expr – print with trailing newline character
%% expr – print without a trailing newline character


String-related Functions [LibString]

Radix conversion:

to_base(String, Int dest_base, [Int src_base = 10]) -> String – returns a string representation of the provided numeric string converted from base src_base to base dest_base. This function automatically converts its first argument to string, so numeric values can be passed to it too.


Data Structure Operators & Functions [LibData]

Hashing Values of Any Type

hash_code: expr

Can be overloaded for classes via defining a hash_code() method.

Deleting Values

delete: idfr

Delete the identifier from the data table (and the value associated with it if it’s a primitive or a heap-stored value with refcount == 0 after identifier deletion).

Type Operators

Type Conversion

expr.convert(type_expr)

/* Or via an operator: */

expr to: type_expr

Here type_expr can be a type name, a string, or a numeric type id (that was obtained via a type reference expression or by invoking the class_id() method of an object).
Converts the value of the expression on the left hand side to specified type, for example:

bool = "true".convert(Boolean)
str = 1337.convert(String)
dbl = "-1.234".convert(Double)
set = $(123, 234, 345).convert(Set)

Variadic Function Arguments

args = get_args()

Can be called from inside a function’s body to get a list of all arguments passed to it, including extra arguments not defined in the function’s parameter list.

Command Line Arguments

get_launch_args()

Get command line args passed to the currently running Methan0l program.

Range

Create a Range iterable object (an IntRange or a FloatRange depending on argument types):

Range [0, n):

range(Int n) -> Range


Range [start, n):

range(Int start, n) -> Range


Range [start, start + step, …, n):

range(Int start, Int n, Int step) -> Range


Internal Functions [LibInternal]

Get Environment Info

Methan0l Version Info

sync_work_dir() – change working directory to the location of currently running script

Persistence

unit.make_box() – get a persistent copy of Unit (preserves Unit’s data table after the execution)

Check if current Unit is the program’s entry point

is_main_unit() – true if unit currently being executed is at the bottom of the execution stack

Execution Control

Benchmark

measure_time(expr) – returns time spent on evaluation of expr in milliseconds, discarding the result, if any.

Reflection

Get a reference to identifier’s value by name:


Common Math Functions [LibMath]

Trigonometry

Power functions

Exponential and Logarithmic Functions

Rounding

Absolute Value


Standard Modules

System

import: "system"

Ncurses

import: "ncurses"

Partial libncurses bindings.