diff --git a/interpreter/src/ir/lower.rs b/interpreter/src/ir/lower.rs index 73a601d..1732ba7 100644 --- a/interpreter/src/ir/lower.rs +++ b/interpreter/src/ir/lower.rs @@ -3,7 +3,7 @@ // For the full copyright and license information, please view the LICENSE // files that was distributed with this source code. -use std::mem::forget; +use std::{borrow::Cow, mem::forget}; use bumpalo::{Bump, collections::Vec}; use parser::{ @@ -38,7 +38,7 @@ pub enum ValueContext { Array, } -impl Code<'_> { +impl<'a> Code<'a> { fn lower_body(&mut self, body: &Body) { for stmnt in &body.0 { self.lower_statement(stmnt); @@ -123,6 +123,43 @@ impl Code<'_> { )); return Hint::UnboxedFloat64; } + atom @ (Atom::String(s) | Atom::TypedRegex(s)) => { + let val = if matches!(atom, Atom::String(_)) { + Value::String + } else { + Value::Regex + }; + let src = self.register_const(val(Cow::Borrowed( + self.arena.alloc_slice_copy(s.as_ref()), + ))); + self.bc.emit(Instruction::load_store( + OpCode::LoadConst, + dest, + src, + ValueContext::Scalar, + )); + } + Atom::Regex(r) => { + let src = self.register_const(Value::Regex(Cow::Borrowed( + self.arena.alloc_slice_copy(r.as_ref()), + ))); + self.bc.emit(Instruction::load_store( + OpCode::LoadConst, + dest, + src, + ValueContext::Scalar, + )); + let dest = LinearReg(dest, Hint::None); + let rec = self.lower_expr(&Expr::Leaf(Atom::Number(0.)), ctx); + self.bc.emit(Instruction::binary( + OpCode::Matches, + dest.reg(), + &rec, + &dest, + )); + forget(dest); + self.free_reg(rec); + } _ => todo!(), }, Expr::Node(node) => match node.as_ref() { @@ -190,7 +227,7 @@ impl Code<'_> { self.free_regs.push(reg.into_inner()); } - fn register_const(&mut self, value: Value) -> NonLocal { + fn register_const(&mut self, value: Value<'a>) -> NonLocal { NonLocal(self.consts.0.insert_full(value).0 as u16) } diff --git a/interpreter/src/types.rs b/interpreter/src/types.rs index d4782ea..b61a5b7 100644 --- a/interpreter/src/types.rs +++ b/interpreter/src/types.rs @@ -1,4 +1,5 @@ use std::{ + borrow::Cow, hash::Hash, mem::discriminant, ops::{Add, Div, Mul, Sub}, @@ -8,16 +9,17 @@ use ahash::RandomState; use hashbrown::HashMap; #[derive(Debug, Clone, PartialEq)] -pub enum Value { +pub enum Value<'a> { Float(f64), - String(Vec), + String(Cow<'a, [u8]>), + Regex(Cow<'a, [u8]>), Array(HashMap), Bool(bool), Untyped, Unassigned, } -impl Value { +impl Value<'_> { /// Called when loading a variable's value. Forces subsequent uses to be /// typed as an AWK scalar (anything that's not an array, basically). pub fn scalar_context(&mut self) -> &mut Self { @@ -62,32 +64,32 @@ impl Value { } } -impl Add for &'_ Value { - type Output = Value; +impl<'a> Add for &'_ Value<'a> { + type Output = Value<'a>; fn add(self, rhs: Self) -> Self::Output { Value::Float(self.to_num() + rhs.to_num()) } } -impl Sub for &'_ Value { - type Output = Value; +impl<'a> Sub for &'_ Value<'a> { + type Output = Value<'a>; fn sub(self, rhs: Self) -> Self::Output { Value::Float(self.to_num() - rhs.to_num()) } } -impl Mul for &'_ Value { - type Output = Value; +impl<'a> Mul for &'_ Value<'a> { + type Output = Value<'a>; fn mul(self, rhs: Self) -> Self::Output { Value::Float(self.to_num() * rhs.to_num()) } } -impl Div for &'_ Value { - type Output = Value; +impl<'a> Div for &'_ Value<'a> { + type Output = Value<'a>; fn div(self, rhs: Self) -> Self::Output { // TODO: panic "nicely" on div by zero. @@ -95,8 +97,8 @@ impl Div for &'_ Value { } } -impl Eq for Value {} -impl Hash for Value { +impl Eq for Value<'_> {} +impl Hash for Value<'_> { fn hash(&self, state: &mut H) { discriminant(self).hash(state); match self { diff --git a/interpreter/src/vm.rs b/interpreter/src/vm.rs index 353a3a0..fee5280 100644 --- a/interpreter/src/vm.rs +++ b/interpreter/src/vm.rs @@ -36,18 +36,18 @@ pub struct Interpreter<'a> { } #[derive(Debug)] -pub struct Registers<'a>(Vec<'a, Value>); +pub struct Registers<'a>(Vec<'a, Value<'a>>); #[derive(Debug)] pub struct SymbolTable<'a> { - user: IndexMap, Value, RandomState, &'a Bump>, + user: IndexMap, Value<'a>, RandomState, &'a Bump>, // separate table for cheap invalidation. It's an arena _visibly shrugs_. - records: HashMap, + records: HashMap, RandomState, &'a Bump>, // etc } #[derive(Debug)] -pub struct Consts<'a>(pub IndexSet); +pub struct Consts<'a>(pub IndexSet, RandomState, &'a Bump>); impl<'a> Interpreter<'a> { pub fn new(compat: ExecMode, code: Code<'a>) -> Self { @@ -71,7 +71,7 @@ impl<'a> SymbolTable<'a> { } } - fn lookup_user_var(&mut self, var: NonLocal, ctx: ValueContext) -> &Value { + fn lookup_user_var(&mut self, var: NonLocal, ctx: ValueContext) -> &Value<'a> { let v = self.user.get_index_mut(var.0 as _).unwrap().1; match ctx { ValueContext::Untyped => v, @@ -80,7 +80,7 @@ impl<'a> SymbolTable<'a> { } } - fn write_user_val(&mut self, var: NonLocal, value: Value) { + fn write_user_val(&mut self, var: NonLocal, value: Value<'a>) { *self.user.get_index_mut(var.0 as _).unwrap().1 = value; } @@ -109,30 +109,31 @@ impl Interpreter<'_> { match instr { // ix if let Some(&(dest, src)) = ix.get_unary() => {} ix if let Some(&(dest, lhs, rhs)) = ix.get_binary() => { - let lhs = self.registers.get(lhs); - let rhs = self.registers.get(rhs); - let val = match ix.opcode { - OpCode::Add => lhs + rhs, - OpCode::Subtract => lhs - rhs, - OpCode::Multiply => lhs * rhs, - OpCode::Divide => lhs / rhs, - _ => todo!(), + let val = { + let lhs = self.registers.get(lhs); + let rhs = self.registers.get(rhs); + match ix.opcode { + OpCode::Add => lhs + rhs, + OpCode::Subtract => lhs - rhs, + OpCode::Multiply => lhs * rhs, + OpCode::Divide => lhs / rhs, + _ => todo!(), + } }; self.registers.write(dest, val); } ix if let Some(&(dest, src)) = ix.get_load_store() => match ix.opcode { - OpCode::LoadConst => self - .registers - .write(dest, self.consts.0.get_index(src.0 as _).unwrap().clone()), + OpCode::LoadConst => { + let val = self.consts.0.get_index(src.0 as _).unwrap().clone(); + self.registers.write(dest, val); + } OpCode::LoadUser => { - self.registers.write( - dest, - self.symbols.lookup_user_var(src, ix.hint.into()).clone(), - ); + let val = self.symbols.lookup_user_var(src, ix.hint.into()).clone(); + self.registers.write(dest, val); } OpCode::StoreUser => { - self.symbols - .write_user_val(src, self.registers.get(dest).clone()); + let val = self.registers.get(dest).clone(); + self.symbols.write_user_val(src, val); } _ => todo!(), }, @@ -157,18 +158,18 @@ impl Interpreter<'_> { } } -impl Registers<'_> { - fn replace(&mut self, src: Reg, f: impl FnOnce(Value) -> Value) { +impl<'a> Registers<'a> { + fn replace(&mut self, src: Reg, f: impl FnOnce(Value<'a>) -> Value<'a>) { let val = replace(self.get_mut(src), Value::Untyped); self.write(src, f(val)); } - fn get(&self, src: Reg) -> &Value { + fn get(&self, src: Reg) -> &Value<'a> { &self.0[src.0 as usize] } - fn get_mut(&mut self, src: Reg) -> &mut Value { + fn get_mut(&mut self, src: Reg) -> &mut Value<'a> { &mut self.0[src.0 as usize] } - fn write(&mut self, dest: Reg, src: Value) { + fn write(&mut self, dest: Reg, src: Value<'a>) { self.0[dest.0 as usize] = src; } }