Comments
(( Any documentation comment or note. ))
Comments are delimited with double parentheses and are ignored by compilation.
A working reference for the current Ricochet toolchain: stack words, declaration operators, symbols, OOP, MVC, Active Record, templates, tests, and debugger behavior.
rco new my_apprco fmt app.rcorco routes my_apprco test my_apprco run --debug --step app.rcoVerify your local virtual machine installation works correctly with this bootstrap class and execution sequence.
User Model subclass
email field
"displayName" [ $self .email ] !method
end
User new
"ada@example.com" swap .email set
.displayName
println
Key lexer tokens, comment formatting, blocks, OOP declarations, HTML views, and routes.
(( Any documentation comment or note. ))
Comments are delimited with double parentheses and are ignored by compilation.
User Model subclass
users table
email field
end
Declaration shape stays postfix: declaration name first, declaration operator last.
users array
settings map
queue list
tags Set
Name-first collection declarations bind mutable shared collections. Use `Array new`, `Map new`, `List new`, or `Set new` for anonymous values.
( ctx -> Response ) "index" [
$ctx "home/index" swap view
] !method
Parentheses create optional input/output metadata for functions and methods.
[ $self .email ]
Square brackets create first-class bytecode blocks. Use `call` to execute a block value.
result dup ok? if
value
else
error .message
end
`if else end` is postfix: the condition is already on the stack before `if`.
$count 10 < while
$count 1 + $count set
end
The condition expression before `while` is re-executed before every iteration. `break` exits and `continue` rechecks the condition.
$user .email
"ada@example.com" $user .email set
Dot words push member selectors for `get` and `set`, and call methods when used directly.
"lib/math" import
7 triple
"greeter/greeting" import
packageHello
Static string imports load relative `.rco` files before the importing file. If the relative file is missing, imports shaped like `package/module` resolve through `[dependencies.package]` in `ricochet.toml`. Dynamic imports remain a future package/runtime-loader feature.
<strong>{ $user .name }</strong>
<small>{ 20 22 + }</small>
Each `{ ... }` expression runs Ricochet and must leave exactly one renderable value.
GET "/" HomeController "index" route
POST "/users" UserController "create" route
DELETE "/users/:id" UserController "destroy" route
Route files are line-oriented and accept quoted paths and action names.
Search, filter, and inspect postfix operators built into the core bytecode engine.
How OOP works under the hood in a concatenative environment.
Project style is one class per file, with the filename matching the class name.
(( app/Models/User.rco ))
User Model subclass
users table
id field
email field
name field
"displayName" [
$self .name
dup nil? if
drop $self .email
else
return
end
] !method
end
Strings and variables can drive declaration operators, which is where Ricochet starts to feel different.
"Widget" className var
"label" methodName var
$className "Object" subclass
$className "name" field
$className $methodName [ $self .name ] !method
$className new
"dynamic" swap .name set
.label
Use `.methodName` for direct method calls or `send` when the method name is itself a value.
User new
"ada@example.com" swap .email set
dup .displayName println
"displayName" send println
The default structure of a server-side web application running under Ricochet serve.
[package]
name = "ricochet_app"
[web]
mode = "mvc"
routes = "config/routes.rco"
[web.views]
escape = "html"
[dependencies.greeter]
path = "./packages/greeter"
GET "/" HomeController "index" route
GET "/users" UserController "index" route
GET "/users/show" UserController "show" route
POST "/users" UserController "create" route
DELETE "/users/:id" UserController "destroy" route
(( app/Controllers/HomeController.rco ))
HomeController Controller subclass
"index" [
"Hello Ricochet" title var
$ctx
"home/index" swap view
] !method
end
(( app/Models/User.rco ))
User Model subclass
email field
name field
"displayName" [
$self .name nil? if
$self .email
else
$self .name
end
] !method
end
(( app/Controllers/UserController.rco ))
UserController Controller subclass
"index" [
users array
User new
"ada@example.com" swap .email set
"Ada Lovelace" swap .name set
$users .push! drop
$users .count userCount var
"Users" title var
$ctx
"users/index" swap view
] !method
end
LoginController Controller subclass
"create" [
"/dashboard" redirect
303 status
"cache-control" "no-store" header
] !method
end
<main>
<h1>{ title get }</h1>
<p>{ 20 22 + }</p>
</main>
Interact with Postgres schemas using simple, stack-based ORM words.
(( app/Models/User.rco ))
User Model subclass
users table
id field
email field
name field
end
User .all
42 User .find
"email" "ada@example.com" User .where
10 User .limit
User .count
User .first
1 User .exists?
attributes map
"email" "ada@example.com" $attributes .put! drop
"name" "Ada" $attributes .put! drop
$attributes User .insert
updates map
"email" "grace@example.com" $updates .put! drop
42 $updates User .update
(( app/Controllers/UserController.rco ))
UserController Controller subclass
( ctx -> Response ) "index" [
User .all
dup ok? if
value users var
$ctx "users/index" swap view
else
error .message text
end
] !method
end
Mutable counters, Peano numerals, and conditional backward jumps.
Mutable counters, conditional branching, decrement, and backward jumps provide the core WHILE-machine model. This program computes `6 * 7` without a multiplication word.
0 product var
6 multiplicand var
7 multiplier var
$multiplier 0 > while
product get multiplicand get + product set
$multiplier 1 - $multiplier set
end
product get println
0 count var
$count 10 < while
$count 1 + $count set
$count 3 = if continue end
$count 6 = if break end
$count println
end
For an abstract unbounded counter, object chains can represent Peano-style natural numbers independently of the fixed-width integer convenience type.
Counter Object subclass
previous field
end
nil counter var
counter get Counter new .previous set counter set
counter get Counter new .previous set counter set
counter get nil? false = while
counter get .previous counter set
end
Interactive execution traces, break-on-fault logs, and unit testing support.
Debug mode prints each instruction with stack before and after. Step mode pauses and accepts `step`, `continue`, or `abort`.
rco run --debug app.rco
rco run --debug --step app.rco
rco run --breakpoint 12 app.rco
rco repl --debug
Runtime errors preserve the relevant stack when an operation fails loudly.
TRACE app.rco:3 [<main>] CallWord("+")
before: [Number(20), Number(22)]
after: [Number(42)]
FAULT [<main>] unknown word typo
stack: [Number(42)]
(( tests/UserTest.rco ))
UserTest TestCase subclass
"testDisplayName" [
"Ada"
"Ada" assert-equals
] !method
end
Comprehensive list of commands available in the Ricochet command-line interface.
args .count println
"DATABASE_URL" env dup ok? if value println else error .message eprint end
cwd value println
now println
100 random println
rco add ./packages/greeter
rco add github:BARKx4/ricochet_auth@v0.1.0 --no-fetch
"README.md" fs .read-text value .count println
"https://example.com" http .get value response var
"status" response get .at println
cargo build -p ricochet_cli --bin rco
powershell.exe -NoProfile -ExecutionPolicy Bypass -File scriptscceptance.ps1
The bounds of the v1.0.0 draft specification. Be aware of these rules in your application code.