Complete guide from beginner to advanced.
Get running immediately:
Build HLVM first (see the Build Guide), then:
echo '(print "Hello, World!")' > hello.hql
# Run it
./hlvm run hello.hql
If you install system-wide, use hlvm instead of ./hlvm.
Try the REPL:
./hlvm repl
hlvm> (+ 1 2 3)
6
hlvm> (let square (fn [x] (* x x)))
hlvm> (map square [1 2 3 4])
(1 4 9 16)
Ready to learn more? Continue with the full guide below.
You should know:
See the build guide for build and install options.
Create hello.hql:
(print "Hello, World!")
Run:
hlvm run hello.hql
Output:
Hello, World!
// Block-scoped mutable (like JS let)
(let x 10)
(let name "Alice")
(print x) // → 10
(print name) // → Alice
// Function-scoped mutable (like JS var)
(var counter 0)
(= counter 100)
(print counter) // → 100
// Immutable (like JS const)
(const PI 3.14159)
(print PI) // → 3.14159
(+ 1 2 3) // → 6
(- 10 3) // → 7
(* 2 3 4) // → 24
(/ 10 2) // → 5
(% 10 3) // → 1
// This is a single line comment
// Use /* ... */ for multi-line comments
(+ 1 2) // inline comment
Simple function:
(fn greet [name]
(print "Hello," name))
(greet "World")
// → Hello, World
Return values:
(fn add [a b]
(+ a b))
(let result (add 5 3))
(print result) // → 8
(fn greet [name = "World"]
(print "Hello," name))
(greet) // → Hello, World
(greet "Alice") // → Hello, Alice
(fn calculate [a b op]
(cond
((=== op "add") (+ a b))
((=== op "sub") (- a b))
((=== op "mul") (* a b))
(else "Unknown")))
(calculate 10 5 "add") // → 15
(calculate 10 5 "mul") // → 50
square functionmax function (returns larger of two numbers)greet-person with name and age parameters(let numbers [1 2 3 4 5])
(get numbers 0) // → 1
(first numbers) // → 1
(rest numbers) // → [2 3 4 5]
(let person {name: "Alice", age: 30, city: "NYC"})
(get person "name") // → "Alice"
(get person "age") // → 30
Updating maps:
(let updated (assoc person "job" "Engineer"))
// → {name: "Alice", age: 30, city: "NYC", job: "Engineer"}
(let removed (dissoc person "city"))
// → {name: "Alice", age: 30}
Map (transform):
(let numbers [1 2 3 4 5])
(let doubled (map (fn [x] (* x 2)) numbers))
(print doubled) // → [2 4 6 8 10]
Filter:
(let evens (filter (fn [x] (=== (% x 2) 0)) numbers))
(print evens) // → [2 4]
Reduce (aggregate):
(let sum (reduce + 0 numbers))
(print sum) // → 15
If/else:
(let age 20)
(if (>= age 18)
(print "Adult")
(print "Minor"))
Cond (multi-way):
(let score 85)
(cond
((>= score 90) (print "A"))
((>= score 80) (print "B"))
((>= score 70) (print "C"))
(else (print "F")))
Pattern matching:
// Match values with patterns
(match status-code
(case 200 "OK")
(case 404 "Not Found")
(default "Unknown"))
// Or-patterns: match multiple values
(match status-code
(case (| 200 201 204) "success")
(case (| 400 422) "client error")
(default "other"))
// Destructure arrays
(match point
(case [x, y] (+ "x=" x ", y=" y))
(default "Invalid point"))
// Destructure objects
(match user
(case {name: n, age: a} (+ n " is " a))
(default "Unknown user"))
// Guards for conditions
(match n
(case x (if (> x 0)) "positive")
(case x (if (< x 0)) "negative")
(default "zero"))
// Rest patterns for lists
(fn sum [lst]
(match lst
(case [] 0)
(case [h, & t] (+ h (sum t)))))
For loop:
(for [i 0 5]
(print "Count:" i))
While loop:
(var i 0)
(while (< i 5)
(print i)
(= i (+ i 1)))
// Direct dot notation
(console.log "Hello from HQL!")
(Math.floor 3.7) // → 3
(Math.random) // → random number
Math.PI // → 3.14159...
(let date (new Date))
(date.toISOString)
(let arr (new Array 1 2 3))
(print arr) // → [1, 2, 3]
(import fs from "npm:fs/promises")
(let content (await (fs.readFile "./hello.hql" "utf-8")))
(print content)
Macros transform code at compile time:
(macro when [test & body]
`(if ~test
(do ~@body)))
// Use it
(when (> x 10)
(print "x is large")
(print "Processing..."))
// Expands to:
// (if (> x 10)
// (do
// (print "x is large")
// (print "Processing...")))
// Quote (`) - creates template
// Unquote (~) - inserts value
// Unquote-splicing (~@) - inserts list items
(macro log [expr]
`(do
(print "Evaluating:" '~expr)
(let result ~expr)
(print "Result:" result)
result))
(log (+ 1 2))
// Evaluating: (+ 1 2)
// Result: 3
// → 3
Unless macro:
(macro unless [test & body]
`(if (not ~test)
(do ~@body)))
(unless (< age 18)
(print "Access granted"))
Time macro:
(macro time [& body]
`(do
(let start (Date.now))
(let result (do ~@body))
(let end (Date.now))
(print "Took:" (- end start) "ms")
result))
(time
(let sum (reduce + 0 (range 0 1000000))))
debug macro that prints expression and resultrepeat macro: (repeat 3 (print "Hi")) (note: HQL already has this built-in)assert macro for testingmy-project/
├── main.hql # Entry point
├── src/
│ ├── utils.hql # Utilities
│ └── core.hql # Core logic
└── test/
└── test.hql # Tests
Export from utils.hql:
(fn add [a b]
(+ a b))
(fn multiply [a b]
(* a b))
(export [add multiply])
Import in main.hql:
(import [add multiply] from "./src/utils.hql")
(print (add 5 3)) // → 8
(print (multiply 4 2)) // → 8
Create todo.hql:
(let todos [])
(fn add-todo [text]
(todos.push text)
(print "Added:" text))
(fn list-todos []
(for [i 0 todos.length]
(print (+ i 1) "." (get todos i))))
(fn main []
(add-todo "Learn HQL")
(add-todo "Build project")
(list-todos))
(main)
Run:
hlvm run todo.hql
Create server.hql:
(fn handle-request [req]
(let url req.url)
(new Response
(+ "You visited: " url)
{status: 200,
headers: {"content-type": "text/plain"}}))
(print "Server on http://localhost:8000")
(Deno.serve {port: 8000} handle-request)
Run:
hlvm run server.hql
HLVM includes a built-in AI agent for coding tasks.
Interactive mode (default):
hlvm ask "explain what this project does"
hlvm ask "find all functions that use async/await"
The agent can:
For automation and CI/CD:
# Non-interactive analysis
hlvm ask -p "analyze code quality"
# Only allow specific tools
hlvm ask -p --allowedTools write_file "generate documentation"
Non-interactive mode (-p/--print):
dontAsk permission mode)Fine-grained control over what the agent can do:
# Allow specific tools (repeatable flag)
hlvm ask --allowedTools write_file --allowedTools edit_file "fix linting errors"
# Deny specific tools (repeatable flag)
hlvm ask --disallowedTools shell_exec "refactor code"
# Permission modes
hlvm ask --permission-mode acceptEdits "apply fixes"
hlvm ask --permission-mode bypassPermissions "full automation"
Safety levels:
Code review:
hlvm ask "review auth.ts for security issues"
Refactoring:
hlvm ask "convert all var to let in src/"
Documentation:
hlvm ask -p --allowedTools write_file "generate API docs"
CI/CD:
# In your CI pipeline
hlvm ask -p "check for unused imports" || exit 1
Run HQL's test suite:
make test
See Testing Guide for writing your own tests.