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::syn::ast::*;
|
||||
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::{scope::Scope, syn::span::Span, vm::inst::SpInst};
|
||||
use gc::{unsafe_empty_trace, Finalize, Gc, Trace};
|
||||
use gc::{Finalize, Gc, Trace};
|
||||
use std::any::Any;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::{self, Debug};
|
||||
use std::rc::Rc;
|
||||
use std::fmt::Debug;
|
||||
|
||||
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>;
|
||||
|
||||
// /////////////////////////////////////////////////////////////////////////////
|
||||
// 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.
|
||||
pub trait Obj: Trace + Finalize + Debug {
|
||||
/// Gets the vtable for this object.
|
||||
@@ -161,239 +66,3 @@ pub trait Obj: Trace + Finalize + Debug {
|
||||
|
||||
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::*;
|
||||
|
||||
/// 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::vm::{error::RuntimeError, machine::MachineBuilder};
|
||||
use crate::obj::{builtin::BuiltinExit, str::StrObj, Obj};
|
||||
use crate::vm::{
|
||||
error::RuntimeError,
|
||||
machine::{Machine, MachineBuilder},
|
||||
};
|
||||
|
||||
impl MachineBuilder {
|
||||
/// Registers all builtins for calling on the machine.
|
||||
@@ -9,7 +12,7 @@ impl MachineBuilder {
|
||||
//
|
||||
// panic
|
||||
//
|
||||
self.register_builtin_fun("panic", |machine, _| {
|
||||
self.register_builtin_fun("panic", |machine: &mut Machine, _| {
|
||||
println!("!!! panic");
|
||||
println!("!!! top of stack");
|
||||
for (i, value) in machine.stack().iter().enumerate().rev() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::compile::Compile;
|
||||
use crate::obj::*;
|
||||
use crate::obj::prelude::*;
|
||||
use crate::scope::*;
|
||||
use crate::syn::{ast::SpStmt, span::Span};
|
||||
use crate::vm::{error::*, inst::*};
|
||||
|
||||
Reference in New Issue
Block a user