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