feat: less clone on symbol
This commit is contained in:
@@ -1,14 +1,13 @@
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::ty::common::Symbol;
|
|
||||||
use crate::ty::internal::{_Thunk, Const, PrimOp, RecAttrSet, Thunk, Value};
|
use crate::ty::internal::{_Thunk, Const, PrimOp, RecAttrSet, Thunk, Value};
|
||||||
use crate::vm::Env;
|
use crate::vm::{Env, VM};
|
||||||
|
|
||||||
pub fn env<'vm>() -> Rc<Env<'vm>> {
|
pub fn env<'vm>(vm: &'vm VM) -> Rc<Env<'vm>> {
|
||||||
let env = Rc::new(Env::empty());
|
let env = Rc::new(Env::empty());
|
||||||
env.insert(Symbol::from("true"), Value::Const(Const::Bool(true)));
|
env.insert(vm.new_sym("true"), Value::Const(Const::Bool(true)));
|
||||||
env.insert(Symbol::from("false"), Value::Const(Const::Bool(false)));
|
env.insert(vm.new_sym("false"), Value::Const(Const::Bool(false)));
|
||||||
|
|
||||||
let primops = [
|
let primops = [
|
||||||
PrimOp::new("add", 2, |_, args| {
|
PrimOp::new("add", 2, |_, args| {
|
||||||
@@ -47,17 +46,17 @@ pub fn env<'vm>() -> Rc<Env<'vm>> {
|
|||||||
let map = builtins_env.clone().new_rec();
|
let map = builtins_env.clone().new_rec();
|
||||||
for primop in primops {
|
for primop in primops {
|
||||||
env.insert(
|
env.insert(
|
||||||
Symbol::from(format!("__{}", primop.name)),
|
vm.new_sym(format!("__{}", primop.name)),
|
||||||
Value::PrimOp(primop.clone()),
|
Value::PrimOp(primop.clone()),
|
||||||
);
|
);
|
||||||
map.insert(Symbol::from(primop.name), Value::PrimOp(primop));
|
map.insert(vm.new_sym(primop.name), Value::PrimOp(primop));
|
||||||
}
|
}
|
||||||
let builtins = Value::RecAttrSet(RecAttrSet::from_inner(map.clone()));
|
let builtins = Value::RecAttrSet(RecAttrSet::from_inner(map.clone()));
|
||||||
let thunk = Thunk {
|
let thunk = Thunk {
|
||||||
thunk: Rc::new(RefCell::new(_Thunk::Value(Box::new(builtins.clone())))),
|
thunk: Rc::new(RefCell::new(_Thunk::Value(Box::new(builtins.clone())))),
|
||||||
};
|
};
|
||||||
map.insert(Symbol::from("builtins"), Value::Thunk(thunk));
|
map.insert(vm.new_sym("builtins"), Value::Thunk(thunk));
|
||||||
|
|
||||||
env.insert(Symbol::from("builtins"), builtins);
|
env.insert(vm.new_sym("builtins"), builtins);
|
||||||
env
|
env
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use ecow::EcoString;
|
use ecow::EcoString;
|
||||||
|
|
||||||
use crate::ty::internal::{Const, Param};
|
use crate::ty::internal::{Const, Param};
|
||||||
@@ -11,10 +13,10 @@ pub enum OpCode {
|
|||||||
/// load a constant onto stack
|
/// load a constant onto stack
|
||||||
Const { value: Const },
|
Const { value: Const },
|
||||||
/// load a dynamic var onto stack
|
/// load a dynamic var onto stack
|
||||||
LookUp { sym: EcoString },
|
LookUp { sym: usize },
|
||||||
/// load a thunk lazily onto stack
|
/// load a thunk lazily onto stack
|
||||||
LoadThunk { idx: usize },
|
LoadThunk { idx: usize },
|
||||||
/// TODO:
|
/// let TOS capture current environment
|
||||||
CaptureEnv,
|
CaptureEnv,
|
||||||
/// force TOS to value
|
/// force TOS to value
|
||||||
ForceValue,
|
ForceValue,
|
||||||
@@ -40,7 +42,7 @@ pub enum OpCode {
|
|||||||
/// finalize the recursive attribute set at TOS
|
/// finalize the recursive attribute set at TOS
|
||||||
FinalizeRec,
|
FinalizeRec,
|
||||||
/// [ .. set value ] consume 1 element, push a static kv pair (`name`, `value`) into `set`
|
/// [ .. set value ] consume 1 element, push a static kv pair (`name`, `value`) into `set`
|
||||||
PushStaticAttr { name: EcoString },
|
PushStaticAttr { name: usize },
|
||||||
/// [ .. set name value ] consume 2 elements, push a dynamic kv pair (`name`, `value`) in to `set`
|
/// [ .. set name value ] consume 2 elements, push a dynamic kv pair (`name`, `value`) in to `set`
|
||||||
PushDynamicAttr,
|
PushDynamicAttr,
|
||||||
|
|
||||||
@@ -59,13 +61,13 @@ pub enum OpCode {
|
|||||||
/// [ .. a ] consume 1 element, perform a unary operation `op` `a`
|
/// [ .. a ] consume 1 element, perform a unary operation `op` `a`
|
||||||
UnOp { op: UnOp },
|
UnOp { op: UnOp },
|
||||||
/// set TOS to the bool value of whether TOS contains `sym`
|
/// set TOS to the bool value of whether TOS contains `sym`
|
||||||
HasAttr { sym: EcoString },
|
HasAttr { sym: usize },
|
||||||
/// [ .. set sym ] consume 2 elements, set TOS to the bool value of whether `set` contains `sym`
|
/// [ .. set sym ] consume 2 elements, set TOS to the bool value of whether `set` contains `sym`
|
||||||
HasDynamicAttr,
|
HasDynamicAttr,
|
||||||
/// [ .. set ] select `sym` from `set`
|
/// [ .. set ] select `sym` from `set`
|
||||||
Select { sym: EcoString },
|
Select { sym: usize },
|
||||||
/// [ .. set default ] select `sym` from `set` or `default`
|
/// [ .. set default ] select `sym` from `set` or `default`
|
||||||
SelectOrDefault { sym: EcoString },
|
SelectOrDefault { sym: usize },
|
||||||
/// [ .. set sym ] select `sym` from `set`
|
/// [ .. set sym ] select `sym` from `set`
|
||||||
SelectDynamic,
|
SelectDynamic,
|
||||||
/// [ .. set sym default ] select `sym` from `set` or `default`
|
/// [ .. set sym default ] select `sym` from `set` or `default`
|
||||||
@@ -82,15 +84,20 @@ pub enum OpCode {
|
|||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum BinOp {
|
pub enum BinOp {
|
||||||
Add,
|
Add,
|
||||||
|
Sub,
|
||||||
|
Mul,
|
||||||
|
Div,
|
||||||
And,
|
And,
|
||||||
Or,
|
Or,
|
||||||
Eq,
|
Eq,
|
||||||
|
Lt,
|
||||||
Con,
|
Con,
|
||||||
Upd,
|
Upd,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum UnOp {
|
pub enum UnOp {
|
||||||
|
Neg,
|
||||||
Not,
|
Not,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,4 +112,6 @@ pub struct Program {
|
|||||||
pub top_level: OpCodes,
|
pub top_level: OpCodes,
|
||||||
pub thunks: Slice<OpCodes>,
|
pub thunks: Slice<OpCodes>,
|
||||||
pub funcs: Slice<Func>,
|
pub funcs: Slice<Func>,
|
||||||
|
pub symbols: Vec<EcoString>,
|
||||||
|
pub symmap: HashMap<EcoString, usize>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ pub fn compile(downgraded: ir::Downgraded) -> Program {
|
|||||||
opcodes: Compiler::new().compile(*func.body),
|
opcodes: Compiler::new().compile(*func.body),
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
|
symbols: downgraded.symbols,
|
||||||
|
symmap: downgraded.symmap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,14 +134,8 @@ impl Compile for ir::UnOp {
|
|||||||
use ir::UnOpKind::*;
|
use ir::UnOpKind::*;
|
||||||
match self.kind {
|
match self.kind {
|
||||||
Neg => {
|
Neg => {
|
||||||
comp.push(OpCode::LookUp {
|
|
||||||
sym: "__sub".into(),
|
|
||||||
});
|
|
||||||
comp.push(OpCode::Const {
|
|
||||||
value: Const::Int(0),
|
|
||||||
});
|
|
||||||
self.rhs.compile(comp);
|
self.rhs.compile(comp);
|
||||||
comp.push(OpCode::Call { arity: 2 });
|
comp.push(OpCode::UnOp { op: UnOp::Neg });
|
||||||
}
|
}
|
||||||
Not => {
|
Not => {
|
||||||
self.rhs.compile(comp);
|
self.rhs.compile(comp);
|
||||||
@@ -159,20 +155,14 @@ impl Compile for ir::BinOp {
|
|||||||
comp.push(OpCode::BinOp { op: BinOp::Add });
|
comp.push(OpCode::BinOp { op: BinOp::Add });
|
||||||
}
|
}
|
||||||
Mul => {
|
Mul => {
|
||||||
comp.push(OpCode::LookUp {
|
|
||||||
sym: "__mul".into(),
|
|
||||||
});
|
|
||||||
self.lhs.compile(comp);
|
self.lhs.compile(comp);
|
||||||
self.rhs.compile(comp);
|
self.rhs.compile(comp);
|
||||||
comp.push(OpCode::Call { arity: 2 });
|
comp.push(OpCode::BinOp { op: BinOp::Mul });
|
||||||
}
|
}
|
||||||
Div => {
|
Div => {
|
||||||
comp.push(OpCode::LookUp {
|
|
||||||
sym: "__div".into(),
|
|
||||||
});
|
|
||||||
self.lhs.compile(comp);
|
self.lhs.compile(comp);
|
||||||
self.rhs.compile(comp);
|
self.rhs.compile(comp);
|
||||||
comp.push(OpCode::Call { arity: 2 });
|
comp.push(OpCode::BinOp { op: BinOp::Div });
|
||||||
}
|
}
|
||||||
And => {
|
And => {
|
||||||
self.lhs.compile(comp);
|
self.lhs.compile(comp);
|
||||||
@@ -190,12 +180,9 @@ impl Compile for ir::BinOp {
|
|||||||
comp.push(OpCode::BinOp { op: BinOp::Eq });
|
comp.push(OpCode::BinOp { op: BinOp::Eq });
|
||||||
}
|
}
|
||||||
Lt => {
|
Lt => {
|
||||||
comp.push(OpCode::LookUp {
|
|
||||||
sym: "__lessThan".into(),
|
|
||||||
});
|
|
||||||
self.lhs.compile(comp);
|
self.lhs.compile(comp);
|
||||||
self.rhs.compile(comp);
|
self.rhs.compile(comp);
|
||||||
comp.push(OpCode::Call { arity: 2 });
|
comp.push(OpCode::BinOp { op: BinOp::Lt });
|
||||||
}
|
}
|
||||||
Con => {
|
Con => {
|
||||||
self.lhs.compile(comp);
|
self.lhs.compile(comp);
|
||||||
@@ -209,12 +196,9 @@ impl Compile for ir::BinOp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Sub => {
|
Sub => {
|
||||||
comp.push(OpCode::LookUp {
|
|
||||||
sym: "__sub".into(),
|
|
||||||
});
|
|
||||||
self.lhs.compile(comp);
|
self.lhs.compile(comp);
|
||||||
self.rhs.compile(comp);
|
self.rhs.compile(comp);
|
||||||
comp.push(OpCode::Call { arity: 2 });
|
comp.push(OpCode::BinOp { op: BinOp::Sub });
|
||||||
}
|
}
|
||||||
Impl => {
|
Impl => {
|
||||||
self.lhs.compile(comp);
|
self.lhs.compile(comp);
|
||||||
@@ -229,29 +213,20 @@ impl Compile for ir::BinOp {
|
|||||||
comp.push(OpCode::UnOp { op: UnOp::Not });
|
comp.push(OpCode::UnOp { op: UnOp::Not });
|
||||||
}
|
}
|
||||||
Gt => {
|
Gt => {
|
||||||
comp.push(OpCode::LookUp {
|
|
||||||
sym: "__lessThan".into(),
|
|
||||||
});
|
|
||||||
self.rhs.compile(comp);
|
self.rhs.compile(comp);
|
||||||
self.lhs.compile(comp);
|
self.lhs.compile(comp);
|
||||||
comp.push(OpCode::Call { arity: 2 });
|
comp.push(OpCode::BinOp { op: BinOp::Lt });
|
||||||
}
|
}
|
||||||
Leq => {
|
Leq => {
|
||||||
comp.push(OpCode::LookUp {
|
|
||||||
sym: "__lessThan".into(),
|
|
||||||
});
|
|
||||||
self.rhs.compile(comp);
|
self.rhs.compile(comp);
|
||||||
self.lhs.compile(comp);
|
self.lhs.compile(comp);
|
||||||
comp.push(OpCode::Call { arity: 2 });
|
comp.push(OpCode::BinOp { op: BinOp::Lt });
|
||||||
comp.push(OpCode::UnOp { op: UnOp::Not });
|
comp.push(OpCode::UnOp { op: UnOp::Not });
|
||||||
}
|
}
|
||||||
Geq => {
|
Geq => {
|
||||||
comp.push(OpCode::LookUp {
|
|
||||||
sym: "__lessThan".into(),
|
|
||||||
});
|
|
||||||
self.lhs.compile(comp);
|
self.lhs.compile(comp);
|
||||||
self.rhs.compile(comp);
|
self.rhs.compile(comp);
|
||||||
comp.push(OpCode::Call { arity: 2 });
|
comp.push(OpCode::BinOp { op: BinOp::Lt });
|
||||||
comp.push(OpCode::UnOp { op: UnOp::Not });
|
comp.push(OpCode::UnOp { op: UnOp::Not });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
59
src/ir.rs
59
src/ir.rs
@@ -13,6 +13,8 @@ pub fn downgrade(expr: Expr) -> Result<Downgraded> {
|
|||||||
Ok(Downgraded {
|
Ok(Downgraded {
|
||||||
top_level: ir,
|
top_level: ir,
|
||||||
consts: ctx.consts.into(),
|
consts: ctx.consts.into(),
|
||||||
|
symbols: ctx.symbols,
|
||||||
|
symmap: ctx.symmap,
|
||||||
thunks: ctx.thunks.into(),
|
thunks: ctx.thunks.into(),
|
||||||
funcs: ctx.funcs.into(),
|
funcs: ctx.funcs.into(),
|
||||||
})
|
})
|
||||||
@@ -96,7 +98,7 @@ macro_rules! ir {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ir! {
|
ir! {
|
||||||
Attrs => { stcs: HashMap<EcoString, Ir>, dyns: Vec<DynamicAttrPair>, rec: bool },
|
Attrs => { stcs: HashMap<usize, Ir>, dyns: Vec<DynamicAttrPair>, rec: bool },
|
||||||
List => { items: Vec<Ir> },
|
List => { items: Vec<Ir> },
|
||||||
HasAttr => { lhs: Box<Ir>, rhs: Vec<Attr> },
|
HasAttr => { lhs: Box<Ir>, rhs: Vec<Attr> },
|
||||||
BinOp => { lhs: Box<Ir>, rhs: Box<Ir>, kind: BinOpKind },
|
BinOp => { lhs: Box<Ir>, rhs: Box<Ir>, kind: BinOpKind },
|
||||||
@@ -111,7 +113,7 @@ ir! {
|
|||||||
Assert => { assertion: Box<Ir>, expr: Box<Ir> },
|
Assert => { assertion: Box<Ir>, expr: Box<Ir> },
|
||||||
ConcatStrings => { parts: Vec<Ir> },
|
ConcatStrings => { parts: Vec<Ir> },
|
||||||
Const => { value: i::Const },
|
Const => { value: i::Const },
|
||||||
Var => { sym: EcoString },
|
Var => { sym: usize },
|
||||||
#[derive(Copy)]
|
#[derive(Copy)]
|
||||||
Thunk => { idx: usize },
|
Thunk => { idx: usize },
|
||||||
Path => { expr: Box<Ir> },
|
Path => { expr: Box<Ir> },
|
||||||
@@ -125,11 +127,15 @@ pub struct DowngradeContext {
|
|||||||
thunks: Vec<Ir>,
|
thunks: Vec<Ir>,
|
||||||
funcs: Vec<Func>,
|
funcs: Vec<Func>,
|
||||||
consts: Vec<i::Const>,
|
consts: Vec<i::Const>,
|
||||||
|
symbols: Vec<EcoString>,
|
||||||
|
symmap: HashMap<EcoString, usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Downgraded {
|
pub struct Downgraded {
|
||||||
pub top_level: Ir,
|
pub top_level: Ir,
|
||||||
pub consts: Box<[i::Const]>,
|
pub consts: Box<[i::Const]>,
|
||||||
|
pub symbols: Vec<EcoString>,
|
||||||
|
pub symmap: HashMap<EcoString, usize>,
|
||||||
pub thunks: Box<[Ir]>,
|
pub thunks: Box<[Ir]>,
|
||||||
pub funcs: Box<[Func]>,
|
pub funcs: Box<[Func]>,
|
||||||
}
|
}
|
||||||
@@ -150,6 +156,17 @@ impl DowngradeContext {
|
|||||||
self.funcs.push(func);
|
self.funcs.push(func);
|
||||||
LoadFunc { idx }
|
LoadFunc { idx }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn new_sym(&mut self, sym: impl Into<EcoString>) -> usize {
|
||||||
|
let sym = sym.into();
|
||||||
|
if let Some(&idx) = self.symmap.get(&sym) {
|
||||||
|
idx
|
||||||
|
} else {
|
||||||
|
self.symmap.insert(sym.clone(), self.symbols.len());
|
||||||
|
self.symbols.push(sym);
|
||||||
|
self.symbols.len() - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Attrs {
|
impl Attrs {
|
||||||
@@ -231,7 +248,7 @@ impl Attrs {
|
|||||||
match path.next() {
|
match path.next() {
|
||||||
Some(Attr::Str(ident)) => self
|
Some(Attr::Str(ident)) => self
|
||||||
.stcs
|
.stcs
|
||||||
.get(ident.as_str())
|
.get(ident)
|
||||||
.and_then(|attrs| attrs.downcast_ref())
|
.and_then(|attrs| attrs.downcast_ref())
|
||||||
.map_or(Some(false), |attrs: &Attrs| attrs._has_attr(path, name)),
|
.map_or(Some(false), |attrs: &Attrs| attrs._has_attr(path, name)),
|
||||||
None => match name {
|
None => match name {
|
||||||
@@ -253,7 +270,7 @@ impl Attrs {
|
|||||||
pub enum Attr {
|
pub enum Attr {
|
||||||
Dynamic(Ir),
|
Dynamic(Ir),
|
||||||
Strs(ConcatStrings),
|
Strs(ConcatStrings),
|
||||||
Str(EcoString),
|
Str(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@@ -327,11 +344,11 @@ pub struct Func {
|
|||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Param {
|
pub enum Param {
|
||||||
Ident(EcoString),
|
Ident(usize),
|
||||||
Formals {
|
Formals {
|
||||||
formals: Vec<(EcoString, Option<Thunk>)>,
|
formals: Vec<(usize, Option<Thunk>)>,
|
||||||
ellipsis: bool,
|
ellipsis: bool,
|
||||||
alias: Option<EcoString>,
|
alias: Option<usize>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -460,9 +477,9 @@ impl Downgrade for ast::Literal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Downgrade for ast::Ident {
|
impl Downgrade for ast::Ident {
|
||||||
fn downgrade(self, _ctx: &mut DowngradeContext) -> Result<Ir> {
|
fn downgrade(self, ctx: &mut DowngradeContext) -> Result<Ir> {
|
||||||
Var {
|
Var {
|
||||||
sym: self.to_string().into(),
|
sym: ctx.new_sym(self.to_string()),
|
||||||
}
|
}
|
||||||
.ir()
|
.ir()
|
||||||
.ok()
|
.ok()
|
||||||
@@ -547,7 +564,7 @@ impl Downgrade for ast::LegacyLet {
|
|||||||
let attrs = downgrade_has_entry(self, true, ctx)?;
|
let attrs = downgrade_has_entry(self, true, ctx)?;
|
||||||
Select {
|
Select {
|
||||||
expr: attrs.ir().boxed(),
|
expr: attrs.ir().boxed(),
|
||||||
attrpath: vec![Attr::Str("body".to_string().into())],
|
attrpath: vec![Attr::Str(ctx.new_sym("body".to_string()))],
|
||||||
default: None,
|
default: None,
|
||||||
}
|
}
|
||||||
.ir()
|
.ir()
|
||||||
@@ -603,7 +620,7 @@ impl Downgrade for ast::Apply {
|
|||||||
|
|
||||||
fn downgrade_param(param: ast::Param, ctx: &mut DowngradeContext) -> Result<Param> {
|
fn downgrade_param(param: ast::Param, ctx: &mut DowngradeContext) -> Result<Param> {
|
||||||
match param {
|
match param {
|
||||||
ast::Param::IdentParam(ident) => Ok(Param::Ident(ident.to_string().into())),
|
ast::Param::IdentParam(ident) => Ok(Param::Ident(ctx.new_sym(ident.to_string()))),
|
||||||
ast::Param::Pattern(pattern) => downgrade_pattern(pattern, ctx),
|
ast::Param::Pattern(pattern) => downgrade_pattern(pattern, ctx),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -612,7 +629,7 @@ fn downgrade_pattern(pattern: ast::Pattern, ctx: &mut DowngradeContext) -> Resul
|
|||||||
let formals = pattern
|
let formals = pattern
|
||||||
.pat_entries()
|
.pat_entries()
|
||||||
.map(|entry| {
|
.map(|entry| {
|
||||||
let ident = entry.ident().unwrap().to_string().into();
|
let ident = ctx.new_sym(entry.ident().unwrap().to_string());
|
||||||
if entry.default().is_none() {
|
if entry.default().is_none() {
|
||||||
Ok((ident, None))
|
Ok((ident, None))
|
||||||
} else {
|
} else {
|
||||||
@@ -627,7 +644,7 @@ fn downgrade_pattern(pattern: ast::Pattern, ctx: &mut DowngradeContext) -> Resul
|
|||||||
let ellipsis = pattern.ellipsis_token().is_some();
|
let ellipsis = pattern.ellipsis_token().is_some();
|
||||||
let alias = pattern
|
let alias = pattern
|
||||||
.pat_bind()
|
.pat_bind()
|
||||||
.map(|alias| alias.ident().unwrap().to_string().into());
|
.map(|alias| ctx.new_sym(alias.ident().unwrap().to_string()));
|
||||||
Ok(Param::Formals {
|
Ok(Param::Formals {
|
||||||
formals,
|
formals,
|
||||||
ellipsis,
|
ellipsis,
|
||||||
@@ -659,7 +676,7 @@ fn downgrade_has_entry(
|
|||||||
|
|
||||||
fn downgrade_inherit(
|
fn downgrade_inherit(
|
||||||
inherit: ast::Inherit,
|
inherit: ast::Inherit,
|
||||||
stcs: &mut HashMap<EcoString, Ir>,
|
stcs: &mut HashMap<usize, Ir>,
|
||||||
ctx: &mut DowngradeContext,
|
ctx: &mut DowngradeContext,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let from = if let Some(from) = inherit.from() {
|
let from = if let Some(from) = inherit.from() {
|
||||||
@@ -669,8 +686,8 @@ fn downgrade_inherit(
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
for attr in inherit.attrs() {
|
for attr in inherit.attrs() {
|
||||||
let ident: EcoString = match downgrade_attr(attr, ctx)? {
|
let ident = match downgrade_attr(attr, ctx)? {
|
||||||
Attr::Str(ident) => ident.to_string().into(),
|
Attr::Str(ident) => ctx.new_sym(ident.to_string()),
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::DowngradeError(
|
return Err(Error::DowngradeError(
|
||||||
"dynamic attributes not allowed in inherit".to_string(),
|
"dynamic attributes not allowed in inherit".to_string(),
|
||||||
@@ -678,11 +695,11 @@ fn downgrade_inherit(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
let expr = from.map_or_else(
|
let expr = from.map_or_else(
|
||||||
|| Var { sym: ident.clone() }.ir().ok(),
|
|| Var { sym: ident }.ir().ok(),
|
||||||
|from| {
|
|from| {
|
||||||
Ok(Select {
|
Ok(Select {
|
||||||
expr: from.ir().boxed(),
|
expr: from.ir().boxed(),
|
||||||
attrpath: vec![Attr::Str(ident.clone())],
|
attrpath: vec![Attr::Str(ident)],
|
||||||
default: None,
|
default: None,
|
||||||
}
|
}
|
||||||
.ir())
|
.ir())
|
||||||
@@ -697,14 +714,14 @@ fn downgrade_attr(attr: ast::Attr, ctx: &mut DowngradeContext) -> Result<Attr> {
|
|||||||
use ast::Attr::*;
|
use ast::Attr::*;
|
||||||
use ast::InterpolPart::*;
|
use ast::InterpolPart::*;
|
||||||
match attr {
|
match attr {
|
||||||
Ident(ident) => Ok(Attr::Str(ident.to_string().into())),
|
Ident(ident) => Ok(Attr::Str(ctx.new_sym(ident.to_string()))),
|
||||||
Str(string) => {
|
Str(string) => {
|
||||||
let parts = string.normalized_parts();
|
let parts = string.normalized_parts();
|
||||||
if parts.len() == 0 {
|
if parts.len() == 0 {
|
||||||
Ok(Attr::Str("".into()))
|
Ok(Attr::Str(ctx.new_sym("")))
|
||||||
} else if parts.len() == 1 {
|
} else if parts.len() == 1 {
|
||||||
match parts.into_iter().next().unwrap() {
|
match parts.into_iter().next().unwrap() {
|
||||||
Literal(ident) => Ok(Attr::Str(ident.into())),
|
Literal(ident) => Ok(Attr::Str(ctx.new_sym(ident))),
|
||||||
Interpolation(interpol) => {
|
Interpolation(interpol) => {
|
||||||
Ok(Attr::Dynamic(interpol.expr().unwrap().downgrade(ctx)?))
|
Ok(Attr::Dynamic(interpol.expr().unwrap().downgrade(ctx)?))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
use std::fmt::{Display, Formatter, Result as FmtResult};
|
use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||||
use std::ops::Deref;
|
|
||||||
|
|
||||||
use std::sync::LazyLock;
|
|
||||||
|
|
||||||
use derive_more::Constructor;
|
use derive_more::Constructor;
|
||||||
use ecow::EcoString;
|
|
||||||
use regex::Regex;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Constructor)]
|
#[derive(Clone, Debug, PartialEq, Constructor)]
|
||||||
pub struct Catchable {
|
pub struct Catchable {
|
||||||
@@ -18,46 +14,3 @@ impl Display for Catchable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Constructor)]
|
|
||||||
pub struct Symbol(EcoString);
|
|
||||||
|
|
||||||
impl<T: Into<EcoString>> From<T> for Symbol {
|
|
||||||
fn from(value: T) -> Self {
|
|
||||||
Symbol(value.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Symbol {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
|
||||||
if self.normal() {
|
|
||||||
write!(f, r#""{}""#, self.0)
|
|
||||||
} else {
|
|
||||||
write!(f, "{}", self.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static REGEX: LazyLock<Regex> =
|
|
||||||
LazyLock::new(|| Regex::new(r#"^[a-zA-Z\_][a-zA-Z0-9\_\'\-]*$"#).unwrap());
|
|
||||||
impl Symbol {
|
|
||||||
fn normal(&self) -> bool {
|
|
||||||
!REGEX.is_match(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for Symbol {
|
|
||||||
type Target = str;
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Symbol {
|
|
||||||
pub fn into_inner(self) -> EcoString {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_inner(&self) -> &EcoString {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -5,15 +5,13 @@ use rpds::HashTrieMap;
|
|||||||
|
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::vm::{Env, VM};
|
use crate::vm::{Env, VM};
|
||||||
|
|
||||||
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};
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Constructor, Clone, PartialEq)]
|
#[derive(Debug, Constructor, Clone, PartialEq)]
|
||||||
pub struct AttrSet<'vm> {
|
pub struct AttrSet<'vm> {
|
||||||
data: HashTrieMap<Symbol, Value<'vm>>,
|
data: HashTrieMap<usize, Value<'vm>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'vm> AttrSet<'vm> {
|
impl<'vm> AttrSet<'vm> {
|
||||||
@@ -23,22 +21,22 @@ impl<'vm> AttrSet<'vm> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_attr_force(&mut self, sym: Symbol, val: Value<'vm>) {
|
pub fn push_attr_force(&mut self, sym: usize, val: Value<'vm>) {
|
||||||
self.data.insert_mut(sym, val);
|
self.data.insert_mut(sym, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_attr(&mut self, sym: Symbol, val: Value<'vm>) {
|
pub fn push_attr(&mut self, sym: usize, val: Value<'vm>) {
|
||||||
if self.data.get_mut(&sym).is_some() {
|
if self.data.get_mut(&sym).is_some() {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
self.data.insert_mut(sym, val);
|
self.data.insert_mut(sym, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn select(&self, sym: &Symbol) -> Option<Value<'vm>> {
|
pub fn select(&self, sym: usize) -> Option<Value<'vm>> {
|
||||||
self.data.get(&sym).cloned()
|
self.data.get(&sym).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_attr(&self, sym: &Symbol) -> bool {
|
pub fn has_attr(&self, sym: usize) -> bool {
|
||||||
self.data.get(&sym).is_some()
|
self.data.get(&sym).is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,11 +68,11 @@ impl<'vm> AttrSet<'vm> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_inner(self) -> HashTrieMap<Symbol, Value<'vm>> {
|
pub fn into_inner(self) -> HashTrieMap<usize, Value<'vm>> {
|
||||||
self.data
|
self.data
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_inner(&self) -> &HashTrieMap<Symbol, Value<'vm>> {
|
pub fn as_inner(&self) -> &HashTrieMap<usize, Value<'vm>> {
|
||||||
&self.data
|
&self.data
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,7 +96,7 @@ impl ToPublic for AttrSet<'_> {
|
|||||||
p::Value::AttrSet(p::AttrSet::new(
|
p::Value::AttrSet(p::AttrSet::new(
|
||||||
self.data
|
self.data
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(sym, value)| (sym.clone(), value.clone().to_public(vm)))
|
.map(|(&sym, value)| (vm.get_sym(sym), value.clone().to_public(vm)))
|
||||||
.collect(),
|
.collect(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@@ -116,22 +114,22 @@ impl<'vm> RecAttrSet<'vm> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_attr_force(&mut self, sym: Symbol, val: Value<'vm>) {
|
pub fn push_attr_force(&mut self, sym: usize, val: Value<'vm>) {
|
||||||
self.data.insert(sym, val);
|
self.data.insert(sym, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_attr(&mut self, sym: Symbol, val: Value<'vm>) {
|
pub fn push_attr(&mut self, sym: usize, val: Value<'vm>) {
|
||||||
if self.data.lookup(&sym).is_some() {
|
if self.data.lookup(sym).is_some() {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
self.data.insert(sym, val);
|
self.data.insert(sym, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn select(&self, sym: &Symbol) -> Option<Value<'vm>> {
|
pub fn select(&self, sym: usize) -> Option<Value<'vm>> {
|
||||||
self.data.lookup(sym)
|
self.data.lookup(sym)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_attr(&self, sym: &Symbol) -> bool {
|
pub fn has_attr(&self, sym: usize) -> bool {
|
||||||
self.data.lookup(sym).is_some()
|
self.data.lookup(sym).is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,7 +187,7 @@ impl ToPublic for RecAttrSet<'_> {
|
|||||||
.map
|
.map
|
||||||
.borrow()
|
.borrow()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(sym, value)| (sym.clone(), value.clone().to_public(vm)))
|
.map(|(&sym, value)| (vm.get_sym(sym), value.clone().to_public(vm)))
|
||||||
.collect(),
|
.collect(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use ecow::EcoString;
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use rpds::HashTrieMap;
|
use rpds::HashTrieMap;
|
||||||
use derive_more::Constructor;
|
use derive_more::Constructor;
|
||||||
@@ -13,11 +12,11 @@ use crate::vm::{Env, VM};
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Param {
|
pub enum Param {
|
||||||
Ident(EcoString),
|
Ident(usize),
|
||||||
Formals {
|
Formals {
|
||||||
formals: Vec<(EcoString, Option<usize>)>,
|
formals: Vec<(usize, Option<usize>)>,
|
||||||
ellipsis: bool,
|
ellipsis: bool,
|
||||||
alias: Option<EcoString>,
|
alias: Option<usize>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,7 +68,7 @@ impl<'vm> Func<'vm> {
|
|||||||
&& arg
|
&& arg
|
||||||
.as_inner()
|
.as_inner()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(k, _)| k.as_inner())
|
.map(|(k, _)| k)
|
||||||
.sorted()
|
.sorted()
|
||||||
.ne(formals.iter().map(|(k, _)| k).sorted())
|
.ne(formals.iter().map(|(k, _)| k).sorted())
|
||||||
{
|
{
|
||||||
@@ -78,7 +77,7 @@ impl<'vm> Func<'vm> {
|
|||||||
for (formal, default) in formals {
|
for (formal, default) in formals {
|
||||||
let formal = formal.clone().into();
|
let formal = formal.clone().into();
|
||||||
let arg = arg
|
let arg = arg
|
||||||
.select(&formal)
|
.select(formal)
|
||||||
.or_else(|| default.map(|idx| Value::Thunk(Thunk::new(vm.get_thunk(idx)))))
|
.or_else(|| default.map(|idx| Value::Thunk(Thunk::new(vm.get_thunk(idx)))))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
new.insert_mut(formal, arg);
|
new.insert_mut(formal, arg);
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ use derive_more::{IsVariant, Unwrap};
|
|||||||
use super::common as c;
|
use super::common as c;
|
||||||
use super::public as p;
|
use super::public as p;
|
||||||
|
|
||||||
use c::Symbol;
|
|
||||||
|
|
||||||
use crate::bytecode::OpCodes;
|
use crate::bytecode::OpCodes;
|
||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
use crate::vm::{Env, VM};
|
use crate::vm::{Env, VM};
|
||||||
@@ -285,7 +283,7 @@ impl<'vm> Value<'vm> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_attr(&mut self, sym: Symbol, val: Value<'vm>) -> &mut Self {
|
pub fn push_attr(&mut self, sym: usize, val: Value<'vm>) -> &mut Self {
|
||||||
if let Value::AttrSet(attrs) = self {
|
if let Value::AttrSet(attrs) = self {
|
||||||
attrs.push_attr(sym, val)
|
attrs.push_attr(sym, val)
|
||||||
} else if let Value::RecAttrSet(attrs) = self {
|
} else if let Value::RecAttrSet(attrs) = self {
|
||||||
@@ -309,7 +307,7 @@ impl<'vm> Value<'vm> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn select(&mut self, sym: &Symbol) -> Result<&mut Self> {
|
pub fn select(&mut self, sym: usize) -> Result<&mut Self> {
|
||||||
let val = match self {
|
let val = match self {
|
||||||
Value::AttrSet(attrs) => attrs
|
Value::AttrSet(attrs) => attrs
|
||||||
.select(sym)
|
.select(sym)
|
||||||
@@ -327,7 +325,7 @@ impl<'vm> Value<'vm> {
|
|||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn select_with_default(&mut self, sym: &Symbol, default: Value<'vm>) -> Result<&mut Self> {
|
pub fn select_with_default(&mut self, sym: usize, default: Value<'vm>) -> Result<&mut Self> {
|
||||||
let val = match self {
|
let val = match self {
|
||||||
Value::AttrSet(attrs) => attrs.select(sym).unwrap_or(default),
|
Value::AttrSet(attrs) => attrs.select(sym).unwrap_or(default),
|
||||||
Value::RecAttrSet(attrs) => attrs.select(sym).unwrap_or(default),
|
Value::RecAttrSet(attrs) => attrs.select(sym).unwrap_or(default),
|
||||||
@@ -343,7 +341,7 @@ impl<'vm> Value<'vm> {
|
|||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_attr(&mut self, sym: &Symbol) -> &mut Self {
|
pub fn has_attr(&mut self, sym: usize) -> &mut Self {
|
||||||
if let Value::AttrSet(attrs) = self {
|
if let Value::AttrSet(attrs) = self {
|
||||||
let val = VmConst(Const::Bool(attrs.has_attr(sym)));
|
let val = VmConst(Const::Bool(attrs.has_attr(sym)));
|
||||||
*self = val;
|
*self = val;
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
|
use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
use derive_more::{Constructor, IsVariant, Unwrap};
|
use derive_more::{Constructor, IsVariant, Unwrap};
|
||||||
use rpds::{HashTrieMap, VectorSync};
|
use rpds::{HashTrieMap, VectorSync};
|
||||||
|
use ecow::EcoString;
|
||||||
|
use regex::Regex;
|
||||||
|
|
||||||
use super::common::*;
|
use super::common::*;
|
||||||
|
|
||||||
@@ -9,6 +13,50 @@ mod cnst;
|
|||||||
|
|
||||||
pub use cnst::Const;
|
pub use cnst::Const;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Constructor)]
|
||||||
|
pub struct Symbol(EcoString);
|
||||||
|
|
||||||
|
impl<T: Into<EcoString>> From<T> for Symbol {
|
||||||
|
fn from(value: T) -> Self {
|
||||||
|
Symbol(value.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Symbol {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
|
||||||
|
if self.normal() {
|
||||||
|
write!(f, r#""{}""#, self.0)
|
||||||
|
} else {
|
||||||
|
write!(f, "{}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static REGEX: LazyLock<Regex> =
|
||||||
|
LazyLock::new(|| Regex::new(r#"^[a-zA-Z\_][a-zA-Z0-9\_\'\-]*$"#).unwrap());
|
||||||
|
impl Symbol {
|
||||||
|
fn normal(&self) -> bool {
|
||||||
|
!REGEX.is_match(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for Symbol {
|
||||||
|
type Target = str;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Symbol {
|
||||||
|
pub fn into_inner(self) -> EcoString {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_inner(&self) -> &EcoString {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Constructor, Clone, PartialEq)]
|
#[derive(Constructor, Clone, PartialEq)]
|
||||||
pub struct AttrSet {
|
pub struct AttrSet {
|
||||||
data: HashTrieMap<Symbol, Value>,
|
data: HashTrieMap<Symbol, Value>,
|
||||||
|
|||||||
@@ -3,13 +3,12 @@ use std::rc::Rc;
|
|||||||
|
|
||||||
use rpds::HashTrieMap;
|
use rpds::HashTrieMap;
|
||||||
|
|
||||||
use crate::ty::common::Symbol;
|
|
||||||
use crate::ty::internal::Value;
|
use crate::ty::internal::Value;
|
||||||
|
|
||||||
#[derive(Debug, Default, PartialEq)]
|
#[derive(Debug, Default, PartialEq)]
|
||||||
pub struct Env<'vm> {
|
pub struct Env<'vm> {
|
||||||
last: RefCell<Option<Rc<Env<'vm>>>>,
|
last: RefCell<Option<Rc<Env<'vm>>>>,
|
||||||
pub map: RefCell<HashTrieMap<Symbol, Value<'vm>>>,
|
pub map: RefCell<HashTrieMap<usize, Value<'vm>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for Env<'_> {
|
impl Clone for Env<'_> {
|
||||||
@@ -31,15 +30,15 @@ impl<'vm> Env<'vm> {
|
|||||||
Env::default()
|
Env::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lookup(&self, symbol: &Symbol) -> Option<Value<'vm>> {
|
pub fn lookup(&self, symbol: usize) -> Option<Value<'vm>> {
|
||||||
self.map.borrow().get(symbol).cloned()
|
self.map.borrow().get(&symbol).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert(&self, symbol: Symbol, value: Value<'vm>) {
|
pub fn insert(&self, symbol: usize, value: Value<'vm>) {
|
||||||
self.map.borrow_mut().insert_mut(symbol, value);
|
self.map.borrow_mut().insert_mut(symbol, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enter(&self, new: HashTrieMap<Symbol, Value<'vm>>) {
|
pub fn enter(&self, new: HashTrieMap<usize, Value<'vm>>) {
|
||||||
let mut map = self.map.borrow().clone();
|
let mut map = self.map.borrow().clone();
|
||||||
for (k, v) in new.iter() {
|
for (k, v) in new.iter() {
|
||||||
map.insert_mut(k.clone(), v.clone());
|
map.insert_mut(k.clone(), v.clone());
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
|
use std::cell::RefCell;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::builtins::env;
|
use crate::builtins::env;
|
||||||
use crate::bytecode::{BinOp, OpCode, OpCodes, Program, UnOp, Func as F};
|
use crate::bytecode::{BinOp, OpCode, OpCodes, Program, UnOp, Func as F};
|
||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
use crate::ty::common::Symbol;
|
|
||||||
use crate::ty::internal::*;
|
use crate::ty::internal::*;
|
||||||
use crate::ty::public as p;
|
use crate::ty::public::{self as p, Symbol};
|
||||||
|
|
||||||
use crate::stack::Stack;
|
use crate::stack::Stack;
|
||||||
|
|
||||||
|
use derive_more::Constructor;
|
||||||
|
use ecow::EcoString;
|
||||||
pub use env::Env;
|
pub use env::Env;
|
||||||
pub use jit::JITContext;
|
pub use jit::JITContext;
|
||||||
|
|
||||||
@@ -24,37 +27,47 @@ pub fn run(prog: Program, jit: JITContext<'_>) -> Result<p::Value> {
|
|||||||
let vm = VM::new(
|
let vm = VM::new(
|
||||||
prog.thunks,
|
prog.thunks,
|
||||||
prog.funcs,
|
prog.funcs,
|
||||||
|
RefCell::new(prog.symbols),
|
||||||
|
RefCell::new(prog.symmap),
|
||||||
jit
|
jit
|
||||||
);
|
);
|
||||||
let env = env();
|
let env = env(&vm);
|
||||||
let temp = vm.eval(prog.top_level, env)?;
|
let temp = vm.eval(prog.top_level, env)?;
|
||||||
let temp = temp.to_public(&vm);
|
let temp = temp.to_public(&vm);
|
||||||
Ok(temp)
|
Ok(temp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Constructor)]
|
||||||
pub struct VM<'jit> {
|
pub struct VM<'jit> {
|
||||||
thunks: Box<[OpCodes]>,
|
thunks: Box<[OpCodes]>,
|
||||||
funcs: Box<[F]>,
|
funcs: Box<[F]>,
|
||||||
|
symbols: RefCell<Vec<EcoString>>,
|
||||||
|
symmap: RefCell<HashMap<EcoString, usize>>,
|
||||||
jit: JITContext<'jit>,
|
jit: JITContext<'jit>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'vm, 'jit: 'vm> VM<'jit> {
|
impl<'vm, 'jit: 'vm> VM<'jit> {
|
||||||
fn new(thunks: Box<[OpCodes]>, funcs: Box<[F]>, jit: JITContext<'jit>) -> Self {
|
|
||||||
VM { thunks, funcs, jit }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_thunk(&self, idx: usize) -> &OpCodes {
|
pub fn get_thunk(&self, idx: usize) -> &OpCodes {
|
||||||
// SAFETY: The `idx` is within bounds as `thunks` is initialized with `prog.thunks`
|
&self.thunks[idx]
|
||||||
// and `idx` is expected to be a valid index into this collection.
|
|
||||||
// The lifetime of the returned reference is tied to `&self`.
|
|
||||||
unsafe { &*(&self.thunks[idx] as *const _) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_func(&self, idx: usize) -> &F {
|
pub fn get_func(&self, idx: usize) -> &F {
|
||||||
// SAFETY: The `idx` is within bounds as `funcs` is initialized with `prog.funcs`
|
&self.funcs[idx]
|
||||||
// and `idx` is expected to be a valid index into this collection.
|
}
|
||||||
// The lifetime of the returned reference is tied to `&self`.
|
|
||||||
unsafe { &*(&self.funcs[idx] as *const _) }
|
pub fn get_sym(&self, idx: usize) -> Symbol{
|
||||||
|
self.symbols.borrow()[idx].clone().into()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_sym(&self, sym: impl Into<EcoString>) -> usize {
|
||||||
|
let sym = sym.into();
|
||||||
|
if let Some(&idx) = self.symmap.borrow().get(&sym) {
|
||||||
|
idx
|
||||||
|
} else {
|
||||||
|
self.symmap.borrow_mut().insert(sym.clone(), self.symbols.borrow().len());
|
||||||
|
self.symbols.borrow_mut().push(sym);
|
||||||
|
self.symbols.borrow().len() - 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eval(&'vm self, opcodes: OpCodes, env: Rc<Env<'vm>>) -> Result<Value<'vm>> {
|
pub fn eval(&'vm self, opcodes: OpCodes, env: Rc<Env<'vm>>) -> Result<Value<'vm>> {
|
||||||
@@ -123,6 +136,7 @@ impl<'vm, 'jit: 'vm> VM<'jit> {
|
|||||||
let mut value = stack.pop();
|
let mut value = stack.pop();
|
||||||
value.force(self)?;
|
value.force(self)?;
|
||||||
stack.push(match op {
|
stack.push(match op {
|
||||||
|
Neg => value.neg(),
|
||||||
Not => value.not(),
|
Not => value.not(),
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
@@ -134,9 +148,13 @@ impl<'vm, 'jit: 'vm> VM<'jit> {
|
|||||||
rhs.force(self)?;
|
rhs.force(self)?;
|
||||||
stack.push(match op {
|
stack.push(match op {
|
||||||
Add => lhs.add(rhs),
|
Add => lhs.add(rhs),
|
||||||
|
Sub => lhs.add(rhs.neg()),
|
||||||
|
Mul => lhs.mul(rhs),
|
||||||
|
Div => lhs.div(rhs),
|
||||||
And => lhs.and(rhs),
|
And => lhs.and(rhs),
|
||||||
Or => lhs.or(rhs),
|
Or => lhs.or(rhs),
|
||||||
Eq => lhs.eq(rhs),
|
Eq => lhs.eq(rhs),
|
||||||
|
Lt => lhs.lt(rhs),
|
||||||
Con => lhs.concat(rhs),
|
Con => lhs.concat(rhs),
|
||||||
Upd => lhs.update(rhs),
|
Upd => lhs.update(rhs),
|
||||||
})?;
|
})?;
|
||||||
@@ -169,57 +187,56 @@ impl<'vm, 'jit: 'vm> VM<'jit> {
|
|||||||
}
|
}
|
||||||
OpCode::PushStaticAttr { name } => {
|
OpCode::PushStaticAttr { name } => {
|
||||||
let val = stack.pop();
|
let val = stack.pop();
|
||||||
stack.tos_mut()?.push_attr(Symbol::new(name.clone()), val);
|
stack.tos_mut()?.push_attr(name, val);
|
||||||
}
|
}
|
||||||
OpCode::PushDynamicAttr => {
|
OpCode::PushDynamicAttr => {
|
||||||
let val = stack.pop();
|
let val = stack.pop();
|
||||||
let mut sym = stack.pop();
|
let mut sym = stack.pop();
|
||||||
sym.force(self)?.coerce_to_string();
|
sym.force(self)?.coerce_to_string();
|
||||||
let sym = sym.unwrap_const().unwrap_string().into();
|
let sym = self.new_sym(sym.unwrap_const().unwrap_string());
|
||||||
stack.tos_mut()?.push_attr(sym, val);
|
stack.tos_mut()?.push_attr(sym, val);
|
||||||
}
|
}
|
||||||
OpCode::Select { sym } => {
|
OpCode::Select { sym } => {
|
||||||
stack.tos_mut()?.force(self)?.select(&Symbol::new(sym))?;
|
stack.tos_mut()?.force(self)?.select(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(sym, default)?;
|
||||||
}
|
}
|
||||||
OpCode::SelectDynamic => {
|
OpCode::SelectDynamic => {
|
||||||
let mut val = stack.pop();
|
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 = self.new_sym(val.unwrap_const().unwrap_string());
|
||||||
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();
|
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 = self.new_sym(val.unwrap_const().unwrap_string());
|
||||||
stack
|
stack
|
||||||
.tos_mut()?
|
.tos_mut()?
|
||||||
.force(self)?
|
.force(self)?
|
||||||
.select_with_default(&sym, default)?;
|
.select_with_default(sym, default)?;
|
||||||
}
|
}
|
||||||
OpCode::HasAttr { sym } => {
|
OpCode::HasAttr { sym } => {
|
||||||
stack.tos_mut()?.force(self)?.has_attr(&Symbol::new(sym));
|
stack.tos_mut()?.force(self)?.has_attr(sym);
|
||||||
}
|
}
|
||||||
OpCode::HasDynamicAttr => {
|
OpCode::HasDynamicAttr => {
|
||||||
let mut val = stack.pop();
|
let mut val = stack.pop();
|
||||||
val.coerce_to_string();
|
val.coerce_to_string();
|
||||||
let sym = val.unwrap_const().unwrap_string().into();
|
let sym = self.new_sym(val.unwrap_const().unwrap_string());
|
||||||
stack.tos_mut()?.force(self)?.has_attr(&sym);
|
stack.tos_mut()?.force(self)?.has_attr(sym);
|
||||||
}
|
}
|
||||||
OpCode::LookUp { sym } => {
|
OpCode::LookUp { sym } => {
|
||||||
let sym = Symbol::new(sym);
|
|
||||||
stack.push(
|
stack.push(
|
||||||
env.lookup(&sym)
|
env.lookup(sym)
|
||||||
.ok_or_else(|| Error::EvalError(format!(r#""{sym}" not found"#)))?,
|
.ok_or_else(|| Error::EvalError(format!("{} not found", self.get_sym(sym))))?,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
OpCode::EnterEnv => match stack.pop() {
|
OpCode::EnterEnv => match stack.pop() {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use rpds::{ht_map, vector_sync};
|
|||||||
|
|
||||||
use crate::compile::compile;
|
use crate::compile::compile;
|
||||||
use crate::ir::downgrade;
|
use crate::ir::downgrade;
|
||||||
use crate::ty::common::Symbol;
|
use crate::ty::public::Symbol;
|
||||||
use crate::ty::public::*;
|
use crate::ty::public::*;
|
||||||
use crate::vm::JITContext;
|
use crate::vm::JITContext;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user