Add branching and more coherent method of function calls
We're turing-complete, babey! * Call stack for functions now differentiates between native and quote calls * Better API for builtin functions allowing for more control * Example showing off branches Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use crate::syn::ast::SpExpr;
|
||||
use crate::vm::machine::Machine;
|
||||
use crate::vm::{error::Result, machine::Machine};
|
||||
use crate::{scope::Scope, syn::span::Span, vm::inst::Inst};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
@@ -33,7 +33,7 @@ impl Quote {
|
||||
/// A table of compiled quotes, their expression trees, and their spans.
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct QuoteTable {
|
||||
table: Vec<(Span, Scope, Vec<SpExpr>, Vec<Inst>)>,
|
||||
table: Vec<(Span, Scope, Vec<SpExpr>, Rc<Vec<Inst>>)>,
|
||||
}
|
||||
|
||||
impl QuoteTable {
|
||||
@@ -46,14 +46,14 @@ impl QuoteTable {
|
||||
span: Span,
|
||||
scope: Scope,
|
||||
quote: Vec<SpExpr>,
|
||||
compiled: Vec<Inst>,
|
||||
compiled: Rc<Vec<Inst>>,
|
||||
) -> Quote {
|
||||
let next = Quote(self.table.len());
|
||||
self.table.push((span, scope, quote, compiled));
|
||||
next
|
||||
}
|
||||
|
||||
pub fn get(&self, quote: Quote) -> &(Span, Scope, Vec<SpExpr>, Vec<Inst>) {
|
||||
pub fn get(&self, quote: Quote) -> &(Span, Scope, Vec<SpExpr>, Rc<Vec<Inst>>) {
|
||||
&self.table[quote.0]
|
||||
}
|
||||
}
|
||||
@@ -86,6 +86,19 @@ impl Value {
|
||||
BuiltinFn(_) => "builtin function",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_truthy(&self) -> bool {
|
||||
use Value::*;
|
||||
match self {
|
||||
Array(a) => a.len() > 0,
|
||||
Float(f) => *f != 0.0,
|
||||
Int(i) => *i != 0,
|
||||
Str(s) => s.len() > 0,
|
||||
Quote(_) => true,
|
||||
ObjPtr(_) => true,
|
||||
BuiltinFn(_) => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Value {
|
||||
@@ -103,8 +116,40 @@ impl Display for Value {
|
||||
}
|
||||
}
|
||||
|
||||
/// The intent of a builtin function once the function proper returns.
|
||||
///
|
||||
/// When a builtin function itself returns, it may want to remain on the call
|
||||
/// stack, or do some kind of cleanup before it's finished. So, a function may
|
||||
/// pre-empt itself with the understanding that it will eventually return.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum BuiltinExit {
|
||||
/// Pop this builtin off the call stack, and then call the given quote.
|
||||
Call(Quote),
|
||||
|
||||
/// Continue with the assumption that some other function has been pushed to
|
||||
/// the call stack, updating the reentry for this function call to the
|
||||
/// specified constant.
|
||||
Resume(usize),
|
||||
|
||||
/// Pops this builtin off the call stack, returning like normal.
|
||||
Return,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct BuiltinFn(Rc<dyn FnMut(&mut Machine)>);
|
||||
pub struct BuiltinFn(Rc<BuiltinFnPtr>);
|
||||
|
||||
impl BuiltinFn {
|
||||
pub fn new(fun: Rc<BuiltinFnPtr>) -> Self {
|
||||
BuiltinFn(fun)
|
||||
}
|
||||
|
||||
pub fn call(&self, machine: &mut Machine, reentry: usize) -> Result<BuiltinExit> {
|
||||
(self.0)(machine, reentry)
|
||||
}
|
||||
}
|
||||
|
||||
//pub type BuiltinFnPtr = dyn Fn(&mut Machine, usize) -> Result<BuiltinExit>;
|
||||
pub type BuiltinFnPtr = fn(&mut Machine, usize) -> Result<BuiltinExit>;
|
||||
|
||||
impl Debug for BuiltinFn {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
|
||||
Reference in New Issue
Block a user