P1SCode Language Guide

This is a practical, guide-style introduction to writing P1SCode (.p1s): what you can type today, how it maps to a generated Rust app, and where the real limits are. It complements P1SCode Toolchain Workflow (commands and CI), P1SCode Status And Scope (supported vs preview), P1SCode — Language reference (concise) (compact syntax/builtins tables), P1SCode — Modules, imports, and the std story (imports / virtual std story), and P1SCode — Architecture (language & SDK) (how the SDK stack fits together).

Note

P1SCode is still transpiler-driven: most “language” behavior is whatever SDK/p1sdk/p1sc.py emits, checked by fixtures (SDK/p1sdk/fixtures/) and the shared parser crate SDK/p1sdk/p1sc_syntax. If this guide disagrees with a fixture or the transpiler, treat the code as truth and open a doc fix.


1. What you are writing

  • Files use the extension .p1s.

  • Entry is usually a func main() -> int { ... } (see below for main and return codes).

  • The host tool p1sc.py reads your sources, merges import "…" graphs, tokenizes, transpiles to Rust, and feeds Cargo using the p1scode-app template pattern.

  • On device, /bin/p1sc.elf can lex+parse (after the same import merge rules) for a fast syntax check; it does not compile your program by itself.


2. Your first program

Save as hello.p1s:

import "os/sys";

func main() -> int {
    sys.print("hello, P1SCode");
    return 0;
}
  • import "os/sys" — virtual module: the transpiler wires sys.print and friends for you (no os/sys file on disk).

  • func main() -> int — main becomes a Rust pub extern "C" fn main with a numeric process exit code (return 0 → success).

From the repo root, validate without building:

python SDK/p1sdk/p1sc.py check hello.p1s --project-root .

For a full template (local library + build.ps1), use SDK/template/p1scode-app/ — that is the best “real project” starting point.


3. How a small project is structured

Typical layout (matches the official template):

my-app/
  main.p1s          # entry; imports other modules
  lib/
    helpers.p1s   # sibling module
  • import "lib/helpers" — resolves next to the current file’s directory: looks for helpers or helpers.p1s.

  • import "os/sys", import "std/…", import "p1/…" — virtual prefixes: not real paths; they tell the toolchain you want the built-in / SDK-facing surface (see §9).

After merging, file-import lines disappear from the compilation unit (same as p1sc.py and p1sc.elf).


4. Functions

func add(a: int, b: int) -> int {
    return a + b;
}

func main() -> int {
    var x = add(1, 2);
    return x;
}
  • Name then ( parameter list ).

  • Optional : type on parameters and optional -> return_type (often int today).

  • `main is special-cased in the transpiler (see §2).


5. Variables and assignment

var x = 0;
let y = 10;    // same as var for transpile output (both become `let mut` in Rust)
x = x + 1;

Optional type on declarations (common in signatures; in bodies the transpiler often infers from usage):

var n: int = 5;

Type names you will see in examples and signatures:

In .p1s

Emitted Rust (typical)

int

i32

float

f32

string

&str (in type positions)

There is no separate user manual for the type system yet: treat types as hints for the transpiler and the generated boilerplate, not a full checked language spec.


6. Literals and operators

Literals (as modeled in the shared AST):

  • Integers: 42, hex 0xFF.

  • Floats: 3.14 (decimal point form).

  • Strings: "text" with escapes like \", \n, \t, \\, \0 (lexer-level; transpiler may re-escape for Rust).

  • Booleans: true, false.

  • null.

Operators (typical uses):

  • Arithmetic: +, -, *, /, %

  • Comparison: ==, !=, <, >, <=, >=

  • Logical: &&, ||, !

  • Unary - on numbers

Keywords reserved by the profile (used as names only if you want confusing errors) include:
func, var, let, const, if, else, while, for, loop, return, break, continue, struct, enum, import, true, false, null, and, or, not
— see SDK/p1sdk/p1scode_profile.json.


7. Control flow

If / else:

if x < 3 {
    sys.print("small");
} else {
    sys.print("ok");
}

While:

while x < 10 {
    x = x + 1;
}

Loop (infinite):

loop {
    if done { break; }
}

For — parsed in p1sc_syntax; prefer matching a fixture or keeping loops simple until you need it.

Return / break / continue — use as in C-like languages; main should return an int exit code.


8. Imports: files vs virtual

Form

Meaning

import "lib/foo"

Project file lib/foo.p1s (or lib/foo) next to the importing file’s directory

import "os/sys"

Virtual — sys.* surface

import "std/…"

Virtual namespace (reserved pattern)

import "p1/…"

Virtual namespace (reserved pattern)

Syntax must match: import "path" with optional ;. Malformed lines are diagnostics P1SC-EIMP003 on the host; missing files P1SC-EIMP001.

std/io (virtual import; import "std/io")

Use this when you want io.* without import "os/sys". The import line is removed after merge (like os/sys).

Call

Role

io.print(expr), io.print_err(expr)

Print line to stdout (fd 1) or stderr (fd 2); same shaping as sys.print.

io.read_line()

Read one line from stdin (fd 0); see P1SCode — Modules, imports, and the std story §3.

io.read_file(path), io.read_text(path)

Read file as String; same lowering as sys.read_file / fs.read_text.

io.write_file(path, data)

Write text via syscall 202; same as sys.write_file.

io.read_bytes(path), io.write_bytes(path, data)

Binary file I/O; same as fs.read_file / fs.write_file.

io.sleep(ms), io.execute(path)

Same as sys.sleep / sys.execute.


9. Built-in surfaces the transpiler knows

These are not a frozen standard library contract — they are what p1sc.py recognizes today. Names mirror Rust cstd / helpers where possible.

sys (requires import "os/sys" in entry-oriented samples)

Call

Role

sys.print(expr)

Print line (string literal fast path, or debug-format)

sys.read_file(path)

Read file as string (UTF-8-ish chunk loop)

sys.write_file(path, data)

Write bytes via syscall 202

sys.sleep(ms)

Sleep ms

sys.execute(path)

Exec helper

math

Call

Role

math.random(max)

Random 0 .. max (backed by template p1_random)

str

Call

Role

str.concat(a, b)

String concatenation

fs (binary vs text variants)

Call

Role

fs.read_file(path)

Read raw Vec<u8>

fs.read_text(path)

Read String

fs.write_file(path, data)

Write (expects byte-oriented data in generated code)

crypto (maps to cstd::crypto)

Call

Role

crypto.get_random(n)

Random bytes

crypto.hash_sha256(data)

SHA-256

crypto.hmac_sha256(key, msg)

HMAC

crypto.to_hex(bytes)

Hex encode

ui (windowing sample surface)

Call

Role

ui.create_window(title, w, h)

Open window

ui.poll()

Poll events

ui.event_type(), ui.mouse_x(), ui.mouse_y()

Event query

Window / framebuffer helpers (on a value you stored from create_window): .get_framebuffer(), .set_pixel(x, y, color), .draw() — see transpiler for exact arity.


10. Arrays, maps, and “extra” syntax

The transpilier has special cases for array / map-like literals in Rust (e.g. [ → alloc::vec![ in some contexts, { may become map-like construction). If you need this, copy a working pattern from SDK/p1sdk/fixtures/ or from a known sample — this is the least documented corner of the surface.


11. How to learn safely

  1. Run check often:
    python SDK/p1sdk/p1sc.py check your.p1s --project-root .

  2. Read fixtures under SDK/p1sdk/fixtures/ — each .p1s is a pinned behavior example.

  3. Run the fixture harness:
    python SDK/p1sdk/run_fixtures.py

  4. Prefer the template SDK/template/p1scode-app/ for structure (imports, build.ps1, package output paths).


12. What this guide is not

  • Not a formal grammar (use p1sc_syntax parser + lexer for that).

  • Not a promise of stable ABI or stable std — see P1SCode Status And Scope.

  • Not a replacement for Rust or Cargo docs for the generated apps/p1scode_app crate.

When you add a user-visible language feature, add a fixture and a short subsection here so the next person finds it.


See also

  • P1SCode Toolchain Workflow — flags, JSON diagnostics, p1sc.elf, dump_tokens

  • newdocs/p1scode-m1.md — M1 platform contract and ramdisk paths

  • SDK/template/p1scode-app/README.md — copy-paste quick start