Add vm and compile modules
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
42
src/compile/mod.rs
Normal file
42
src/compile/mod.rs
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
pub mod sym;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
syn::ast::Stmt,
|
||||||
|
compile::sym::SymStack,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub trait Pass {
|
||||||
|
type Out;
|
||||||
|
fn pass(&self, ctx: &mut Ctx) -> Self::Out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// * Desugar
|
||||||
|
// * Collect names as symbols
|
||||||
|
// * Create basic blocks
|
||||||
|
|
||||||
|
pub struct Ctx {
|
||||||
|
sym_stack: SymStack,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ctx {
|
||||||
|
pub fn sym_stack(&self) -> &SymStack {
|
||||||
|
&self.sym_stack
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sym_stack_mut(&mut self) -> &mut SymStack {
|
||||||
|
&mut self.sym_stack
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no sugar in the syntax quite yet
|
||||||
|
/*
|
||||||
|
pub struct Desugar;
|
||||||
|
|
||||||
|
impl Pass<Vec<Stmt>> for Desugar {
|
||||||
|
type Out = Vec<Stmt>;
|
||||||
|
|
||||||
|
fn pass(&mut self, input: Vec<Stmt>) -> Vec<Stmt> {
|
||||||
|
input
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
16
src/compile/sym.rs
Normal file
16
src/compile/sym.rs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
use crate::obj::Sym;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
pub struct SymStack {
|
||||||
|
syms: HashMap<String, Sym>,
|
||||||
|
stack: Vec<Vec<Sym>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SymStack {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
SymStack {
|
||||||
|
syms: Default::default(),
|
||||||
|
stack: vec![Default::default()],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
#![feature(new_uninit)]
|
#![feature(new_uninit)]
|
||||||
|
|
||||||
|
mod compile;
|
||||||
mod syn;
|
mod syn;
|
||||||
mod obj;
|
mod obj;
|
||||||
mod mem;
|
mod mem;
|
||||||
|
mod vm;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
convert::TryFrom,
|
convert::TryFrom,
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ use crate::{
|
|||||||
intern::Intern,
|
intern::Intern,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
use std::ptr::NonNull;
|
|
||||||
|
|
||||||
pub trait Gc: Intern {
|
pub trait Gc: Intern {
|
||||||
fn alloc<O: Obj + 'static>(&mut self, obj: O) -> ObjRef<O>;
|
fn alloc<O: Obj + 'static>(&mut self, obj: O) -> ObjRef<O>;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::obj::Obj;
|
use crate::obj::Obj;
|
||||||
use std::{
|
use std::{
|
||||||
any,
|
any::{self, Any},
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
fmt::{self, Debug, Formatter},
|
fmt::{self, Debug, Formatter},
|
||||||
ops::Deref,
|
ops::Deref,
|
||||||
@@ -10,13 +10,14 @@ use std::{
|
|||||||
pub type DynRef = ObjRef<dyn Obj>;
|
pub type DynRef = ObjRef<dyn Obj>;
|
||||||
|
|
||||||
pub struct ObjRef<O>
|
pub struct ObjRef<O>
|
||||||
where O: Obj + ?Sized
|
where O: Obj + ?Sized,
|
||||||
{
|
{
|
||||||
ptr: NonNull<ObjCell<O>>,
|
ptr: NonNull<ObjCell<O>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<O> ObjRef<O>
|
impl<O> ObjRef<O>
|
||||||
where O: Obj + ?Sized
|
where
|
||||||
|
O: Obj + ?Sized,
|
||||||
{
|
{
|
||||||
pub fn new(ptr: NonNull<ObjCell<O>>) -> Self {
|
pub fn new(ptr: NonNull<ObjCell<O>>) -> Self {
|
||||||
ObjRef { ptr }
|
ObjRef { ptr }
|
||||||
@@ -27,8 +28,16 @@ impl<O> ObjRef<O>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<O: Obj + ?Sized> AsRef<ObjCell<O>> for ObjRef<O> {
|
||||||
|
fn as_ref(&self) -> &ObjCell<O> {
|
||||||
|
// safe because pointer should point at live data assuming GC is working appropriately
|
||||||
|
unsafe { &*self.as_ptr() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<O> ObjRef<O>
|
impl<O> ObjRef<O>
|
||||||
where O: Obj
|
where
|
||||||
|
O: Obj,
|
||||||
{
|
{
|
||||||
pub fn as_dyn(&self) -> ObjRef<dyn Obj> {
|
pub fn as_dyn(&self) -> ObjRef<dyn Obj> {
|
||||||
let ptr = self.as_ptr() as *const ObjCell<dyn Obj>;
|
let ptr = self.as_ptr() as *const ObjCell<dyn Obj>;
|
||||||
@@ -37,7 +46,8 @@ impl<O> ObjRef<O>
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<O> Deref for ObjRef<O>
|
impl<O> Deref for ObjRef<O>
|
||||||
where O: Obj + ?Sized
|
where
|
||||||
|
O: Obj + ?Sized,
|
||||||
{
|
{
|
||||||
type Target = RefCell<O>;
|
type Target = RefCell<O>;
|
||||||
|
|
||||||
@@ -48,28 +58,37 @@ impl<O> Deref for ObjRef<O>
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<O> Clone for ObjRef<O>
|
impl<O> Clone for ObjRef<O>
|
||||||
where O: Obj + ?Sized
|
where
|
||||||
|
O: Obj + ?Sized,
|
||||||
{
|
{
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
ObjRef { ptr: self.ptr }
|
ObjRef { ptr: self.ptr }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<O> Copy for ObjRef<O>
|
impl<O> Copy for ObjRef<O> where O: Obj + ?Sized {}
|
||||||
where O: Obj + ?Sized
|
|
||||||
{}
|
|
||||||
|
|
||||||
impl<O> Debug for ObjRef<O>
|
impl<O> Debug for ObjRef<O>
|
||||||
where O: Obj + Debug + ?Sized
|
where
|
||||||
|
O: Obj + Debug + ?Sized,
|
||||||
{
|
{
|
||||||
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
|
||||||
write!(fmt, "<{} object at {:#x}>", any::type_name::<O>(), self.as_ptr() as *const () as usize)
|
write!(
|
||||||
|
fmt,
|
||||||
|
"<{} object at {:#x}>",
|
||||||
|
any::type_name::<O>(),
|
||||||
|
self.as_ptr() as *const () as usize
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for ObjRef<dyn Obj> {
|
impl Debug for ObjRef<dyn Obj> {
|
||||||
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
|
||||||
write!(fmt, "<? object at {:#x}>", self.as_ptr() as *const () as usize)
|
write!(
|
||||||
|
fmt,
|
||||||
|
"<? object at {:#x}>",
|
||||||
|
self.as_ptr() as *const () as usize
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ impl<'ctx> AttrsBuilder<'ctx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn attr(mut self, symbol_name: &str, value: DynRef) -> Self {
|
pub fn attr(self, symbol_name: &str, value: DynRef) -> Self {
|
||||||
let sym = self.ctx.gc_mut().add_sym(symbol_name);
|
let sym = self.ctx.gc_mut().add_sym(symbol_name);
|
||||||
self.attr_sym(sym, value)
|
self.attr_sym(sym, value)
|
||||||
}
|
}
|
||||||
|
|||||||
92
src/obj/fun.rs
Normal file
92
src/obj/fun.rs
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
use crate::{obj::prelude::*, vm::op::Op};
|
||||||
|
use std::{any::Any, cell::Cell, rc::Rc};
|
||||||
|
|
||||||
|
pub type NativeFunPtr = fn(argv: Vec<DynRef>);
|
||||||
|
|
||||||
|
pub struct NativeFun {
|
||||||
|
attrs: ObjRef<Attrs>,
|
||||||
|
fn_ptr: NativeFunPtr,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NativeFun {
|
||||||
|
pub fn new(ctx: &mut ObjCtx, name: StrRef, fn_ptr: NativeFunPtr) -> Self {
|
||||||
|
let attrs = Attrs::new(ctx, Default::default());
|
||||||
|
NativeFun {
|
||||||
|
attrs,
|
||||||
|
fn_ptr,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn call(&self, argv: Vec<DynRef>) {
|
||||||
|
(self.fn_ptr)(argv)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Obj for NativeFun {
|
||||||
|
fn attrs(&self) -> ObjRef<Attrs> {
|
||||||
|
self.attrs
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_marked(&self) -> bool {
|
||||||
|
// native functions are always available
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mark(&self) {}
|
||||||
|
|
||||||
|
fn unmark(&self) {}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Fun {
|
||||||
|
attrs: ObjRef<Attrs>,
|
||||||
|
code: Rc<Vec<Op>>,
|
||||||
|
marked: Cell<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Fun {
|
||||||
|
pub fn new(attrs: ObjRef<Attrs>, code: Rc<Vec<Op>>) -> Self {
|
||||||
|
Fun {
|
||||||
|
attrs,
|
||||||
|
code,
|
||||||
|
marked: Cell::new(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn code(&self) -> Rc<Vec<Op>> {
|
||||||
|
Rc::clone(&self.code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Obj for Fun {
|
||||||
|
fn attrs(&self) -> ObjRef<Attrs> {
|
||||||
|
self.attrs
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_marked(&self) -> bool {
|
||||||
|
self.marked.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mark(&self) {
|
||||||
|
if self.is_marked() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.marked.set(true);
|
||||||
|
self.attrs.borrow().mark();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unmark(&self) {
|
||||||
|
if !self.is_marked() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.marked.set(false);
|
||||||
|
self.attrs.borrow().unmark();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,7 @@ pub mod attrs;
|
|||||||
pub mod ctx;
|
pub mod ctx;
|
||||||
pub mod dict;
|
pub mod dict;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
//pub mod native_fun;
|
pub mod fun;
|
||||||
//pub mod num;
|
//pub mod num;
|
||||||
pub mod str;
|
pub mod str;
|
||||||
pub mod sym {
|
pub mod sym {
|
||||||
@@ -13,7 +13,7 @@ pub mod sym {
|
|||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
obj::{
|
obj::{
|
||||||
Attrs, Dict, DictRef, Str, StrRef, Sym, ObjCtx, Obj,
|
Attrs, Dict, DictRef, Fun, NativeFun, Str, StrRef, Sym, ObjCtx, Obj,
|
||||||
},
|
},
|
||||||
mem::{
|
mem::{
|
||||||
ptr::{ObjRef, DynRef},
|
ptr::{ObjRef, DynRef},
|
||||||
@@ -25,8 +25,9 @@ pub mod prelude {
|
|||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
attrs::Attrs,
|
attrs::Attrs,
|
||||||
dict::{Dict, DictRef},
|
|
||||||
ctx::ObjCtx,
|
ctx::ObjCtx,
|
||||||
|
dict::{Dict, DictRef},
|
||||||
|
fun::{NativeFun, Fun},
|
||||||
str::{Str, StrRef},
|
str::{Str, StrRef},
|
||||||
sym::Sym,
|
sym::Sym,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
use crate::obj::prelude::*;
|
|
||||||
|
|
||||||
pub type NativeFunPtr = *const fn();
|
|
||||||
|
|
||||||
pub struct NativeFun {
|
|
||||||
attrs: Attrs,
|
|
||||||
fn_ptr: NativeFunPtr,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NativeFun {
|
|
||||||
pub fn new(ctx: &mut ObjCtx, name: StrRef, fn_ptr: NativeFunPtr) -> Self {
|
|
||||||
todo!()
|
|
||||||
/*
|
|
||||||
let attrs = Attrs::default();
|
|
||||||
NativeFun {
|
|
||||||
attrs,
|
|
||||||
fn_ptr,
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
|
|
||||||
impl Obj for NativeFun {
|
|
||||||
fn get_attr(&self, key: &DynRef) -> Option<DynRef>
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::obj::{attrs::AttrsBuilder, prelude::*};
|
use crate::obj::prelude::*;
|
||||||
use derivative::Derivative;
|
use derivative::Derivative;
|
||||||
use std::{any::Any, cell::Cell, collections::BTreeMap};
|
use std::{any::Any, cell::Cell};
|
||||||
|
|
||||||
pub type StrRef = ObjRef<Str>;
|
pub type StrRef = ObjRef<Str>;
|
||||||
|
|
||||||
|
|||||||
49
src/vm/frame.rs
Normal file
49
src/vm/frame.rs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
use crate::obj::prelude::*;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Frame {
|
||||||
|
stack: Vec<DynRef>,
|
||||||
|
ip: usize,
|
||||||
|
return_value: Option<DynRef>,
|
||||||
|
locals: BTreeMap<Sym, DynRef>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Frame {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(&mut self, obj_ref: DynRef) {
|
||||||
|
self.stack.push(obj_ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pop(&mut self) -> Option<DynRef> {
|
||||||
|
self.stack.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ip(&self) -> usize {
|
||||||
|
self.ip
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_ip(&mut self, ip: usize) {
|
||||||
|
self.ip = ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn return_value(&self) -> Option<DynRef> {
|
||||||
|
self.return_value
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_return_value(&mut self, obj_ref: DynRef) {
|
||||||
|
self.return_value = Some(obj_ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_local(&self, sym: Sym) -> Option<DynRef> {
|
||||||
|
self.locals.get(&sym).copied()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_local(&mut self, sym: Sym, obj_ref: DynRef) -> Option<DynRef> {
|
||||||
|
self.locals.insert(sym, obj_ref)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
131
src/vm/mod.rs
Normal file
131
src/vm/mod.rs
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
pub mod op;
|
||||||
|
pub mod frame;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
obj::prelude::*,
|
||||||
|
vm::{
|
||||||
|
op::Op,
|
||||||
|
frame::Frame,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
pub struct State {
|
||||||
|
frames: Vec<Frame>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
State { frames: Default::default(), }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn frame(&self) -> &Frame {
|
||||||
|
self.frames
|
||||||
|
.last()
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn frame_mut(&mut self) -> &mut Frame {
|
||||||
|
self.frames
|
||||||
|
.last_mut()
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_stack(&mut self, value: DynRef) {
|
||||||
|
self.frame_mut()
|
||||||
|
.push(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop_stack(&mut self) -> Option<DynRef> {
|
||||||
|
self.frame_mut()
|
||||||
|
.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ip(&self) -> usize {
|
||||||
|
self.frame().ip()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_ip(&mut self, ip: usize) {
|
||||||
|
self.frame_mut().set_ip(ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_local(&self, sym: Sym) -> Option<DynRef> {
|
||||||
|
self.frame().get_local(sym)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_local(&mut self, sym: Sym, obj_ref: DynRef) -> Option<DynRef> {
|
||||||
|
self.frame_mut().set_local(sym, obj_ref)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(&mut self, ops: Rc<Vec<Op>>) {
|
||||||
|
self.frames.push(Default::default());
|
||||||
|
while self.ip() < ops.len() {
|
||||||
|
let mut next_ip = self.ip() + 1;
|
||||||
|
match &ops[self.ip()] {
|
||||||
|
Op::Push(sym) => {
|
||||||
|
// TODO - local not found
|
||||||
|
let obj_ref = self.get_local(*sym)
|
||||||
|
.expect("TODO - local not found");
|
||||||
|
self.push_stack(obj_ref);
|
||||||
|
}
|
||||||
|
Op::Pop(sym) => {
|
||||||
|
// stack should not underflow
|
||||||
|
let obj_ref = self.pop_stack()
|
||||||
|
.expect("misaligned stack for pop");
|
||||||
|
if let Some(sym) = *sym {
|
||||||
|
self.set_local(sym, obj_ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Op::GetAttr(sym) => {
|
||||||
|
let top = self.pop_stack()
|
||||||
|
.expect("misaligned stack for getattrs");
|
||||||
|
let obj_ref = {
|
||||||
|
let top_ref = top.borrow();
|
||||||
|
let attrs = top_ref.attrs();
|
||||||
|
let attrs_ref = attrs.borrow();
|
||||||
|
// TODO - local not found
|
||||||
|
attrs_ref.get(*sym)
|
||||||
|
.expect("TODO - local not found")
|
||||||
|
};
|
||||||
|
self.push_stack(obj_ref);
|
||||||
|
}
|
||||||
|
Op::Call(argc) => {
|
||||||
|
let fun = self.pop_stack()
|
||||||
|
.expect("misaligned stack for function call");
|
||||||
|
let mut argv = Vec::with_capacity(*argc);
|
||||||
|
for i in 0 .. *argc {
|
||||||
|
let arg = self.pop_stack()
|
||||||
|
.expect("misaligned stack for argv");
|
||||||
|
argv.push(arg);
|
||||||
|
}
|
||||||
|
// reverse since arguments are pushed in order of being passed
|
||||||
|
argv.reverse();
|
||||||
|
|
||||||
|
// call function
|
||||||
|
// TODO - call the function indirectly?
|
||||||
|
//
|
||||||
|
// problem: downcast_ref returns a reference bound by the lifetime of the
|
||||||
|
// function (because of the ref cell). This keeps the fun object borrowed,
|
||||||
|
// which means any attempts to modify the function while it is running will
|
||||||
|
// cause the VM to panic.
|
||||||
|
//
|
||||||
|
// possible solution:
|
||||||
|
// pop the function object, and then determine which function to call on the
|
||||||
|
// object (possibly after downcasting?)
|
||||||
|
//
|
||||||
|
// TODO
|
||||||
|
// Figure out a way to either call a native function with NativeFun::call, or
|
||||||
|
// call a user function with Fun::code()
|
||||||
|
if let Some(fun) = fun.borrow().as_any().downcast_ref::<Fun>() {
|
||||||
|
} else if let Some(fun) = fun.borrow().as_any().downcast_ref::<NativeFun>() {
|
||||||
|
} else {
|
||||||
|
todo!("TODO - not a function")
|
||||||
|
}
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.set_ip(next_ip);
|
||||||
|
}
|
||||||
|
self.frames.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
22
src/vm/op.rs
Normal file
22
src/vm/op.rs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
use crate::obj::Sym;
|
||||||
|
|
||||||
|
// VM execution model:
|
||||||
|
// * every function call has its own stack frame
|
||||||
|
// * stack frames keep track of locals
|
||||||
|
// * ops deal with symbols directly
|
||||||
|
// * stack values are either obj references or symbols
|
||||||
|
|
||||||
|
pub enum Op {
|
||||||
|
/// Push a value from a symbol
|
||||||
|
Push(Sym),
|
||||||
|
|
||||||
|
/// Pop the top stack value into a local (if supplied)
|
||||||
|
Pop(Option<Sym>),
|
||||||
|
|
||||||
|
/// Pop the top stack value, getting an attribute and replacing pushing that value to the
|
||||||
|
/// stack.
|
||||||
|
GetAttr(Sym),
|
||||||
|
|
||||||
|
/// Pop the top stack value and the number of arguments, and attempt to call the function.
|
||||||
|
Call(usize),
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user