Documentation · v0.1.0

The Qingchu language reference

Everything the language can say today — with runnable examples for every construct. Statements end with ., blocks open with indentation, and types travel inside names.

Declarations #

let creates a binding. The indented ts line declares its type. Abbreviations: ts = type_is, ats = above_type_is, const = constant.

declare.qc
let name = Bob
    name ts string

print Hello name_string .
OutputHello Bob

A declaration has two parts: the binding (let name = Bob) and its type block (name ts string). The type block is indented under the binding it describes.

Once declared, the binding is referenced by name plus type: name_string. That suffix is not decoration — it's how the runtime finds the right value.

Types & bindings #

Three built-in types today, each with its own reference suffix:

TypeReference suffixExample
number _number total_number — integers and decimals (3, 3.14)
string _string greeting_string — text like Hello
boolean _boolean flag_boolean — truth values

Context markers #

Prefix a statement with math or string to drop the type suffix so code reads naturally. This is the whole purpose of context markers.

math-context.qc
math let total = price * quantity .
math print total .
Meanstotal → total_number inside math
string-context.qc
string let first = Alice .
string let last = Smith .
string print Full name: first last .
OutputFull name: Alice Smith
KeywordEffect
mathBare names resolve to _number
stringBare names resolve to _string

Constants #

Add the constant (or const) modifier in the type block and the binding can't be reassigned later.

constant.qc
let pi = 3.14
    pi ts constant number

print pi_constant_number .
Output3.14

Output — print #

Everything between print and the terminating . is content. Words that match a declared binding are resolved; everything else prints as text.

print.qc
print Hello World .
OutputHello World

Input — ask #

ask prints the question, waits for input, and binds the answer. The indented response = … block names the binding that receives it.

greet.qc
ask What is your name? .
    response = name
        name ts string

string print Nice to meet you, name .
SessionWhat is your name? Ada Nice to meet you, Ada

Branching — if / else #

Conditions read like math. Blocks are indented; else continues at the same level. Nested branches compose the same way.

if.qc
let age = 25
    age ts number

math if age > 18
    print You are an adult .
else
    print You are a minor .
OutputYou are an adult
nested-if.qc
math if score > 18
    print grade A .
else
    math if score > 12
        print grade B .
    else
        print grade C .

Loops — when #

when repeats while its condition holds. Reassign loop state with new — explicit, readable mutation.

loop.qc
let i = 0
    i ts number

math when i < 3
    print Count: i .
    new i = i + 1 .
OutputCount: 0 Count: 1 Count: 2
countdown.qc
math when n > 0
    print n .
    new n = n - 1 .

print Liftoff .
Output5 4 3 2 1 Liftoff

Functions — define #

define name(params) as … declares a function; calculate returns a value from a block body. Parsing is complete in v0.1.0 — calling execution is on the roadmap.

expression body
define double(x) as x * 2
    x ts number
    double ts number
block body
define square(x) as
    x ts number
    square ts number

    let result = x_number * x_number
        result ts number

    calculate result_number .

Comments & escapes #

comments.qc
!! This is a single-line comment !!

!!! This is a multi-line comment
    it continues here
!!!

Use \ to escape characters that would otherwise be parsed:

EscapeProduces
\.a literal period, not a terminator
\_a literal underscore, not a type suffix
\\a literal backslash

Error messages #

Every error follows one shape: error <what> on line <N>(<which statement>). Line numbers and statement context included, always.

error cannot reassign constant on line 12(new statement)
error undefined binding on line 4(print statement)
error missing type declaration on line 2(let statement)

The interpreter reports what went wrong, where it happened, and which kind of statement caused it — no stack traces required to start debugging.

Cheat sheet #

KeywordMeaningExample
letCreate a bindinglet name = Bob
tsType of this bindingname ts string
atsAbove type is (parent binding)ats string
printOutput until .print Hello World .
askPrompt + read inputask Your name? .
newReassign a bindingnew i = i + 1 .
if / elseBranchmath if age > 18 … else …
whenLoop while truemath when i < 3 …
defineDeclare a functiondefine double(x) as x * 2
calculateReturn from a functioncalculate result_number .
mathContext: bare names → _numbermath print total .
stringContext: bare names → _stringstring print name .
constant / constNo-reassignment modifierpi ts constant number
!! … !!Single-line comment!! note !!
!!! … !!!Multi-line comment!!! long note !!!