feat: stash
This commit is contained in:
26
Cargo.lock
generated
26
Cargo.lock
generated
@@ -177,7 +177,7 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"llvm-sys",
|
"llvm-sys",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"thiserror",
|
"thiserror 1.0.69",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -278,7 +278,6 @@ dependencies = [
|
|||||||
name = "nixjit"
|
name = "nixjit"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
|
||||||
"derive_more",
|
"derive_more",
|
||||||
"ecow",
|
"ecow",
|
||||||
"inkwell",
|
"inkwell",
|
||||||
@@ -287,6 +286,7 @@ dependencies = [
|
|||||||
"rnix",
|
"rnix",
|
||||||
"rpds",
|
"rpds",
|
||||||
"rustyline",
|
"rustyline",
|
||||||
|
"thiserror 2.0.12",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -477,7 +477,16 @@ version = "1.0.69"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl",
|
"thiserror-impl 1.0.69",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror"
|
||||||
|
version = "2.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror-impl 2.0.12",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -491,6 +500,17 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "thiserror-impl"
|
||||||
|
version = "2.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "triomphe"
|
name = "triomphe"
|
||||||
version = "0.1.11"
|
version = "0.1.11"
|
||||||
|
|||||||
19
Cargo.toml
19
Cargo.toml
@@ -3,20 +3,29 @@ name = "nixjit"
|
|||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["vm", "jit", "repl"]
|
||||||
|
vm = []
|
||||||
|
jit = ["dep:inkwell"]
|
||||||
|
repl = ["dep:rustyline"]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "repl-vm"
|
||||||
|
required-features = ["vm", "repl"]
|
||||||
|
|
||||||
[profile.perf]
|
[profile.perf]
|
||||||
opt-level = 3
|
|
||||||
debug = 1
|
debug = 1
|
||||||
inherits = "dev"
|
inherits = "release"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rnix = "0.11"
|
rnix = "0.11"
|
||||||
anyhow = "1.0"
|
thiserror = "2.0"
|
||||||
itertools = "0.12"
|
itertools = "0.12"
|
||||||
rpds = "1.1"
|
rpds = "1.1"
|
||||||
derive_more = { version = "2.0", features = [ "full" ] }
|
derive_more = { version = "2.0", features = [ "full" ] }
|
||||||
ecow = "0.2"
|
ecow = "0.2"
|
||||||
regex = "1.11"
|
regex = "1.11"
|
||||||
|
|
||||||
inkwell = { version = "0.6.0", features = ["llvm18-1"] }
|
inkwell = { version = "0.6.0", features = ["llvm18-1"], optional = true }
|
||||||
|
|
||||||
rustyline = "15.0"
|
rustyline = { version = "15.0", optional = true }
|
||||||
|
|||||||
16
flake.nix
16
flake.nix
@@ -23,7 +23,23 @@
|
|||||||
"rustfmt"
|
"rustfmt"
|
||||||
"rust-analyzer"
|
"rust-analyzer"
|
||||||
])
|
])
|
||||||
|
llvm_18
|
||||||
|
libffi
|
||||||
|
libxml2
|
||||||
|
ncurses
|
||||||
];
|
];
|
||||||
|
LLVM_SYS_181_PREFIX = toString pkgs.llvm_18.dev;
|
||||||
|
LD_LIBRARY_PATH = let
|
||||||
|
libs = with pkgs; [
|
||||||
|
llvm_18.lib
|
||||||
|
stdenv.cc.cc.lib
|
||||||
|
libffi
|
||||||
|
libxml2
|
||||||
|
ncurses
|
||||||
|
];
|
||||||
|
in
|
||||||
|
builtins.concatStringsSep ":" (map (lib: "${lib}/lib") libs)
|
||||||
|
;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,21 @@
|
|||||||
use rustyline::error::ReadlineError;
|
use rustyline::error::ReadlineError;
|
||||||
use rustyline::{DefaultEditor, Result};
|
use rustyline::{DefaultEditor, Result};
|
||||||
|
|
||||||
use nixjit::*;
|
use nixjit::compile::compile;
|
||||||
|
use nixjit::ir::downgrade;
|
||||||
|
use nixjit::vm::run;
|
||||||
|
|
||||||
|
macro_rules! unwrap {
|
||||||
|
($e:expr) => {
|
||||||
|
match $e {
|
||||||
|
Ok(ok) => ok,
|
||||||
|
Err(err) => {
|
||||||
|
println!("{err}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
let mut rl = DefaultEditor::new()?;
|
let mut rl = DefaultEditor::new()?;
|
||||||
@@ -12,8 +26,11 @@ fn main() -> Result<()> {
|
|||||||
if expr.trim().is_empty() {
|
if expr.trim().is_empty() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let prog = compile(expr.as_str()).unwrap();
|
let downgraded = unwrap!(downgrade(
|
||||||
println!("{}", run(prog).unwrap());
|
rnix::Root::parse(expr.as_str()).tree().expr().unwrap()
|
||||||
|
));
|
||||||
|
let prog = compile(downgraded);
|
||||||
|
println!("{}", unwrap!(run(prog)));
|
||||||
rl.add_history_entry(expr.as_str())?;
|
rl.add_history_entry(expr.as_str())?;
|
||||||
}
|
}
|
||||||
Err(ReadlineError::Interrupted) => {
|
Err(ReadlineError::Interrupted) => {
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
use crate::bytecode::*;
|
use crate::bytecode::*;
|
||||||
|
use crate::ir;
|
||||||
use crate::ty::internal::Const;
|
use crate::ty::internal::Const;
|
||||||
|
|
||||||
use super::ir;
|
|
||||||
|
|
||||||
pub struct Compiler {
|
pub struct Compiler {
|
||||||
opcodes: Vec<OpCode>,
|
opcodes: Vec<OpCode>,
|
||||||
}
|
}
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
use itertools::Itertools;
|
|
||||||
|
|
||||||
mod compile;
|
|
||||||
mod ir;
|
|
||||||
|
|
||||||
pub fn compile(expr: &str) -> anyhow::Result<crate::bytecode::Program> {
|
|
||||||
let root = rnix::Root::parse(expr);
|
|
||||||
if !root.errors().is_empty() {
|
|
||||||
return Err(anyhow::anyhow!(
|
|
||||||
root.errors().iter().map(|err| err.to_string()).join(";")
|
|
||||||
));
|
|
||||||
}
|
|
||||||
assert!(root.errors().is_empty());
|
|
||||||
let expr = root.tree().expr().unwrap();
|
|
||||||
let ir = ir::downgrade(expr)?;
|
|
||||||
Ok(compile::compile(ir))
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
pub trait Downcast<T: Sized>
|
|
||||||
where
|
|
||||||
Self: Sized,
|
|
||||||
{
|
|
||||||
fn downcast_ref(&self) -> Option<&T>;
|
|
||||||
fn downcast_mut(&mut self) -> Option<&mut T>;
|
|
||||||
fn downcast(self) -> Result<T, Self>;
|
|
||||||
}
|
|
||||||
13
src/error.rs
Normal file
13
src/error.rs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
pub type Result<T> = core::result::Result<T, Error>;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("error occurred during downgrade stage: {0}")]
|
||||||
|
DowngradeError(String),
|
||||||
|
#[error("error occurred during evaluation stage: {0}")]
|
||||||
|
EvalError(String),
|
||||||
|
#[error("unknown error")]
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
@@ -1,14 +1,13 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use anyhow::{Result, anyhow};
|
|
||||||
use ecow::EcoString;
|
use ecow::EcoString;
|
||||||
use rnix::ast::{self, Expr};
|
use rnix::ast::{self, Expr};
|
||||||
|
|
||||||
use crate::bytecode::{ConstIdx, Consts, ThunkIdx};
|
use crate::bytecode::{ConstIdx, Consts, ThunkIdx};
|
||||||
|
use crate::compile::*;
|
||||||
|
use crate::error::*;
|
||||||
use crate::ty::internal as i;
|
use crate::ty::internal as i;
|
||||||
|
|
||||||
use super::compile::*;
|
|
||||||
|
|
||||||
pub fn downgrade(expr: Expr) -> Result<Downgraded> {
|
pub fn downgrade(expr: Expr) -> Result<Downgraded> {
|
||||||
let mut state = DowngradeState::new();
|
let mut state = DowngradeState::new();
|
||||||
let ir = expr.downgrade(&mut state)?;
|
let ir = expr.downgrade(&mut state)?;
|
||||||
@@ -19,7 +18,15 @@ pub fn downgrade(expr: Expr) -> Result<Downgraded> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
trait Downcast<T: Sized>
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
fn downcast_ref(&self) -> Option<&T>;
|
||||||
|
fn downcast_mut(&mut self) -> Option<&mut T>;
|
||||||
|
fn downcast(self) -> core::result::Result<T, Self>;
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! ir {
|
macro_rules! ir {
|
||||||
(
|
(
|
||||||
$(
|
$(
|
||||||
@@ -30,8 +37,6 @@ macro_rules! ir {
|
|||||||
)
|
)
|
||||||
,*$(,)?
|
,*$(,)?
|
||||||
) => {
|
) => {
|
||||||
use crate::downcast::Downcast;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Ir {
|
pub enum Ir {
|
||||||
$(
|
$(
|
||||||
@@ -73,16 +78,6 @@ macro_rules! ir {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<Ir> for $ty {
|
|
||||||
type Error = anyhow::Error;
|
|
||||||
fn try_from(value: Ir) -> Result<Self> {
|
|
||||||
match value {
|
|
||||||
Ir::$ty(value) => Ok(value),
|
|
||||||
_ => Err(anyhow!("")),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Downcast<$ty> for Ir {
|
impl Downcast<$ty> for Ir {
|
||||||
fn downcast_ref(&self) -> Option<&$ty> {
|
fn downcast_ref(&self) -> Option<&$ty> {
|
||||||
match self {
|
match self {
|
||||||
@@ -132,12 +127,6 @@ ir! {
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct DynamicAttrPair(pub Ir, pub Ir);
|
pub struct DynamicAttrPair(pub Ir, pub Ir);
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct DowngradeError {
|
|
||||||
errno: u16,
|
|
||||||
text: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct DowngradeState {
|
pub struct DowngradeState {
|
||||||
thunks: Vec<Ir>,
|
thunks: Vec<Ir>,
|
||||||
consts: Vec<i::Const>,
|
consts: Vec<i::Const>,
|
||||||
@@ -180,7 +169,9 @@ impl Attrs {
|
|||||||
.get_mut(&ident)
|
.get_mut(&ident)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.downcast_mut()
|
.downcast_mut()
|
||||||
.ok_or(anyhow!(r#""{ident}" already exsists in this set"#))
|
.ok_or(Error::DowngradeError(format!(
|
||||||
|
r#""{ident}" already exsists in this set"#
|
||||||
|
)))
|
||||||
.and_then(|attrs: &mut Attrs| attrs._insert(path, name, value))
|
.and_then(|attrs: &mut Attrs| attrs._insert(path, name, value))
|
||||||
} else {
|
} else {
|
||||||
let mut attrs = Attrs {
|
let mut attrs = Attrs {
|
||||||
@@ -218,7 +209,9 @@ impl Attrs {
|
|||||||
match name {
|
match name {
|
||||||
Attr::Str(ident) => {
|
Attr::Str(ident) => {
|
||||||
if self.stcs.get(&ident).is_some() {
|
if self.stcs.get(&ident).is_some() {
|
||||||
return Err(anyhow!(r#""{ident}" already exsists in this set"#));
|
return Err(Error::DowngradeError(format!(
|
||||||
|
r#""{ident}" already exsists in this set"#
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
self.stcs.insert(ident, value);
|
self.stcs.insert(ident, value);
|
||||||
}
|
}
|
||||||
@@ -349,7 +342,7 @@ impl Downgrade for Expr {
|
|||||||
match self {
|
match self {
|
||||||
Expr::Apply(apply) => apply.downgrade(state),
|
Expr::Apply(apply) => apply.downgrade(state),
|
||||||
Expr::Assert(assert) => assert.downgrade(state),
|
Expr::Assert(assert) => assert.downgrade(state),
|
||||||
Expr::Error(error) => return Err(anyhow!(error.to_string())),
|
Expr::Error(error) => return Err(Error::DowngradeError(error.to_string())),
|
||||||
Expr::IfElse(ifelse) => ifelse.downgrade(state),
|
Expr::IfElse(ifelse) => ifelse.downgrade(state),
|
||||||
Expr::Select(select) => select.downgrade(state),
|
Expr::Select(select) => select.downgrade(state),
|
||||||
Expr::Str(str) => str.downgrade(state),
|
Expr::Str(str) => str.downgrade(state),
|
||||||
@@ -675,7 +668,11 @@ fn downgrade_inherit(
|
|||||||
for attr in inherit.attrs() {
|
for attr in inherit.attrs() {
|
||||||
let ident: EcoString = match downgrade_attr(attr, state)? {
|
let ident: EcoString = match downgrade_attr(attr, state)? {
|
||||||
Attr::Str(ident) => ident.to_string().into(),
|
Attr::Str(ident) => ident.to_string().into(),
|
||||||
_ => return Err(anyhow!("dynamic attributes not allowed in inherit")),
|
_ => {
|
||||||
|
return Err(Error::DowngradeError(
|
||||||
|
"dynamic attributes not allowed in inherit".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let expr = from.map_or_else(
|
let expr = from.map_or_else(
|
||||||
|| Var { sym: ident.clone() }.ir().ok(),
|
|| Var { sym: ident.clone() }.ir().ok(),
|
||||||
@@ -694,29 +691,31 @@ fn downgrade_inherit(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn downgrade_attr(attr: ast::Attr, state: &mut DowngradeState) -> Result<Attr> {
|
fn downgrade_attr(attr: ast::Attr, state: &mut DowngradeState) -> Result<Attr> {
|
||||||
|
use ast::Attr::*;
|
||||||
|
use ast::InterpolPart::*;
|
||||||
match attr {
|
match attr {
|
||||||
ast::Attr::Ident(ident) => Ok(Attr::Str(ident.to_string().into())),
|
Ident(ident) => Ok(Attr::Str(ident.to_string().into())),
|
||||||
ast::Attr::Str(string) => {
|
Str(string) => {
|
||||||
let parts = string.normalized_parts();
|
let parts = string.normalized_parts();
|
||||||
if parts.len() == 1 {
|
if parts.len() == 1 {
|
||||||
let ast::InterpolPart::Literal(ident) = parts.into_iter().next().unwrap() else {
|
match parts.into_iter().next().unwrap() {
|
||||||
unreachable!()
|
Literal(ident) => Ok(Attr::Str(ident.into())),
|
||||||
};
|
Interpolation(interpol) => {
|
||||||
Ok(Attr::Str(ident.into()))
|
Ok(Attr::Dynamic(interpol.expr().unwrap().downgrade(state)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
let parts = parts
|
let parts = parts
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|part| match part {
|
.map(|part| match part {
|
||||||
ast::InterpolPart::Literal(lit) => Const { value: lit.into() }.ir().ok(),
|
Literal(lit) => Const { value: lit.into() }.ir().ok(),
|
||||||
ast::InterpolPart::Interpolation(interpol) => {
|
Interpolation(interpol) => interpol.expr().unwrap().downgrade(state),
|
||||||
interpol.expr().unwrap().downgrade(state)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>>>()?;
|
.collect::<Result<Vec<_>>>()?;
|
||||||
Ok(Attr::Strs(ConcatStrings { parts }))
|
Ok(Attr::Strs(ConcatStrings { parts }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::Attr::Dynamic(dynamic) => Ok(Attr::Dynamic(dynamic.expr().unwrap().downgrade(state)?)),
|
Dynamic(dynamic) => Ok(Attr::Dynamic(dynamic.expr().unwrap().downgrade(state)?)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
5
src/jit/codegen.rs
Normal file
5
src/jit/codegen.rs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
use super::JITContext;
|
||||||
|
|
||||||
|
pub trait CodeGen {
|
||||||
|
fn codegen(self, ctx: JITContext);
|
||||||
|
}
|
||||||
@@ -1,21 +1,27 @@
|
|||||||
|
use inkwell::OptimizationLevel;
|
||||||
use inkwell::builder::Builder;
|
use inkwell::builder::Builder;
|
||||||
use inkwell::context::Context;
|
use inkwell::context::Context;
|
||||||
use inkwell::module::Module;
|
|
||||||
use inkwell::OptimizationLevel;
|
|
||||||
use inkwell::execution_engine::ExecutionEngine;
|
use inkwell::execution_engine::ExecutionEngine;
|
||||||
|
use inkwell::module::Module;
|
||||||
|
|
||||||
pub struct JIT<'ctx> {
|
mod codegen;
|
||||||
|
|
||||||
|
pub use codegen::CodeGen;
|
||||||
|
|
||||||
|
pub struct JITContext<'ctx> {
|
||||||
context: &'ctx Context,
|
context: &'ctx Context,
|
||||||
module: Module<'ctx>,
|
module: Module<'ctx>,
|
||||||
builder: Builder<'ctx>,
|
builder: Builder<'ctx>,
|
||||||
execution_engine: ExecutionEngine<'ctx>,
|
execution_engine: ExecutionEngine<'ctx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> JIT<'ctx> {
|
impl<'ctx> JITContext<'ctx> {
|
||||||
pub fn new(context: &Context) -> JIT {
|
pub fn new(context: &Context) -> JITContext {
|
||||||
let module = context.create_module("nixjit");
|
let module = context.create_module("nixjit");
|
||||||
JIT {
|
JITContext {
|
||||||
execution_engine: module.create_jit_execution_engine(OptimizationLevel::None).unwrap(),
|
execution_engine: module
|
||||||
|
.create_jit_execution_engine(OptimizationLevel::None)
|
||||||
|
.unwrap(),
|
||||||
builder: context.create_builder(),
|
builder: context.create_builder(),
|
||||||
context,
|
context,
|
||||||
module,
|
module,
|
||||||
|
|||||||
14
src/lib.rs
14
src/lib.rs
@@ -2,12 +2,14 @@
|
|||||||
|
|
||||||
mod builtins;
|
mod builtins;
|
||||||
mod bytecode;
|
mod bytecode;
|
||||||
mod compile;
|
|
||||||
mod downcast;
|
|
||||||
mod ty;
|
mod ty;
|
||||||
mod vm;
|
|
||||||
mod jit;
|
|
||||||
|
|
||||||
pub use compile::compile;
|
pub mod compile;
|
||||||
|
pub mod error;
|
||||||
|
pub mod ir;
|
||||||
|
#[cfg(feature = "jit")]
|
||||||
|
pub mod jit;
|
||||||
|
#[cfg(feature = "vm")]
|
||||||
|
pub mod vm;
|
||||||
|
|
||||||
pub use ty::public::Value;
|
pub use ty::public::Value;
|
||||||
pub use vm::run;
|
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use derive_more::Constructor;
|
use derive_more::Constructor;
|
||||||
use rpds::HashTrieMapSync;
|
use rpds::HashTrieMapSync;
|
||||||
|
|
||||||
|
use crate::error::Result;
|
||||||
|
use crate::vm::VM;
|
||||||
|
|
||||||
use super::super::common::Symbol;
|
use super::super::common::Symbol;
|
||||||
use super::super::public as p;
|
use super::super::public as p;
|
||||||
|
|
||||||
use super::{ToPublic, Value};
|
use super::{ToPublic, Value};
|
||||||
use crate::vm::VM;
|
|
||||||
|
|
||||||
#[derive(Debug, Constructor, Clone, PartialEq)]
|
#[derive(Debug, Constructor, Clone, PartialEq)]
|
||||||
pub struct AttrSet {
|
pub struct AttrSet {
|
||||||
@@ -28,7 +28,7 @@ impl AttrSet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_attr(&mut self, sym: Symbol, val: Value) {
|
pub fn push_attr(&mut self, sym: Symbol, val: Value) {
|
||||||
if self.data.get(&sym).is_some() {
|
if let Some(_) = self.data.get_mut(&sym) {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
self.data.insert_mut(sym, val);
|
self.data.insert_mut(sym, val);
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
use anyhow::Error;
|
|
||||||
use derive_more::{IsVariant, Unwrap};
|
use derive_more::{IsVariant, Unwrap};
|
||||||
|
|
||||||
use ecow::EcoString;
|
use ecow::EcoString;
|
||||||
|
|
||||||
#[derive(Debug, Clone, IsVariant, Unwrap)]
|
#[derive(Debug, Clone, IsVariant, Unwrap)]
|
||||||
@@ -47,49 +45,6 @@ impl From<&str> for Const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TryFrom<&'a Const> for &'a bool {
|
|
||||||
type Error = Error;
|
|
||||||
|
|
||||||
fn try_from(value: &'a Const) -> Result<Self, Self::Error> {
|
|
||||||
match value {
|
|
||||||
Const::Bool(b) => Ok(b),
|
|
||||||
_ => panic!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<'a> TryFrom<&'a Const> for &'a i64 {
|
|
||||||
type Error = Error;
|
|
||||||
|
|
||||||
fn try_from(value: &'a Const) -> Result<Self, Self::Error> {
|
|
||||||
match value {
|
|
||||||
Const::Int(int) => Ok(int),
|
|
||||||
_ => panic!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> TryFrom<&'a Const> for &'a f64 {
|
|
||||||
type Error = Error;
|
|
||||||
|
|
||||||
fn try_from(value: &'a Const) -> Result<Self, Self::Error> {
|
|
||||||
match value {
|
|
||||||
Const::Float(float) => Ok(float),
|
|
||||||
_ => panic!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> TryFrom<&'a Const> for &'a str {
|
|
||||||
type Error = Error;
|
|
||||||
|
|
||||||
fn try_from(value: &'a Const) -> Result<Self, Self::Error> {
|
|
||||||
match value {
|
|
||||||
Const::String(string) => Ok(string),
|
|
||||||
_ => panic!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PartialEq for Const {
|
impl PartialEq for Const {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
use Const::*;
|
use Const::*;
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ use itertools::Itertools;
|
|||||||
use rpds::HashTrieMap;
|
use rpds::HashTrieMap;
|
||||||
|
|
||||||
use crate::bytecode::OpCodes;
|
use crate::bytecode::OpCodes;
|
||||||
|
use crate::error::Result;
|
||||||
use crate::ty::internal::{Thunk, Value};
|
use crate::ty::internal::{Thunk, Value};
|
||||||
|
|
||||||
use crate::vm::{CapturedEnv, VM};
|
use crate::vm::{CapturedEnv, VM};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -33,7 +33,7 @@ impl Func {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn call(self, vm: &VM, arg: Value) -> Value {
|
pub fn call(self, vm: &VM, arg: Value) -> Result<Value> {
|
||||||
use Param::*;
|
use Param::*;
|
||||||
|
|
||||||
let env = self.env.released();
|
let env = self.env.released();
|
||||||
@@ -71,7 +71,7 @@ impl Func {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vm.eval(self.opcodes, env).unwrap()
|
vm.eval(self.opcodes, env)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_ident_param(&mut self, param: EcoString) {
|
pub fn push_ident_param(&mut self, param: EcoString) {
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
use anyhow::Result;
|
|
||||||
use derive_more::Constructor;
|
use derive_more::Constructor;
|
||||||
use rpds::VectorSync;
|
use rpds::VectorSync;
|
||||||
|
|
||||||
|
use crate::error::Result;
|
||||||
use crate::ty::public as p;
|
use crate::ty::public as p;
|
||||||
|
use crate::vm::VM;
|
||||||
|
|
||||||
use super::{ToPublic, Value};
|
use super::{ToPublic, Value};
|
||||||
use crate::vm::VM;
|
|
||||||
|
|
||||||
#[derive(Debug, Constructor, Clone, PartialEq)]
|
#[derive(Debug, Constructor, Clone, PartialEq)]
|
||||||
pub struct List {
|
pub struct List {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use anyhow::{Result, anyhow};
|
|
||||||
use derive_more::{IsVariant, Unwrap};
|
use derive_more::{IsVariant, Unwrap};
|
||||||
|
|
||||||
use super::common as c;
|
use super::common as c;
|
||||||
@@ -11,6 +10,7 @@ use super::public as p;
|
|||||||
use c::Symbol;
|
use c::Symbol;
|
||||||
|
|
||||||
use crate::bytecode::OpCodes;
|
use crate::bytecode::OpCodes;
|
||||||
|
use crate::error::*;
|
||||||
use crate::vm::{Env, VM};
|
use crate::vm::{Env, VM};
|
||||||
|
|
||||||
mod attrset;
|
mod attrset;
|
||||||
@@ -65,9 +65,10 @@ impl Thunk {
|
|||||||
match &*self.thunk.borrow() {
|
match &*self.thunk.borrow() {
|
||||||
_Thunk::Value(value) => return Ok(value.as_ref().clone()),
|
_Thunk::Value(value) => return Ok(value.as_ref().clone()),
|
||||||
_Thunk::SuspendedFrom(from) => {
|
_Thunk::SuspendedFrom(from) => {
|
||||||
return Err(anyhow!(
|
return Err(Error::EvalError(format!(
|
||||||
"already suspended from {from:p} (infinite recursion encountered)"
|
"thunk {:p} already suspended from {from:p} (infinite recursion encountered)",
|
||||||
));
|
self as *const Thunk
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
_Thunk::Code(_) => (),
|
_Thunk::Code(_) => (),
|
||||||
}
|
}
|
||||||
@@ -77,9 +78,7 @@ impl Thunk {
|
|||||||
_Thunk::SuspendedFrom(self as *const Thunk),
|
_Thunk::SuspendedFrom(self as *const Thunk),
|
||||||
)
|
)
|
||||||
.unwrap_code();
|
.unwrap_code();
|
||||||
let value = vm
|
let value = vm.eval(opcodes, self.env.borrow().clone().unwrap())?;
|
||||||
.eval(opcodes, self.env.borrow().clone().unwrap())
|
|
||||||
.unwrap();
|
|
||||||
let _ = std::mem::replace(
|
let _ = std::mem::replace(
|
||||||
&mut *self.thunk.borrow_mut(),
|
&mut *self.thunk.borrow_mut(),
|
||||||
_Thunk::Value(value.clone().into()),
|
_Thunk::Value(value.clone().into()),
|
||||||
@@ -199,9 +198,9 @@ impl Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn call(self, vm: &VM, args: Vec<Value>) -> Value {
|
pub fn call(self, vm: &VM, args: Vec<Value>) -> Result<Value> {
|
||||||
use Value::*;
|
use Value::*;
|
||||||
match self {
|
Ok(match self {
|
||||||
PrimOp(func) => func.call(vm, args),
|
PrimOp(func) => func.call(vm, args),
|
||||||
PartialPrimOp(func) => func.call(vm, args),
|
PartialPrimOp(func) => func.call(vm, args),
|
||||||
mut func @ Value::Func(_) => {
|
mut func @ Value::Func(_) => {
|
||||||
@@ -209,12 +208,12 @@ impl Value {
|
|||||||
while let Some(arg) = iter.next() {
|
while let Some(arg) = iter.next() {
|
||||||
func = match func {
|
func = match func {
|
||||||
PrimOp(func) => {
|
PrimOp(func) => {
|
||||||
return func.call(vm, [arg].into_iter().chain(iter).collect());
|
return Ok(func.call(vm, [arg].into_iter().chain(iter).collect()));
|
||||||
}
|
}
|
||||||
PartialPrimOp(func) => {
|
PartialPrimOp(func) => {
|
||||||
return func.call(vm, [arg].into_iter().chain(iter).collect());
|
return Ok(func.call(vm, [arg].into_iter().chain(iter).collect()));
|
||||||
}
|
}
|
||||||
Func(func) => func.call(vm, arg),
|
Func(func) => func.call(vm, arg)?,
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -222,7 +221,7 @@ impl Value {
|
|||||||
}
|
}
|
||||||
x @ Catchable(_) => x,
|
x @ Catchable(_) => x,
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn not(self) -> Value {
|
pub fn not(self) -> Value {
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
use std::fmt::{Display, Formatter, Result as FmtResult};
|
use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||||
|
|
||||||
use anyhow::Error;
|
|
||||||
use derive_more::{IsVariant, Unwrap};
|
use derive_more::{IsVariant, Unwrap};
|
||||||
use ecow::EcoString;
|
use ecow::EcoString;
|
||||||
|
|
||||||
|
use crate::error::Error;
|
||||||
|
|
||||||
use super::super::internal as i;
|
use super::super::internal as i;
|
||||||
|
|
||||||
#[derive(Debug, Clone, IsVariant, Unwrap)]
|
#[derive(Debug, Clone, IsVariant, Unwrap)]
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
use std::mem::{MaybeUninit, size_of, transmute};
|
use std::mem::{MaybeUninit, replace, size_of, transmute};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use anyhow::{Result, anyhow};
|
use crate::error::*;
|
||||||
|
|
||||||
use crate::ty::internal::Value;
|
use crate::ty::internal::Value;
|
||||||
|
|
||||||
pub const STACK_SIZE: usize = 8 * 1024 / size_of::<Value>();
|
pub const STACK_SIZE: usize = 8 * 1024 / size_of::<Value>();
|
||||||
@@ -12,6 +11,12 @@ pub struct Stack<const CAP: usize> {
|
|||||||
top: usize,
|
top: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! into {
|
||||||
|
($e:expr) => {
|
||||||
|
unsafe { transmute($e) }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
impl<const CAP: usize> Stack<CAP> {
|
impl<const CAP: usize> Stack<CAP> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Stack {
|
Stack {
|
||||||
@@ -27,51 +32,34 @@ impl<const CAP: usize> Stack<CAP> {
|
|||||||
pub fn push(&mut self, item: Value) -> Result<()> {
|
pub fn push(&mut self, item: Value) -> Result<()> {
|
||||||
self.items
|
self.items
|
||||||
.get_mut(self.top)
|
.get_mut(self.top)
|
||||||
.map_or(Err(anyhow!("stack overflow")), |ok| Ok(ok))?
|
.map_or(Err(Error::EvalError("stack overflow".to_string())), |ok| {
|
||||||
|
Ok(ok)
|
||||||
|
})?
|
||||||
.write(item);
|
.write(item);
|
||||||
self.top += 1;
|
self.top += 1;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pop(&mut self) -> Result<Value> {
|
pub fn pop(&mut self) -> Value {
|
||||||
self.top -= 1;
|
self.top -= 1;
|
||||||
let item = self
|
let item = self.items.get_mut(self.top).unwrap();
|
||||||
.items
|
|
||||||
.get_mut(self.top)
|
unsafe { replace(item, MaybeUninit::uninit()).assume_init() }
|
||||||
.map_or(Err(anyhow!("stack empty")), |ok| Ok(ok))?;
|
|
||||||
unsafe { Ok(std::mem::replace(item, MaybeUninit::uninit()).assume_init()) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tos(&self) -> Result<&Value> {
|
pub fn tos(&self) -> Result<&Value> {
|
||||||
if self.top == 0 {
|
if self.top == 0 {
|
||||||
Err(anyhow!(""))
|
panic!("stack empty")
|
||||||
} else {
|
} else {
|
||||||
unsafe { Ok(transmute(self.items.get(self.top - 1).unwrap())) }
|
Ok(into!(&self.items[self.top - 1]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tos_mut(&mut self) -> Result<&mut Value> {
|
pub fn tos_mut(&mut self) -> Result<&mut Value> {
|
||||||
if self.top == 0 {
|
if self.top == 0 {
|
||||||
Err(anyhow!(""))
|
panic!("stack empty")
|
||||||
} else {
|
} else {
|
||||||
unsafe { Ok(transmute(self.items.get_mut(self.top - 1).unwrap())) }
|
Ok(into!(&mut self.items[self.top - 1]))
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_tos(&self, func: impl Fn(&Value)) -> Result<()> {
|
|
||||||
if self.top != 0 {
|
|
||||||
Err(anyhow!(""))
|
|
||||||
} else {
|
|
||||||
unsafe { func(transmute(self.items.get(self.top - 1).unwrap())) }
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn with_tos_mut(&mut self, func: impl Fn(&mut Value)) -> Result<()> {
|
|
||||||
if self.top != 0 {
|
|
||||||
Err(anyhow!(""))
|
|
||||||
} else {
|
|
||||||
unsafe { func(transmute(self.items.get_mut(self.top - 1).unwrap())) }
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -79,7 +67,7 @@ impl<const CAP: usize> Stack<CAP> {
|
|||||||
impl<const CAP: usize> Deref for Stack<CAP> {
|
impl<const CAP: usize> Deref for Stack<CAP> {
|
||||||
type Target = [Value];
|
type Target = [Value];
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
unsafe { transmute(&self.items[0..self.top]) }
|
into!(&self.items[0..self.top])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use ecow::EcoString;
|
|||||||
use rpds::{ht_map_sync, vector_sync};
|
use rpds::{ht_map_sync, vector_sync};
|
||||||
|
|
||||||
use crate::compile::compile;
|
use crate::compile::compile;
|
||||||
|
use crate::ir::downgrade;
|
||||||
use crate::ty::common::Symbol;
|
use crate::ty::common::Symbol;
|
||||||
use crate::ty::public::*;
|
use crate::ty::public::*;
|
||||||
|
|
||||||
@@ -9,7 +10,8 @@ use super::vm::run;
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn test_expr(expr: &str, expected: Value) {
|
fn test_expr(expr: &str, expected: Value) {
|
||||||
let prog = compile(expr).unwrap();
|
let downgraded = downgrade(rnix::Root::parse(expr).tree().expr().unwrap()).unwrap();
|
||||||
|
let prog = compile(downgraded);
|
||||||
dbg!(&prog);
|
dbg!(&prog);
|
||||||
assert_eq!(run(prog).unwrap(), expected);
|
assert_eq!(run(prog).unwrap(), expected);
|
||||||
}
|
}
|
||||||
|
|||||||
55
src/vm/vm.rs
55
src/vm/vm.rs
@@ -1,9 +1,8 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use anyhow::{Result, anyhow};
|
|
||||||
|
|
||||||
use crate::builtins::env;
|
use crate::builtins::env;
|
||||||
use crate::bytecode::{self, BinOp, OpCode, OpCodes, Program, Thunks, UnOp};
|
use crate::bytecode::{self, BinOp, OpCode, OpCodes, Program, Thunks, UnOp};
|
||||||
|
use crate::error::*;
|
||||||
use crate::ty::common::Symbol;
|
use crate::ty::common::Symbol;
|
||||||
use crate::ty::internal::*;
|
use crate::ty::internal::*;
|
||||||
use crate::ty::public as p;
|
use crate::ty::public as p;
|
||||||
@@ -44,10 +43,8 @@ impl VM {
|
|||||||
}
|
}
|
||||||
assert_eq!(stack.len(), 1);
|
assert_eq!(stack.len(), 1);
|
||||||
let mut ret = stack.pop();
|
let mut ret = stack.pop();
|
||||||
if let Ok(ref mut value) = ret {
|
ret.force(self)?;
|
||||||
value.force(self)?;
|
Ok(ret)
|
||||||
}
|
|
||||||
ret
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -58,7 +55,7 @@ impl VM {
|
|||||||
env: Arc<Env>,
|
env: Arc<Env>,
|
||||||
) -> Result<usize> {
|
) -> Result<usize> {
|
||||||
match opcode {
|
match opcode {
|
||||||
OpCode::Illegal => return Err(anyhow!("illegal opcode")),
|
OpCode::Illegal => panic!("illegal opcode"),
|
||||||
OpCode::Const { value } => stack.push(Value::Const(value))?,
|
OpCode::Const { value } => stack.push(Value::Const(value))?,
|
||||||
OpCode::LoadThunk { idx } => {
|
OpCode::LoadThunk { idx } => {
|
||||||
self.thunks[idx].capture(env);
|
self.thunks[idx].capture(env);
|
||||||
@@ -72,23 +69,23 @@ impl VM {
|
|||||||
}
|
}
|
||||||
OpCode::Jmp { step } => return Ok(step),
|
OpCode::Jmp { step } => return Ok(step),
|
||||||
OpCode::JmpIfTrue { step } => {
|
OpCode::JmpIfTrue { step } => {
|
||||||
if let Value::Const(Const::Bool(true)) = stack.pop()? {
|
if let Value::Const(Const::Bool(true)) = stack.pop() {
|
||||||
return Ok(step);
|
return Ok(step);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OpCode::JmpIfFalse { step } => {
|
OpCode::JmpIfFalse { step } => {
|
||||||
if let Value::Const(Const::Bool(false)) = stack.pop()? {
|
if let Value::Const(Const::Bool(false)) = stack.pop() {
|
||||||
return Ok(step);
|
return Ok(step);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OpCode::Call { arity } => {
|
OpCode::Call { arity } => {
|
||||||
let mut args = Vec::with_capacity(arity);
|
let mut args = Vec::with_capacity(arity);
|
||||||
for _ in 0..arity {
|
for _ in 0..arity {
|
||||||
args.insert(0, stack.pop()?);
|
args.insert(0, stack.pop());
|
||||||
}
|
}
|
||||||
let mut func = stack.pop()?;
|
let mut func = stack.pop();
|
||||||
func.force(self)?;
|
func.force(self)?;
|
||||||
stack.push(func.call(self, args))?;
|
stack.push(func.call(self, args)?)?;
|
||||||
}
|
}
|
||||||
OpCode::Func { idx } => {
|
OpCode::Func { idx } => {
|
||||||
stack.push(Value::Func(Func::new(
|
stack.push(Value::Func(Func::new(
|
||||||
@@ -125,7 +122,7 @@ impl VM {
|
|||||||
}
|
}
|
||||||
OpCode::UnOp { op } => {
|
OpCode::UnOp { op } => {
|
||||||
use UnOp::*;
|
use UnOp::*;
|
||||||
let mut value = stack.pop()?;
|
let mut value = stack.pop();
|
||||||
value.force(self)?;
|
value.force(self)?;
|
||||||
stack.push(match op {
|
stack.push(match op {
|
||||||
Not => value.not(),
|
Not => value.not(),
|
||||||
@@ -133,8 +130,8 @@ impl VM {
|
|||||||
}
|
}
|
||||||
OpCode::BinOp { op } => {
|
OpCode::BinOp { op } => {
|
||||||
use BinOp::*;
|
use BinOp::*;
|
||||||
let mut rhs = stack.pop()?;
|
let mut rhs = stack.pop();
|
||||||
let mut lhs = stack.pop()?;
|
let mut lhs = stack.pop();
|
||||||
lhs.force(self)?;
|
lhs.force(self)?;
|
||||||
rhs.force(self)?;
|
rhs.force(self)?;
|
||||||
stack.push(match op {
|
stack.push(match op {
|
||||||
@@ -147,7 +144,7 @@ impl VM {
|
|||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
OpCode::ConcatString => {
|
OpCode::ConcatString => {
|
||||||
let mut rhs = stack.pop()?;
|
let mut rhs = stack.pop();
|
||||||
rhs.force(self)?;
|
rhs.force(self)?;
|
||||||
stack.tos_mut()?.concat_string(rhs);
|
stack.tos_mut()?.concat_string(rhs);
|
||||||
}
|
}
|
||||||
@@ -158,7 +155,7 @@ impl VM {
|
|||||||
stack.push(Value::List(List::empty()))?;
|
stack.push(Value::List(List::empty()))?;
|
||||||
}
|
}
|
||||||
OpCode::PushElem => {
|
OpCode::PushElem => {
|
||||||
let elem = stack.pop()?;
|
let elem = stack.pop();
|
||||||
stack.tos_mut()?.push(elem);
|
stack.tos_mut()?.push(elem);
|
||||||
}
|
}
|
||||||
OpCode::AttrSet => {
|
OpCode::AttrSet => {
|
||||||
@@ -169,13 +166,13 @@ impl VM {
|
|||||||
stack.push(Value::RecAttrSet(RecAttrSet::new(new)))?;
|
stack.push(Value::RecAttrSet(RecAttrSet::new(new)))?;
|
||||||
}
|
}
|
||||||
OpCode::PushStaticAttr { name } => {
|
OpCode::PushStaticAttr { name } => {
|
||||||
let val = stack.pop()?;
|
let val = stack.pop();
|
||||||
stack.tos_mut()?.push_attr(Symbol::new(name), val);
|
stack.tos_mut()?.push_attr(Symbol::new(name), val);
|
||||||
}
|
}
|
||||||
OpCode::PushDynamicAttr => {
|
OpCode::PushDynamicAttr => {
|
||||||
let val = stack.pop()?;
|
let val = stack.pop();
|
||||||
let mut sym = stack.pop().unwrap();
|
let mut sym = stack.pop();
|
||||||
sym.coerce_to_string();
|
sym.force(self)?.coerce_to_string();
|
||||||
let sym = sym.unwrap_const().unwrap_string().into();
|
let sym = sym.unwrap_const().unwrap_string().into();
|
||||||
stack.tos_mut()?.push_attr(sym, val);
|
stack.tos_mut()?.push_attr(sym, val);
|
||||||
}
|
}
|
||||||
@@ -183,22 +180,22 @@ impl VM {
|
|||||||
stack.tos_mut()?.force(self)?.select(Symbol::new(sym));
|
stack.tos_mut()?.force(self)?.select(Symbol::new(sym));
|
||||||
}
|
}
|
||||||
OpCode::SelectOrDefault { sym } => {
|
OpCode::SelectOrDefault { sym } => {
|
||||||
let default = stack.pop()?;
|
let default = stack.pop();
|
||||||
stack
|
stack
|
||||||
.tos_mut()?
|
.tos_mut()?
|
||||||
.force(self)?
|
.force(self)?
|
||||||
.select_with_default(Symbol::new(sym), default);
|
.select_with_default(Symbol::new(sym), default);
|
||||||
}
|
}
|
||||||
OpCode::SelectDynamic => {
|
OpCode::SelectDynamic => {
|
||||||
let mut val = stack.pop().unwrap();
|
let mut val = stack.pop();
|
||||||
val.force(self)?;
|
val.force(self)?;
|
||||||
val.coerce_to_string();
|
val.coerce_to_string();
|
||||||
let sym = val.unwrap_const().unwrap_string().into();
|
let sym = val.unwrap_const().unwrap_string().into();
|
||||||
stack.tos_mut()?.force(self)?.select(sym);
|
stack.tos_mut()?.force(self)?.select(sym);
|
||||||
}
|
}
|
||||||
OpCode::SelectDynamicOrDefault => {
|
OpCode::SelectDynamicOrDefault => {
|
||||||
let default = stack.pop()?;
|
let default = stack.pop();
|
||||||
let mut val = stack.pop().unwrap();
|
let mut val = stack.pop();
|
||||||
val.force(self)?;
|
val.force(self)?;
|
||||||
val.coerce_to_string();
|
val.coerce_to_string();
|
||||||
let sym = val.unwrap_const().unwrap_string().into();
|
let sym = val.unwrap_const().unwrap_string().into();
|
||||||
@@ -211,7 +208,7 @@ impl VM {
|
|||||||
stack.tos_mut()?.force(self)?.has_attr(Symbol::new(sym));
|
stack.tos_mut()?.force(self)?.has_attr(Symbol::new(sym));
|
||||||
}
|
}
|
||||||
OpCode::HasDynamicAttr => {
|
OpCode::HasDynamicAttr => {
|
||||||
let mut val = stack.pop().unwrap();
|
let mut val = stack.pop();
|
||||||
val.coerce_to_string();
|
val.coerce_to_string();
|
||||||
let sym = val.unwrap_const().unwrap_string().into();
|
let sym = val.unwrap_const().unwrap_string().into();
|
||||||
stack.tos_mut()?.force(self)?.has_attr(sym);
|
stack.tos_mut()?.force(self)?.has_attr(sym);
|
||||||
@@ -219,10 +216,10 @@ impl VM {
|
|||||||
OpCode::LookUp { sym } => {
|
OpCode::LookUp { sym } => {
|
||||||
stack.push(
|
stack.push(
|
||||||
env.lookup(Symbol::new(sym.clone()))
|
env.lookup(Symbol::new(sym.clone()))
|
||||||
.ok_or(anyhow!(r#""{sym}" not found"#))?,
|
.ok_or(Error::EvalError(format!(r#""{sym}" not found"#)))?,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
OpCode::EnterEnv => match stack.pop()? {
|
OpCode::EnterEnv => match stack.pop() {
|
||||||
Value::AttrSet(attrs) => env.enter(attrs.into_inner()),
|
Value::AttrSet(attrs) => env.enter(attrs.into_inner()),
|
||||||
Value::RecAttrSet(attrs) => env.enter(attrs.into_inner()),
|
Value::RecAttrSet(attrs) => env.enter(attrs.into_inner()),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
@@ -231,7 +228,7 @@ impl VM {
|
|||||||
env.leave();
|
env.leave();
|
||||||
}
|
}
|
||||||
OpCode::Assert => {
|
OpCode::Assert => {
|
||||||
if !stack.pop()?.unwrap_const().unwrap_bool() {
|
if !stack.pop().unwrap_const().unwrap_bool() {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user