What
Add cooperative multitasking (green threads) to O²L via a spawn keyword, a cooperative Scheduler, and first-class Channel values for coroutine communication.
Key additions:
spawn <expr> — launches a new coroutine that runs cooperatively inside the same OS thread
Channel built-in — buffered/unbuffered channel for send/receive between coroutines
io.sleep(ms) — suspends the calling coroutine for a duration without blocking the scheduler
io.yield() — voluntarily yields the CPU to the next ready coroutine
IOThreadPool — offloads blocking I/O to a background thread pool; the calling coroutine suspends and resumes when the I/O completes
Why
O²L targets application-level scripting where concurrent tasks (timers, network calls, event handlers) are common. OS threads are too heavy for fine-grained concurrency; callbacks fragment control flow. Cooperative green threads let code stay sequential in style while handling many concurrent logical tasks efficiently — the same tradeoff that made Go goroutines and Python asyncio popular.
How
Runtime:
Coroutine — owns an ASTNode* body and a cloned Context; carries state (Ready, Running, Suspended, Completed, Failed) and an optional resume value
Scheduler (singleton run-loop) — maintains a ready_queue_ (deque), timer_queue_, and suspended_ map; drives evaluation by calling body->evaluate(context) on each coroutine in turn
- Suspension is signalled by throwing
SuspendException inside evaluate(); the scheduler catches it and moves the coroutine to the appropriate queue
IOThreadPool — a fixed thread pool; when a coroutine suspends for I/O the work lambda is posted there; on completion Scheduler::resumeCoroutine(id, result) is called from the pool thread
ChannelInstance — value-typed channel with configurable buffer capacity; send suspends the sender when full, receive suspends the receiver when empty
Language:
- New token
SPAWN in the lexer
SpawnNode AST node — clones the current Context, calls Scheduler::spawn(body, ctx)
Channel exposed as a global class object; Channel.new(capacity) creates a channel
Tests (8 new unit test files):
test_scheduler.cpp — run-loop, multi-coroutine scheduling
test_spawn_basic.cpp — spawn keyword end-to-end
test_channel_basic.cpp — send/receive, buffering, blocking
test_resume_logic.cpp — suspendCurrent / resumeCoroutine round-trip
test_io_yield.cpp — yield and sleep integration
test_suspend_exception.cpp — exception propagation through coroutines
test_context_clone.cpp — context isolation between coroutines
test_carray_from_list.cpp — CArray.fromList() helper (used by FFI bridge in async callbacks)
All 464 tests pass (including pre-existing suite).
What
Add cooperative multitasking (green threads) to O²L via a
spawnkeyword, a cooperativeScheduler, and first-classChannelvalues for coroutine communication.Key additions:
spawn <expr>— launches a new coroutine that runs cooperatively inside the same OS threadChannelbuilt-in — buffered/unbuffered channel for send/receive between coroutinesio.sleep(ms)— suspends the calling coroutine for a duration without blocking the schedulerio.yield()— voluntarily yields the CPU to the next ready coroutineIOThreadPool— offloads blocking I/O to a background thread pool; the calling coroutine suspends and resumes when the I/O completesWhy
O²L targets application-level scripting where concurrent tasks (timers, network calls, event handlers) are common. OS threads are too heavy for fine-grained concurrency; callbacks fragment control flow. Cooperative green threads let code stay sequential in style while handling many concurrent logical tasks efficiently — the same tradeoff that made Go goroutines and Python asyncio popular.
How
Runtime:
Coroutine— owns anASTNode* bodyand a clonedContext; carries state (Ready,Running,Suspended,Completed,Failed) and an optional resume valueScheduler(singleton run-loop) — maintains aready_queue_(deque),timer_queue_, andsuspended_map; drives evaluation by callingbody->evaluate(context)on each coroutine in turnSuspendExceptioninsideevaluate(); the scheduler catches it and moves the coroutine to the appropriate queueIOThreadPool— a fixed thread pool; when a coroutine suspends for I/O the work lambda is posted there; on completionScheduler::resumeCoroutine(id, result)is called from the pool threadChannelInstance— value-typed channel with configurable buffer capacity;sendsuspends the sender when full,receivesuspends the receiver when emptyLanguage:
SPAWNin the lexerSpawnNodeAST node — clones the currentContext, callsScheduler::spawn(body, ctx)Channelexposed as a global class object;Channel.new(capacity)creates a channelTests (8 new unit test files):
test_scheduler.cpp— run-loop, multi-coroutine schedulingtest_spawn_basic.cpp—spawnkeyword end-to-endtest_channel_basic.cpp— send/receive, buffering, blockingtest_resume_logic.cpp—suspendCurrent/resumeCoroutineround-triptest_io_yield.cpp—yieldandsleepintegrationtest_suspend_exception.cpp— exception propagation through coroutinestest_context_clone.cpp— context isolation between coroutinestest_carray_from_list.cpp—CArray.fromList()helper (used by FFI bridge in async callbacks)All 464 tests pass (including pre-existing suite).