Getting started
This chapter installs Pepper on your machine, compiles and runs a first program, and sets up your editor.
Install Pepper
Each release has the Pepper toolchain prebuilt for Linux, macOS and Windows. One command installs it:
# Linux and macOS
curl -fsSL https://raw.githubusercontent.com/justinboswell/pepper/main/scripts/install.sh | sh
# Windows (PowerShell)
irm https://raw.githubusercontent.com/justinboswell/pepper/main/scripts/install.ps1 | iex
It installs into ~/.pepper (%LOCALAPPDATA%\pepper on Windows), adds its
bin folder to your PATH, and offers to install what linking a program
needs when it is missing: clang on Linux, Xcode’s command line tools on
macOS, LLVM and the Visual Studio Build Tools on Windows. Open a new terminal
afterwards. Installing Pepper covers the options, what
it installs, and uninstalling.
Building from source
To work on Pepper itself, or on a platform with no prebuilt binaries, build the toolchain from source: see Building Pepper from source.
Your first program
Pepper source files end in .pep. Create a file named hello.pep:
# Every program starts at main. Its return value is the process exit code.
main(): int {
print("Hello, world!");
return 0;
}
Every program starts at main, which here takes no arguments and returns an
int (it can also take the command-line arguments; see
Functions):
the process’s exit code, where 0 means success. print writes a value’s text to
standard output, followed by a new line. Comments start with # and run to
the end of the line.
Compile and run it
Pass the source file to pepper build. It compiles and links a native executable,
but does not run it, so run the result yourself:
pepper build hello.pep -o hello
./hello
Hello, world!
On Windows, name the output with .exe (-o hello.exe), since Windows will
not run a file without an extension, and run it as .\hello.exe. Without -o
the executable is written to the current directory, named after the source
file with no extension (hello for hello.pep).
Running a program
To build and run in one step, as python hello.py does, use pepper run.
It keeps the executable out of your folder, and runs it again at once when
nothing changed:
pepper run hello.pep
Arguments after the file go to the program’s main; see
Running a program: pep-run.
Where the compiler finds the standard library
Every program is compiled together with Pepper’s standard library, the
runtime/ folder of the repository. The compiler looks for it in this order:
- The directory named by the
PEPPER_RUNTIMEenvironment variable, if it is set. Nothing else is searched. - Starting from the directory you run it from:
runtime/,.pep/runtime/, then../runtime/,../../runtime/, and so on, up to five levels up. - Starting from the directory that holds the compiler executable:
runtime/beside it, then in each parent directory, up to five levels up.
So an installed compiler, in ~/.pepper/bin, finds ~/.pepper/runtime, and
one built in target/bin finds the runtime of the clone it was built
from, wherever you run it. To use a different runtime, set
PEPPER_RUNTIME or link the runtime into a project’s .pep folder:
mkdir .pep
ln -s /path/to/pepper/runtime .pep/runtime
If the compiler cannot find the runtime, it stops with an error:
error: cannot find the Pepper runtime: no runtime directory near /home/me/project or the compiler; set PEPPER_RUNTIME to its path
The compiler also writes intermediate files to .pep/build/ under the
directory you run it from, and keeps a build cache in .pep/cache/: each file
of the program (and the standard library) is compiled to its own object, and
on the next build a file whose sources did not change reuses its object
without being compiled or checked again, as long as what its imports declare
did not change either: editing a function’s body recompiles that file alone,
while changing a signature also recompiles the files that import it. A file
that compiled with warnings is checked again, so its warnings print on every
build. When nothing changed, nothing is checked or linked again. The cache also
keeps the standard library checked, so a program’s own files are the only ones
checked on each build. Deleting .pep/cache/ is always safe.
When something is wrong
The compiler reports errors the way clang does: the file, line and column, a message, and the source line with a caret under the exact token to fix. Store the message in a variable first, then misspell its name:
main(): int {
var greeting = "Hello, world!";
print(greting);
return 0;
}
The compiler reports:
main.pep:3:11: error: use of undeclared identifier 'greting'
3 | print(greting);
| ^~~~~~~
Errors are colored when the output is a terminal; set NO_COLOR to turn
color off. The chapter on compiler errors
covers them in more detail.
A failed assert or a panic at run time prints its message and stops the
program abnormally. For example, value() on a failed Result prints
Result.value on an Err value.
Useful compiler options
| Option | What it does |
|---|---|
-o <file> | Name the output executable (or library, with --lib). |
-O, -O<n> | Optimize: -O0 (the default) through -O3; -O alone is -O2. |
-g | Emit debug info for gdb, lldb, Visual Studio and WinDbg. See debugging. |
-I <dir> | Add a directory to search for imported modules. See modules and imports. |
-l <lib>, -L <dir> | Link a C library, and add a folder to find it in. See linking. |
-D <name>[=<value>] | Define a build option. |
--target <triple> | Compile for another platform; see Cross-compiling. |
--lib static, --lib shared | Build a library for C code to link. See calling Pepper from C. |
--help | List every option. |
The compiler: pep-build describes every option and environment variable the compiler reads.
A program can span several files: pass the entry file, and the compiler finds the files it imports on its own.
Editor support
The VS Code extension adds syntax highlighting and a language server, which reports compiler errors as you type and provides hover information, completion, go to definition, and an outline of each file.
The packaged extension is published as a .vsix file on the repository’s
releases page, under the
release whose tag starts with vsix-v. Download it and install it in VS Code
with Extensions: Install from VSIX… from the command palette. The
language server is bundled with the extension, so there is nothing else to
install.
A few things are useful once it is installed:
- Pepper: Restart Language Server restarts the server on demand.
- Where a value is converted by an
[Implicit]constructor, the editor shows the call it stands for as an inlay hint (Path(before"notes.txt"and)after), and hovering the value says so. Thepepper.inlayHints.implicitConversionssetting turns the hints off. - A literal passed by position shows the name of its parameter as an inlay
hint (
resize(width: 800, height: 600)); thepepper.inlayHints.parameterNamessetting turns these off. Inside a call’s parentheses, completion offers the parameter names to name (width =). - Hover and go to definition also work where the compiler has not checked
the code yet: in a generic function or method nothing calls, on a
matcharm’s case and the names it binds (Circle(r) => ...), and on the values an enum case declares. - The
pepper.lspPathsetting points the extension at a language server you built yourself (pep-build -O tools/pep-lsp/main.pep -o target/pep-lsp/pep-lspin a checkout of the repository; see The language server: pep-lsp). The server restarts whenever that file changes.
To install the extension from the branch you have checked out instead of the release, see The VS Code extension from a branch.
What to read next
- A tour of Pepper builds a small program step by step and shows the main features of the language along the way.
- The language guide covers each part of the language in depth.
- The standard library reference lists every built-in type and function.