Examples

Complete programs that show off Quill's features. Copy any of these into the Playground to try them out.

Hello World

The classic first program.

-- hello.quill
say "Hello, World!"

name is "Quill"
say "Welcome to {name}!"

Output:

Hello, World!
Welcome to Quill!

FizzBuzz

The classic interview question, solved in Quill.

-- fizzbuzz.quill
to fizzbuzz n:
  i is 1
  while i is less than n + 1:
    if i % 15 is 0:
      say "FizzBuzz"
    otherwise if i % 3 is 0:
      say "Fizz"
    otherwise if i % 5 is 0:
      say "Buzz"
    otherwise:
      say i
    i is i + 1

fizzbuzz(20)

Todo list manager

A simple todo list using lists and functions.

-- todo.quill
todos are []

to addTodo task:
  say "Added: {task}"

to showTodos list:
  if length(list) is 0:
    say "No todos yet!"
  otherwise:
    say "Your todos:"
    i is 0
    for each todo in list:
      i is i + 1
      say "  {i}. {todo}"

-- Add some tasks
tasks are ["Learn Quill", "Build a project", "Share with friends"]

say "--- Todo List ---"
showTodos(tasks)
say ""
say "Total: {length(tasks)} tasks"

Number guessing game

Demonstrates functions, loops, and conditionals working together.

-- guess.quill
-- Since we can't get user input in the playground,
-- we'll simulate a game

secret is randomInt(1, 20)
say "I'm thinking of a number between 1 and 20..."
say "(The secret number is {secret})"

-- Simulate guesses
guesses are [5, 10, 15, 3, 17, 8, 12]
found is no
attempts is 0

for each guess in guesses:
  if not found:
    attempts is attempts + 1
    if guess is secret:
      say "Guess {guess}: Correct! Found in {attempts} tries!"
      found is yes
    otherwise if guess is less than secret:
      say "Guess {guess}: Too low!"
    otherwise:
      say "Guess {guess}: Too high!"

if not found:
  say "Didn't find it! The number was {secret}."

Text analyzer

Analyze text: count words, characters, and find the longest word.

-- analyzer.quill
to analyze text:
  say "--- Text Analysis ---"
  say "Text: {text}"
  say "Characters: {length(text)}"

  words are split(text, " ")
  say "Words: {length(words)}"

  -- Find the longest word
  longest is ""
  for each word in words:
    if length(word) is greater than length(longest):
      longest is word

  say "Longest word: {longest} ({length(longest)} chars)"

  -- Check for specific content
  if text contains "Quill":
    say "This text mentions Quill!"

analyze("The quick brown fox jumps over the lazy dog")
say ""
analyze("Quill is a programming language for humans")

Simple calculator

A calculator with multiple operations and error handling.

-- calculator.quill
to add a b:
  give back a + b

to subtract a b:
  give back a - b

to multiply a b:
  give back a * b

to divide a b:
  if b is 0:
    say "Error: Cannot divide by zero!"
    give back 0
  give back a / b

to power base exp:
  result is 1
  i is 0
  while i is less than exp:
    result is result * base
    i is i + 1
  give back result

-- Run some calculations
say "--- Calculator ---"
x is 100
y is 25

say "{x} + {y} = {add(x, y)}"
say "{x} - {y} = {subtract(x, y)}"
say "{x} * {y} = {multiply(x, y)}"
say "{x} / {y} = {divide(x, y)}"
say "2^10 = {power(2, 10)}"
say ""
say "Division by zero:"
divide(5, 0)

-- Test our calculator
test "calculator operations":
  expect add(2, 3) is 5
  expect subtract(10, 4) is 6
  expect multiply(3, 7) is 21
  expect divide(15, 3) is 5
  expect power(2, 8) is 256

Working with Objects

Create a student record, modify it, and display the results.

-- objects.quill
-- Create a student record
student is {
  name: "Maya",
  age: 16,
  grade: "10th",
  subjects: ["Math", "Science", "English"],
  scores: {
    math: 92,
    science: 88,
    english: 95
  }
}

-- Display the student info
say "--- Student Record ---"
say "Name: {student.name}"
say "Age: {student.age}"
say "Grade: {student.grade}"
say "Subjects: {join(student.subjects, ", ")}"

-- Calculate average score
scores are [student.scores.math, student.scores.science, student.scores.english]
avg is sum(scores) / length(scores)
say "Average score: {round(avg)}"

-- Modify the record
student.age is 17
push(student.subjects, "History")
student.scores.history is 90

say ""
say "--- Updated Record ---"
say "Age: {student.age}"
say "Subjects: {join(student.subjects, ", ")}"

Output:

--- Student Record ---
Name: Maya
Age: 16
Grade: 10th
Subjects: Math, Science, English
Average score: 92

--- Updated Record ---
Age: 17
Subjects: Math, Science, English, History

Fetching from an API

Fetch JSON data from a public API and display it.

-- fetch-users.quill
say "Fetching users from API..."

try:
  response is await fetch("https://jsonplaceholder.typicode.com/users")
  users is await response.json()

  say "Found {length(users)} users:"
  say ""

  for each user in users:
    say "  {user.name} ({user.email})"
    say "    City: {user.address.city}"

if it fails error:
  say "Error fetching data: {error}"

Output:

Fetching users from API...
Found 10 users:

  Leanne Graham (Sincere@april.biz)
    City: Gwenborough
  Ervin Howell (Shanna@melissa.tv)
    City: Wisokyburgh
  ...

File I/O

Read a file, process its contents, and write the results to a new file.

-- file-processor.quill
-- Write a sample input file first
writeFile("input.txt", "hello world\nquill is great\nfoo bar baz")

-- Read the file
content is readFile("input.txt")
say "--- Original ---"
say content

-- Process each line: uppercase it and add a line number
fileLines are lines(content)
result are []
i is 0

for each line in fileLines:
  i is i + 1
  push(result, "{i}. {upper(line)}")

-- Write the processed output
output is join(result, "\n")
writeFile("output.txt", output)

say ""
say "--- Processed ---"
say output
say ""
say "Saved to output.txt"

Output:

--- Original ---
hello world
quill is great
foo bar baz

--- Processed ---
1. HELLO WORLD
2. QUILL IS GREAT
3. FOO BAR BAZ

Saved to output.txt

Error Handling

Use try / if it fails to gracefully handle things that can go wrong.

-- error-handling.quill

to safeDivide a b:
  if b is 0:
    throw "Cannot divide by zero!"
  give back a / b

to loadConfig path:
  try:
    content is readFile(path)
    give back parseJSON(content)
  if it fails error:
    say "Warning: Could not load {path}: {error}"
    say "Using default settings."
    give back {theme: "light", language: "en"}

-- Test safe division
say "--- Safe Division ---"
try:
  say "10 / 2 = {safeDivide(10, 2)}"
  say "10 / 0 = {safeDivide(10, 0)}"
if it fails error:
  say "Caught error: {error}"

-- Test config loading
say ""
say "--- Config Loading ---"
config is loadConfig("settings.json")
say "Theme: {config.theme}"

Output:

--- Safe Division ---
10 / 2 = 5
Caught error: Cannot divide by zero!

--- Config Loading ---
Warning: Could not load settings.json: File not found
Using default settings.
Theme: light

A Simple CLI Tool

Build a command-line tool that takes arguments and does something useful.

-- wordcount.quill
-- A simple word counter tool
-- Usage: quill run wordcount.quill myfile.txt

arguments are args()

if length(arguments) is 0:
  say "Usage: quill run wordcount.quill <filename>"
  say "  Counts words, lines, and characters in a file."
  exit(1)

filename is arguments[0]

try:
  content is readFile(filename)

  -- Count lines
  fileLines are lines(content)
  lineCount is length(fileLines)

  -- Count words
  allWords are words(content)
  wordCount is length(allWords)

  -- Count characters
  charCount is length(content)

  -- Find most common word
  counts is {}
  for each w in allWords:
    word is lower(w)
    if counts[word] is nothing:
      counts[word] is 0
    counts[word] is counts[word] + 1

  say "--- {filename} ---"
  say "  Lines:      {lineCount}"
  say "  Words:      {wordCount}"
  say "  Characters: {charCount}"

if it fails error:
  say "Error: {error}"
  exit(1)

Output (when run on a sample file):

--- readme.txt ---
  Lines:      12
  Words:      85
  Characters: 523
Try these! All of these examples can be run in the Playground. Just copy-paste the code (without the syntax highlighting spans) and hit Run.

AI Chatbot

A conversational AI chatbot using Claude, in just a few lines:

-- AI Chatbot
-- Run: quill ai my-chatbot && cd my-chatbot && npm install

use "readline" as readline

rl is readline.createInterface({ input: process.stdin, output: process.stdout })

messages are []

to chat prompt:
  messages.push({ role: "user", content: prompt })
  answer is ask claude messages with system "You are a helpful assistant"
  messages.push({ role: "assistant", content: answer })
  say answer

to askQuestion:
  rl.question("You: ", with input:
    if input is "exit":
      rl.close()
      give back nothing
    chat(input)
    askQuestion()
  )

say "Chatbot ready! Type 'exit' to quit."
askQuestion()

Simple AI query

-- Ask Claude anything
answer is ask claude "What are 3 fun facts about space?"
say answer

Streaming AI response

-- Stream a long response token by token
stream claude "Write a short story about a robot learning to paint":
  say chunk