Skip to content

joe-chelladurai/bubblecode

Repository files navigation

Bubble

A programming language inspired by HyperTalk — where code reads like English.

Bubble is a dynamically typed, interpreted programming language with English-like syntax inspired by Apple's HyperTalk. It's designed to be approachable, readable, and fun. If you've ever wished your code could sound more like a conversation, Bubble is for you.

put "Hello, World!" into greeting
say greeting

Table of Contents


Installation

Pre-built Binary

If you already have the compiled binary, simply place it somewhere on your PATH:

chmod +x bubble
sudo mv bubble /usr/local/bin/

Building from Source

Requires Go 1.21 or later:

git clone https://github.com/bubblecode/bubble.git
cd bubble
go build -o bubble .

Verify the installation:

bubble --version
# Bubble v0.1.0

Quick Start

Run a script

Create a file called hello.bubble:

say "Hello, World!"

Run it:

bubble hello.bubble

The .bubble extension is optional on the command line — bubble hello works too.

Start the REPL

Run bubble with no arguments to enter interactive mode:

bubble
  ____        _     _     _
 | __ ) _   _| |__ | |__ | | ___
 |  _ \| | | | '_ \| '_ \| |/ _ \
 | |_) | |_| | |_) | |_) | |  __/
 |____/ \__,_|_.__/|_.__/|_|\___|

 🫧 Bubble Language v0.1.0
 Type "bye" or "quit" to exit.

bubble> say "Hello!"
Hello!
bubble>

Language Guide

Comments

Comments begin with -- and continue to the end of the line:

-- This is a comment
say "Hello" -- This is also a comment

Variables

Bubble has two ways to assign variables, both reading like natural English.

put ... into (HyperTalk style)

put "Bubble" into language
put 42 into answer
put true into isReady

set ... to

set language to "Bubble"
set answer to 42
set isReady to true

Both forms are interchangeable. Use whichever reads better in context.

add ... to

The add command increments a numeric variable:

put 0 into score
add 10 to score
add 5 to score
say score
-- Output: 15

Variable names

Variable names can contain letters, digits, and underscores. They are case-insensitivemyName, MyName, and MYNAME all refer to the same variable.

put "Alice" into myName
say MyName
-- Output: Alice

Data Types

Bubble has five core data types:

Type Examples Notes
Number 42, 3.14, -7 All numbers are 64-bit floats
String "hello", 'Bubble 🫧' Enclosed in double or single quotes
Boolean true, false Logical values
List [1, 2, 3], ["a", "b"] Ordered collections
Null (no literal) Absence of a value

Output

Use say to print to the console:

say "Hello, World!"
say 2 + 2
say "The answer is" && 42

say automatically adds a newline at the end.

Input

Use ask to prompt the user for input:

ask "What is your name?"
say "Hello," && it

By default, the answer is stored in the special variable it. You can specify a different variable:

ask "What is your name?" into name
ask "How old are you?" into age
say name && "is" && age && "years old."

Arithmetic

Bubble supports standard arithmetic operators:

say 2 + 3        -- Addition: 5
say 10 - 4       -- Subtraction: 6
say 6 * 7        -- Multiplication: 42
say 20 / 4       -- Division: 5
say 17 mod 5     -- Modulo: 2
say 2 ^ 10       -- Exponentiation: 1024

Parentheses control order of operations:

say (2 + 3) * 4  -- 20
say 2 + 3 * 4    -- 14

Operator precedence (highest to lowest):

  1. ^ (power)
  2. *, /, mod
  3. +, -
  4. &, && (string concatenation)
  5. <, >, <=, >=, contains
  6. is, =, is not, <>
  7. not
  8. and
  9. or

String Operations

Concatenation

Bubble uses HyperTalk-style concatenation operators:

-- & joins strings directly (no space)
say "Hello" & "World"
-- Output: HelloWorld

-- && joins strings with a space
say "Hello" && "World"
-- Output: Hello World

Building complex strings:

put "Hello" into greeting
put "World" into target
put greeting & ", " & target & "!" into message
say message
-- Output: Hello, World!

Single and double quotes

Strings can be enclosed in either double quotes or single quotes. Both are equivalent:

say "Hello, World!"
say 'Hello, World!'

This makes it easy to include one type of quote inside the other:

say 'She said "hello"'
say "It's a beautiful day"

Escape sequences

Strings support the following escape sequences:

Escape Meaning
\n Newline
\t Tab
\\ Literal \
\" Literal "
\' Literal '
say "Line 1\nLine 2"
say "Col1\tCol2"

The contains operator

Check if a string contains a substring (case-insensitive):

put "Hello, Bubble World!" into text
say text contains "bubble"   -- true
say text contains "python"   -- false

Comparisons

Bubble supports both symbolic and English-style comparisons:

Symbolic operators

if x = 5 then ...
if x <> 5 then ...
if x < 10 then ...
if x > 3 then ...
if x <= 10 then ...
if x >= 0 then ...

English-style operators

if x is 5 then ...
if x is not 5 then ...
if x is less than 10 then ...
if x is greater than 3 then ...
if x is less than or equal to 10 then ...
if x is greater than or equal to 0 then ...
if x is equal to 5 then ...
if x is not equal to 5 then ...

String comparisons are case-insensitive (following HyperTalk convention):

if "Hello" is "hello" then
  say "These are equal!"
end if
-- Output: These are equal!

Logical Operators

if x > 0 and x < 100 then
  say "x is between 1 and 99"
end if

if name is "Alice" or name is "Bob" then
  say "Welcome!"
end if

if not isReady then
  say "Not yet..."
end if

Conditionals

Basic if/then

put 42 into age

if age is greater than or equal to 18 then
  say "You are an adult."
end if

if/else

put 15 into temperature

if temperature is less than 0 then
  say "It's freezing!"
else
  say "It's not freezing."
end if

else if chains

put 85 into score

if score is greater than or equal to 90 then
  say "Grade: A"
else if score is greater than or equal to 80 then
  say "Grade: B"
else if score is greater than or equal to 70 then
  say "Grade: C"
else if score is greater than or equal to 60 then
  say "Grade: D"
else
  say "Grade: F"
end if

Loops

Bubble offers a rich variety of loop constructs.

Repeat N times

repeat 5 times
  say "Hello!"
end repeat

Repeat with (counted for-loop)

repeat with i from 1 to 10
  say i
end repeat

Repeat with step

-- Count by 5s
repeat with i from 0 to 50 by 5
  say i
end repeat

Repeat with countdown

repeat with i from 10 down to 1
  say i & "..."
end repeat
say "Blast off!"

Repeat while

put 1 into n
repeat while n is less than or equal to 100
  say n
  put n * 2 into n
end repeat

Repeat until

put 0 into total
repeat until total is greater than or equal to 100
  add 7 to total
end repeat
say "Total:" && total

Repeat forever

repeat forever
  ask "Say something (or 'quit'):" into input
  if input is "quit" then
    exit repeat
  end if
  say "You said:" && input
end repeat

Repeat for each

Iterate over lists or characters in a string:

put ["apple", "banana", "cherry"] into fruits
repeat for each fruit in fruits
  say "I like" && fruit
end repeat
repeat for each letter in "Bubble"
  say letter
end repeat
-- Output: B u b b l e (each on its own line)

Loop control

-- Skip an iteration with 'next repeat'
repeat with i from 1 to 10
  if i mod 2 is 0 then
    next repeat
  end if
  say i
end repeat
-- Output: 1 3 5 7 9

-- Break out of a loop with 'exit repeat'
repeat with i from 1 to 100
  if i is greater than 5 then
    exit repeat
  end if
  say i
end repeat
-- Output: 1 2 3 4 5

Functions and Handlers

Bubble has two styles for defining callable routines.

Functions (return values)

function double(x)
  return x * 2
end double

say double(21)
-- Output: 42

Handlers (actions)

Handlers are defined with on and are ideal for procedures that perform side effects rather than returning values:

on greet name
  say "Hello," && name & "! Welcome to Bubble! 🫧"
end greet

greet("World")
-- Output: Hello, World! Welcome to Bubble! 🫧

Both function and on support parameters and can call each other. Functions use return to produce a value. If a handler is called as a function, it returns null.

Parameters

Parameters can be listed with or without parentheses:

-- With parentheses
function add(a, b)
  return a + b
end add

-- Without parentheses (handler style)
on greet name, title
  say "Hello," && title && name
end greet

Recursion

Functions can call themselves:

function factorial(n)
  if n is less than 2 then
    return 1
  end if
  return n * factorial(n - 1)
end factorial

say factorial(10)
-- Output: 3628800

Closures and scope

Functions capture the environment where they are defined. Each function call creates its own local scope:

put "global" into scope

function showScope
  put "local" into scope
  say "Inside:" && scope
end showScope

showScope()
say "Outside:" && scope
-- Output:
-- Inside: local
-- Outside: global

Lists

Lists are ordered collections enclosed in square brackets:

put [1, 2, 3, 4, 5] into numbers
put ["apple", "banana", "cherry"] into fruits
put [] into emptyList

Accessing items (1-based indexing)

put ["a", "b", "c", "d"] into letters
say itemof(1, letters)   -- a
say itemof(3, letters)   -- c
say firstitem(letters)   -- a
say lastitem(letters)    -- d

Modifying lists

put [10, 20, 30] into nums

-- Change an item by index
put 99 into item 2 of nums
say nums
-- Output: [10, 99, 30]

-- Append an item
put append(nums, 40) into nums
say nums
-- Output: [10, 99, 30, 40]

-- Delete an item by index
delete item 1 of nums
say nums
-- Output: [99, 30, 40]

-- Insert at a position
put insertitem(nums, 2, 55) into nums
say nums
-- Output: [99, 55, 30, 40]

List functions

put [3, 1, 4, 1, 5, 9] into nums

say length(nums)           -- 6
say count(nums)            -- 6
say sort(nums)             -- [1, 1, 3, 4, 5, 9]
say reverse(nums)          -- [9, 5, 1, 4, 1, 3]
say shuffle(nums)          -- (random order)
say indexof(4, nums)       -- 3
say slice(nums, 2, 4)      -- [1, 4] (items 2 through 4)

Generating lists

say range(5)            -- [1, 2, 3, 4, 5]
say range(3, 7)         -- [3, 4, 5, 6, 7]
say range(0, 10, 2)     -- [0, 2, 4, 6, 8, 10]
say range(10, 0, -2)    -- [10, 8, 6, 4, 2, 0]

Joining and splitting

put ["red", "green", "blue"] into colors
say join(colors, ", ")
-- Output: red, green, blue

put split("one,two,three", ",") into words
say words
-- Output: [one, two, three]

Screen and Timing

-- Clear the terminal screen
clear

-- Pause for a duration in seconds
wait 2
wait 0.5 seconds

Constants

Bubble provides several built-in constants:

Constant Value Description
true true Boolean true
false false Boolean false
empty "" The empty string
quote " A literal double-quote character
put empty into result
say "She said" && quote & "hello" & quote
-- Output: She said "hello"

Built-in Functions Reference

String Functions

Function Description Example
length(s) Length of a string or list length("hello")5
uppercase(s) Convert to uppercase uppercase("hi")"HI"
lowercase(s) Convert to lowercase lowercase("HI")"hi"
trim(s) Strip leading/trailing whitespace trim(" hi ")"hi"
reverse(s) Reverse a string or list reverse("abc")"cba"
replace(s, old, new) Replace all occurrences replace("hello", "l", "r")"herro"
mid(s, start, len) Substring from position (1-based) mid("hello", 2, 3)"ell"
left(s, n) First n characters left("hello", 3)"hel"
right(s, n) Last n characters right("hello", 3)"llo"
char(n, s) Character at position n (1-based) char(1, "hello")"h"
offset(needle, haystack) Position of first occurrence (1-based, 0 if not found) offset("ll", "hello")3
repeattext(s, n) Repeat a string n times repeattext("*", 5)"*****"
padright(s, width) Pad with trailing spaces padright("hi", 6)"hi "
padleft(s, width) Pad with leading spaces padleft("42", 5)" 42"
startswith(s, prefix) Check if string starts with prefix startswith("hello", "he")true
endswith(s, suffix) Check if string ends with suffix endswith("hello", "lo")true
split(s, sep) Split string into list split("a,b,c", ",")["a","b","c"]
join(list, sep) Join list into string join(["a","b"], "-")"a-b"
chartonum(s) ASCII/Unicode value of first character chartonum("A")65
numtochar(n) Character from ASCII/Unicode value numtochar(65)"A"
tab(n) String of n spaces tab(4)" "
newline() Newline character

Math Functions

Function Description Example
abs(n) Absolute value abs(-42)42
round(n) Round to nearest integer round(3.7)4
floor(n) Round down floor(3.7)3
ceil(n) Round up ceil(3.2)4
trunc(n) Truncate decimal part trunc(3.9)3
sqrt(n) Square root sqrt(144)12
min(a, b, ...) Minimum of values min(5, 3, 8)3
max(a, b, ...) Maximum of values max(5, 3, 8)8
random(n) Random integer from 1 to n random(10)7
sin(n) Sine (radians) sin(0)0
cos(n) Cosine (radians) cos(0)1
tan(n) Tangent (radians) tan(0)0
log(n) Natural logarithm log(1)0
exp(n) Euler's number raised to n exp(1)2.718...

List Functions

Function Description Example
count(list) Number of items count([1,2,3])3
append(list, item) Add item to end append([1,2], 3)[1,2,3]
list(a, b, ...) Create list from arguments list(1, 2, 3)[1,2,3]
itemof(n, list) Get item at index (1-based) itemof(2, [10,20,30])20
setitem(list, n, val) Return list with item replaced setitem([1,2,3], 2, 99)[1,99,3]
removeitem(list, n) Return list with item removed removeitem([1,2,3], 2)[1,3]
insertitem(list, n, val) Return list with item inserted insertitem([1,3], 2, 2)[1,2,3]
indexof(item, list) Find item position (0 = not found) indexof("b", ["a","b","c"])2
firstitem(list) First item firstitem([10,20,30])10
lastitem(list) Last item lastitem([10,20,30])30
sort(list) Return sorted list sort([3,1,2])[1,2,3]
shuffle(list) Return list in random order
reverse(list) Return reversed list reverse([1,2,3])[3,2,1]
slice(list, start, end) Sub-list (1-based start) slice([10,20,30,40], 2, 3)[20,30]
range(n) Generate [1..n] range(4)[1,2,3,4]
range(start, end) Generate [start..end] range(3,6)[3,4,5,6]
range(start, end, step) Generate with step range(0, 10, 3)[0,3,6,9]

Type Functions

Function Description Example
typeof(val) Return type as string typeof(42)"NUMBER"
isnumber(val) Check if value is numeric isnumber("3.14")true
isempty(val) Check if value is empty isempty("")true
number(val) Convert to number number("42")42
text(val) Convert to string text(42)"42"

Date and Time

Function Description Example Output
time() Current time "3:04:05 PM"
date() Full date "Monday, January 2, 2006"
shortdate() Short date "1/2/06"
seconds() Unix timestamp (seconds) 1709827200
ticks() Unix timestamp (milliseconds) 1709827200000

Utility Functions

Function Description
newline() Returns a newline character \n
tab(n) Returns a string of n spaces

Examples

Hello World

say "Hello, World!"
say "Welcome to Bubble! 🫧"

FizzBuzz

repeat with i from 1 to 100
  if i mod 15 is 0 then
    say "FizzBuzz"
  else if i mod 3 is 0 then
    say "Fizz"
  else if i mod 5 is 0 then
    say "Buzz"
  else
    say i
  end if
end repeat

Factorial

function factorial(n)
  if n is less than 2 then
    return 1
  end if
  return n * factorial(n - 1)
end factorial

repeat with i from 1 to 10
  say i & "! =" && factorial(i)
end repeat

Output:

1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5040
8! = 40320
9! = 362880
10! = 3628800

Fibonacci Sequence

function fibonacci(n)
  if n is less than 2 then
    return n
  end if
  return fibonacci(n - 1) + fibonacci(n - 2)
end fibonacci

repeat with i from 0 to 12
  say "fib(" & i & ") =" && fibonacci(i)
end repeat

Multiplication Table

say "Multiplication table (1-5):"
repeat with row from 1 to 5
  put "" into line
  repeat with col from 1 to 5
    put padleft(text(row * col), 4) into cell
    put line & cell into line
  end repeat
  say line
end repeat

Output:

Multiplication table (1-5):
   1   2   3   4   5
   2   4   6   8  10
   3   6   9  12  15
   4   8  12  16  20
   5  10  15  20  25

Number Guessing Game

put random(100) into secret
put 0 into guesses

say "🫧 I'm thinking of a number between 1 and 100."
say ""

repeat forever
  ask "Your guess:" into guess
  put number(guess) into guess
  add 1 to guesses

  if guess is secret then
    say "🎉 Correct! You got it in" && guesses && "guesses!"
    exit repeat
  else if guess is less than secret then
    say "📈 Too low! Try higher."
  else
    say "📉 Too high! Try lower."
  end if
end repeat

Tic Tac Toe

The examples/tictactoe.bubble file contains a full two-player Tic Tac Toe game with board rendering, win detection, and input validation. Run it with:

bubble examples/tictactoe.bubble

The REPL

The interactive REPL (Read-Eval-Print Loop) starts when you run bubble with no arguments. It supports:

  • Multi-line input: blocks like if, repeat, function, and on automatically continue to the next line until closed with end.
  • Persistent state: variables and functions defined in one line carry over to the next.
  • Expression evaluation: typing an expression shows its result.
bubble> put 2 + 2 into x
bubble> say x
4
bubble> function cube(n)
   ...>   return n ^ 3
   ...> end cube
bubble> say cube(5)
125
bubble> say date()
Saturday, March 7, 2026

REPL commands:

Command Action
help Show quick reference
cancel Cancel the current unfinished block
bye Exit the REPL
quit Exit the REPL
exit Exit the REPL

If you forget to close a block like if ... end if or repeat ... end repeat, Bubble now tells you which end ... is missing. Messages include beginner-friendly tips (for spelling mistakes, unclosed blocks, and wrong function inputs).


Monorepo Layout

Bubble now supports a monorepo structure so the language runtime and web app live in one repository.

Workspaces

  • apps/web: Astro website (React + Tailwind), ready to call Bubble WASM for long script compile tasks.
  • packages/bubble-wasm: shared WASM compile bridge package used by the web app.
  • packages/bubble-notebook: reserved package for notebook/Jupyter-style integration.

Web app quick start

# Install all workspace dependencies
npm install

# Build Bubble runtime to WebAssembly (writes into apps/web/public/wasm)
npm run build:wasm

# Start Astro web app
npm run dev:web

Project Structure

bubblecode/
├── package.json             # npm workspaces for apps/* and packages/*
├── apps/
│   └── web/                 # Astro + React + Tailwind frontend
│       └── public/wasm/      # Built WASM artifacts used in browser
├── cmd/
│   └── wasm/                 # Go WASM entrypoint exposing bubbleCompile()
├── packages/
│   ├── bubble-wasm/         # Shared Bubble WASM compile API
│   └── bubble-notebook/     # Notebook integration placeholder
├── main.go                  # Bubble CLI entry point (Go)
├── go.mod                   # Go module definition
├── token/
│   └── token.go             # Token types and keyword lookup
├── lexer/
│   └── lexer.go             # Tokenizer (source → tokens)
├── ast/
│   └── ast.go               # Abstract syntax tree node definitions
├── parser/
│   └── parser.go            # Pratt parser (tokens → AST)
├── interpreter/
│   ├── environment.go       # Value types and scoped environments
│   ├── interpreter.go       # Tree-walking interpreter (AST → execution)
│   └── builtins.go          # Built-in function implementations
├── repl/
│   └── repl.go              # Interactive REPL
└── examples/
    ├── hello.bubble         # Hello World
    ├── variables.bubble     # Variable assignment demo
    ├── math.bubble          # Arithmetic and math functions
    ├── strings.bubble       # String operations
    ├── control_flow.bubble  # Conditionals, loops, nested loops
    ├── functions.bubble     # Functions, handlers, recursion
    ├── interactive.bubble   # User input example
    └── tictactoe.bubble     # Full Tic Tac Toe game

Building from Source

# Clone the repository
git clone https://github.com/bubblecode/bubble.git
cd bubble

# Install JS workspace dependencies (Astro app + shared packages)
npm install

# Build Bubble WASM runtime used by the web app
npm run build:wasm

# Build
go build -o bubble .

# Run tests
go test ./...

# Run an example
./bubble examples/hello.bubble

# Build web app
npm run build:web

License

Bubble is open-source software. See the LICENSE file for details.

About

bubblecode — A new beginner-friendly programming language

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors