A visual, user-friendly implementation of a template instantiation machine to understand how a lazily evaluated functional programming language is evaluated.
Supercombinator
Update
Primitive
TIM
is written in Rust because:
- Rust is a systems language, so it'll hopefully be faster than an implementation in Haskell
- Rust is strict, which means that implementing certain things like letrec needs some more elbow grease
- Rust has nice libraries (and a slick stdlib
) that let you write safe and pretty code
peek()
return PeekNoToken
instead of error?in a lot of the parsing, we usually check if the next token is something. if it isn't, we just return immediately.
Semantically, it makes sense, since you're just "peeking" at the next token, so we can signal that there is no token by returning a sentinel token.
try!(cursor.peek())
causes us to lose control flow and propogate
an error if we peek at something that doesn't exist, which is the wrong
semantics. We want the user to be able to peek and make decisions based on
whether something is present ahead or not. consume()
and expect()
should
return errors since you're asking the cursor to go one token ahead.
[..]
and &[..]
Slice without ref versus Slice with ref
the difference is that the second slice is being taken inside tokenize
, which somehow maintains length info
(which is needed for [..]
(since [..]
means that you know the number of elements in it).
So, when it is outside, you need to take a slice &[..]
, so that Sized
information is not needed
STGi
implementation whose style I straight up copied for this machine.