Compiler Reference

mplc compiles MPL source modules to textual LLVM IR. Use clang to compile that IR into an executable.

Invocation

mplc [options] <sources>

A source argument is a module file path. The compiler uses the path as supplied; it does not append .mpl to a top-level source argument. Several source arguments are loaded, parsed, and compiled as separate modules in one compilation context, in argument order. They are not concatenated. Processing stops at the first source that fails.

A successful compilation still prints its module list and status.

Sources and module paths

use resolves a module descriptor against the directory of the module containing the use first. It then tries the -I directories in command-line order. The first file that loads wins.

For example, "a/b" use resolves the path suffix a/b.mpl. The compiler appends .mpl to a module descriptor. The main source is loaded from its supplied path first; its containing directory is the implicit search path for its use calls. A main source with no directory component therefore uses the current directory first. Each imported module supplies its own containing directory for subsequent imports.

A descriptor may contain a symbol suffix after a dot. The suffix selects a name from the loaded module; the file path still uses the part before the suffix.

-I paths are normalized to have a trailing slash when needed.

Windows

WINDOWS is not a command-line option. The compiler's own main.mpl uses the build-time WINDOWS definition to select Windows CRT stream setup. A user -D WINDOWS defines a name in the program's <BASE> module; it does not change an already-built compiler. The Standard Library does not use the name: its test scripts pass PLATFORM="windows" and a Windows include directory.

Output

With no -o, the compiler does not write the generated IR to a file. With -o <path>, it saves the complete LLVM IR text at exactly that path, including the code generated while the module-level DIE fields run at the end of compilation. The option does not add an extension.

The saved file is intended for a second compiler invocation:

mplc ... -o prog.ll prog.mpl
clang prog.ll -O3 -lm -o prog

-debug adds LLVM debug metadata to the IR. It does not change the DEBUG builtin flag.

Options

Option Meaning Default
-32bits Use 32-bit references. 64-bit references.
-64bits Use 64-bit references. If both width options are present, the last one wins. 64-bit references.
-D <name>[=<value>] Add a global definition to <BASE>. The compiler turns NAME=value into overload NAME: [value]; and parses value as MPL source. Without =, it creates overload NAME: ();, an empty tuple, not TRUE. Quote text in the shell, for example -D MPLC=\"/path/to/mplc\". No definitions.
-I <path> Add a module search directory. Explicit directories are tried in the order given, after the containing directory of the importing module. No explicit directories.
-callDepthLimit <limit> Set the maximum compiler call depth. The limit must be a non-negative integral number below 2,147,483,648. 1024.
-callTrace <level> Enable generated runtime call tracing when the argument is not exactly 0; 0 disables it. getCallTrace then reads the generated call-trace chain. Disabled.
-debug Generate LLVM debug information. LLVM debug information disabled. The DEBUG builtin flag is enabled independently.
-detectRedundantUses Print every unused use word after processing the sources. Disabled.
-hidePrefix <prefix> Suppress error-trace and redundant-use locations whose file names start with <prefix>. No hidden prefixes.
-linker_option <argument> Accepted for compatibility. It consumes one argument but has no effect in this LLVM compiler. No effect.
-ndebug Disable the DEBUG builtin flag. It also disables LLVM debug information. DEBUG is enabled; LLVM debug information is disabled.
-o <path> Save LLVM IR text to <path>. Empty path; no IR file is written.
-permissiveParsing Allow carriage returns outside text and comments, and spaces immediately before LF. See Strict and permissive parsing. Disabled.
-staticLoopLengthLimit <limit> Set the maximum number of iterations for a static loop. The limit uses the same non-negative integral argument check as -callDepthLimit. 256.
-version Print MPL Compiler version 260513.1 and stop processing sources. Not applicable.

-debug and -ndebug are mutually exclusive. The later option reports the conflict: -debug -ndebug reports -ndebug is incompatible with -debug; -ndebug -debug reports -debug is incompatible with -ndebug.

The DEBUG builtin returns the compiler's debug flag. It is TRUE by default and FALSE with -ndebug. A user definition with the same name can be selected instead; for example, -ndebug -D DEBUG=TRUE prints TRUE.

Diagnostics and status

Except for compiler-output transcripts on this page, the Reference's expected-output blocks omit module-loading and final compilation-status lines; stack dumps produced by printStack use its documented notation. Expected-output blocks use the default 64-bit target unless an example states otherwise.

The compiler prints one line for each loaded module. The first line is <BASE>, which contains command-line definitions. Source and imported module paths follow. Compile-time messages from the program appear as they are emitted. The final status line is one of:

Compilation succeeded
Compilation failed

A normal diagnostic has this shape:

file(line,col): «token», message
file(line,col): «token», Called from here
file(line,col): «token», Created here

The first line is the message location. Nested compiler scopes add Called from here. Value diagnostics can add Created here or Referenced here locations. -hidePrefix removes matching location lines.

Parse errors use file(line,col): message, followed by Parse error.

The messages themselves, with the condition that raises each one and the change that resolves it, are catalogued on the Diagnostics page.

With -detectRedundantUses, an unused import is reported as file(line,col): «use», «module» has never been used.

The process status is 0 after Compilation succeeded, 1 after Compilation failed or when a source file cannot be read, and 2 for an invalid command line. Build scripts can rely on the status; captured output carries the same information in the final status line.

Runtime call trace

With -callTrace 1, generated callable calls maintain a linked runtime chain. getCallTrace returns the current item with fields name, line, column, and prev. The compiler records the source path and call-site coordinates when entering a generated call and restores the previous item when leaving it.

printStackTrace is separate. It prints the compiler's current compile-time scope stack, using source locations and Called from here; it is not the runtime call-trace printer.

Examples

Hello world

hello.mpl:

"String"  use
"control" use

{} Int32 {} [
  ("Hello, world!\n") printList
  0
] "main" exportFunction
mplc -I mpl-sl -o hello.ll hello.mpl
clang hello.ll -O3 -lm -o hello
./hello

The compiler output ends with:

<BASE>
hello.mpl
mpl-sl/String.mpl
mpl-sl/Array.mpl
mpl-sl/Span.mpl
mpl-sl/control.mpl
mpl-sl/conventions.mpl
mpl-sl/algorithm.mpl
mpl-sl/memory.mpl
Compilation succeeded

The program prints:

Hello, world!

A command-line definition

define.mpl reads LIMIT twice.

# mplc -D LIMIT=5
"control" use

{} Int32 {} [
  LIMIT printStack _:;
  LIMIT 0 same printStack _:;
  0
] "main" exportFunction
mplc -I mpl-sl -D LIMIT=5 -o define.ll define.mpl

The relevant compiler output is:

5
TRUE
Compilation succeeded

The first line is the value. The second line confirms that the definition has the default Int32 schema by comparing it with 0.

A failed compilation

For a source containing missingName, the output is:

<BASE>
failure.mpl
mpl-sl/control.mpl
mpl-sl/conventions.mpl
failure.mpl(4,3): «missingName», Name was not found
failure.mpl(6,10): «exportFunction», Called from here
Compilation failed