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_free
in previous commits)Just useRc<RefCell<dyn Object>>
- Heap is a
SlotMap
ofBox<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 theObject
s submit change requests to theHeap
which will only carry them out when there can no longer be anyBox<dyn Objects>
in free space. - Do
unsafe
funny business to get around the problem with the limitation that only way to get a reference to anObject
is if the heap still exists, or totake
it from the heap entirely. This could be spicy since we'd have to uphold the safety invariants ofSlotMap
and potentially guarantee implementors ofObject
would 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
EmitterContext
s 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