2020-01-25 19:35:57 -05:00
|
|
|
use core::fmt;
|
|
|
|
use std::fmt::{Debug, Formatter};
|
2020-01-25 07:05:07 -05:00
|
|
|
use std::ops::{Index, IndexMut};
|
2019-12-25 04:44:51 -05:00
|
|
|
|
2020-07-22 04:57:47 -04:00
|
|
|
use crate::err::{Error, ErrorType, ProcessingResult, debug_repr};
|
2020-01-25 02:04:02 -05:00
|
|
|
use crate::proc::MatchAction::*;
|
|
|
|
use crate::proc::MatchMode::*;
|
2020-01-25 07:05:07 -05:00
|
|
|
use crate::proc::range::ProcessorRange;
|
2020-07-04 06:33:02 -04:00
|
|
|
use memchr::memchr;
|
2020-07-22 04:57:47 -04:00
|
|
|
use crate::gen::codepoints::Lookup;
|
2020-07-21 03:59:56 -04:00
|
|
|
#[cfg(feature = "js-esbuild")]
|
2020-07-21 03:57:39 -04:00
|
|
|
use std::sync::{Arc, Mutex};
|
2020-07-21 03:59:56 -04:00
|
|
|
#[cfg(feature = "js-esbuild")]
|
2020-07-21 03:57:39 -04:00
|
|
|
use esbuild_rs::TransformResult;
|
2020-07-21 03:59:56 -04:00
|
|
|
#[cfg(feature = "js-esbuild")]
|
2020-07-21 03:57:39 -04:00
|
|
|
use crossbeam::sync::WaitGroup;
|
2019-12-25 04:44:51 -05:00
|
|
|
|
2020-01-25 07:05:07 -05:00
|
|
|
pub mod checkpoint;
|
2020-07-04 06:33:02 -04:00
|
|
|
pub mod entity;
|
2020-01-25 07:05:07 -05:00
|
|
|
pub mod range;
|
2020-01-18 06:19:06 -05:00
|
|
|
|
2020-01-26 04:32:06 -05:00
|
|
|
pub enum MatchMode {
|
|
|
|
IsChar(u8),
|
|
|
|
IsNotChar(u8),
|
|
|
|
WhileChar(u8),
|
|
|
|
WhileNotChar(u8),
|
2020-07-11 08:52:27 -04:00
|
|
|
// Through is like WhileNot followed by Is, but matches zero if Is is zero.
|
|
|
|
ThroughChar(u8),
|
2020-01-26 04:32:06 -05:00
|
|
|
|
|
|
|
IsPred(fn(u8) -> bool),
|
|
|
|
IsNotPred(fn(u8) -> bool),
|
|
|
|
WhilePred(fn(u8) -> bool),
|
|
|
|
WhileNotPred(fn(u8) -> bool),
|
|
|
|
|
2020-07-09 03:06:08 -04:00
|
|
|
IsInLookup(&'static Lookup),
|
|
|
|
WhileInLookup(&'static Lookup),
|
|
|
|
WhileNotInLookup(&'static Lookup),
|
|
|
|
|
2020-01-26 04:32:06 -05:00
|
|
|
IsSeq(&'static [u8]),
|
2020-01-25 02:04:02 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
pub enum MatchAction {
|
|
|
|
Keep,
|
|
|
|
Discard,
|
|
|
|
MatchOnly,
|
|
|
|
}
|
|
|
|
|
2020-07-21 03:59:56 -04:00
|
|
|
#[cfg(feature = "js-esbuild")]
|
2020-07-21 03:57:39 -04:00
|
|
|
pub struct JsMinSection {
|
2020-07-21 09:27:56 -04:00
|
|
|
pub src: ProcessorRange,
|
2020-07-21 03:57:39 -04:00
|
|
|
pub result: TransformResult,
|
|
|
|
}
|
|
|
|
|
2020-01-25 19:49:43 -05:00
|
|
|
// Processing state of a file. Single use only; create one per processing.
|
2019-12-25 04:44:51 -05:00
|
|
|
pub struct Processor<'d> {
|
2020-01-16 08:05:48 -05:00
|
|
|
code: &'d mut [u8],
|
2019-12-27 05:52:49 -05:00
|
|
|
// Index of the next character to read.
|
2020-01-16 08:05:48 -05:00
|
|
|
read_next: usize,
|
2019-12-27 05:52:49 -05:00
|
|
|
// Index of the next unwritten space.
|
2020-01-16 08:05:48 -05:00
|
|
|
write_next: usize,
|
2020-07-21 03:57:39 -04:00
|
|
|
#[cfg(feature = "js-esbuild")]
|
|
|
|
script_wg: WaitGroup,
|
|
|
|
#[cfg(feature = "js-esbuild")]
|
|
|
|
script_results: Arc<Mutex<Vec<JsMinSection>>>,
|
2019-12-25 04:44:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'d> Index<ProcessorRange> for Processor<'d> {
|
|
|
|
type Output = [u8];
|
|
|
|
|
|
|
|
fn index(&self, index: ProcessorRange) -> &Self::Output {
|
2019-12-25 07:29:18 -05:00
|
|
|
&self.code[index.start..index.end]
|
2019-12-25 04:44:51 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-16 08:05:48 -05:00
|
|
|
impl<'d> IndexMut<ProcessorRange> for Processor<'d> {
|
|
|
|
fn index_mut(&mut self, index: ProcessorRange) -> &mut Self::Output {
|
|
|
|
debug_assert!(index.end <= self.write_next);
|
|
|
|
&mut self.code[index.start..index.end]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-25 04:44:51 -05:00
|
|
|
impl<'d> Processor<'d> {
|
2019-12-25 07:29:18 -05:00
|
|
|
// Constructor.
|
|
|
|
pub fn new(code: &mut [u8]) -> Processor {
|
2020-07-21 03:57:39 -04:00
|
|
|
Processor {
|
|
|
|
write_next: 0,
|
|
|
|
read_next: 0,
|
|
|
|
code,
|
|
|
|
#[cfg(feature = "js-esbuild")]
|
|
|
|
script_wg: WaitGroup::new(),
|
|
|
|
#[cfg(feature = "js-esbuild")]
|
|
|
|
script_results: Arc::new(Mutex::new(Vec::new())),
|
|
|
|
}
|
2019-12-25 07:29:18 -05:00
|
|
|
}
|
|
|
|
|
2019-12-25 04:44:51 -05:00
|
|
|
// INTERNAL APIs.
|
2019-12-25 07:29:18 -05:00
|
|
|
// Bounds checking.
|
|
|
|
fn _in_bounds(&self, offset: usize) -> bool {
|
2019-12-25 04:44:51 -05:00
|
|
|
self.read_next + offset < self.code.len()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reading.
|
|
|
|
/// Get the `offset` character from next.
|
|
|
|
/// When `offset` is 0, the next character is returned.
|
|
|
|
/// Panics. Does not check bounds for performance (e.g. already checked).
|
2019-12-25 07:29:18 -05:00
|
|
|
fn _read_offset(&self, offset: usize) -> u8 {
|
|
|
|
self.code[self.read_next + offset]
|
2019-12-25 04:44:51 -05:00
|
|
|
}
|
2020-01-25 07:05:07 -05:00
|
|
|
|
2019-12-25 07:29:18 -05:00
|
|
|
fn _maybe_read_offset(&self, offset: usize) -> Option<u8> {
|
2020-01-25 02:04:02 -05:00
|
|
|
self.code.get(self.read_next + offset).map(|c| *c)
|
|
|
|
}
|
2020-01-25 07:05:07 -05:00
|
|
|
|
2020-01-25 02:04:02 -05:00
|
|
|
fn _maybe_read_slice_offset(&self, offset: usize, count: usize) -> Option<&[u8]> {
|
2020-01-25 19:49:43 -05:00
|
|
|
self.code.get(self.read_next + offset..self.read_next + offset + count)
|
2019-12-25 04:44:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Move next `amount` characters to output.
|
|
|
|
/// Panics. Does not check bounds for performance (e.g. already checked).
|
2020-01-31 07:15:35 -05:00
|
|
|
#[inline(always)]
|
2019-12-25 07:29:18 -05:00
|
|
|
fn _shift(&mut self, amount: usize) -> () {
|
|
|
|
// Optimisation: Don't shift if already there (but still update offsets).
|
|
|
|
if self.read_next != self.write_next {
|
|
|
|
self.code.copy_within(self.read_next..self.read_next + amount, self.write_next);
|
|
|
|
};
|
2019-12-25 04:44:51 -05:00
|
|
|
self.read_next += amount;
|
2019-12-25 07:29:18 -05:00
|
|
|
self.write_next += amount;
|
2019-12-25 04:44:51 -05:00
|
|
|
}
|
2020-01-25 07:05:07 -05:00
|
|
|
|
2020-01-31 07:15:35 -05:00
|
|
|
#[inline(always)]
|
2020-01-25 07:05:07 -05:00
|
|
|
fn _replace(&mut self, start: usize, end: usize, data: &[u8]) -> usize {
|
2020-01-26 00:38:23 -05:00
|
|
|
debug_assert!(start <= end);
|
2020-01-25 07:05:07 -05:00
|
|
|
let added = data.len() - (end - start);
|
|
|
|
// Do not allow writing over source.
|
|
|
|
debug_assert!(self.write_next + added <= self.read_next);
|
|
|
|
self.code.copy_within(end..self.write_next, end + added);
|
|
|
|
self.code[start..start + data.len()].copy_from_slice(data);
|
|
|
|
// Don't need to update read_next as only data before it has changed.
|
|
|
|
self.write_next += added;
|
|
|
|
added
|
|
|
|
}
|
|
|
|
|
2020-01-31 07:15:35 -05:00
|
|
|
#[inline(always)]
|
2020-01-25 07:05:07 -05:00
|
|
|
fn _insert(&mut self, at: usize, data: &[u8]) -> usize {
|
|
|
|
self._replace(at, at, data)
|
2020-01-14 01:55:27 -05:00
|
|
|
}
|
2019-12-25 04:44:51 -05:00
|
|
|
|
2019-12-25 07:29:18 -05:00
|
|
|
// Matching.
|
2020-01-31 07:15:35 -05:00
|
|
|
#[inline(always)]
|
2020-01-25 02:04:02 -05:00
|
|
|
fn _one<C: FnOnce(u8) -> bool>(&mut self, cond: C) -> usize {
|
|
|
|
self._maybe_read_offset(0).filter(|n| cond(*n)).is_some() as usize
|
2019-12-25 07:29:18 -05:00
|
|
|
}
|
2020-01-25 19:49:43 -05:00
|
|
|
|
2020-01-31 07:15:35 -05:00
|
|
|
#[inline(always)]
|
2020-01-25 02:04:02 -05:00
|
|
|
fn _many<C: Fn(u8) -> bool>(&mut self, cond: C) -> usize {
|
2019-12-25 07:29:18 -05:00
|
|
|
let mut count = 0usize;
|
2020-01-25 02:04:02 -05:00
|
|
|
while self._maybe_read_offset(count).filter(|c| cond(*c)).is_some() {
|
2019-12-25 07:29:18 -05:00
|
|
|
count += 1;
|
|
|
|
};
|
2020-01-25 02:04:02 -05:00
|
|
|
count
|
2019-12-25 07:29:18 -05:00
|
|
|
}
|
2020-01-25 02:04:02 -05:00
|
|
|
|
2020-07-11 08:52:27 -04:00
|
|
|
fn _remaining(&self) -> usize {
|
|
|
|
self.code.len() - self.read_next
|
|
|
|
}
|
|
|
|
|
2020-01-31 07:15:35 -05:00
|
|
|
#[inline(always)]
|
2020-01-26 04:32:06 -05:00
|
|
|
pub fn m(&mut self, mode: MatchMode, action: MatchAction) -> ProcessorRange {
|
|
|
|
let count = match mode {
|
|
|
|
IsChar(c) => self._one(|n| n == c),
|
|
|
|
IsNotChar(c) => self._one(|n| n != c),
|
|
|
|
WhileChar(c) => self._many(|n| n == c),
|
2020-07-11 08:52:27 -04:00
|
|
|
WhileNotChar(c) => memchr(c, &self.code[self.read_next..]).unwrap_or(self._remaining()),
|
|
|
|
ThroughChar(c) => memchr(c, &self.code[self.read_next..]).map_or(0, |p| p + 1),
|
2020-01-26 04:32:06 -05:00
|
|
|
|
2020-07-09 03:06:08 -04:00
|
|
|
IsInLookup(lookup) => self._one(|n| lookup[n]),
|
|
|
|
WhileInLookup(lookup) => self._many(|n| lookup[n]),
|
|
|
|
WhileNotInLookup(lookup) => self._many(|n| !lookup[n]),
|
|
|
|
|
2020-01-26 04:32:06 -05:00
|
|
|
IsPred(p) => self._one(|n| p(n)),
|
|
|
|
IsNotPred(p) => self._one(|n| !p(n)),
|
|
|
|
WhilePred(p) => self._many(|n| p(n)),
|
|
|
|
WhileNotPred(p) => self._many(|n| !p(n)),
|
2020-01-25 02:04:02 -05:00
|
|
|
|
2020-01-26 04:32:06 -05:00
|
|
|
IsSeq(seq) => self._maybe_read_slice_offset(0, seq.len()).filter(|src| *src == seq).map_or(0, |_| seq.len()),
|
2020-01-25 02:04:02 -05:00
|
|
|
};
|
|
|
|
// If keeping, match will be available in written range (which is better as source might eventually get overwritten).
|
|
|
|
// If discarding, then only option is source range.
|
|
|
|
let start = match action {
|
|
|
|
Discard | MatchOnly => self.read_next,
|
|
|
|
Keep => self.write_next,
|
|
|
|
};
|
|
|
|
match action {
|
|
|
|
Discard => self.read_next += count,
|
|
|
|
Keep => self._shift(count),
|
|
|
|
MatchOnly => {}
|
|
|
|
};
|
|
|
|
|
|
|
|
ProcessorRange { start, end: start + count }
|
|
|
|
}
|
|
|
|
|
2019-12-25 07:29:18 -05:00
|
|
|
// PUBLIC APIs.
|
|
|
|
// Bounds checking
|
2019-12-25 04:44:51 -05:00
|
|
|
pub fn at_end(&self) -> bool {
|
2019-12-25 07:29:18 -05:00
|
|
|
!self._in_bounds(0)
|
2019-12-25 04:44:51 -05:00
|
|
|
}
|
2020-01-25 07:05:07 -05:00
|
|
|
|
2020-07-11 08:52:27 -04:00
|
|
|
pub fn require_not_at_end(&self) -> ProcessingResult<()> {
|
|
|
|
if self.at_end() {
|
|
|
|
Err(ErrorType::UnexpectedEnd)
|
|
|
|
} else {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-25 07:29:18 -05:00
|
|
|
/// Get how many characters have been consumed from source.
|
|
|
|
pub fn read_len(&self) -> usize {
|
|
|
|
self.read_next
|
|
|
|
}
|
2020-01-25 07:05:07 -05:00
|
|
|
|
2020-01-16 08:05:48 -05:00
|
|
|
pub fn reserve_output(&mut self, amount: usize) -> () {
|
|
|
|
self.write_next += amount;
|
|
|
|
}
|
|
|
|
|
2019-12-25 07:29:18 -05:00
|
|
|
// Looking ahead.
|
2019-12-25 04:44:51 -05:00
|
|
|
/// Get the `offset` character from next.
|
|
|
|
/// When `offset` is 0, the next character is returned.
|
2020-01-25 07:05:07 -05:00
|
|
|
pub fn peek(&self, offset: usize) -> Option<u8> {
|
2019-12-25 07:29:18 -05:00
|
|
|
self._maybe_read_offset(offset)
|
2019-12-25 04:44:51 -05:00
|
|
|
}
|
2020-01-25 07:05:07 -05:00
|
|
|
|
|
|
|
pub fn peek_many(&self, offset: usize, count: usize) -> Option<&[u8]> {
|
2020-01-25 02:04:02 -05:00
|
|
|
self._maybe_read_slice_offset(offset, count)
|
2020-01-04 21:28:34 -05:00
|
|
|
}
|
2019-12-25 04:44:51 -05:00
|
|
|
|
2020-07-10 06:40:33 -04:00
|
|
|
// Looking behind.
|
|
|
|
pub fn last(&self, count: usize) -> &[u8] {
|
|
|
|
self.code.get(self.write_next - count..self.write_next).unwrap()
|
|
|
|
}
|
|
|
|
|
2019-12-25 07:29:18 -05:00
|
|
|
// Consuming source characters.
|
2019-12-25 04:44:51 -05:00
|
|
|
/// Skip and return the next character.
|
|
|
|
/// Will result in an error if exceeds bounds.
|
2019-12-25 21:47:18 -05:00
|
|
|
pub fn skip(&mut self) -> ProcessingResult<u8> {
|
2020-01-25 02:04:02 -05:00
|
|
|
self._maybe_read_offset(0).map(|c| {
|
2019-12-25 07:29:18 -05:00
|
|
|
self.read_next += 1;
|
2020-01-25 02:04:02 -05:00
|
|
|
c
|
|
|
|
}).ok_or(ErrorType::UnexpectedEnd)
|
2019-12-25 04:44:51 -05:00
|
|
|
}
|
2020-01-25 07:05:07 -05:00
|
|
|
|
2019-12-29 19:33:49 -05:00
|
|
|
pub fn skip_amount_expect(&mut self, amount: usize) -> () {
|
|
|
|
debug_assert!(!self.at_end(), "skip known characters");
|
|
|
|
self.read_next += amount;
|
|
|
|
}
|
2020-01-25 07:05:07 -05:00
|
|
|
|
2019-12-29 05:00:20 -05:00
|
|
|
pub fn skip_expect(&mut self) -> () {
|
2019-12-29 19:33:49 -05:00
|
|
|
debug_assert!(!self.at_end(), "skip known character");
|
2019-12-29 05:00:20 -05:00
|
|
|
self.read_next += 1;
|
|
|
|
}
|
2019-12-25 04:44:51 -05:00
|
|
|
|
2019-12-25 07:29:18 -05:00
|
|
|
// Writing characters directly.
|
2019-12-25 04:44:51 -05:00
|
|
|
/// Write `c` to output. Will panic if exceeds bounds.
|
|
|
|
pub fn write(&mut self, c: u8) -> () {
|
2019-12-25 07:29:18 -05:00
|
|
|
self.code[self.write_next] = c;
|
|
|
|
self.write_next += 1;
|
2019-12-25 04:44:51 -05:00
|
|
|
}
|
2020-01-25 07:05:07 -05:00
|
|
|
|
2020-01-06 07:36:05 -05:00
|
|
|
pub fn write_range(&mut self, s: ProcessorRange) -> ProcessorRange {
|
|
|
|
let dest_start = self.write_next;
|
|
|
|
let dest_end = dest_start + s.len();
|
|
|
|
self.code.copy_within(s.start..s.end, dest_start);
|
|
|
|
self.write_next = dest_end;
|
|
|
|
ProcessorRange { start: dest_start, end: dest_end }
|
2019-12-28 07:06:04 -05:00
|
|
|
}
|
2020-01-25 07:05:07 -05:00
|
|
|
|
2019-12-25 04:44:51 -05:00
|
|
|
/// Write `s` to output. Will panic if exceeds bounds.
|
|
|
|
pub fn write_slice(&mut self, s: &[u8]) -> () {
|
2019-12-25 07:29:18 -05:00
|
|
|
self.code[self.write_next..self.write_next + s.len()].copy_from_slice(s);
|
|
|
|
self.write_next += s.len();
|
2019-12-25 04:44:51 -05:00
|
|
|
}
|
2020-01-25 07:05:07 -05:00
|
|
|
|
2019-12-26 08:23:33 -05:00
|
|
|
pub fn write_utf8(&mut self, c: char) -> () {
|
2019-12-27 19:16:28 -05:00
|
|
|
let mut encoded = [0u8; 4];
|
2020-01-26 00:38:23 -05:00
|
|
|
self.write_slice(c.encode_utf8(&mut encoded).as_bytes());
|
2019-12-25 04:44:51 -05:00
|
|
|
}
|
|
|
|
|
2019-12-25 07:29:18 -05:00
|
|
|
// Shifting characters.
|
2019-12-25 21:47:18 -05:00
|
|
|
pub fn accept(&mut self) -> ProcessingResult<u8> {
|
2020-01-25 02:04:02 -05:00
|
|
|
self._maybe_read_offset(0).map(|c| {
|
2020-01-06 02:13:24 -05:00
|
|
|
self.code[self.write_next] = c;
|
|
|
|
self.read_next += 1;
|
|
|
|
self.write_next += 1;
|
2020-01-25 02:04:02 -05:00
|
|
|
c
|
|
|
|
}).ok_or(ErrorType::UnexpectedEnd)
|
2019-12-25 04:44:51 -05:00
|
|
|
}
|
2020-01-25 07:05:07 -05:00
|
|
|
|
2019-12-29 19:33:49 -05:00
|
|
|
pub fn accept_expect(&mut self) -> u8 {
|
|
|
|
debug_assert!(!self.at_end());
|
|
|
|
let c = self._read_offset(0);
|
2020-01-06 02:13:24 -05:00
|
|
|
self.code[self.write_next] = c;
|
|
|
|
self.read_next += 1;
|
|
|
|
self.write_next += 1;
|
2019-12-29 19:33:49 -05:00
|
|
|
c
|
|
|
|
}
|
2020-01-25 07:05:07 -05:00
|
|
|
|
2020-01-04 21:28:34 -05:00
|
|
|
pub fn accept_amount_expect(&mut self, count: usize) -> () {
|
|
|
|
debug_assert!(self._in_bounds(count - 1));
|
|
|
|
self._shift(count);
|
|
|
|
}
|
2020-07-21 03:57:39 -04:00
|
|
|
|
2020-07-21 03:59:56 -04:00
|
|
|
#[cfg(feature = "js-esbuild")]
|
2020-07-21 03:57:39 -04:00
|
|
|
pub fn new_script_section(&self) -> (WaitGroup, Arc<Mutex<Vec<JsMinSection>>>) {
|
|
|
|
(self.script_wg.clone(), self.script_results.clone())
|
|
|
|
}
|
|
|
|
|
2020-07-21 09:27:56 -04:00
|
|
|
// Since we consume the Processor, we must provide a full Error with positions.
|
|
|
|
#[cfg(not(feature = "js-esbuild"))]
|
|
|
|
pub fn finish(self) -> Result<usize, Error> {
|
2020-07-21 03:57:39 -04:00
|
|
|
debug_assert!(self.at_end());
|
2020-07-21 09:27:56 -04:00
|
|
|
Ok(self.write_next)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Since we consume the Processor, we must provide a full Error with positions.
|
|
|
|
#[cfg(feature = "js-esbuild")]
|
|
|
|
pub fn finish(self) -> Result<usize, Error> {
|
|
|
|
debug_assert!(self.at_end());
|
|
|
|
self.script_wg.wait();
|
|
|
|
let mut results = Arc::try_unwrap(self.script_results)
|
|
|
|
.unwrap_or_else(|_| panic!("failed to acquire script results"))
|
|
|
|
.into_inner()
|
|
|
|
.unwrap();
|
|
|
|
results.sort_unstable_by_key(|r| r.src.start);
|
|
|
|
// As we write minified JS code for sections from left to right, we will be shifting code
|
|
|
|
// towards the left as previous source JS code sections shrink. We need to keep track of
|
|
|
|
// the write pointer after previous compaction.
|
|
|
|
// If there are no script sections, then we get self.write_next which will be returned.
|
|
|
|
let mut write_next = results.get(0).map_or(self.write_next, |r| r.src.start);
|
|
|
|
for (i, JsMinSection { result, src }) in results.iter().enumerate() {
|
|
|
|
// Resulting minified JS to write.
|
2020-07-22 04:57:47 -04:00
|
|
|
let min_js = result.js.trim().as_bytes();
|
|
|
|
let js_len = if min_js.len() < src.len() {
|
|
|
|
self.code[write_next..write_next + min_js.len()].copy_from_slice(min_js);
|
|
|
|
min_js.len()
|
|
|
|
} else {
|
|
|
|
// If minified result is actually longer than source, then write source instead.
|
|
|
|
// NOTE: We still need to write source as previous iterations may have shifted code down.
|
|
|
|
self.code.copy_within(src.start..src.end, write_next);
|
|
|
|
src.len()
|
2020-07-21 03:57:39 -04:00
|
|
|
};
|
2020-07-22 04:57:47 -04:00
|
|
|
let write_end = write_next + js_len;
|
2020-07-21 09:27:56 -04:00
|
|
|
let next_start = results.get(i + 1).map_or(self.write_next, |r| r.src.start);
|
|
|
|
self.code.copy_within(src.end..next_start, write_end);
|
|
|
|
write_next = write_end + (next_start - src.end);
|
2020-07-21 03:57:39 -04:00
|
|
|
};
|
2020-07-21 09:27:56 -04:00
|
|
|
Ok(write_next)
|
2020-07-21 03:57:39 -04:00
|
|
|
}
|
2019-12-25 04:44:51 -05:00
|
|
|
}
|
2020-01-25 09:25:07 -05:00
|
|
|
|
|
|
|
impl Debug for Processor<'_> {
|
|
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
2020-07-22 04:57:47 -04:00
|
|
|
f.write_str(&debug_repr(self.code, self.read_next as isize, self.write_next as isize))?;
|
2020-01-25 09:25:07 -05:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|