fn walk(&mut self, sst: &Spanned<SST>) -> Result<(), Syntax> {
        // TODO: move this to a better spot
        self.lambda.decls = self.scope.locals.len();

        // the entire span of the current node
        self.lambda.emit_span(&sst.span);

        // push left, push right, push center
        return match sst.item.clone() {
            SST::Base(Base::Lit(lit)) => Ok(self.lit(lit)),
            SST::Base(Base::Symbol(unique)) => Ok(self.symbol(unique)),
            SST::Base(Base::Block(block)) => self.block(block),
            // SST::Base(Base::Label(name, expression)) => {
            //     self.label(name, *expression)
            // },
            SST::Base(Base::Label(_)) => todo!(),
            SST::Base(Base::Tuple(tuple)) => self.tuple(tuple),
            SST::Base(Base::Assign(pattern, expression)) => self.assign(pattern, *expression),
            SST::ScopedLambda(ScopedLambda { arg, body, scope }) => self.lambda(arg, *body, scope),
            SST::Base(Base::Call(fun, arg)) => self.call(*fun, *arg),
            SST::Base(Base::Module(_)) => todo!("need to handle modules"),
            SST::Base(Base::Effect(_)) => todo!("need to handle effects"),
        };
    }
Walks an SST to generate bytecode.
At this stage, the SST should've been verified, pruned, typechecked,
etc. A malformed SST will cause a panic, as SSTs should be correct
at this stage, and for them to be incorrect is an error in the
compiler itself.
passerine/src/compiler/compile.rs