1use crate::{
2 BlockId, DeclId, Filesize, RegId, Span, Value, VarId,
3 ast::{CellPath, Expression, Operator, Pattern, RangeInclusion},
4 engine::EngineState,
5};
6use chrono::{DateTime, FixedOffset};
7use serde::{Deserialize, Serialize};
8use std::{fmt, sync::Arc};
9
10mod call;
11mod display;
12
13pub use call::*;
14pub use display::{FmtInstruction, FmtIrBlock};
15
16#[derive(Clone, Serialize, Deserialize)]
17pub struct IrBlock {
18 pub instructions: Vec<Instruction>,
19 pub spans: Vec<Span>,
20 #[serde(with = "serde_arc_u8_array")]
21 pub data: Arc<[u8]>,
22 pub ast: Vec<Option<IrAstRef>>,
23 pub comments: Vec<Box<str>>,
25 pub register_count: u32,
26 pub file_count: u32,
27}
28
29impl fmt::Debug for IrBlock {
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 f.debug_struct("IrBlock")
33 .field("instructions", &self.instructions)
34 .field("spans", &self.spans)
35 .field("data", &self.data)
36 .field("comments", &self.comments)
37 .field("register_count", &self.register_count)
38 .field("file_count", &self.file_count)
39 .finish_non_exhaustive()
40 }
41}
42
43impl IrBlock {
44 pub fn display<'a>(&'a self, engine_state: &'a EngineState) -> FmtIrBlock<'a> {
47 FmtIrBlock {
48 engine_state,
49 ir_block: self,
50 }
51 }
52}
53
54#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
57pub struct DataSlice {
58 pub start: u32,
59 pub len: u32,
60}
61
62impl DataSlice {
63 pub const fn empty() -> DataSlice {
65 DataSlice { start: 0, len: 0 }
66 }
67}
68
69impl std::ops::Index<DataSlice> for [u8] {
70 type Output = [u8];
71
72 fn index(&self, index: DataSlice) -> &Self::Output {
73 &self[index.start as usize..(index.start as usize + index.len as usize)]
74 }
75}
76
77#[derive(Debug, Clone)]
80pub struct IrAstRef(pub Arc<Expression>);
81
82impl Serialize for IrAstRef {
83 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
84 where
85 S: serde::Serializer,
86 {
87 self.0.as_ref().serialize(serializer)
88 }
89}
90
91impl<'de> Deserialize<'de> for IrAstRef {
92 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
93 where
94 D: serde::Deserializer<'de>,
95 {
96 Expression::deserialize(deserializer).map(|expr| IrAstRef(Arc::new(expr)))
97 }
98}
99
100#[derive(Debug, Clone, Serialize, Deserialize)]
101pub enum Instruction {
102 Unreachable,
104 LoadLiteral { dst: RegId, lit: Literal },
106 LoadValue { dst: RegId, val: Box<Value> },
108 Move { dst: RegId, src: RegId },
110 Clone { dst: RegId, src: RegId },
112 Collect { src_dst: RegId },
114 Span { src_dst: RegId },
116 Drop { src: RegId },
118 Drain { src: RegId },
124 DrainIfEnd { src: RegId },
127 LoadVariable { dst: RegId, var_id: VarId },
129 StoreVariable { var_id: VarId, src: RegId },
131 DropVariable { var_id: VarId },
133 LoadEnv { dst: RegId, key: DataSlice },
135 LoadEnvOpt { dst: RegId, key: DataSlice },
138 StoreEnv { key: DataSlice, src: RegId },
140 PushPositional { src: RegId },
142 AppendRest { src: RegId },
144 PushFlag { name: DataSlice },
146 PushShortFlag { short: DataSlice },
148 PushNamed { name: DataSlice, src: RegId },
150 PushShortNamed { short: DataSlice, src: RegId },
152 PushParserInfo {
154 name: DataSlice,
155 info: Box<Expression>,
156 },
157 RedirectOut { mode: RedirectMode },
161 RedirectErr { mode: RedirectMode },
165 CheckErrRedirected { src: RegId },
167 OpenFile {
169 file_num: u32,
170 path: RegId,
171 append: bool,
172 },
173 WriteFile { file_num: u32, src: RegId },
176 CloseFile { file_num: u32 },
178 Call { decl_id: DeclId, src_dst: RegId },
181 StringAppend { src_dst: RegId, val: RegId },
184 GlobFrom { src_dst: RegId, no_expand: bool },
187 ListPush { src_dst: RegId, item: RegId },
189 ListSpread { src_dst: RegId, items: RegId },
191 RecordInsert {
194 src_dst: RegId,
195 key: RegId,
196 val: RegId,
197 },
198 RecordSpread { src_dst: RegId, items: RegId },
201 Not { src_dst: RegId },
203 BinaryOp {
206 lhs_dst: RegId,
207 op: Operator,
208 rhs: RegId,
209 },
210 FollowCellPath { src_dst: RegId, path: RegId },
212 CloneCellPath { dst: RegId, src: RegId, path: RegId },
215 UpsertCellPath {
218 src_dst: RegId,
219 path: RegId,
220 new_value: RegId,
221 },
222 Jump { index: usize },
224 BranchIf { cond: RegId, index: usize },
227 BranchIfEmpty { src: RegId, index: usize },
230 Match {
234 pattern: Box<Pattern>,
235 src: RegId,
236 index: usize,
237 },
238 CheckMatchGuard { src: RegId },
241 Iterate {
244 dst: RegId,
245 stream: RegId,
246 end_index: usize,
247 },
248 OnError { index: usize },
250 OnErrorInto { index: usize, dst: RegId },
253 PopErrorHandler,
256 ReturnEarly { src: RegId },
260 Return { src: RegId },
262}
263
264impl Instruction {
265 pub fn display<'a>(
268 &'a self,
269 engine_state: &'a EngineState,
270 data: &'a [u8],
271 ) -> FmtInstruction<'a> {
272 FmtInstruction {
273 engine_state,
274 instruction: self,
275 data,
276 }
277 }
278
279 pub fn output_register(&self) -> Option<RegId> {
281 match *self {
282 Instruction::Unreachable => None,
283 Instruction::LoadLiteral { dst, .. } => Some(dst),
284 Instruction::LoadValue { dst, .. } => Some(dst),
285 Instruction::Move { dst, .. } => Some(dst),
286 Instruction::Clone { dst, .. } => Some(dst),
287 Instruction::Collect { src_dst } => Some(src_dst),
288 Instruction::Span { src_dst } => Some(src_dst),
289 Instruction::Drop { .. } => None,
290 Instruction::Drain { .. } => None,
291 Instruction::DrainIfEnd { .. } => None,
292 Instruction::LoadVariable { dst, .. } => Some(dst),
293 Instruction::StoreVariable { .. } => None,
294 Instruction::DropVariable { .. } => None,
295 Instruction::LoadEnv { dst, .. } => Some(dst),
296 Instruction::LoadEnvOpt { dst, .. } => Some(dst),
297 Instruction::StoreEnv { .. } => None,
298 Instruction::PushPositional { .. } => None,
299 Instruction::AppendRest { .. } => None,
300 Instruction::PushFlag { .. } => None,
301 Instruction::PushShortFlag { .. } => None,
302 Instruction::PushNamed { .. } => None,
303 Instruction::PushShortNamed { .. } => None,
304 Instruction::PushParserInfo { .. } => None,
305 Instruction::RedirectOut { .. } => None,
306 Instruction::RedirectErr { .. } => None,
307 Instruction::CheckErrRedirected { .. } => None,
308 Instruction::OpenFile { .. } => None,
309 Instruction::WriteFile { .. } => None,
310 Instruction::CloseFile { .. } => None,
311 Instruction::Call { src_dst, .. } => Some(src_dst),
312 Instruction::StringAppend { src_dst, .. } => Some(src_dst),
313 Instruction::GlobFrom { src_dst, .. } => Some(src_dst),
314 Instruction::ListPush { src_dst, .. } => Some(src_dst),
315 Instruction::ListSpread { src_dst, .. } => Some(src_dst),
316 Instruction::RecordInsert { src_dst, .. } => Some(src_dst),
317 Instruction::RecordSpread { src_dst, .. } => Some(src_dst),
318 Instruction::Not { src_dst } => Some(src_dst),
319 Instruction::BinaryOp { lhs_dst, .. } => Some(lhs_dst),
320 Instruction::FollowCellPath { src_dst, .. } => Some(src_dst),
321 Instruction::CloneCellPath { dst, .. } => Some(dst),
322 Instruction::UpsertCellPath { src_dst, .. } => Some(src_dst),
323 Instruction::Jump { .. } => None,
324 Instruction::BranchIf { .. } => None,
325 Instruction::BranchIfEmpty { .. } => None,
326 Instruction::Match { .. } => None,
327 Instruction::CheckMatchGuard { .. } => None,
328 Instruction::Iterate { dst, .. } => Some(dst),
329 Instruction::OnError { .. } => None,
330 Instruction::OnErrorInto { .. } => None,
331 Instruction::PopErrorHandler => None,
332 Instruction::ReturnEarly { .. } => None,
333 Instruction::Return { .. } => None,
334 }
335 }
336
337 pub fn branch_target(&self) -> Option<usize> {
339 match self {
340 Instruction::Jump { index } => Some(*index),
341 Instruction::BranchIf { cond: _, index } => Some(*index),
342 Instruction::BranchIfEmpty { src: _, index } => Some(*index),
343 Instruction::Match {
344 pattern: _,
345 src: _,
346 index,
347 } => Some(*index),
348
349 Instruction::Iterate {
350 dst: _,
351 stream: _,
352 end_index,
353 } => Some(*end_index),
354 Instruction::OnError { index } => Some(*index),
355 Instruction::OnErrorInto { index, dst: _ } => Some(*index),
356 _ => None,
357 }
358 }
359
360 pub fn set_branch_target(&mut self, target_index: usize) -> Result<(), usize> {
364 match self {
365 Instruction::Jump { index } => *index = target_index,
366 Instruction::BranchIf { cond: _, index } => *index = target_index,
367 Instruction::BranchIfEmpty { src: _, index } => *index = target_index,
368 Instruction::Match {
369 pattern: _,
370 src: _,
371 index,
372 } => *index = target_index,
373
374 Instruction::Iterate {
375 dst: _,
376 stream: _,
377 end_index,
378 } => *end_index = target_index,
379 Instruction::OnError { index } => *index = target_index,
380 Instruction::OnErrorInto { index, dst: _ } => *index = target_index,
381 _ => return Err(target_index),
382 }
383 Ok(())
384 }
385}
386
387const _: () = assert!(std::mem::size_of::<Instruction>() <= 24);
391
392#[derive(Debug, Clone, Serialize, Deserialize)]
394pub enum Literal {
395 Bool(bool),
396 Int(i64),
397 Float(f64),
398 Filesize(Filesize),
399 Duration(i64),
400 Binary(DataSlice),
401 Block(BlockId),
402 Closure(BlockId),
403 RowCondition(BlockId),
404 Range {
405 start: RegId,
406 step: RegId,
407 end: RegId,
408 inclusion: RangeInclusion,
409 },
410 List {
411 capacity: usize,
412 },
413 Record {
414 capacity: usize,
415 },
416 Filepath {
417 val: DataSlice,
418 no_expand: bool,
419 },
420 Directory {
421 val: DataSlice,
422 no_expand: bool,
423 },
424 GlobPattern {
425 val: DataSlice,
426 no_expand: bool,
427 },
428 String(DataSlice),
429 RawString(DataSlice),
430 CellPath(Box<CellPath>),
431 Date(Box<DateTime<FixedOffset>>),
432 Nothing,
433}
434
435#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
445pub enum RedirectMode {
446 Pipe,
447 PipeSeparate,
448 Value,
449 Null,
450 Inherit,
451 Print,
452 File {
454 file_num: u32,
455 },
456 Caller,
458}
459
460mod serde_arc_u8_array {
462 use serde::{Deserialize, Serialize};
463 use std::sync::Arc;
464
465 pub fn serialize<S>(data: &Arc<[u8]>, ser: S) -> Result<S::Ok, S::Error>
466 where
467 S: serde::Serializer,
468 {
469 data.as_ref().serialize(ser)
470 }
471
472 pub fn deserialize<'de, D>(de: D) -> Result<Arc<[u8]>, D::Error>
473 where
474 D: serde::Deserializer<'de>,
475 {
476 let data: Vec<u8> = Deserialize::deserialize(de)?;
477 Ok(data.into())
478 }
479}