Break out obj module into individual files by type
object.rs was getting a little big and the implementations are only going to get bigger. Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
use crate::obj::*;
|
use crate::obj::prelude::*;
|
||||||
use crate::scope::*;
|
use crate::scope::*;
|
||||||
use crate::syn::ast::*;
|
use crate::syn::ast::*;
|
||||||
use crate::vm::inst::*;
|
use crate::vm::inst::*;
|
||||||
|
|||||||
110
src/obj/builtin.rs
Normal file
110
src/obj/builtin.rs
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
use crate::obj::{quote::Quote, Obj, VTable};
|
||||||
|
use crate::syn::span::Span;
|
||||||
|
use crate::vm::{error::Result, machine::Machine};
|
||||||
|
use gc::{unsafe_empty_trace, Finalize, Trace};
|
||||||
|
use std::fmt::{self, Debug};
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
/// 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, Finalize)]
|
||||||
|
pub struct BuiltinFn {
|
||||||
|
name: Rc<String>,
|
||||||
|
fun: BuiltinFnPtr,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Trace for BuiltinFn {
|
||||||
|
unsafe_empty_trace!();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for BuiltinFn {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
(&self.fun as *const _ as usize) == (&other.fun as *const _ as usize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BuiltinFn {
|
||||||
|
pub fn new(name: String, fun: BuiltinFnPtr) -> Self {
|
||||||
|
BuiltinFn {
|
||||||
|
name: Rc::new(name),
|
||||||
|
fun,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn call(&self, machine: &mut Machine, reentry: usize) -> Result<BuiltinExit> {
|
||||||
|
(self.fun)(machine, reentry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// BuiltinFn types must be function pointers, and not closures.
|
||||||
|
///
|
||||||
|
/// This has to do with how the garbage collector works, and it apparently does
|
||||||
|
/// not play nicely with closures.
|
||||||
|
pub type BuiltinFnPtr = fn(&mut Machine, usize) -> Result<BuiltinExit>;
|
||||||
|
|
||||||
|
impl Debug for BuiltinFn {
|
||||||
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
fmt,
|
||||||
|
"builtin function {} at {:#x}",
|
||||||
|
self.name,
|
||||||
|
(&self.fun as *const _ as usize)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Trace, Finalize)]
|
||||||
|
pub struct BuiltinFnObj {
|
||||||
|
value: BuiltinFn,
|
||||||
|
vtable: VTable,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BuiltinFnObj {
|
||||||
|
pub fn new(value: BuiltinFn) -> Self {
|
||||||
|
BuiltinFnObj {
|
||||||
|
value,
|
||||||
|
vtable: vtable! {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn value(&self) -> &BuiltinFn {
|
||||||
|
&self.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Obj for BuiltinFnObj {
|
||||||
|
fn vtable(&self) -> &VTable {
|
||||||
|
&self.vtable
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vtable_mut(&mut self) -> &mut VTable {
|
||||||
|
&mut self.vtable
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call(&self, call_site: Option<Span>, machine: &mut Machine) -> Result<()> {
|
||||||
|
machine.call_native(call_site, self.value.clone());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &(dyn std::any::Any + 'static) {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
58
src/obj/float.rs
Normal file
58
src/obj/float.rs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
use crate::obj::{builtin::BuiltinExit, str::StrObj, Obj, ObjPtr, VTable};
|
||||||
|
use crate::syn::span::Span;
|
||||||
|
use crate::vm::{error::*, machine::Machine};
|
||||||
|
use gc::{Finalize, Trace};
|
||||||
|
|
||||||
|
pub type Float = f64;
|
||||||
|
|
||||||
|
#[derive(Debug, Trace, Finalize)]
|
||||||
|
pub struct FloatObj {
|
||||||
|
value: Float,
|
||||||
|
vtable: VTable,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FloatObj {
|
||||||
|
pub fn new(value: Float) -> Self {
|
||||||
|
let float_str: ObjPtr = builtin_fn!("__str__", |machine, _| {
|
||||||
|
let obj_ptr: ObjPtr = machine.stack_pop()?;
|
||||||
|
let obj: &(dyn Obj + 'static) = &*obj_ptr;
|
||||||
|
if let Some(float) = obj.as_any().downcast_ref::<FloatObj>() {
|
||||||
|
let string = StrObj::new(float.value.to_string()).into_gc();
|
||||||
|
machine.stack_push(string)?;
|
||||||
|
Ok(BuiltinExit::Return)
|
||||||
|
} else {
|
||||||
|
Err(RuntimeError::WrongValue("float".to_string()))
|
||||||
|
}
|
||||||
|
// Create the builtin float string
|
||||||
|
});
|
||||||
|
FloatObj {
|
||||||
|
value,
|
||||||
|
vtable: vtable! {
|
||||||
|
"__str__" => float_str,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn value(&self) -> Float {
|
||||||
|
self.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Obj for FloatObj {
|
||||||
|
fn vtable(&self) -> &VTable {
|
||||||
|
&self.vtable
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vtable_mut(&mut self) -> &mut VTable {
|
||||||
|
&mut self.vtable
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call(&self, call_site: Option<Span>, _: &mut Machine) -> Result<()> {
|
||||||
|
Err(RuntimeError::CannotCall("float value".to_string()).with_location(call_site))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &(dyn std::any::Any + 'static) {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
44
src/obj/int.rs
Normal file
44
src/obj/int.rs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
use crate::obj::{Obj, VTable};
|
||||||
|
use crate::syn::span::Span;
|
||||||
|
use crate::vm::{error::*, machine::Machine};
|
||||||
|
use gc::{Finalize, Trace};
|
||||||
|
|
||||||
|
pub type Int = i64;
|
||||||
|
|
||||||
|
#[derive(Debug, Trace, Finalize)]
|
||||||
|
pub struct IntObj {
|
||||||
|
value: Int,
|
||||||
|
vtable: VTable,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntObj {
|
||||||
|
pub fn new(value: Int) -> Self {
|
||||||
|
IntObj {
|
||||||
|
value,
|
||||||
|
vtable: vtable! {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn value(&self) -> Int {
|
||||||
|
self.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Obj for IntObj {
|
||||||
|
fn vtable(&self) -> &VTable {
|
||||||
|
&self.vtable
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vtable_mut(&mut self) -> &mut VTable {
|
||||||
|
&mut self.vtable
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call(&self, call_site: Option<Span>, _: &mut Machine) -> Result<()> {
|
||||||
|
Err(RuntimeError::CannotCall("int value".to_string()).with_location(call_site))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &(dyn std::any::Any + 'static) {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
23
src/obj/macros.rs
Normal file
23
src/obj/macros.rs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#[macro_export]
|
||||||
|
macro_rules! vtable {
|
||||||
|
($($key:expr => $value:expr),* $(,)?) => {{
|
||||||
|
$crate::obj::VTable::from(
|
||||||
|
[
|
||||||
|
$(
|
||||||
|
($key.to_string(), $value)
|
||||||
|
),*
|
||||||
|
]
|
||||||
|
)
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! builtin_fn {
|
||||||
|
($name:expr, $fun:expr) => {{
|
||||||
|
$crate::obj::builtin::BuiltinFnObj::new($crate::obj::builtin::BuiltinFn::new(
|
||||||
|
$name.to_string(),
|
||||||
|
$fun,
|
||||||
|
))
|
||||||
|
.into_gc()
|
||||||
|
}};
|
||||||
|
}
|
||||||
371
src/obj/mod.rs
371
src/obj/mod.rs
@@ -1,125 +1,30 @@
|
|||||||
use crate::syn::ast::SpStmt;
|
#[macro_use]
|
||||||
|
mod macros;
|
||||||
|
pub mod builtin;
|
||||||
|
pub mod float;
|
||||||
|
pub mod int;
|
||||||
|
pub mod quote;
|
||||||
|
pub mod str;
|
||||||
|
|
||||||
|
pub mod prelude {
|
||||||
|
pub use crate::obj::builtin::*;
|
||||||
|
pub use crate::obj::float::*;
|
||||||
|
pub use crate::obj::int::*;
|
||||||
|
pub use crate::obj::quote::*;
|
||||||
|
pub use crate::obj::str::*;
|
||||||
|
pub use crate::obj::{Obj, ObjPtr, VTable};
|
||||||
|
}
|
||||||
|
|
||||||
|
use crate::syn::span::Span;
|
||||||
use crate::vm::{error::*, machine::Machine};
|
use crate::vm::{error::*, machine::Machine};
|
||||||
use crate::{scope::Scope, syn::span::Span, vm::inst::SpInst};
|
use gc::{Finalize, Gc, Trace};
|
||||||
use gc::{unsafe_empty_trace, Finalize, Gc, Trace};
|
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt::{self, Debug};
|
use std::fmt::Debug;
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
pub type ObjPtr = Gc<dyn Obj + 'static>;
|
pub type ObjPtr = Gc<dyn Obj + 'static>;
|
||||||
pub type Str = String;
|
|
||||||
pub type Int = i64;
|
|
||||||
pub type Float = f64;
|
|
||||||
pub type VTable = HashMap<String, ObjPtr>;
|
pub type VTable = HashMap<String, ObjPtr>;
|
||||||
|
|
||||||
// /////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Quote
|
|
||||||
// /////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
/// A handle to a quote pointing to an element in a `QuoteTable`.
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Finalize)]
|
|
||||||
pub struct Quote(usize);
|
|
||||||
|
|
||||||
impl Quote {
|
|
||||||
pub fn index(&self) -> usize {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Trace for Quote {
|
|
||||||
unsafe_empty_trace!();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A table of compiled quotes, their expression trees, and their spans.
|
|
||||||
#[derive(Debug, Clone, Default)]
|
|
||||||
pub struct QuoteTable {
|
|
||||||
table: Vec<(Span, Scope, Vec<SpStmt>, Rc<Vec<SpInst>>)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl QuoteTable {
|
|
||||||
pub fn insert(
|
|
||||||
&mut self,
|
|
||||||
span: Span,
|
|
||||||
scope: Scope,
|
|
||||||
quote: Vec<SpStmt>,
|
|
||||||
compiled: Rc<Vec<SpInst>>,
|
|
||||||
) -> Quote {
|
|
||||||
let next = Quote(self.table.len());
|
|
||||||
self.table.push((span, scope, quote, compiled));
|
|
||||||
next
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get(&self, quote: Quote) -> &(Span, Scope, Vec<SpStmt>, Rc<Vec<SpInst>>) {
|
|
||||||
&self.table[quote.index()]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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, Finalize)]
|
|
||||||
pub struct BuiltinFn {
|
|
||||||
name: Rc<String>,
|
|
||||||
fun: BuiltinFnPtr,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Trace for BuiltinFn {
|
|
||||||
unsafe_empty_trace!();
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for BuiltinFn {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
(&self.fun as *const _ as usize) == (&other.fun as *const _ as usize)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BuiltinFn {
|
|
||||||
pub fn new(name: String, fun: BuiltinFnPtr) -> Self {
|
|
||||||
BuiltinFn {
|
|
||||||
name: Rc::new(name),
|
|
||||||
fun,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn call(&self, machine: &mut Machine, reentry: usize) -> Result<BuiltinExit> {
|
|
||||||
(self.fun)(machine, reentry)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// BuiltinFn types must be function pointers, and not closures.
|
|
||||||
///
|
|
||||||
/// This has to do with how the garbage collector works, and it apparently does
|
|
||||||
/// not play nicely with closures.
|
|
||||||
pub type BuiltinFnPtr = fn(&mut Machine, usize) -> Result<BuiltinExit>;
|
|
||||||
|
|
||||||
impl Debug for BuiltinFn {
|
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(
|
|
||||||
fmt,
|
|
||||||
"builtin function {} at {:#x}",
|
|
||||||
self.name,
|
|
||||||
(&self.fun as *const _ as usize)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An object that has a vtable and common functions.
|
/// An object that has a vtable and common functions.
|
||||||
pub trait Obj: Trace + Finalize + Debug {
|
pub trait Obj: Trace + Finalize + Debug {
|
||||||
/// Gets the vtable for this object.
|
/// Gets the vtable for this object.
|
||||||
@@ -161,239 +66,3 @@ pub trait Obj: Trace + Finalize + Debug {
|
|||||||
|
|
||||||
fn as_any(&self) -> &(dyn Any + 'static);
|
fn as_any(&self) -> &(dyn Any + 'static);
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! vtable {
|
|
||||||
($($key:expr => $value:expr),* $(,)?) => {{
|
|
||||||
VTable::from(
|
|
||||||
[
|
|
||||||
$(
|
|
||||||
($key.to_string(), $value)
|
|
||||||
),*
|
|
||||||
]
|
|
||||||
)
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! builtin_fn {
|
|
||||||
($name:expr, $fun:expr) => {{
|
|
||||||
BuiltinFnObj::new(BuiltinFn::new($name.to_string(), $fun)).into_gc()
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Trace, Finalize)]
|
|
||||||
pub struct FloatObj {
|
|
||||||
value: Float,
|
|
||||||
vtable: VTable,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FloatObj {
|
|
||||||
pub fn new(value: Float) -> Self {
|
|
||||||
let float_str: ObjPtr = builtin_fn!("__str__", |machine, _| {
|
|
||||||
let obj_ptr: ObjPtr = machine.stack_pop()?;
|
|
||||||
let obj: &(dyn Obj + 'static) = &*obj_ptr;
|
|
||||||
if let Some(float) = obj.as_any().downcast_ref::<FloatObj>() {
|
|
||||||
let string = StrObj::new(float.value.to_string()).into_gc();
|
|
||||||
machine.stack_push(string)?;
|
|
||||||
Ok(BuiltinExit::Return)
|
|
||||||
} else {
|
|
||||||
Err(RuntimeError::WrongValue("float".to_string()))
|
|
||||||
}
|
|
||||||
// Create the builtin float string
|
|
||||||
});
|
|
||||||
FloatObj {
|
|
||||||
value,
|
|
||||||
vtable: vtable! {
|
|
||||||
"__str__" => float_str,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn value(&self) -> Float {
|
|
||||||
self.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Obj for FloatObj {
|
|
||||||
fn vtable(&self) -> &VTable {
|
|
||||||
&self.vtable
|
|
||||||
}
|
|
||||||
|
|
||||||
fn vtable_mut(&mut self) -> &mut VTable {
|
|
||||||
&mut self.vtable
|
|
||||||
}
|
|
||||||
|
|
||||||
fn call(&self, call_site: Option<Span>, _: &mut Machine) -> Result<()> {
|
|
||||||
Err(RuntimeError::CannotCall("float value".to_string()).with_location(call_site))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_any(&self) -> &(dyn Any + 'static) {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Trace, Finalize)]
|
|
||||||
pub struct IntObj {
|
|
||||||
value: Int,
|
|
||||||
vtable: VTable,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntObj {
|
|
||||||
pub fn new(value: Int) -> Self {
|
|
||||||
IntObj {
|
|
||||||
value,
|
|
||||||
vtable: vtable! {},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn value(&self) -> Int {
|
|
||||||
self.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Obj for IntObj {
|
|
||||||
fn vtable(&self) -> &VTable {
|
|
||||||
&self.vtable
|
|
||||||
}
|
|
||||||
|
|
||||||
fn vtable_mut(&mut self) -> &mut VTable {
|
|
||||||
&mut self.vtable
|
|
||||||
}
|
|
||||||
|
|
||||||
fn call(&self, call_site: Option<Span>, _: &mut Machine) -> Result<()> {
|
|
||||||
Err(RuntimeError::CannotCall("int value".to_string()).with_location(call_site))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_any(&self) -> &(dyn Any + 'static) {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Trace, Finalize)]
|
|
||||||
pub struct StrObj {
|
|
||||||
value: String,
|
|
||||||
vtable: VTable,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StrObj {
|
|
||||||
pub fn new(value: String) -> Self {
|
|
||||||
let str_str: ObjPtr = builtin_fn!("__str__", |machine, _| {
|
|
||||||
let obj_ptr: ObjPtr = machine.stack_pop()?;
|
|
||||||
let obj: &(dyn Obj + 'static) = &*obj_ptr;
|
|
||||||
if obj.as_any().is::<StrObj>() {
|
|
||||||
machine.stack_push(obj_ptr)?;
|
|
||||||
Ok(BuiltinExit::Return)
|
|
||||||
} else {
|
|
||||||
Err(RuntimeError::WrongValue("float".to_string()))
|
|
||||||
}
|
|
||||||
});
|
|
||||||
StrObj {
|
|
||||||
value,
|
|
||||||
vtable: vtable! {
|
|
||||||
"__str__" => str_str,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn value(&self) -> &String {
|
|
||||||
&self.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Obj for StrObj {
|
|
||||||
fn vtable(&self) -> &VTable {
|
|
||||||
&self.vtable
|
|
||||||
}
|
|
||||||
|
|
||||||
fn vtable_mut(&mut self) -> &mut VTable {
|
|
||||||
&mut self.vtable
|
|
||||||
}
|
|
||||||
|
|
||||||
fn call(&self, call_site: Option<Span>, _: &mut Machine) -> Result<()> {
|
|
||||||
Err(RuntimeError::CannotCall("string value".to_string()).with_location(call_site))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_any(&self) -> &(dyn Any + 'static) {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Trace, Finalize)]
|
|
||||||
pub struct QuoteObj {
|
|
||||||
value: Quote,
|
|
||||||
vtable: VTable,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl QuoteObj {
|
|
||||||
pub fn new(value: Quote) -> Self {
|
|
||||||
QuoteObj {
|
|
||||||
value,
|
|
||||||
vtable: vtable! {},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn value(&self) -> Quote {
|
|
||||||
self.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Obj for QuoteObj {
|
|
||||||
fn vtable(&self) -> &VTable {
|
|
||||||
&self.vtable
|
|
||||||
}
|
|
||||||
|
|
||||||
fn vtable_mut(&mut self) -> &mut VTable {
|
|
||||||
&mut self.vtable
|
|
||||||
}
|
|
||||||
|
|
||||||
fn call(&self, _call_site: Option<Span>, machine: &mut Machine) -> Result<()> {
|
|
||||||
machine.call_quote(self.value);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_any(&self) -> &(dyn Any + 'static) {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Trace, Finalize)]
|
|
||||||
pub struct BuiltinFnObj {
|
|
||||||
value: BuiltinFn,
|
|
||||||
vtable: VTable,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BuiltinFnObj {
|
|
||||||
pub fn new(value: BuiltinFn) -> Self {
|
|
||||||
BuiltinFnObj {
|
|
||||||
value,
|
|
||||||
vtable: vtable! {},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn value(&self) -> &BuiltinFn {
|
|
||||||
&self.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Obj for BuiltinFnObj {
|
|
||||||
fn vtable(&self) -> &VTable {
|
|
||||||
&self.vtable
|
|
||||||
}
|
|
||||||
|
|
||||||
fn vtable_mut(&mut self) -> &mut VTable {
|
|
||||||
&mut self.vtable
|
|
||||||
}
|
|
||||||
|
|
||||||
fn call(&self, call_site: Option<Span>, machine: &mut Machine) -> Result<()> {
|
|
||||||
machine.call_native(call_site, self.value.clone());
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_any(&self) -> &(dyn Any + 'static) {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
84
src/obj/quote.rs
Normal file
84
src/obj/quote.rs
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
use crate::obj::{Obj, VTable};
|
||||||
|
use crate::syn::ast::SpStmt;
|
||||||
|
use crate::vm::{error::*, machine::Machine};
|
||||||
|
use crate::{scope::Scope, syn::span::Span, vm::inst::SpInst};
|
||||||
|
use gc::{unsafe_empty_trace, Finalize, Trace};
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
/// A handle to a quote pointing to an element in a `QuoteTable`.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Finalize)]
|
||||||
|
pub struct Quote(usize);
|
||||||
|
|
||||||
|
impl Quote {
|
||||||
|
pub fn index(&self) -> usize {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Trace for Quote {
|
||||||
|
unsafe_empty_trace!();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Trace, Finalize)]
|
||||||
|
pub struct QuoteObj {
|
||||||
|
value: Quote,
|
||||||
|
vtable: VTable,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl QuoteObj {
|
||||||
|
pub fn new(value: Quote) -> Self {
|
||||||
|
QuoteObj {
|
||||||
|
value,
|
||||||
|
vtable: vtable! {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn value(&self) -> Quote {
|
||||||
|
self.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Obj for QuoteObj {
|
||||||
|
fn vtable(&self) -> &VTable {
|
||||||
|
&self.vtable
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vtable_mut(&mut self) -> &mut VTable {
|
||||||
|
&mut self.vtable
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call(&self, _call_site: Option<Span>, machine: &mut Machine) -> Result<()> {
|
||||||
|
machine.call_quote(self.value);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &(dyn std::any::Any + 'static) {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A table of compiled quotes, their expression trees, and their spans.
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
|
pub struct QuoteTable {
|
||||||
|
table: Vec<(Span, Scope, Vec<SpStmt>, Rc<Vec<SpInst>>)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl QuoteTable {
|
||||||
|
pub fn insert(
|
||||||
|
&mut self,
|
||||||
|
span: Span,
|
||||||
|
scope: Scope,
|
||||||
|
quote: Vec<SpStmt>,
|
||||||
|
compiled: Rc<Vec<SpInst>>,
|
||||||
|
) -> Quote {
|
||||||
|
let next = Quote(self.table.len());
|
||||||
|
self.table.push((span, scope, quote, compiled));
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&self, quote: Quote) -> &(Span, Scope, Vec<SpStmt>, Rc<Vec<SpInst>>) {
|
||||||
|
&self.table[quote.index()]
|
||||||
|
}
|
||||||
|
}
|
||||||
56
src/obj/str.rs
Normal file
56
src/obj/str.rs
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
use crate::obj::{builtin::BuiltinExit, Obj, ObjPtr, VTable};
|
||||||
|
use crate::syn::span::Span;
|
||||||
|
use crate::vm::{error::*, machine::Machine};
|
||||||
|
use gc::{Finalize, Trace};
|
||||||
|
|
||||||
|
pub type Str = String;
|
||||||
|
|
||||||
|
#[derive(Debug, Trace, Finalize)]
|
||||||
|
pub struct StrObj {
|
||||||
|
value: String,
|
||||||
|
vtable: VTable,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StrObj {
|
||||||
|
pub fn new(value: String) -> Self {
|
||||||
|
let str_str: ObjPtr = builtin_fn!("__str__", |machine, _| {
|
||||||
|
let obj_ptr: ObjPtr = machine.stack_pop()?;
|
||||||
|
let obj: &(dyn Obj + 'static) = &*obj_ptr;
|
||||||
|
if obj.as_any().is::<StrObj>() {
|
||||||
|
machine.stack_push(obj_ptr)?;
|
||||||
|
Ok(BuiltinExit::Return)
|
||||||
|
} else {
|
||||||
|
Err(RuntimeError::WrongValue("float".to_string()))
|
||||||
|
}
|
||||||
|
});
|
||||||
|
StrObj {
|
||||||
|
value,
|
||||||
|
vtable: vtable! {
|
||||||
|
"__str__" => str_str,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn value(&self) -> &String {
|
||||||
|
&self.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Obj for StrObj {
|
||||||
|
fn vtable(&self) -> &VTable {
|
||||||
|
&self.vtable
|
||||||
|
}
|
||||||
|
|
||||||
|
fn vtable_mut(&mut self) -> &mut VTable {
|
||||||
|
&mut self.vtable
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call(&self, call_site: Option<Span>, _: &mut Machine) -> Result<()> {
|
||||||
|
Err(RuntimeError::CannotCall("string value".to_string()).with_location(call_site))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &(dyn std::any::Any + 'static) {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::obj::{Float, Int, Str};
|
use crate::obj::{float::Float, int::Int, str::Str};
|
||||||
use crate::syn::span::*;
|
use crate::syn::span::*;
|
||||||
|
|
||||||
/// A single statement, which may be a meta-expression or a normal expression.
|
/// A single statement, which may be a meta-expression or a normal expression.
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
use crate::obj::{BuiltinExit, Obj, StrObj};
|
use crate::obj::{builtin::BuiltinExit, str::StrObj, Obj};
|
||||||
use crate::vm::{error::RuntimeError, machine::MachineBuilder};
|
use crate::vm::{
|
||||||
|
error::RuntimeError,
|
||||||
|
machine::{Machine, MachineBuilder},
|
||||||
|
};
|
||||||
|
|
||||||
impl MachineBuilder {
|
impl MachineBuilder {
|
||||||
/// Registers all builtins for calling on the machine.
|
/// Registers all builtins for calling on the machine.
|
||||||
@@ -9,7 +12,7 @@ impl MachineBuilder {
|
|||||||
//
|
//
|
||||||
// panic
|
// panic
|
||||||
//
|
//
|
||||||
self.register_builtin_fun("panic", |machine, _| {
|
self.register_builtin_fun("panic", |machine: &mut Machine, _| {
|
||||||
println!("!!! panic");
|
println!("!!! panic");
|
||||||
println!("!!! top of stack");
|
println!("!!! top of stack");
|
||||||
for (i, value) in machine.stack().iter().enumerate().rev() {
|
for (i, value) in machine.stack().iter().enumerate().rev() {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::compile::Compile;
|
use crate::compile::Compile;
|
||||||
use crate::obj::*;
|
use crate::obj::prelude::*;
|
||||||
use crate::scope::*;
|
use crate::scope::*;
|
||||||
use crate::syn::{ast::SpStmt, span::Span};
|
use crate::syn::{ast::SpStmt, span::Span};
|
||||||
use crate::vm::{error::*, inst::*};
|
use crate::vm::{error::*, inst::*};
|
||||||
|
|||||||
Reference in New Issue
Block a user