use crate::ast::BinOp;
use crate::runtime::Value;
use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RedirKind {
Stdout,
Overwrite,
Append,
Pipe,
Coproc,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum GetlineSource {
Primary,
File,
Coproc,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SubTarget {
Record,
Var(u32),
SlotVar(u16),
Field,
Index(u32),
}
#[allow(dead_code)]
#[derive(Debug, Clone, Copy)]
pub enum Op {
PushNum(f64),
PushStr(u32),
GetVar(u32),
SetVar(u32),
GetSlot(u16),
SetSlot(u16),
GetField,
SetField,
GetArrayElem(u32),
SetArrayElem(u32),
CompoundAssignVar(u32, BinOp),
CompoundAssignSlot(u16, BinOp),
CompoundAssignField(BinOp),
CompoundAssignIndex(u32, BinOp),
Add,
Sub,
Mul,
Div,
Mod,
CmpEq,
CmpNe,
CmpLt,
CmpLe,
CmpGt,
CmpGe,
Concat,
RegexMatch,
RegexNotMatch,
Neg,
Pos,
Not,
ToBool,
Jump(usize),
JumpIfFalsePop(usize),
JumpIfTruePop(usize),
Print {
argc: u16,
redir: RedirKind,
},
Printf {
argc: u16,
redir: RedirKind,
},
Next,
ExitWithCode,
ExitDefault,
ReturnVal,
ReturnEmpty,
CallBuiltin(u32, u16),
CallUser(u32, u16),
InArray(u32),
DeleteArray(u32),
DeleteElem(u32),
JoinArrayKey(u16),
GetLine {
var: Option<u32>,
source: GetlineSource,
},
SubFn(SubTarget),
GsubFn(SubTarget),
Split {
arr: u32,
has_fs: bool,
},
Patsplit {
arr: u32,
has_fp: bool,
seps: Option<u32>,
},
MatchBuiltin {
arr: Option<u32>,
},
ForInStart(u32),
ForInNext {
var: u32,
end_jump: usize,
},
ForInEnd,
Pop,
MatchRegexp(u32),
}
#[derive(Debug, Clone, Default)]
pub struct Chunk {
pub ops: Vec<Op>,
}
#[derive(Debug, Clone, Default)]
pub struct StringPool {
strings: Vec<String>,
index: HashMap<String, u32>,
}
impl StringPool {
pub fn intern(&mut self, s: &str) -> u32 {
if let Some(&idx) = self.index.get(s) {
return idx;
}
let idx = self.strings.len() as u32;
self.strings.push(s.to_string());
self.index.insert(s.to_string(), idx);
idx
}
pub fn get(&self, idx: u32) -> &str {
&self.strings[idx as usize]
}
}
#[derive(Debug, Clone)]
pub struct CompiledProgram {
pub begin_chunks: Vec<Chunk>,
pub end_chunks: Vec<Chunk>,
pub beginfile_chunks: Vec<Chunk>,
pub endfile_chunks: Vec<Chunk>,
pub record_rules: Vec<CompiledRule>,
pub functions: HashMap<String, CompiledFunc>,
pub strings: StringPool,
pub slot_count: u16,
pub slot_names: Vec<String>,
pub slot_map: HashMap<String, u16>,
}
impl CompiledProgram {
pub fn init_slots(&self, vars: &HashMap<String, Value>) -> Vec<Value> {
let mut slots = vec![Value::Str(String::new()); self.slot_count as usize];
for (i, name) in self.slot_names.iter().enumerate() {
if let Some(v) = vars.get(name) {
slots[i] = v.clone();
}
}
slots
}
}
#[derive(Debug, Clone)]
pub struct CompiledRule {
pub pattern: CompiledPattern,
pub body: Chunk,
pub original_index: usize,
}
#[derive(Debug, Clone)]
pub enum CompiledPattern {
Always,
Regexp(u32),
Expr(Chunk),
Range,
}
#[derive(Debug, Clone)]
pub struct CompiledFunc {
pub params: Vec<String>,
pub body: Chunk,
}