Sunflower is a small, interpreted programming language implemented in C++ with a focus on:
- Clean, indentation-based syntax
- First-class functions and classes
- Rich built-in data structures
- Practical standard library for files, sockets, HTTP, threading, and small DBs
This document summarizes the features that are currently implemented in the language, based on the interpreter (tokenize, ast, expr, stmt, func, sfclass, sfarray, sfdict, module, environment, native) and the test programs under tests/*.sf and lib/**.
-
Indentation-based blocks
- Blocks are introduced by keywords (like
if,fun,class,for,while,try,catch) and are delimited by indentation, not braces.
if true putln ("Inside if") else if false putln ("Inside else if") else putln ("Inside else") - Blocks are introduced by keywords (like
-
Comments
#starts a line comment.
# This is a comment a = 10 # trailing comment -
Variables and assignment
- Simple assignment with
=. - Reassignment is allowed, dynamic typing.
a = 10 b = "Hello, World!" c = a d = none e = true f = false - Simple assignment with
-
Primitive types
- Integers and floats (tokenized as
Integer/Float). - Booleans:
true,false. - None:
none(distinctNoneType). - Strings: single or double-quoted text.
i = 42 f = 3.14 s = "Hello" t = true n = none - Integers and floats (tokenized as
-
Arrays (lists)
- Ordered, indexable, mutable sequences.
- Support nested arrays, indexing, slicing, comprehension-like construction, and methods like
push,pop, andclear.
a = [1, [2, 3], 4, 5] x = a[0] y = a[1][1] # Slices with optional step write ("0123456789"[1 to 10 step 2]) write ([1, 2, 3, 4, 5][0 to 5 step 2]) # Comprehension-style nested construction grid = [ [i, j] for j in 1 to 10 for i in 1 to 10 ] -
Dictionaries (maps)
- String-keyed maps with nested dictionaries supported.
a = { "hello": "hi", "a": { "a": 1, "b": 2 } } for key in a write (key, a[key]) -
Class objects
- User-defined classes are objects; class values and instances are both first-class.
-
Arithmetic
- Standard operators:
+,-,*,/,%(via expression tree inExprArith). - Used in loops, math functions, algorithms (e.g. Fibonacci, factorial, TSP).
a = 1 a = a + 1 - Standard operators:
-
Comparisons
==,!=,<,>,<=,>=(seeConditionalExprandConditionalType).
if n == 1 return n if value < self.value ... -
Logical operators
and,or,notwith proper short-circuit semantics (LogicalAndExpr,LogicalOrExpr,LogicalNotExpr).
write (true or false and false) write (not true and false) write (not (true and false) or false) -
Bitwise operators
&,|,~,<<,>>(BitAndExpr,BitOrExpr,BitNegateExpr,BitLeftShiftExpr,BitRightShiftExpr).
APPLE = 1 << 0 BANANA = 1 << 1 cart = 0 cart = cart | APPLE cart = cart | BANANA if cart & APPLE write ("Apple is in cart") cart = cart & ~APPLE -
Indexing and slicing
arr[idx]for arrays and strings (ArrayAccess).start to end step kas a range expression (ExprToStep), used for loops and slices.
write ("a123456789"[0]) write ("0123456789"[1 to 10 step 2]) -
Membership / iteration target
x in y(viaInExpr) used infor-loops to iterate over arrays, dicts, ranges, etc.
for i in details write (i)
-
If / else-if / else
if cond ... else if other_cond ... else ... -
While loops
while n > 1 t = f2 f2 = f1 + f2 f1 = t n = n - 1 -
For loops
- General form:
for name in iterable. - Supports arrays, dictionaries (iterating keys), and
1 to Nranges.
for i in 1 to 30 nth_fib (i) for i in a write (i) - General form:
-
Repeat loops
repeat-based loops for counting and inline repetition (RepeatExpr,RepeatStatement).
i = 10 repeat i repeat i put ('*') i = i - 1 putln ('') # Expression form i = 10 repeat 5 grid = 0 repeat 5 repeat 5 -
Break and continue
- Structured loop control (
BreakStmt,ContinueStmt).
for i in 1 to 10 for j in 0 to i if i == 4 or i == 8 continue put (i) - Structured loop control (
-
Function declarations
funkeyword, with positional parameters.
fun test (a) write ("Received argument: ", a) return a test (10) -
Return values
returnfor normal returns (ReturnStatement).return ? "message"or just? "message"to raise an error-like value fortry/catch(see Error Handling).
fun fact (n) if n == 1 return n return fact (n - 1) * n -
Short multiple assignment
- Supported via array destructuring.
fun nth_fib_short (n) [f1, f2] = [0, 1] while n > 1 [f1, f2, n] = [f2, f1 + f2, n - 1] return f2 -
First-class and higher-order usage
- Functions can be passed as values, stored in arrays, and used with native modules like threads and sockets.
fun test (a) s = 0 for i in 1 to 10000 s = s + i write ("hi", a)
-
Class declarations
class Namewith fields and methods.- Implicit
selfparameter for instance methods. _initis the constructor, invoked on instance creation.
class List n = none v = none fun _init (self, v, n) self.n = n self.v = v fun print (self) b = self while b write (b.v) b = b.n a = List (10, List (20, List (30, none))) a.print () -
More complex classes
- Full example with a binary search tree (
TreeNode), featuring:- Methods with recursion
- Mutating instance fields
- Multiple traversal algorithms (
inorder_traversal,preorder_traversal,postorder_traversal) searchmethod using recursion and conditionals.
- Full example with a binary search tree (
-
Inheritance and
extends- Classes can extend other classes using
extends. supercalls parent constructors/methods (seetests/window.sf).
import dove class Window extends dove.Window fun _init (self) super (dove.Window, dove.WIN_TYPE.Windowed, (800, 600), 'Hello, World!') - Classes can extend other classes using
-
Raising errors with
?? value(andreturn ? value) is used to signal an error/exception-like value that can be caught bytry/catch.
fun legal_age (a) if a < 18 return ? "Below legal age" return true -
Try/Catch as statements
try…catchblocks for handling raised values (TryCatchStmt).
try legal_age (17) catch E if E == "Below legal age" write ("<18") -
Try/Catch as expressions
- Expression-level
trywith an optional catch variable and handler expression (TryCatchExpr).
fun age (a) if a < 18 return ? "Below legal age" else if a > 999 return ? "Too old" return a a = try age (17) catch 18 write (a) a = try age (17) catch e -> e write (a) a = try age (17) catch e -> {'Below legal age': 18}[e] write (a) - Expression-level
-
Import syntax
- Import by path or module name with optional alias.
import '_Native_File' as file import '../../lib/thread/_init.sf' as thread import 'file' as file import 'thread' as thread import 'socket' as s import 'net' as net -
Module system
- Backed by
Moduleobjects in C++. importsupports:- Relative
.sffiles - Native bindings (e.g.
_Native_File,_Native_Socket,_Native_Thread,_Native_http) - High-level stdlib modules in
lib/**that wrap native modules in idiomatic Sunflower code.
- Relative
- Backed by
Many built-ins are provided via the native layer (native/*.cpp), and re-exported through simple .sf wrappers in lib/**.
-
Core I/O
input (prompt): read a line from standard input.put (value): write to stdout without newline.putln (value): write with newline.write (...values): formatted/debug printing of multiple values.sleep (ms): sleep for a given time in milliseconds.len (x): length of strings, arrays, etc.
-
String methods (via
native/string/*.cpp)s.count (sub): count occurrences of a substring.s.find (sub): find index of a substring.s.replace (old, new): return a new string with replacements.
-
Integer helpers
- Base conversions via
int/base(e.g. formatting/converting integers with arbitrary bases).
- Base conversions via
-
List methods
list.push (value): append.list.pop (): pop last element.list.clear (): clear the list (used in SmallDB).
-
File API (
lib/file/_init.sf)- High-level file wrapper around
_Native_File:
import 'file' as file f = file ('./test.txt', 'w') f.write ("Hello, World!") f.close ()- Methods:
File.read ()File.write (s)File.seekr (offset, whence),File.seekw (offset, whence),File.seek (offset, whence)File.close ()
- Errors (e.g. not opened) are reported via
? "..."so they can be caught bytry/catch.
- High-level file wrapper around
-
Threading (
lib/thread/_init.sf)- Thin wrapper over
_Native_Threadwith aThreadclass and helpers:
import 'thread' as thread fun work (id) s = 0 for i in 1 to 10000 s = s + i write ("hi", id) t1 = thread (work, [1]) t2 = thread (work, [2]) t1.run () t2.run () thread.join_all ()- Features:
Thread (fn, args)constructor.run (),join (),_kill ().- Global
join_all ()to join all created threads.
- Thin wrapper over
-
Sockets (
lib/socket/_init.sfand native socket)- Low-level
_Native_Socketand higher-levelsocketmodule.
import 'socket' as s sock = s.socket () sock.bind ('localhost', 8000) sock.listen (1000) while 1 try con = sock.accept () data = con.read () con.send ("hello") catch E write ("Error:", E) - Low-level
-
HTTP Server (
lib/http/_init.sf,lib/http/server.sf)- Simple HTTP server abstraction built on
_Native_http.
import 'net' as net server = net.Server ( port = 8000 ) server.get ('/', fun (req, res) \ res.status (200).body ('<h1>Hello, World!</h1>')) server.serve () - Simple HTTP server abstraction built on
-
SmallDB (
lib/smalldb/_init.sf)- Very small file-backed database with a schema and tuples.
import 'smalldb' as smalldb db = smalldb ('./test.sdb') schema = smalldb.Schema (['id', 'name', 'email']) db.set_schema (schema) db.commit_schema () db.add_tuple ([0, "name", "[email protected]"]) db.commit_tuples ()
-
Threaded input / parsing
- Example patterns in
tests/langfeatures.sfshow using threads to decouple input and parsing.
import 'thread' as thread line = [''] got_line = [false] fun get_line () while 1 line[0] = input (">>> ") got_line[0] = true fun parse () while 1 while not got_line[0] t = 0 # busy-wait write ("Input:", line[0]) got_line[0] = false gl_thread = thread (get_line, []) p_thread = thread (parse, []) gl_thread.run () p_thread.run () thread.join_all () - Example patterns in
Some features are present in tests/testfeatures.sf but are explicitly marked as not implemented as of June 30, 2025. They represent ideas for future evolution of the language:
unsafeblock syntax for scoped error-handling sugar.return?shorthand (no space) as an alternative toreturn ?.- Custom iterator protocol via
_iteron classes to supportfor i in cwith internal state.
These are not currently part of the stable feature set but are documented in the repository for experimentation.
Sunflower is an evolving language with an interpreter and runtime implemented in C++. The features described above are inferred from the current implementation and tests and represent the capabilities that are actively exercised by the codebase. As the language grows, this README should be kept in sync with new syntax, semantics, and standard library modules.