do functions work finally maybe

This commit is contained in:
nora 2022-04-24 19:53:58 +02:00
parent ebd3dd8d82
commit 237fb34d97
12 changed files with 132 additions and 86 deletions

3
.rustfmt.toml Normal file
View file

@ -0,0 +1,3 @@
imports_granularity = "Crate"
newline_style = "Unix"
group_imports = "StdExternalCrate"

View file

@ -3,8 +3,7 @@
//! //!
//! All AST nodes are bump allocated into the lifetime `'ast` //! All AST nodes are bump allocated into the lifetime `'ast`
use crate::errors::Span; use crate::{errors::Span, gc::Symbol};
use crate::gc::Symbol;
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
#[cfg_attr(feature = "_debug", derive(dbg_pls::DebugPls))] #[cfg_attr(feature = "_debug", derive(dbg_pls::DebugPls))]

View file

@ -58,11 +58,12 @@
//! //!
//! ``` //! ```
use crate::errors::Span;
use crate::vm::Value;
use bumpalo::collections::Vec;
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Formatter};
use bumpalo::collections::Vec;
use crate::{errors::Span, vm::Value};
/// This struct contains all data for a function. /// This struct contains all data for a function.
pub struct FnBlock<'bc> { pub struct FnBlock<'bc> {
/// The bytecode of the function /// The bytecode of the function
@ -129,9 +130,12 @@ pub enum Instr {
/// Calls the function at the top of the stack, after the parameters /// Calls the function at the top of the stack, after the parameters
Call, Call,
/// Returns from the function, removing that stack frame
Return, Return,
/// Stop the program
Exit,
/// Shrinks the stack by `usize` elements, should always be emitted before backwards jumps /// Shrinks the stack by `usize` elements, should always be emitted before backwards jumps
ShrinkStack(usize), ShrinkStack(usize),
} }

View file

@ -1,18 +1,20 @@
//! The compiler that compiles the AST down to bytecode //! The compiler that compiles the AST down to bytecode
use crate::ast::{ use std::{cell::RefCell, rc::Rc};
Assignment, BinaryOp, BinaryOpKind, Block, Call, CallKind, Declaration, ElsePart, Expr, FnDecl,
Ident, IfStmt, Literal, Program, Stmt, UnaryOp, WhileStmt, use bumpalo::{collections::Vec, Bump};
use crate::{
ast::{
Assignment, BinaryOp, BinaryOpKind, Block, Call, CallKind, Declaration, ElsePart, Expr,
FnDecl, Ident, IfStmt, Literal, Program, Stmt, UnaryOp, WhileStmt,
},
bytecode::{FnBlock, Instr},
errors::{CompilerError, Span},
gc::Symbol,
vm::Value,
HashMap, RtAlloc,
}; };
use crate::bytecode::{FnBlock, Instr};
use crate::errors::{CompilerError, Span};
use crate::gc::Symbol;
use crate::vm::Value;
use crate::{HashMap, RtAlloc};
use bumpalo::collections::Vec;
use bumpalo::Bump;
use std::cell::RefCell;
use std::rc::Rc;
type CResult<T = ()> = Result<T, CompilerError>; type CResult<T = ()> = Result<T, CompilerError>;
@ -119,8 +121,8 @@ impl<'bc, 'gc> Compiler<'bc, 'gc> {
StackChange::Grow, StackChange::Grow,
Span::dummy(), Span::dummy(),
); );
// exit the program. // exit the program. here, we use `exit` instead of `return` because there is no stack frame
self.push_instr(Instr::Return, StackChange::None, Span::dummy()); self.push_instr(Instr::Exit, StackChange::None, Span::dummy());
Ok(()) Ok(())
} }
@ -128,7 +130,7 @@ impl<'bc, 'gc> Compiler<'bc, 'gc> {
// padding for backwards jumps // padding for backwards jumps
self.push_instr(Instr::Nop, StackChange::None, block.span); self.push_instr(Instr::Nop, StackChange::None, block.span);
self.compile_stmts(&block.stmts) self.compile_stmts(block.stmts)
} }
fn compile_stmts(&mut self, stmts: &[Stmt]) -> CResult { fn compile_stmts(&mut self, stmts: &[Stmt]) -> CResult {
@ -222,7 +224,7 @@ impl<'bc, 'gc> Compiler<'bc, 'gc> {
.push(decl.params.len() + CALLCONV_OFFSET_DATA); .push(decl.params.len() + CALLCONV_OFFSET_DATA);
} }
self.compile_stmts(&decl.body.stmts)?; self.compile_stmts(decl.body.stmts)?;
self.push_instr(Instr::PushVal(Value::Null), StackChange::Grow, decl.span); self.push_instr(Instr::PushVal(Value::Null), StackChange::Grow, decl.span);
self.push_instr(Instr::Return, StackChange::None, decl.span); self.push_instr(Instr::Return, StackChange::None, decl.span);
@ -380,7 +382,7 @@ impl<'bc, 'gc> Compiler<'bc, 'gc> {
let next_env = Env::new_inner(self.env.clone(), OuterEnvKind::Block); let next_env = Env::new_inner(self.env.clone(), OuterEnvKind::Block);
self.env = next_env; self.env = next_env;
self.compile_stmts(&block.stmts)?; self.compile_stmts(block.stmts)?;
let outer = self.env.borrow().outer.clone().expect("outer env got lost"); let outer = self.env.borrow().outer.clone().expect("outer env got lost");
self.env = outer; self.env = outer;

View file

@ -2,14 +2,17 @@
//! //!
//! The structure of the GC might change, but for now it's simply a `LinkedList` of `Object`s. //! The structure of the GC might change, but for now it's simply a `LinkedList` of `Object`s.
use crate::vm::Value; use std::{
use crate::{HashMap, HashSet}; collections::LinkedList,
fmt::{Debug, Formatter},
hash::{Hash, Hasher},
ops::Deref,
ptr::NonNull,
};
use dbg_pls::DebugPls; use dbg_pls::DebugPls;
use std::collections::LinkedList;
use std::fmt::{Debug, Formatter}; use crate::{vm::Value, HashMap, HashSet};
use std::hash::{Hash, Hasher};
use std::ops::Deref;
use std::ptr::NonNull;
/// A pointer to a garbage collected value. This pointer *must* always be valid, and a value /// A pointer to a garbage collected value. This pointer *must* always be valid, and a value
/// is only allowed to be freed once no Gc is pointing at it anymore. This is achieved through /// is only allowed to be freed once no Gc is pointing at it anymore. This is achieved through

View file

@ -4,11 +4,13 @@
//! For error handling, there is a single `Error` token, which contains the error. The lexer //! For error handling, there is a single `Error` token, which contains the error. The lexer
//! is an iterator, and can therefore be used without any allocations //! is an iterator, and can therefore be used without any allocations
use crate::errors::{CompilerError, Span}; use std::{iter::Peekable, str::CharIndices};
use crate::gc::Symbol;
use crate::RtAlloc; use crate::{
use std::iter::Peekable; errors::{CompilerError, Span},
use std::str::CharIndices; gc::Symbol,
RtAlloc,
};
/// ///
/// A single token generated from the lexer /// A single token generated from the lexer
@ -360,8 +362,7 @@ fn is_valid_ident_start(char: char) -> bool {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::lex::Lexer; use crate::{lex::Lexer, RtAlloc};
use crate::RtAlloc;
type StdString = std::string::String; type StdString = std::string::String;

View file

@ -1,4 +1,4 @@
#![deny(clippy::disallowed_type)] #![deny(clippy::disallowed_types)]
mod ast; mod ast;
mod bytecode; mod bytecode;
@ -10,14 +10,14 @@ mod parse;
mod util; mod util;
mod vm; mod vm;
use crate::ast::Program;
use crate::gc::RtAlloc;
use std::io::Write; use std::io::Write;
pub use bumpalo::Bump; pub use bumpalo::Bump;
pub use lex::*; pub use lex::*;
pub use parse::*; pub use parse::*;
use crate::{ast::Program, gc::RtAlloc};
#[cfg(not(feature = "fxhash"))] #[cfg(not(feature = "fxhash"))]
#[allow(clippy::disallowed_types)] #[allow(clippy::disallowed_types)]
type HashMap<K, V> = std::collections::HashMap<K, V>; type HashMap<K, V> = std::collections::HashMap<K, V>;
@ -73,8 +73,8 @@ fn process_ast(program: &str, ast: &Program, mut runtime: RtAlloc, cfg: &mut Con
} }
let result = vm::execute(code, runtime, cfg); let result = vm::execute(code, runtime, cfg);
if let Err(result) = result { if let Err(msg) = result {
eprintln!("error: {}", result); eprintln!("error: {msg}");
} }
} }
Err(err) => errors::display_error(program, err), Err(err) => errors::display_error(program, err),

View file

@ -1,6 +1,7 @@
use dilaria::Config;
use std::io; use std::io;
use dilaria::Config;
fn main() { fn main() {
let mut args = std::env::args(); let mut args = std::env::args();

View file

@ -6,13 +6,16 @@
#[cfg(test)] #[cfg(test)]
mod test; mod test;
use crate::ast::*;
use crate::errors::{CompilerError, Span};
use crate::lex::{Token, TokenKind};
use bumpalo::collections::Vec;
use bumpalo::Bump;
use std::iter::Peekable; use std::iter::Peekable;
use bumpalo::{collections::Vec, Bump};
use crate::{
ast::*,
errors::{CompilerError, Span},
lex::{Token, TokenKind},
};
#[derive(Debug)] #[derive(Debug)]
struct Parser<'ast, I> struct Parser<'ast, I>
where where

View file

@ -3,16 +3,17 @@
//! These tests are horrible and break all the time. Never do it like this again. //! These tests are horrible and break all the time. Never do it like this again.
//! That said it's too late to fix it. //! That said it's too late to fix it.
use crate::errors::Span;
use crate::parse::Parser;
use crate::RtAlloc;
use bumpalo::Bump; use bumpalo::Bump;
use prelude::*; use prelude::*;
use crate::{errors::Span, parse::Parser, RtAlloc};
mod prelude { mod prelude {
pub(super) use super::{parser, rt, test_literal_bin_op, test_number_literal, token}; pub(super) use super::{parser, rt, test_literal_bin_op, test_number_literal, token};
pub(super) use crate::ast::{Expr, Stmt}; pub(super) use crate::{
pub(super) use crate::lex::TokenKind::*; ast::{Expr, Stmt},
lex::TokenKind::*,
};
pub type Token = crate::lex::Token; pub type Token = crate::lex::Token;
pub type TokenType = crate::lex::TokenKind; pub type TokenType = crate::lex::TokenKind;
pub(super) use bumpalo::Bump; pub(super) use bumpalo::Bump;
@ -58,9 +59,10 @@ fn test_number_literal<F: FnOnce(Vec<Token>, &Bump) -> Expr>(parser: F) {
} }
mod assignment { mod assignment {
use bumpalo::Bump;
use super::prelude::*; use super::prelude::*;
use crate::parse::test::rt; use crate::parse::test::rt;
use bumpalo::Bump;
fn parse_assignment(tokens: Vec<Token>, alloc: &Bump) -> Stmt { fn parse_assignment(tokens: Vec<Token>, alloc: &Bump) -> Stmt {
let mut parser = parser(tokens, alloc); let mut parser = parser(tokens, alloc);

View file

@ -6,9 +6,10 @@ macro_rules! assert_size {
}; };
} }
pub(crate) use assert_size;
use std::fmt::Display; use std::fmt::Display;
pub(crate) use assert_size;
#[cfg(feature = "_debug")] #[cfg(feature = "_debug")]
pub fn dbg(prefix: impl Display, x: impl dbg_pls::DebugPls) { pub fn dbg(prefix: impl Display, x: impl dbg_pls::DebugPls) {
eprintln!("{prefix}{}", dbg_pls::color(&x)) eprintln!("{prefix}{}", dbg_pls::color(&x))

View file

@ -1,21 +1,36 @@
use crate::bytecode::{FnBlock, Function, Instr}; use std::{
use crate::gc::{Object, RtAlloc, Symbol}; fmt::{Debug, Display, Formatter},
use crate::util; io::{Read, Write},
use crate::Config; };
use std::fmt::{Debug, Display, Formatter};
use std::io::{Read, Write}; use crate::{
bytecode::{FnBlock, Function, Instr},
gc::{Object, RtAlloc, Symbol},
util, Config,
};
type ActualBackingVmError = &'static str;
type VmError = Box<VmErrorInner>;
#[derive(Debug)]
enum VmErrorInner {
Exit,
Error(ActualBackingVmError),
}
type VmError = Box<&'static str>;
type VmResult = Result<(), VmError>; type VmResult = Result<(), VmError>;
// never get bigger than a machine word. // never get bigger than a machine word.
util::assert_size!(VmResult <= std::mem::size_of::<usize>()); util::assert_size!(VmResult <= std::mem::size_of::<usize>());
type PublicVmError = ActualBackingVmError;
pub fn execute<'bc>( pub fn execute<'bc>(
bytecode: &'bc [FnBlock<'bc>], bytecode: &'bc [FnBlock<'bc>],
alloc: RtAlloc, alloc: RtAlloc,
cfg: &mut Config, cfg: &mut Config,
) -> Result<(), VmError> { ) -> Result<(), PublicVmError> {
let mut vm = Vm { let mut vm = Vm {
blocks: bytecode, blocks: bytecode,
current: bytecode.first().ok_or("no bytecode found")?, current: bytecode.first().ok_or("no bytecode found")?,
@ -28,7 +43,13 @@ pub fn execute<'bc>(
step: cfg.step, step: cfg.step,
}; };
vm.execute_function() match vm.execute_function() {
Ok(()) => Ok(()),
Err(boxed) => match *boxed {
VmErrorInner::Exit => Ok(()),
VmErrorInner::Error(err) => Err(err),
},
}
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
@ -109,56 +130,56 @@ impl<'bc> Vm<'bc, '_> {
match val { match val {
Value::Bool(bool) => self.stack.push(Value::Bool(!bool)), Value::Bool(bool) => self.stack.push(Value::Bool(!bool)),
Value::Num(float) => self.stack.push(Value::Num(-float)), Value::Num(float) => self.stack.push(Value::Num(-float)),
_ => return Err(self.type_error()), _ => return Err(err("bad type")),
} }
} }
Instr::BinAdd => self.bin_op(|lhs, rhs| match (lhs, rhs) { Instr::BinAdd => self.bin_op(|lhs, rhs| match (lhs, rhs) {
(Value::Num(a), Value::Num(b)) => Ok(Value::Num(a + b)), (Value::Num(a), Value::Num(b)) => Ok(Value::Num(a + b)),
_ => Err("bad type".into()), _ => Err(err("bad type")),
})?, })?,
Instr::BinSub => self.bin_op(|lhs, rhs| match (lhs, rhs) { Instr::BinSub => self.bin_op(|lhs, rhs| match (lhs, rhs) {
(Value::Num(a), Value::Num(b)) => Ok(Value::Num(a - b)), (Value::Num(a), Value::Num(b)) => Ok(Value::Num(a - b)),
_ => Err("bad type".into()), _ => Err(err("bad type")),
})?, })?,
Instr::BinMul => self.bin_op(|lhs, rhs| match (lhs, rhs) { Instr::BinMul => self.bin_op(|lhs, rhs| match (lhs, rhs) {
(Value::Num(a), Value::Num(b)) => Ok(Value::Num(a * b)), (Value::Num(a), Value::Num(b)) => Ok(Value::Num(a * b)),
_ => Err("bad type".into()), _ => Err(err("bad type")),
})?, })?,
Instr::BinDiv => self.bin_op(|lhs, rhs| match (lhs, rhs) { Instr::BinDiv => self.bin_op(|lhs, rhs| match (lhs, rhs) {
(Value::Num(a), Value::Num(b)) => Ok(Value::Num(a / b)), (Value::Num(a), Value::Num(b)) => Ok(Value::Num(a / b)),
_ => Err("bad type".into()), _ => Err(err("bad type")),
})?, })?,
Instr::BinMod => self.bin_op(|lhs, rhs| match (lhs, rhs) { Instr::BinMod => self.bin_op(|lhs, rhs| match (lhs, rhs) {
(Value::Num(a), Value::Num(b)) => Ok(Value::Num(a % b)), (Value::Num(a), Value::Num(b)) => Ok(Value::Num(a % b)),
_ => Err("bad type".into()), _ => Err(err("bad type")),
})?, })?,
Instr::BinAnd => self.bin_op(|lhs, rhs| match (lhs, rhs) { Instr::BinAnd => self.bin_op(|lhs, rhs| match (lhs, rhs) {
(Value::Bool(a), Value::Bool(b)) => Ok(Value::Bool(a && b)), (Value::Bool(a), Value::Bool(b)) => Ok(Value::Bool(a && b)),
_ => Err("bad type".into()), _ => Err(err("bad type")),
})?, })?,
Instr::BinOr => self.bin_op(|lhs, rhs| match (lhs, rhs) { Instr::BinOr => self.bin_op(|lhs, rhs| match (lhs, rhs) {
(Value::Bool(a), Value::Bool(b)) => Ok(Value::Bool(a || b)), (Value::Bool(a), Value::Bool(b)) => Ok(Value::Bool(a || b)),
_ => Err("bad type".into()), _ => Err(err("bad type")),
})?, })?,
Instr::CmpGreater => self.bin_op(|lhs, rhs| match (lhs, rhs) { Instr::CmpGreater => self.bin_op(|lhs, rhs| match (lhs, rhs) {
(Value::Num(a), Value::Num(b)) => Ok(Value::Bool(a > b)), (Value::Num(a), Value::Num(b)) => Ok(Value::Bool(a > b)),
(Value::String(a), Value::String(b)) => Ok(Value::Bool(a.as_str() > b.as_str())), (Value::String(a), Value::String(b)) => Ok(Value::Bool(a.as_str() > b.as_str())),
_ => Err("bad type".into()), _ => Err(err("bad type")),
})?, })?,
Instr::CmpGreaterEq => self.bin_op(|lhs, rhs| match (lhs, rhs) { Instr::CmpGreaterEq => self.bin_op(|lhs, rhs| match (lhs, rhs) {
(Value::Num(a), Value::Num(b)) => Ok(Value::Bool(a >= b)), (Value::Num(a), Value::Num(b)) => Ok(Value::Bool(a >= b)),
(Value::String(a), Value::String(b)) => Ok(Value::Bool(a.as_str() >= b.as_str())), (Value::String(a), Value::String(b)) => Ok(Value::Bool(a.as_str() >= b.as_str())),
_ => Err("bad type".into()), _ => Err(err("bad type")),
})?, })?,
Instr::CmpLess => self.bin_op(|lhs, rhs| match (lhs, rhs) { Instr::CmpLess => self.bin_op(|lhs, rhs| match (lhs, rhs) {
(Value::Num(a), Value::Num(b)) => Ok(Value::Bool(a < b)), (Value::Num(a), Value::Num(b)) => Ok(Value::Bool(a < b)),
(Value::String(a), Value::String(b)) => Ok(Value::Bool(a.as_str() < b.as_str())), (Value::String(a), Value::String(b)) => Ok(Value::Bool(a.as_str() < b.as_str())),
_ => Err("bad type".into()), _ => Err(err("bad type")),
})?, })?,
Instr::CmpLessEq => self.bin_op(|lhs, rhs| match (lhs, rhs) { Instr::CmpLessEq => self.bin_op(|lhs, rhs| match (lhs, rhs) {
(Value::Num(a), Value::Num(b)) => Ok(Value::Bool(a <= b)), (Value::Num(a), Value::Num(b)) => Ok(Value::Bool(a <= b)),
(Value::String(a), Value::String(b)) => Ok(Value::Bool(a.as_str() <= b.as_str())), (Value::String(a), Value::String(b)) => Ok(Value::Bool(a.as_str() <= b.as_str())),
_ => Err("bad type".into()), _ => Err(err("bad type")),
})?, })?,
Instr::CmpEq => self.bin_op(|lhs, rhs| match (lhs, rhs) { Instr::CmpEq => self.bin_op(|lhs, rhs| match (lhs, rhs) {
(Value::Null, Value::Null) => Ok(TRUE), (Value::Null, Value::Null) => Ok(TRUE),
@ -166,7 +187,7 @@ impl<'bc> Vm<'bc, '_> {
(Value::String(a), Value::String(b)) => Ok(Value::Bool(a == b)), (Value::String(a), Value::String(b)) => Ok(Value::Bool(a == b)),
(Value::Object(_a), Value::Object(_b)) => todo!(), (Value::Object(_a), Value::Object(_b)) => todo!(),
(Value::Array, Value::Array) => Ok(TRUE), (Value::Array, Value::Array) => Ok(TRUE),
_ => Err("bad type".into()), _ => Err(err("bad type")),
})?, })?,
Instr::CmpNotEq => self.bin_op(|lhs, rhs| match (lhs, rhs) { Instr::CmpNotEq => self.bin_op(|lhs, rhs| match (lhs, rhs) {
(Value::Null, Value::Null) => Ok(FALSE), (Value::Null, Value::Null) => Ok(FALSE),
@ -174,23 +195,24 @@ impl<'bc> Vm<'bc, '_> {
(Value::String(a), Value::String(b)) => Ok(Value::Bool(a != b)), (Value::String(a), Value::String(b)) => Ok(Value::Bool(a != b)),
(Value::Object(_a), Value::Object(_b)) => todo!(), (Value::Object(_a), Value::Object(_b)) => todo!(),
(Value::Array, Value::Array) => Ok(FALSE), (Value::Array, Value::Array) => Ok(FALSE),
_ => Err("bad type".into()), _ => Err(err("bad type")),
})?, })?,
Instr::Print => { Instr::Print => {
let val = self.stack.pop().unwrap(); let val = self.stack.pop().unwrap();
writeln!(self.stdout, "{}", val).map_err(|_| "failed to write to stdout")?; writeln!(self.stdout, "{}", val).map_err(|_| err("failed to write to stdout"))?;
} }
Instr::JmpFalse(pos) => { Instr::JmpFalse(pos) => {
let val = self.stack.pop().unwrap(); let val = self.stack.pop().unwrap();
match val { match val {
Value::Bool(false) => self.pc = (self.pc as isize + pos) as usize, Value::Bool(false) => self.pc = (self.pc as isize + pos) as usize,
Value::Bool(true) => {} Value::Bool(true) => {}
_ => return Err("bad type".into()), _ => return Err(err("bad type")),
} }
} }
Instr::Jmp(pos) => self.pc = (self.pc as isize + pos) as usize, Instr::Jmp(pos) => self.pc = (self.pc as isize + pos) as usize,
Instr::Call => self.call()?, Instr::Call => self.call()?,
Instr::Return => self.ret()?, Instr::Return => self.ret()?,
Instr::Exit => return Err(Box::new(VmErrorInner::Exit)),
Instr::ShrinkStack(size) => { Instr::ShrinkStack(size) => {
assert!(self.stack.len() >= size); assert!(self.stack.len() >= size);
let new_len = self.stack.len() - size; let new_len = self.stack.len() - size;
@ -246,6 +268,8 @@ impl<'bc> Vm<'bc, '_> {
let bookkeeping_offset = self.stack_offset + current_arity; let bookkeeping_offset = self.stack_offset + current_arity;
let inner_stack_offset = self.stack_offset;
// now, we get all the bookkeeping info out // now, we get all the bookkeeping info out
let old_stack_offset = self.stack[bookkeeping_offset].unwrap_native_int(); let old_stack_offset = self.stack[bookkeeping_offset].unwrap_native_int();
let old_pc = self.stack[bookkeeping_offset + 1].unwrap_native_int(); let old_pc = self.stack[bookkeeping_offset + 1].unwrap_native_int();
@ -259,15 +283,14 @@ impl<'bc> Vm<'bc, '_> {
// and kill the function stack frame // and kill the function stack frame
// note: don't emit a return instruction from the whole global script. // note: don't emit a return instruction from the whole global script.
todo!(); unsafe { self.stack.set_len(inner_stack_offset) };
// everything that remains...
self.stack.push(return_value);
Ok(()) Ok(())
} }
fn type_error(&self) -> VmError {
"bad type".into()
}
fn step_debug(&self, current_instr: Instr) { fn step_debug(&self, current_instr: Instr) {
let curr_stack_size = self.stack.len(); let curr_stack_size = self.stack.len();
// at this point, we've always incremented the pc already // at this point, we've always incremented the pc already
@ -320,3 +343,7 @@ impl Display for Value {
} }
} }
} }
fn err(msg: &'static str) -> VmError {
Box::new(VmErrorInner::Error(msg))
}