Add Bool builtin type, branches, and some more stuff
* obj::Bool builtin type is used for truthiness and decision-making * Branches are compiled and seem to be working for basic integer comparison * Updated version of Shredder to what is current as of writing * CheckTruth VM instruction that will explicitly set the condition flag * Probably some other stuff Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -27,4 +27,5 @@ once_cell = "1.4.1"
|
|||||||
|
|
||||||
[dependencies.shredder]
|
[dependencies.shredder]
|
||||||
git = "https://github.com/Others/shredder"
|
git = "https://github.com/Others/shredder"
|
||||||
|
rev = "c71335"
|
||||||
features = ["nightly-features"]
|
features = ["nightly-features"]
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use not_python::{compile::Compile, syn::ast, vm::Vm};
|
use not_python::{compile::Compile, syn::ast, vm::Vm};
|
||||||
|
|
||||||
|
use shredder::run_with_gc_cleanup;
|
||||||
use std::{fs, path::PathBuf};
|
use std::{fs, path::PathBuf};
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
@@ -23,6 +24,7 @@ struct Options {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
|
run_with_gc_cleanup(|| {
|
||||||
let opt = Options::from_args();
|
let opt = Options::from_args();
|
||||||
let text = fs::read_to_string(&opt.input)?;
|
let text = fs::read_to_string(&opt.input)?;
|
||||||
let action = &opt.action.to_lowercase();
|
let action = &opt.action.to_lowercase();
|
||||||
@@ -59,6 +61,6 @@ fn main() -> Result<()> {
|
|||||||
let mut vm = Vm::new(&const_pool);
|
let mut vm = Vm::new(&const_pool);
|
||||||
vm.call(main, vec![])?;
|
vm.call(main, vec![])?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,6 +76,12 @@ impl Visit for CollectLocals<'_> {
|
|||||||
fn visit_fun_expr(&mut self, _expr: &FunExpr) -> Self::Out {
|
fn visit_fun_expr(&mut self, _expr: &FunExpr) -> Self::Out {
|
||||||
// Do not collect names for function expressions, since they have their own scope.
|
// Do not collect names for function expressions, since they have their own scope.
|
||||||
}
|
}
|
||||||
|
fn visit_if_expr(&mut self, expr: &IfExpr) -> Self::Out {
|
||||||
|
DefaultAccept::default_accept(expr, self);
|
||||||
|
}
|
||||||
|
fn visit_cond_body(&mut self, cond_body: &CondBody) -> Self::Out {
|
||||||
|
DefaultAccept::default_accept(cond_body, self);
|
||||||
|
}
|
||||||
fn visit_atom(&mut self, atom: &Atom) -> Self::Out {
|
fn visit_atom(&mut self, atom: &Atom) -> Self::Out {
|
||||||
DefaultAccept::default_accept(atom, self);
|
DefaultAccept::default_accept(atom, self);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
compile::{basic_block::*, error::*, Compile},
|
compile::{basic_block::*, error::*, Compile},
|
||||||
obj::prelude::*,
|
obj::{prelude::*, reserved::*},
|
||||||
syn::{ast::*, visit::*},
|
syn::{ast::*, visit::*},
|
||||||
vm::inst::*,
|
vm::inst::*,
|
||||||
};
|
};
|
||||||
@@ -25,10 +25,7 @@ pub enum Thunk {
|
|||||||
///
|
///
|
||||||
/// Only one of these thunks will be executed. At the end of either thunk, the program will
|
/// Only one of these thunks will be executed. At the end of either thunk, the program will
|
||||||
/// continue at the address following this branch.
|
/// continue at the address following this branch.
|
||||||
Branch {
|
Branch(ThunkBranch),
|
||||||
thunk_true: Box<Thunk>,
|
|
||||||
thunk_false: Box<Thunk>,
|
|
||||||
},
|
|
||||||
|
|
||||||
/// Based on the conditional flag in the VM, code for this loop will continue to execute.
|
/// Based on the conditional flag in the VM, code for this loop will continue to execute.
|
||||||
///
|
///
|
||||||
@@ -94,11 +91,11 @@ impl Thunk {
|
|||||||
Thunk::List(thunks) => thunks
|
Thunk::List(thunks) => thunks
|
||||||
.iter()
|
.iter()
|
||||||
.fold(0, |n, thunk| n + thunk.basic_block_count()),
|
.fold(0, |n, thunk| n + thunk.basic_block_count()),
|
||||||
Thunk::Branch {
|
Thunk::Branch(ThunkBranch {
|
||||||
|
preamble,
|
||||||
thunk_true,
|
thunk_true,
|
||||||
thunk_false,
|
thunk_false,
|
||||||
// length is true + false block count, + 1 for the branch basic block at the start
|
}) => preamble.basic_block_count() + thunk_true.basic_block_count() + thunk_false.basic_block_count() + 1,
|
||||||
} => thunk_true.basic_block_count() + thunk_false.basic_block_count() + 1,
|
|
||||||
// length is thunk, + 1 for branch at the start of the loop
|
// length is thunk, + 1 for branch at the start of the loop
|
||||||
Thunk::Loop(thunk) => thunk.basic_block_count() + 1,
|
Thunk::Loop(thunk) => thunk.basic_block_count() + 1,
|
||||||
Thunk::Nop => 0,
|
Thunk::Nop => 0,
|
||||||
@@ -128,6 +125,16 @@ impl From<Vec<Thunk>> for Thunk {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// struct ThunkBranch
|
||||||
|
//
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct ThunkBranch {
|
||||||
|
preamble: Box<Thunk>,
|
||||||
|
thunk_true: Box<Thunk>,
|
||||||
|
thunk_false: Box<Thunk>,
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// struct Flatten
|
// struct Flatten
|
||||||
//
|
//
|
||||||
@@ -150,6 +157,9 @@ impl Flatten {
|
|||||||
let last_block = thunk.basic_block_count();
|
let last_block = thunk.basic_block_count();
|
||||||
self.flatten_next(last_block, thunk);
|
self.flatten_next(last_block, thunk);
|
||||||
assert_eq!(self.blocks.len(), last_block);
|
assert_eq!(self.blocks.len(), last_block);
|
||||||
|
// push an extra null block at the very end so that anything pointing to `last_block` will
|
||||||
|
// have a valid block index
|
||||||
|
self.blocks.insert(last_block, BasicBlock::Block { exit: last_block + 1, block: Default::default() });
|
||||||
self.blocks
|
self.blocks
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,13 +184,17 @@ impl Flatten {
|
|||||||
}
|
}
|
||||||
assert_eq!(next_block, self.this_block());
|
assert_eq!(next_block, self.this_block());
|
||||||
}
|
}
|
||||||
Thunk::Branch {
|
Thunk::Branch(ThunkBranch {
|
||||||
|
preamble,
|
||||||
thunk_true,
|
thunk_true,
|
||||||
thunk_false,
|
thunk_false,
|
||||||
} => {
|
}) => {
|
||||||
let branch_block = self.this_block();
|
let preamble_block = self.this_block();
|
||||||
let block_true = self.this_block() + 1;
|
let branch_block = preamble_block + preamble.basic_block_count();
|
||||||
|
let block_true = branch_block + 1;
|
||||||
let block_false = block_true + thunk_true.basic_block_count();
|
let block_false = block_true + thunk_true.basic_block_count();
|
||||||
|
self.flatten_next(branch_block, *preamble);
|
||||||
|
assert_eq!(self.this_block(), branch_block);
|
||||||
self.blocks.insert(
|
self.blocks.insert(
|
||||||
branch_block,
|
branch_block,
|
||||||
BasicBlock::Branch {
|
BasicBlock::Branch {
|
||||||
@@ -188,7 +202,9 @@ impl Flatten {
|
|||||||
block_false,
|
block_false,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
assert_eq!(self.this_block(), block_true);
|
||||||
self.flatten_next(next_block, *thunk_true);
|
self.flatten_next(next_block, *thunk_true);
|
||||||
|
assert_eq!(self.this_block(), block_false);
|
||||||
self.flatten_next(next_block, *thunk_false);
|
self.flatten_next(next_block, *thunk_false);
|
||||||
assert_eq!(self.this_block(), next_block);
|
assert_eq!(self.this_block(), next_block);
|
||||||
}
|
}
|
||||||
@@ -263,7 +279,7 @@ impl Visit for CompileBody<'_> {
|
|||||||
let mut thunk = if let Some(expr) = stmt.expr.as_ref() {
|
let mut thunk = if let Some(expr) = stmt.expr.as_ref() {
|
||||||
self.visit_expr(expr)?
|
self.visit_expr(expr)?
|
||||||
} else {
|
} else {
|
||||||
Inst::PushSym(crate::obj::reserved::NIL_NAME.sym).into()
|
Inst::PushSym(NIL_NAME.sym).into()
|
||||||
};
|
};
|
||||||
thunk.push(Inst::Return);
|
thunk.push(Inst::Return);
|
||||||
|
|
||||||
@@ -394,7 +410,7 @@ impl Visit for CompileBody<'_> {
|
|||||||
// If the last instruction is not a return, or if there are no instructions, then return
|
// If the last instruction is not a return, or if there are no instructions, then return
|
||||||
// :nil value.
|
// :nil value.
|
||||||
if !matches!(code.last(), Some(Inst::Return)) {
|
if !matches!(code.last(), Some(Inst::Return)) {
|
||||||
code.push(Inst::PushSym(crate::obj::reserved::NIL_NAME.sym));
|
code.push(Inst::PushSym(NIL_NAME.sym));
|
||||||
code.push(Inst::Return);
|
code.push(Inst::Return);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -429,6 +445,46 @@ impl Visit for CompileBody<'_> {
|
|||||||
Ok(Inst::PushConst(hdl).into())
|
Ok(Inst::PushConst(hdl).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_if_expr(&mut self, expr: &IfExpr) -> Self::Out {
|
||||||
|
// base if condition
|
||||||
|
let mut thunk = self.visit_cond_body(&expr.cond_body)?;
|
||||||
|
{
|
||||||
|
// elif branches
|
||||||
|
let mut prev_thunk: &mut Thunk = &mut thunk;
|
||||||
|
for elif_cond_body in expr.elif.iter() {
|
||||||
|
let elif_thunk = self.visit_cond_body(elif_cond_body)?;
|
||||||
|
if let Thunk::Branch(thunk_branch) = prev_thunk {
|
||||||
|
thunk_branch.thunk_false = Box::new(elif_thunk);
|
||||||
|
prev_thunk = &mut thunk_branch.thunk_false;
|
||||||
|
} else {
|
||||||
|
unreachable!("accidentally found a non-branch thunk in elif expression")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// el branch
|
||||||
|
if let (Some(el_body), Thunk::Branch(thunk_branch)) = (&expr.el, prev_thunk) {
|
||||||
|
thunk_branch.thunk_false = Box::new(self.visit_body(el_body)?);
|
||||||
|
//prev_thunk = &mut thunk_branch.thunk_false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(thunk)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_cond_body(&mut self, cond_body: &CondBody) -> Self::Out {
|
||||||
|
let mut preamble = self.visit_expr(&cond_body.cond)?;
|
||||||
|
// Attempt to call the __bool__ function on this object which leaves a value on the stack
|
||||||
|
preamble.push_thunk(vec![
|
||||||
|
Inst::GetAttr(BOOL_MEMBER_NAME.sym),
|
||||||
|
Inst::Call(0),
|
||||||
|
Inst::CheckTruth,
|
||||||
|
]);
|
||||||
|
Ok(Thunk::Branch(ThunkBranch {
|
||||||
|
preamble: preamble.into(),
|
||||||
|
thunk_true: self.visit_body(&cond_body.body)?.into(),
|
||||||
|
thunk_false: Box::new(Thunk::Nop),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_atom(&mut self, atom: &Atom) -> Self::Out {
|
fn visit_atom(&mut self, atom: &Atom) -> Self::Out {
|
||||||
let thunk = match atom {
|
let thunk = match atom {
|
||||||
Atom::Ident(ident) => {
|
Atom::Ident(ident) => {
|
||||||
@@ -490,13 +546,12 @@ fn test_flatten_thunk() {
|
|||||||
let end_body = vec![Inst::PushSym(Sym::new(1)), Inst::Call(1)];
|
let end_body = vec![Inst::PushSym(Sym::new(1)), Inst::Call(1)];
|
||||||
|
|
||||||
let thunk = Thunk::List(vec![
|
let thunk = Thunk::List(vec![
|
||||||
// do something before
|
|
||||||
Thunk::Body(init_body.clone()),
|
|
||||||
// branch
|
// branch
|
||||||
Thunk::Branch {
|
Thunk::Branch(ThunkBranch {
|
||||||
|
preamble: Thunk::Body(init_body.clone()).into(),
|
||||||
thunk_true: Thunk::Body(true_body.clone()).into(),
|
thunk_true: Thunk::Body(true_body.clone()).into(),
|
||||||
thunk_false: Thunk::Body(false_body.clone()).into(),
|
thunk_false: Thunk::Body(false_body.clone()).into(),
|
||||||
},
|
}),
|
||||||
// do something after
|
// do something after
|
||||||
Thunk::Body(end_body.clone()),
|
Thunk::Body(end_body.clone()),
|
||||||
]);
|
]);
|
||||||
@@ -504,7 +559,7 @@ fn test_flatten_thunk() {
|
|||||||
let block_count = thunk.basic_block_count();
|
let block_count = thunk.basic_block_count();
|
||||||
|
|
||||||
let blocks = thunk.flatten();
|
let blocks = thunk.flatten();
|
||||||
assert_eq!(blocks.len(), block_count);
|
assert_eq!(blocks.len(), block_count + 1);
|
||||||
|
|
||||||
let mut iter = blocks.into_iter();
|
let mut iter = blocks.into_iter();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -557,5 +612,16 @@ fn test_flatten_thunk() {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
// empty block
|
||||||
|
assert_eq!(
|
||||||
|
iter.next().unwrap(),
|
||||||
|
(
|
||||||
|
5,
|
||||||
|
BasicBlock::Block {
|
||||||
|
exit: 6,
|
||||||
|
block: vec![],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
assert!(iter.next().is_none());
|
assert!(iter.next().is_none());
|
||||||
}
|
}
|
||||||
|
|||||||
92
src/obj/boolean.rs
Normal file
92
src/obj/boolean.rs
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
use crate::{
|
||||||
|
obj::{prelude::*, reserved::*},
|
||||||
|
vm::error::*,
|
||||||
|
};
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
use shredder::Scan;
|
||||||
|
use std::fmt::{self, Debug, Formatter};
|
||||||
|
|
||||||
|
pub type BoolRef = ObjRef<Bool>;
|
||||||
|
|
||||||
|
#[derive(Scan)]
|
||||||
|
pub struct Bool {
|
||||||
|
value: bool,
|
||||||
|
vtable: Vtable,
|
||||||
|
attrs: Attrs,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Bool {
|
||||||
|
/// Gets the value of this boolean.
|
||||||
|
pub fn value(&self) -> bool {
|
||||||
|
self.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<bool> for BoolRef {
|
||||||
|
fn from(value: bool) -> Self {
|
||||||
|
if value {
|
||||||
|
BOOL_TRUE.clone()
|
||||||
|
} else {
|
||||||
|
BOOL_FALSE.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_obj_readonly!(Bool);
|
||||||
|
|
||||||
|
impl Debug for Bool {
|
||||||
|
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
|
||||||
|
fmt.debug_struct("Bool").field("value", &self.value).finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A true boolean value.
|
||||||
|
///
|
||||||
|
/// This value should be the only instance of a "true" boolean.
|
||||||
|
pub static BOOL_TRUE: Lazy<BoolRef> = Lazy::new(||
|
||||||
|
self_referring_obj! {
|
||||||
|
Bool {
|
||||||
|
value: true,
|
||||||
|
vtable: Default::default(),
|
||||||
|
attrs: Default::default(),
|
||||||
|
},
|
||||||
|
vtable: |obj_ref: ObjRef| vtable! {
|
||||||
|
BOOL_MEMBER_NAME.sym => Method::new_obj(obj_ref.clone(), BOOL_BOOL_FUN.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/// A false boolean value.
|
||||||
|
///
|
||||||
|
/// This value should be the only instance of a "false" boolean.
|
||||||
|
pub static BOOL_FALSE: Lazy<BoolRef> = Lazy::new(||
|
||||||
|
self_referring_obj! {
|
||||||
|
Bool {
|
||||||
|
value: false,
|
||||||
|
vtable: Default::default(),
|
||||||
|
attrs: Default::default(),
|
||||||
|
},
|
||||||
|
vtable: |obj_ref: ObjRef| vtable! {
|
||||||
|
BOOL_MEMBER_NAME.sym => Method::new_obj(obj_ref.clone(), BOOL_BOOL_FUN.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Builtin Bool functions
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/// Bool.__bool__(self) impl
|
||||||
|
static BOOL_BOOL_FUN: Lazy<NativeFunRef> = Lazy::new(|| {
|
||||||
|
NativeFun::new_obj(1, |_callee, vm, args| {
|
||||||
|
{
|
||||||
|
read_obj_downcast!(let value: Option<&Bool> = &args[0]);
|
||||||
|
value.ok_or_else(|| Error::ValueError {
|
||||||
|
error: "expected Bool value".to_string(),
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
// just push a copy of the "self" value
|
||||||
|
vm.push(args[0].clone());
|
||||||
|
Ok(crate::vm::signal::Signal::Return)
|
||||||
|
})
|
||||||
|
});
|
||||||
@@ -3,7 +3,7 @@ use crate::{
|
|||||||
vm::{consts::ConstPool, error::*, frame::*, inst::Inst, signal::*, Vm},
|
vm::{consts::ConstPool, error::*, frame::*, inst::Inst, signal::*, Vm},
|
||||||
};
|
};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use shredder::{GcSafeWrapper, Scan};
|
use shredder::Scan;
|
||||||
use std::{
|
use std::{
|
||||||
fmt::{self, Debug, Formatter},
|
fmt::{self, Debug, Formatter},
|
||||||
io::{self, Write},
|
io::{self, Write},
|
||||||
@@ -88,10 +88,10 @@ pub struct UserFun {
|
|||||||
vtable: Vtable,
|
vtable: Vtable,
|
||||||
attrs: Attrs,
|
attrs: Attrs,
|
||||||
// Safe because Vec<Inst> doesn't need to be scanned
|
// Safe because Vec<Inst> doesn't need to be scanned
|
||||||
#[shredder(unsafe_skip)]
|
#[shredder(unsafe_skip_gc_safe)]
|
||||||
code: Arc<Vec<Inst>>,
|
code: Arc<Vec<Inst>>,
|
||||||
// Safe because this is just an interner that points to symbols, which aren't GC'd
|
// Safe because this is just an interner that points to symbols, which aren't GC'd
|
||||||
#[shredder(unsafe_skip)]
|
#[shredder(unsafe_skip_gc_safe)]
|
||||||
locals: FunLocals,
|
locals: FunLocals,
|
||||||
arity: usize,
|
arity: usize,
|
||||||
}
|
}
|
||||||
@@ -179,7 +179,7 @@ impl UserFun {
|
|||||||
("(discarded)".to_string(), String::new())
|
("(discarded)".to_string(), String::new())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Inst::Jump(addr) | Inst::JumpTrue(addr) => (addr.to_string(), String::new()),
|
Inst::Jump(addr) | Inst::JumpTrue(addr) => (format!("{:0addr_w$x}", addr, addr_w = addr_w), String::new()),
|
||||||
Inst::Call(argc) => (argc.to_string(), String::new()),
|
Inst::Call(argc) => (argc.to_string(), String::new()),
|
||||||
_ => (String::new(), String::new()),
|
_ => (String::new(), String::new()),
|
||||||
};
|
};
|
||||||
@@ -261,15 +261,32 @@ pub static USER_FUN_TY: Lazy<ObjRef<Ty>> = Lazy::new(|| Ty::new_obj(USER_FUN_NAM
|
|||||||
// struct NativeFun
|
// struct NativeFun
|
||||||
//
|
//
|
||||||
|
|
||||||
pub type NativeFunPtr = fn(ObjRef, &mut Vm, Vec<ObjRef>) -> Result<Signal>;
|
pub type FunPtr = fn(ObjRef, &mut Vm, Vec<ObjRef>) -> Result<Signal>;
|
||||||
|
pub struct NativeFunPtr(pub FunPtr);
|
||||||
|
|
||||||
|
impl Clone for NativeFunPtr {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
NativeFunPtr(self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Deref for NativeFunPtr {
|
||||||
|
type Target = FunPtr;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsafe impl shredder::marker::GcDrop for NativeFunPtr { }
|
||||||
|
|
||||||
pub type NativeFunRef = ObjRef<NativeFun>;
|
pub type NativeFunRef = ObjRef<NativeFun>;
|
||||||
|
|
||||||
#[derive(Scan)]
|
#[derive(Scan)]
|
||||||
pub struct NativeFun {
|
pub struct NativeFun {
|
||||||
vtable: Vtable,
|
vtable: Vtable,
|
||||||
attrs: Attrs,
|
attrs: Attrs,
|
||||||
#[shredder(skip)]
|
#[shredder(unsafe_skip_gc_safe)]
|
||||||
fun: GcSafeWrapper<NativeFunPtr>,
|
fun: NativeFunPtr,
|
||||||
arity: usize,
|
arity: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,12 +295,12 @@ pub struct NativeFun {
|
|||||||
//
|
//
|
||||||
|
|
||||||
impl NativeFun {
|
impl NativeFun {
|
||||||
pub fn new_obj(arity: usize, fun: NativeFunPtr) -> ObjRef<Self> {
|
pub fn new_obj(arity: usize, fun: FunPtr) -> ObjRef<Self> {
|
||||||
self_referring_obj! (
|
self_referring_obj! (
|
||||||
Self {
|
Self {
|
||||||
vtable: Default::default(),
|
vtable: Default::default(),
|
||||||
attrs: Default::default(),
|
attrs: Default::default(),
|
||||||
fun: GcSafeWrapper::new(fun),
|
fun: NativeFunPtr(fun),
|
||||||
arity,
|
arity,
|
||||||
},
|
},
|
||||||
vtable: |obj_ref: ObjRef| vtable! {
|
vtable: |obj_ref: ObjRef| vtable! {
|
||||||
@@ -345,7 +362,7 @@ impl Fun for NativeFun {
|
|||||||
got: args.len(),
|
got: args.len(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Ok(Frame::Native(NativeFrame::new(callee, *self.fun, args)))
|
Ok(Frame::Native(NativeFrame::new(callee, self.fun.clone(), args)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ impl Int {
|
|||||||
attrs: Default::default(),
|
attrs: Default::default(),
|
||||||
},
|
},
|
||||||
vtable: |obj_ref: ObjRef| vtable! {
|
vtable: |obj_ref: ObjRef| vtable! {
|
||||||
|
BOOL_MEMBER_NAME.sym => Method::new_obj(obj_ref.clone(), INT_BOOL_FUN.clone()),
|
||||||
REPR_MEMBER_NAME.sym => Method::new_obj(obj_ref.clone(), INT_STR_FUN.clone()),
|
REPR_MEMBER_NAME.sym => Method::new_obj(obj_ref.clone(), INT_STR_FUN.clone()),
|
||||||
STR_MEMBER_NAME.sym => Method::new_obj(obj_ref.clone(), INT_STR_FUN.clone()),
|
STR_MEMBER_NAME.sym => Method::new_obj(obj_ref.clone(), INT_STR_FUN.clone()),
|
||||||
INT_MEMBER_NAME.sym => Method::new_obj(obj_ref.clone(), INT_INT_FUN.clone()),
|
INT_MEMBER_NAME.sym => Method::new_obj(obj_ref.clone(), INT_INT_FUN.clone()),
|
||||||
@@ -33,6 +34,8 @@ impl Int {
|
|||||||
MINUS_OP_NAME.sym => Method::new_obj(obj_ref.clone(), INT_SUB_FUN.clone()),
|
MINUS_OP_NAME.sym => Method::new_obj(obj_ref.clone(), INT_SUB_FUN.clone()),
|
||||||
TIMES_OP_NAME.sym => Method::new_obj(obj_ref.clone(), INT_MUL_FUN.clone()),
|
TIMES_OP_NAME.sym => Method::new_obj(obj_ref.clone(), INT_MUL_FUN.clone()),
|
||||||
DIV_OP_NAME.sym => Method::new_obj(obj_ref.clone(), INT_DIV_FUN.clone()),
|
DIV_OP_NAME.sym => Method::new_obj(obj_ref.clone(), INT_DIV_FUN.clone()),
|
||||||
|
EQ_OP_NAME.sym => Method::new_obj(obj_ref.clone(), INT_EQ_FUN.clone()),
|
||||||
|
NE_OP_NAME.sym => Method::new_obj(obj_ref.clone(), INT_NE_FUN.clone()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -54,6 +57,18 @@ impl Debug for Int {
|
|||||||
// Builtin Int functions
|
// Builtin Int functions
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/// Int.__bool__(self) impl
|
||||||
|
static INT_BOOL_FUN: Lazy<NativeFunRef> = Lazy::new(|| {
|
||||||
|
NativeFun::new_obj(1, |_callee, vm, args| {
|
||||||
|
read_obj_downcast!(let int_obj: Option<&Int> = &args[0]);
|
||||||
|
let int_obj = int_obj.ok_or_else(|| Error::ValueError {
|
||||||
|
error: "expected Int value".to_string(),
|
||||||
|
})?;
|
||||||
|
vm.push(BoolRef::from(int_obj.value != 0));
|
||||||
|
Ok(crate::vm::signal::Signal::Return)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
/// Int.__str__(self) impl
|
/// Int.__str__(self) impl
|
||||||
static INT_STR_FUN: Lazy<NativeFunRef> = Lazy::new(|| {
|
static INT_STR_FUN: Lazy<NativeFunRef> = Lazy::new(|| {
|
||||||
NativeFun::new_obj(1, |_callee, vm, args| {
|
NativeFun::new_obj(1, |_callee, vm, args| {
|
||||||
@@ -157,3 +172,41 @@ static INT_DIV_FUN: Lazy<NativeFunRef> = Lazy::new(|| {
|
|||||||
Ok(crate::vm::signal::Signal::Return)
|
Ok(crate::vm::signal::Signal::Return)
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// Int.__eq__(self, Int) impl
|
||||||
|
static INT_EQ_FUN: Lazy<NativeFunRef> = Lazy::new(|| {
|
||||||
|
NativeFun::new_obj(2, |_callee, vm, args| {
|
||||||
|
read_obj_downcast!(let lhs: Option<&Int> = &args[0]);
|
||||||
|
let lhs = lhs.ok_or_else(|| Error::ValueError {
|
||||||
|
error: "expected int for LHS".to_string(),
|
||||||
|
})?;
|
||||||
|
|
||||||
|
read_obj_downcast!(let rhs: Option<&Int> = &args[1]);
|
||||||
|
let rhs = rhs.ok_or_else(|| Error::ValueError {
|
||||||
|
error: "expected int for RHS".to_string(),
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let result = lhs.value == rhs.value;
|
||||||
|
vm.push(BoolRef::from(result));
|
||||||
|
Ok(crate::vm::signal::Signal::Return)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
/// Int.__ne__(self, Int) impl
|
||||||
|
static INT_NE_FUN: Lazy<NativeFunRef> = Lazy::new(|| {
|
||||||
|
NativeFun::new_obj(2, |_callee, vm, args| {
|
||||||
|
read_obj_downcast!(let lhs: Option<&Int> = &args[0]);
|
||||||
|
let lhs = lhs.ok_or_else(|| Error::ValueError {
|
||||||
|
error: "expected int for LHS".to_string(),
|
||||||
|
})?;
|
||||||
|
|
||||||
|
read_obj_downcast!(let rhs: Option<&Int> = &args[1]);
|
||||||
|
let rhs = rhs.ok_or_else(|| Error::ValueError {
|
||||||
|
error: "expected int for RHS".to_string(),
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let result = lhs.value != rhs.value;
|
||||||
|
vm.push(BoolRef::from(result));
|
||||||
|
Ok(crate::vm::signal::Signal::Return)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ macro_rules! vtable {
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! handle_type {
|
macro_rules! handle_type {
|
||||||
($name:ident) => {
|
($name:ident) => {
|
||||||
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, shredder::Scan)]
|
||||||
pub struct $name(usize);
|
pub struct $name(usize);
|
||||||
|
|
||||||
impl $name {
|
impl $name {
|
||||||
@@ -128,7 +128,6 @@ macro_rules! handle_type {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl shredder::EmptyScan for $name {}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
mod macros;
|
mod macros;
|
||||||
|
|
||||||
pub mod attrs;
|
pub mod attrs;
|
||||||
|
pub mod boolean;
|
||||||
pub mod builtin;
|
pub mod builtin;
|
||||||
pub mod fun;
|
pub mod fun;
|
||||||
pub mod int;
|
pub mod int;
|
||||||
@@ -14,11 +15,11 @@ pub mod ty;
|
|||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use crate::obj::{
|
pub use crate::obj::{
|
||||||
attrs::*, fun::*, int::*, intern::*, name::*, str::*, sym::*, ty::*, Obj, ObjRef,
|
attrs::*, boolean::*, fun::*, int::*, intern::*, name::*, str::*, sym::*, ty::*, Obj, ObjRef,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
use shredder::{Gc, Scan};
|
use shredder::{marker::GcDrop, Gc, Scan};
|
||||||
use std::{
|
use std::{
|
||||||
fmt::{self, Debug, Formatter},
|
fmt::{self, Debug, Formatter},
|
||||||
marker::Unsize,
|
marker::Unsize,
|
||||||
@@ -43,7 +44,7 @@ macro_rules! obj_attr {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Obj: Scan + Debug {
|
pub trait Obj: Scan + GcDrop + Debug {
|
||||||
fn vtable(&self) -> &Vtable;
|
fn vtable(&self) -> &Vtable;
|
||||||
fn attrs(&self) -> &Attrs;
|
fn attrs(&self) -> &Attrs;
|
||||||
fn attrs_mut(&mut self) -> Option<&mut Attrs>;
|
fn attrs_mut(&mut self) -> Option<&mut Attrs>;
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ name!(FUNC_MEMBER_NAME, "__func__");
|
|||||||
name!(REPR_MEMBER_NAME, "__repr__");
|
name!(REPR_MEMBER_NAME, "__repr__");
|
||||||
name!(STR_MEMBER_NAME, "__str__");
|
name!(STR_MEMBER_NAME, "__str__");
|
||||||
name!(INT_MEMBER_NAME, "__int__");
|
name!(INT_MEMBER_NAME, "__int__");
|
||||||
|
name!(BOOL_MEMBER_NAME, "__bool__");
|
||||||
|
|
||||||
//
|
//
|
||||||
// Predefined VM-aware symbols
|
// Predefined VM-aware symbols
|
||||||
@@ -64,8 +65,6 @@ name!(PRINT_BUILTIN_NAME, "print");
|
|||||||
//
|
//
|
||||||
// Builtin constants
|
// Builtin constants
|
||||||
//
|
//
|
||||||
name!(TRUE_NAME, "true");
|
|
||||||
name!(FALSE_NAME, "false");
|
|
||||||
name!(NIL_NAME, "nil");
|
name!(NIL_NAME, "nil");
|
||||||
|
|
||||||
// Operator function names
|
// Operator function names
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ pub enum Expr {
|
|||||||
Index(Box<IndexExpr>),
|
Index(Box<IndexExpr>),
|
||||||
Access(Box<AccessExpr>),
|
Access(Box<AccessExpr>),
|
||||||
Fun(Box<FunExpr>),
|
Fun(Box<FunExpr>),
|
||||||
|
If(Box<IfExpr>),
|
||||||
Atom(Atom),
|
Atom(Atom),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,6 +158,7 @@ impl<V: Visit> DefaultAccept<V> for Expr {
|
|||||||
Expr::Index(i) => i.accept(visitor),
|
Expr::Index(i) => i.accept(visitor),
|
||||||
Expr::Access(a) => a.accept(visitor),
|
Expr::Access(a) => a.accept(visitor),
|
||||||
Expr::Fun(f) => f.accept(visitor),
|
Expr::Fun(f) => f.accept(visitor),
|
||||||
|
Expr::If(i) => i.accept(visitor),
|
||||||
Expr::Atom(a) => a.accept(visitor),
|
Expr::Atom(a) => a.accept(visitor),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -207,6 +209,12 @@ impl From<FunExpr> for Expr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<IfExpr> for Expr {
|
||||||
|
fn from(other: IfExpr) -> Self {
|
||||||
|
Expr::If(other.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum BinOp {
|
pub enum BinOp {
|
||||||
Plus,
|
Plus,
|
||||||
@@ -434,6 +442,78 @@ impl<V: Visit> DefaultAccept<V> for FunExpr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// struct IfExpr
|
||||||
|
//
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct IfExpr {
|
||||||
|
pub cond_body: CondBody,
|
||||||
|
pub elif: Vec<CondBody>,
|
||||||
|
pub el: Option<Body>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IfExpr {
|
||||||
|
pub fn new_expr(cond_body: CondBody, elif: Vec<CondBody>, el: Option<Body>) -> Expr {
|
||||||
|
Self {
|
||||||
|
cond_body,
|
||||||
|
elif,
|
||||||
|
el,
|
||||||
|
}.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// impl Accept for IfExpr
|
||||||
|
//
|
||||||
|
impl<V: Visit> Accept<V> for IfExpr {
|
||||||
|
fn accept(&self, visitor: &mut V) -> V::Out {
|
||||||
|
visitor.visit_if_expr(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// impl DefaultAccept for IfExpr
|
||||||
|
//
|
||||||
|
impl<V: Visit<Out=()>> DefaultAccept<V> for IfExpr {
|
||||||
|
fn default_accept(&self, visitor: &mut V) -> V::Out {
|
||||||
|
visitor.visit_cond_body(&self.cond_body);
|
||||||
|
for elif in self.elif.iter() {
|
||||||
|
visitor.visit_cond_body(elif);
|
||||||
|
}
|
||||||
|
if let Some(el) = &self.el {
|
||||||
|
visitor.visit_body(&el);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// struct CondBody
|
||||||
|
//
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct CondBody {
|
||||||
|
pub cond: Expr,
|
||||||
|
pub body: Body,
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// impl Accept for CondBody
|
||||||
|
//
|
||||||
|
impl<V: Visit> Accept<V> for CondBody {
|
||||||
|
fn accept(&self, visitor: &mut V) -> V::Out {
|
||||||
|
visitor.visit_cond_body(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// impl DefaultAccept for CondBody
|
||||||
|
//
|
||||||
|
impl<V: Visit<Out=()>> DefaultAccept<V> for CondBody {
|
||||||
|
fn default_accept(&self, visitor: &mut V) -> V::Out {
|
||||||
|
visitor.visit_expr(&self.cond);
|
||||||
|
visitor.visit_body(&self.body);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// enum Atom
|
// enum Atom
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
%%
|
%%
|
||||||
fn "fn"
|
fn "fn"
|
||||||
return "return"
|
return "return"
|
||||||
|
if "if"
|
||||||
|
elif "elif"
|
||||||
|
el "el"
|
||||||
|
|
||||||
[\r\n;]+ "EOL"
|
[\r\n;]+ "EOL"
|
||||||
[a-zA-Z_][a-zA-Z0-9_]* "IDENT"
|
[a-zA-Z_][a-zA-Z0-9_]* "IDENT"
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ AccessExpr -> Result<Expr>:
|
|||||||
;
|
;
|
||||||
|
|
||||||
FunExpr -> Result<Expr>:
|
FunExpr -> Result<Expr>:
|
||||||
AtomExpr { $1 }
|
IfExpr { $1 }
|
||||||
| 'fn' '(' FunParams ')' '{' Body '}' { Ok(FunExpr::new_expr($3?, $6?)) }
|
| 'fn' '(' FunParams ')' '{' Body '}' { Ok(FunExpr::new_expr($3?, $6?)) }
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -118,6 +118,31 @@ FunParamsTail -> Result<Vec<String>>:
|
|||||||
| Ident { Ok(vec![$1?]) }
|
| Ident { Ok(vec![$1?]) }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
IfExpr -> Result<Expr>:
|
||||||
|
AtomExpr { $1 }
|
||||||
|
| 'if' Expr '{' Body '}' Elif El {
|
||||||
|
Ok(IfExpr::new_expr(
|
||||||
|
CondBody { cond: $2?, body: $4?, },
|
||||||
|
$6?,
|
||||||
|
$7?,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
Elif -> Result<Vec<CondBody>>:
|
||||||
|
Elif 'elif' Expr '{' Body '}' {
|
||||||
|
let mut head = $1?;
|
||||||
|
head.push(CondBody { cond: $3?, body: $5? });
|
||||||
|
Ok(head)
|
||||||
|
}
|
||||||
|
| { Ok(Vec::new()) }
|
||||||
|
;
|
||||||
|
|
||||||
|
El -> Result<Option<Body>>:
|
||||||
|
'el' '{' Body '}' { $3.map(Some) }
|
||||||
|
| { Ok(None) }
|
||||||
|
;
|
||||||
|
|
||||||
AtomExpr -> Result<Expr>:
|
AtomExpr -> Result<Expr>:
|
||||||
Atom { $1.map(Expr::Atom) }
|
Atom { $1.map(Expr::Atom) }
|
||||||
| '(' Expr ')' { $2 }
|
| '(' Expr ')' { $2 }
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ pub trait Visit {
|
|||||||
fn visit_index_expr(&mut self, expr: &IndexExpr) -> Self::Out;
|
fn visit_index_expr(&mut self, expr: &IndexExpr) -> Self::Out;
|
||||||
fn visit_access_expr(&mut self, expr: &AccessExpr) -> Self::Out;
|
fn visit_access_expr(&mut self, expr: &AccessExpr) -> Self::Out;
|
||||||
fn visit_fun_expr(&mut self, expr: &FunExpr) -> Self::Out;
|
fn visit_fun_expr(&mut self, expr: &FunExpr) -> Self::Out;
|
||||||
|
fn visit_if_expr(&mut self, expr: &IfExpr) -> Self::Out;
|
||||||
|
fn visit_cond_body(&mut self, cond_body: &CondBody) -> Self::Out;
|
||||||
fn visit_atom(&mut self, atom: &Atom) -> Self::Out;
|
fn visit_atom(&mut self, atom: &Atom) -> Self::Out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,6 +43,8 @@ copy/paste of default_accepts
|
|||||||
fn visit_index_expr(&mut self, expr: &IndexExpr) -> Self::Out { DefaultAccept::default_accept(expr, self); }
|
fn visit_index_expr(&mut self, expr: &IndexExpr) -> Self::Out { DefaultAccept::default_accept(expr, self); }
|
||||||
fn visit_access_expr(&mut self, expr: &AccessExpr) -> Self::Out { DefaultAccept::default_accept(expr, self); }
|
fn visit_access_expr(&mut self, expr: &AccessExpr) -> Self::Out { DefaultAccept::default_accept(expr, self); }
|
||||||
fn visit_fun_expr(&mut self, expr: &FunExpr) -> Self::Out { DefaultAccept::default_accept(expr, self); }
|
fn visit_fun_expr(&mut self, expr: &FunExpr) -> Self::Out { DefaultAccept::default_accept(expr, self); }
|
||||||
|
fn visit_if_expr(&mut self, expr: &IfExpr) -> Self::Out { DefaultAccept::default_accept(expr, self); }
|
||||||
|
fn visit_cond_body(&mut self, cond_body: &CondBody) -> Self::Out { DefaultAccept::default_accept(cond_body, self); }
|
||||||
fn visit_atom(&mut self, atom: &Atom) -> Self::Out { DefaultAccept(atom, self); }
|
fn visit_atom(&mut self, atom: &Atom) -> Self::Out { DefaultAccept(atom, self); }
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -7,9 +7,6 @@ pub struct ConstPool {
|
|||||||
pool: Vec<ObjRef>,
|
pool: Vec<ObjRef>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constant pools are constant, and live for the lifetime of the entire program.
|
|
||||||
impl shredder::EmptyScan for ConstPool {}
|
|
||||||
|
|
||||||
impl ConstPool {
|
impl ConstPool {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Default::default()
|
Default::default()
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
use crate::{obj::prelude::*, vm::consts::*};
|
use crate::{obj::prelude::*, vm::consts::*};
|
||||||
use shredder::EmptyScan;
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||||
pub enum Inst {
|
pub enum Inst {
|
||||||
@@ -36,6 +35,9 @@ pub enum Inst {
|
|||||||
///
|
///
|
||||||
SetAttr(Sym),
|
SetAttr(Sym),
|
||||||
|
|
||||||
|
/// Pops the top value off of the stack and checks if it is a `Bool` of a true value.
|
||||||
|
CheckTruth,
|
||||||
|
|
||||||
/// Jump to a given address in the current function unconditionally.
|
/// Jump to a given address in the current function unconditionally.
|
||||||
Jump(usize),
|
Jump(usize),
|
||||||
|
|
||||||
@@ -131,6 +133,7 @@ impl Inst {
|
|||||||
Inst::PopGlobal(_) => "POP_GLOBAL",
|
Inst::PopGlobal(_) => "POP_GLOBAL",
|
||||||
Inst::GetAttr(_) => "GET_ATTR",
|
Inst::GetAttr(_) => "GET_ATTR",
|
||||||
Inst::SetAttr(_) => "SET_ATTR",
|
Inst::SetAttr(_) => "SET_ATTR",
|
||||||
|
Inst::CheckTruth => "CHECK_TRUTH",
|
||||||
Inst::Jump(_) => "JUMP",
|
Inst::Jump(_) => "JUMP",
|
||||||
Inst::JumpTrue(_) => "JUMP_TRUE",
|
Inst::JumpTrue(_) => "JUMP_TRUE",
|
||||||
Inst::Call(_) => "CALL",
|
Inst::Call(_) => "CALL",
|
||||||
@@ -154,4 +157,4 @@ impl Inst {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EmptyScan for Inst {}
|
unsafe impl shredder::marker::GcDrop for Inst {}
|
||||||
|
|||||||
@@ -254,6 +254,15 @@ impl<'c> Vm<'c> {
|
|||||||
todo!("TODO: throw an error for attributes that can't be set");
|
todo!("TODO: throw an error for attributes that can't be set");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Inst::CheckTruth => {
|
||||||
|
let source = self.pop().expect("no source available for CheckTruth");
|
||||||
|
read_obj_downcast!(let obj: Option<&Bool> = &source);
|
||||||
|
if let Some(obj) = obj {
|
||||||
|
self.condition = obj.value();
|
||||||
|
} else {
|
||||||
|
unreachable!("Expected a boolean for CheckTruth but got {:?} instead", source);
|
||||||
|
}
|
||||||
|
}
|
||||||
Inst::Jump(addr) => {
|
Inst::Jump(addr) => {
|
||||||
next_pc = addr;
|
next_pc = addr;
|
||||||
}
|
}
|
||||||
@@ -272,12 +281,12 @@ impl<'c> Vm<'c> {
|
|||||||
.expect("TODO: throw an error for missing __call__ attr");
|
.expect("TODO: throw an error for missing __call__ attr");
|
||||||
signal = Some(Signal::Call(callee, args));
|
signal = Some(Signal::Call(callee, args));
|
||||||
}
|
}
|
||||||
Inst::Index => todo!(),
|
Inst::Index => todo!("Inst::Index"),
|
||||||
Inst::Return => {
|
Inst::Return => {
|
||||||
signal = Some(Signal::Return);
|
signal = Some(Signal::Return);
|
||||||
}
|
}
|
||||||
Inst::UnNeg => todo!(),
|
Inst::UnNeg => todo!("Inst::UnNeg"),
|
||||||
Inst::UnPos => todo!(),
|
Inst::UnPos => todo!("Inst::UnPos"),
|
||||||
Inst::BinPlus => {
|
Inst::BinPlus => {
|
||||||
let rhs = self.pop().unwrap();
|
let rhs = self.pop().unwrap();
|
||||||
let lhs = self.pop().unwrap();
|
let lhs = self.pop().unwrap();
|
||||||
|
|||||||
Reference in New Issue
Block a user