mirror of
https://github.com/uutils/awk.git
synced 2026-06-10 16:15:04 -07:00
interpreter: strings & regexes support
This commit is contained in:
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
+15
-13
@@ -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<u8>),
|
||||
String(Cow<'a, [u8]>),
|
||||
Regex(Cow<'a, [u8]>),
|
||||
Array(HashMap<String, Self, RandomState>),
|
||||
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<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
discriminant(self).hash(state);
|
||||
match self {
|
||||
|
||||
+29
-28
@@ -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<Identifier<'a>, Value, RandomState, &'a Bump>,
|
||||
user: IndexMap<Identifier<'a>, Value<'a>, RandomState, &'a Bump>,
|
||||
// separate table for cheap invalidation. It's an arena _visibly shrugs_.
|
||||
records: HashMap<usize, Value, RandomState, &'a Bump>,
|
||||
records: HashMap<usize, Value<'a>, RandomState, &'a Bump>,
|
||||
// etc
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Consts<'a>(pub IndexSet<Value, RandomState, &'a Bump>);
|
||||
pub struct Consts<'a>(pub IndexSet<Value<'a>, 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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user