Not to be confused with kyren/piccolo ❤
Piccolo is a small, lightweight, high-pitched scripting language (eventually) intended for embedding in Rust projects.
Users should be able to implement Object for their own types, so they can be
traced and garbage-collected. We could do this a number of ways:
Continue using the mark-and-sweep implementation from https://github.com/Darksecond/lox with its unsoundness issues (seeruntime::memory::test::use_after_freein previous commits)Just useRc<RefCell<dyn Object>>- Heap is a
SlotMapofBox<dyn Object>
Small issue - We want objects to be able to mutate themselves, so the heap must be able to give out mutable references to its objects. But the objects' mutation potentially requires heap manipulation, however, we cannot allow mutable references to the heap to exist at the same time as mutable references to the object.
- We could use a channel (
std::sync::mpsc::channel) and have theObjects submit change requests to theHeapwhich will only carry them out when there can no longer be anyBox<dyn Objects>in free space. - Do
unsafefunny business to get around the problem with the limitation that only way to get a reference to anObjectis if the heap still exists, or totakeit from the heap entirely. This could be spicy since we'd have to uphold the safety invariants ofSlotMapand potentially guarantee implementors ofObjectwould also do so.
Fun stuff that we probably want to have, but they present a few interesting implementation challenges. A closure needs to:
- Understand that local variables it refers to actually exist. The compiler
needs to check the previous
EmitterContexts for local variables that it captures, and also make sure it's not picking up the dummy variable so that functions can be recursive. - Put captured variables in the correct place on the stack.
We have the test suite which is not great, but it works fine for now. The actual lib tests were megagarbage and honestly should only target the high-level APIs in the top-level module and the module-specific things, as well as the experimental stuff.
The current architecture has a few critical flaws:
a =: [] a.push(a) print(a)overflows the stack and it's unlikely to be an easy fix- You can call Rust from Piccolo (e.g. builtin functions) but you can't call Piccolo to Rust and back to Piccolo, for example passing a callback function written in piccolo to a builtin timer function is not possible.
- Type system? Would be fun
- Parametric/subtype polymorphism
- Dynamic dispatch, monomorphization
- Algebraic data types and pattern matching
- Type inference
- Compiler