use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, PartialEq)]
pub struct Program {
pub rules: Vec<Rule>,
pub funcs: HashMap<String, FunctionDef>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct FunctionDef {
pub name: String,
pub params: Vec<String>,
pub body: Vec<Stmt>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Rule {
pub pattern: Pattern,
pub stmts: Vec<Stmt>,
}
#[derive(Debug, Clone, PartialEq)]
pub enum Pattern {
Begin,
End,
BeginFile,
EndFile,
Expr(Expr),
Regexp(String),
Range(Box<Pattern>, Box<Pattern>),
Empty,
}
#[derive(Debug, Clone, PartialEq)]
pub enum Stmt {
If {
cond: Expr,
then_: Vec<Stmt>,
else_: Vec<Stmt>,
},
While {
cond: Expr,
body: Vec<Stmt>,
},
DoWhile {
body: Vec<Stmt>,
cond: Expr,
},
ForC {
init: Option<Expr>,
cond: Option<Expr>,
iter: Option<Expr>,
body: Vec<Stmt>,
},
ForIn {
var: String,
arr: String,
body: Vec<Stmt>,
},
Block(Vec<Stmt>),
Expr(Expr),
Print {
args: Vec<Expr>,
redir: Option<PrintRedir>,
},
Printf {
args: Vec<Expr>,
redir: Option<PrintRedir>,
},
Break,
Continue,
Next,
NextFile,
Exit(Option<Expr>),
Delete {
name: String,
indices: Option<Vec<Expr>>,
},
Return(Option<Expr>),
GetLine {
pipe_cmd: Option<Box<Expr>>,
var: Option<String>,
redir: GetlineRedir,
},
Switch {
expr: Expr,
arms: Vec<SwitchArm>,
},
}
#[derive(Debug, Clone, PartialEq)]
pub enum SwitchArm {
Case {
label: SwitchLabel,
stmts: Vec<Stmt>,
},
Default {
stmts: Vec<Stmt>,
},
}
#[derive(Debug, Clone, PartialEq)]
pub enum SwitchLabel {
Expr(Expr),
Regexp(String),
}
#[derive(Debug, Clone, PartialEq)]
pub enum PrintRedir {
Overwrite(Box<Expr>),
Append(Box<Expr>),
Pipe(Box<Expr>),
Coproc(Box<Expr>),
}
#[derive(Debug, Clone, PartialEq)]
pub enum GetlineRedir {
Primary,
File(Box<Expr>),
Coproc(Box<Expr>),
}
#[derive(Debug, Clone, PartialEq)]
pub enum Expr {
Number(f64),
IntegerLiteral(String),
Str(String),
RegexpLiteral(String),
Var(String),
Field(Box<Expr>),
Index {
name: String,
indices: Vec<Expr>,
},
Binary {
op: BinOp,
left: Box<Expr>,
right: Box<Expr>,
},
Unary {
op: UnaryOp,
expr: Box<Expr>,
},
Assign {
name: String,
op: Option<BinOp>,
rhs: Box<Expr>,
},
AssignField {
field: Box<Expr>,
op: Option<BinOp>,
rhs: Box<Expr>,
},
AssignIndex {
name: String,
indices: Vec<Expr>,
op: Option<BinOp>,
rhs: Box<Expr>,
},
Call {
name: String,
args: Vec<Expr>,
},
IndirectCall {
callee: Box<Expr>,
args: Vec<Expr>,
},
Ternary {
cond: Box<Expr>,
then_: Box<Expr>,
else_: Box<Expr>,
},
In {
key: Box<Expr>,
arr: String,
},
Tuple(Vec<Expr>),
IncDec {
op: IncDecOp,
target: IncDecTarget,
},
GetLine {
pipe_cmd: Option<Box<Expr>>,
var: Option<String>,
redir: GetlineRedir,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum IncDecOp {
PreInc,
PostInc,
PreDec,
PostDec,
}
#[derive(Debug, Clone, PartialEq)]
pub enum IncDecTarget {
Var(String),
Field(Box<Expr>),
Index {
name: String,
indices: Vec<Expr>,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum BinOp {
Add,
Sub,
Mul,
Div,
Mod,
Pow,
Eq,
Ne,
Lt,
Le,
Gt,
Ge,
Match,
NotMatch,
Concat,
And,
Or,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UnaryOp {
Neg,
Pos,
Not,
}
pub mod parallel;
#[cfg(test)]
mod ast_tests {
use super::*;
#[test]
fn program_empty_clone_eq() {
let p = Program {
rules: vec![],
funcs: HashMap::new(),
};
assert_eq!(p, p.clone());
}
#[test]
fn pattern_range_holds_endpoints() {
let p = Pattern::Range(
Box::new(Pattern::Regexp("a".into())),
Box::new(Pattern::Regexp("b".into())),
);
assert!(matches!(
p,
Pattern::Range(ref a, ref b)
if matches!(**a, Pattern::Regexp(ref s) if s == "a")
&& matches!(**b, Pattern::Regexp(ref s) if s == "b")
));
}
#[test]
fn expr_clones_and_equality() {
let e = Expr::Binary {
op: BinOp::Add,
left: Box::new(Expr::Number(1.0)),
right: Box::new(Expr::Var("x".into())),
};
assert_eq!(e, e.clone());
}
#[test]
fn stmt_clones_and_equality() {
let s = Stmt::If {
cond: Expr::Number(1.0),
then_: vec![Stmt::Break],
else_: vec![Stmt::Continue],
};
assert_eq!(s, s.clone());
}
#[test]
fn tuple_preserves_multiple_expressions() {
let t = Expr::Tuple(vec![Expr::Number(1.0), Expr::Str("a".into())]);
if let Expr::Tuple(ref v) = t {
assert_eq!(v.len(), 2);
} else {
panic!("Expected tuple");
}
}
#[test]
fn ast_multidim_subscript_v2() {
let e = Expr::Index {
name: "a".into(),
indices: vec![Expr::Number(1.0), Expr::Number(2.0)],
};
if let Expr::Index { indices, .. } = e {
assert_eq!(indices.len(), 2);
}
}
#[test]
fn ast_delete_variants_v2() {
let d1 = Stmt::Delete {
name: "a".into(),
indices: None,
};
let d2 = Stmt::Delete {
name: "a".into(),
indices: Some(vec![Expr::Number(1.0)]),
};
assert_ne!(d1, d2);
}
#[test]
fn program_debug_v2() {
let p = Program {
rules: vec![],
funcs: std::collections::HashMap::new(),
};
let s = format!("{:?}", p);
assert!(s.contains("Program"));
}
#[test]
fn binop_debug_v2() {
assert_eq!(format!("{:?}", BinOp::Add), "Add");
}
#[test]
fn binop_sub_debug_v3() {
assert_eq!(format!("{:?}", BinOp::Sub), "Sub");
}
#[test]
fn binop_mul_debug_v3() {
assert_eq!(format!("{:?}", BinOp::Mul), "Mul");
}
#[test]
fn binop_div_debug_v3() {
assert_eq!(format!("{:?}", BinOp::Div), "Div");
}
#[test]
fn binop_mod_debug_v3() {
assert_eq!(format!("{:?}", BinOp::Mod), "Mod");
}
#[test]
fn binop_pow_debug_v3() {
assert_eq!(format!("{:?}", BinOp::Pow), "Pow");
}
#[test]
fn binop_eq_debug_v3() {
assert_eq!(format!("{:?}", BinOp::Eq), "Eq");
}
#[test]
fn binop_ne_debug_v3() {
assert_eq!(format!("{:?}", BinOp::Ne), "Ne");
}
#[test]
fn binop_lt_debug_v3() {
assert_eq!(format!("{:?}", BinOp::Lt), "Lt");
}
#[test]
fn binop_le_debug_v3() {
assert_eq!(format!("{:?}", BinOp::Le), "Le");
}
#[test]
fn binop_gt_debug_v3() {
assert_eq!(format!("{:?}", BinOp::Gt), "Gt");
}
#[test]
fn binop_ge_debug_v3() {
assert_eq!(format!("{:?}", BinOp::Ge), "Ge");
}
#[test]
fn binop_match_debug_v3() {
assert_eq!(format!("{:?}", BinOp::Match), "Match");
}
#[test]
fn binop_notmatch_debug_v3() {
assert_eq!(format!("{:?}", BinOp::NotMatch), "NotMatch");
}
#[test]
fn binop_concat_debug_v3() {
assert_eq!(format!("{:?}", BinOp::Concat), "Concat");
}
#[test]
fn binop_and_debug_v3() {
assert_eq!(format!("{:?}", BinOp::And), "And");
}
#[test]
fn binop_or_debug_v3() {
assert_eq!(format!("{:?}", BinOp::Or), "Or");
}
#[test]
fn unaryop_neg_debug_v3() {
assert_eq!(format!("{:?}", UnaryOp::Neg), "Neg");
}
#[test]
fn unaryop_pos_debug_v3() {
assert_eq!(format!("{:?}", UnaryOp::Pos), "Pos");
}
#[test]
fn unaryop_not_debug_v3() {
assert_eq!(format!("{:?}", UnaryOp::Not), "Not");
}
#[test]
fn incdecop_preinc_debug_v3() {
assert_eq!(format!("{:?}", IncDecOp::PreInc), "PreInc");
}
#[test]
fn incdecop_postinc_debug_v3() {
assert_eq!(format!("{:?}", IncDecOp::PostInc), "PostInc");
}
#[test]
fn incdecop_predec_debug_v3() {
assert_eq!(format!("{:?}", IncDecOp::PreDec), "PreDec");
}
#[test]
fn incdecop_postdec_debug_v3() {
assert_eq!(format!("{:?}", IncDecOp::PostDec), "PostDec");
}
#[test]
fn getlinesource_primary_debug_v3() {
assert!(format!("{:?}", GetlineRedir::Primary).contains("Primary"));
}
#[test]
fn getlinesource_file_debug_v3() {
assert!(format!("{:?}", GetlineRedir::File(Box::new(Expr::Number(1.0)))).contains("File"));
}
#[test]
fn getlinesource_coproc_debug_v3() {
assert!(
format!("{:?}", GetlineRedir::Coproc(Box::new(Expr::Number(1.0)))).contains("Coproc")
);
}
#[test]
fn printredir_overwrite_debug_v3() {
assert!(
format!("{:?}", PrintRedir::Overwrite(Box::new(Expr::Number(1.0))))
.contains("Overwrite")
);
}
#[test]
fn printredir_append_debug_v3() {
assert!(
format!("{:?}", PrintRedir::Append(Box::new(Expr::Number(1.0)))).contains("Append")
);
}
#[test]
fn printredir_pipe_debug_v3() {
assert!(format!("{:?}", PrintRedir::Pipe(Box::new(Expr::Number(1.0)))).contains("Pipe"));
}
#[test]
fn printredir_coproc_debug_v3() {
assert!(
format!("{:?}", PrintRedir::Coproc(Box::new(Expr::Number(1.0)))).contains("Coproc")
);
}
#[test]
fn stmt_break_debug_v3() {
assert_eq!(format!("{:?}", Stmt::Break), "Break");
}
#[test]
fn stmt_continue_debug_v3() {
assert_eq!(format!("{:?}", Stmt::Continue), "Continue");
}
#[test]
fn stmt_next_debug_v3() {
assert_eq!(format!("{:?}", Stmt::Next), "Next");
}
#[test]
fn stmt_nextfile_debug_v3() {
assert_eq!(format!("{:?}", Stmt::NextFile), "NextFile");
}
#[test]
fn ast_clones_batch_v7() {
let e = Expr::Number(1.0);
for _ in 0..30 {
let _ = e.clone();
}
}
#[test]
fn ast_stmt_clones_batch_v7() {
let s = Stmt::Break;
for _ in 0..30 {
let _ = s.clone();
}
}
#[test]
fn ast_expr_num_v8() {
let _ = Expr::Number(0.0).clone();
}
#[test]
fn ast_expr_num_v8_1() {
let _ = Expr::Number(1.0).clone();
}
#[test]
fn ast_expr_num_v8_2() {
let _ = Expr::Number(-1.0).clone();
}
#[test]
fn ast_expr_str_v8() {
let _ = Expr::Str("".into()).clone();
}
#[test]
fn ast_expr_str_v8_1() {
let _ = Expr::Str("a".into()).clone();
}
#[test]
fn ast_expr_regexp_v8() {
let _ = Expr::RegexpLiteral("".into()).clone();
}
#[test]
fn ast_expr_var_v8() {
let _ = Expr::Var("x".into()).clone();
}
#[test]
fn ast_expr_var_v8_1() {
let _ = Expr::Var("y".into()).clone();
}
#[test]
fn ast_expr_field_v8() {
let _ = Expr::Field(Box::new(Expr::Number(0.0))).clone();
}
#[test]
fn ast_expr_index_v8() {
let _ = Expr::Index {
name: "a".into(),
indices: vec![],
}
.clone();
}
#[test]
fn ast_expr_call_v8() {
let _ = Expr::Call {
name: "f".into(),
args: vec![],
}
.clone();
}
#[test]
fn ast_expr_unary_v8() {
let _ = Expr::Unary {
op: UnaryOp::Not,
expr: Box::new(Expr::Number(0.0)),
}
.clone();
}
#[test]
fn ast_expr_binary_v8() {
let _ = Expr::Binary {
op: BinOp::Add,
left: Box::new(Expr::Number(0.0)),
right: Box::new(Expr::Number(0.0)),
}
.clone();
}
#[test]
fn ast_expr_assign_v8() {
let _ = Expr::Assign {
name: "x".into(),
op: None,
rhs: Box::new(Expr::Number(0.0)),
}
.clone();
}
#[test]
fn ast_expr_ternary_v8() {
let _ = Expr::Ternary {
cond: Box::new(Expr::Number(1.0)),
then_: Box::new(Expr::Number(1.0)),
else_: Box::new(Expr::Number(0.0)),
}
.clone();
}
#[test]
fn ast_expr_in_v8() {
let _ = Expr::In {
key: Box::new(Expr::Number(1.0)),
arr: "a".into(),
}
.clone();
}
#[test]
fn ast_expr_getline_v8() {
let _ = Expr::GetLine {
pipe_cmd: None,
var: None,
redir: GetlineRedir::Primary,
}
.clone();
}
#[test]
fn ast_expr_incdec_v8() {
let _ = Expr::IncDec {
op: IncDecOp::PostInc,
target: IncDecTarget::Var("x".into()),
}
.clone();
}
#[test]
fn ast_expr_tuple_v8() {
let _ = Expr::Tuple(vec![]).clone();
}
#[test]
fn ast_expr_integerliteral_v8() {
let _ = Expr::IntegerLiteral("1".into()).clone();
}
#[test]
fn ast_stmt_if_v8() {
let _ = Stmt::If {
cond: Expr::Number(1.0),
then_: vec![],
else_: vec![],
}
.clone();
}
#[test]
fn ast_stmt_while_v8() {
let _ = Stmt::While {
cond: Expr::Number(1.0),
body: vec![],
}
.clone();
}
#[test]
fn ast_stmt_for_v8() {
let _ = Stmt::ForC {
init: None,
cond: None,
iter: None,
body: vec![],
}
.clone();
}
#[test]
fn ast_stmt_forin_v8() {
let _ = Stmt::ForIn {
var: "k".into(),
arr: "a".into(),
body: vec![],
}
.clone();
}
#[test]
fn ast_stmt_block_v8() {
let _ = Stmt::Block(vec![]).clone();
}
#[test]
fn ast_stmt_expr_v8() {
let _ = Stmt::Expr(Expr::Number(1.0)).clone();
}
#[test]
fn ast_stmt_print_v8() {
let _ = Stmt::Print {
args: vec![],
redir: None,
}
.clone();
}
#[test]
fn ast_stmt_printf_v8() {
let _ = Stmt::Printf {
args: vec![],
redir: None,
}
.clone();
}
#[test]
fn ast_stmt_exit_v8() {
let _ = Stmt::Exit(None).clone();
}
#[test]
fn ast_stmt_return_v8() {
let _ = Stmt::Return(None).clone();
}
#[test]
fn ast_stmt_delete_v8() {
let _ = Stmt::Delete {
name: "a".into(),
indices: None,
}
.clone();
}
#[test]
fn ast_stmt_switch_v8() {
let _ = Stmt::Switch {
expr: Expr::Number(1.0),
arms: vec![],
}
.clone();
}
#[test]
fn ast_stmt_case_v8() {
let _ = SwitchArm::Case {
label: SwitchLabel::Expr(Expr::Number(1.0)),
stmts: vec![],
}
.clone();
}
#[test]
fn ast_stmt_default_v8() {
let _ = SwitchArm::Default { stmts: vec![] }.clone();
}
#[test]
fn ast_expr_v53_0() {
let _ = Expr::Number(1.0).clone();
}
#[test]
fn ast_expr_v53_1() {
let _ = Expr::Str("".into()).clone();
}
#[test]
fn ast_expr_v53_2() {
let _ = Expr::Var("x".into()).clone();
}
#[test]
fn ast_expr_v53_3() {
let _ = Expr::Field(Box::new(Expr::Number(1.0))).clone();
}
#[test]
fn ast_expr_v53_4() {
let _ = Expr::Index {
name: "a".into(),
indices: vec![Expr::Number(1.0)],
}
.clone();
}
#[test]
fn ast_expr_v53_5() {
let _ = Expr::Call {
name: "f".into(),
args: vec![],
}
.clone();
}
#[test]
fn ast_expr_v53_6() {
let _ = Expr::Unary {
op: UnaryOp::Not,
expr: Box::new(Expr::Number(1.0)),
}
.clone();
}
#[test]
fn ast_expr_v53_7() {
let _ = Expr::Binary {
op: BinOp::Add,
left: Box::new(Expr::Number(1.0)),
right: Box::new(Expr::Number(1.0)),
}
.clone();
}
#[test]
fn ast_expr_v53_8() {
let _ = Expr::Assign {
name: "x".into(),
op: None,
rhs: Box::new(Expr::Number(1.0)),
}
.clone();
}
#[test]
fn ast_expr_v53_9() {
let _ = Expr::Ternary {
cond: Box::new(Expr::Number(1.0)),
then_: Box::new(Expr::Number(1.0)),
else_: Box::new(Expr::Number(1.0)),
}
.clone();
}
#[test]
fn ast_expr_v53_10() {
let _ = Expr::In {
key: Box::new(Expr::Number(1.0)),
arr: "a".into(),
}
.clone();
}
#[test]
fn ast_expr_v53_11() {
let _ = Expr::GetLine {
pipe_cmd: None,
var: None,
redir: GetlineRedir::Primary,
}
.clone();
}
#[test]
fn ast_expr_v53_12() {
let _ = Expr::IncDec {
op: IncDecOp::PostInc,
target: IncDecTarget::Var("x".into()),
}
.clone();
}
#[test]
fn ast_expr_v53_13() {
let _ = Expr::Tuple(vec![]).clone();
}
#[test]
fn ast_expr_v53_14() {
let _ = Expr::IntegerLiteral("1".into()).clone();
}
#[test]
fn ast_stmt_v53_0() {
let _ = Stmt::Break.clone();
}
#[test]
fn ast_stmt_v53_1() {
let _ = Stmt::Continue.clone();
}
#[test]
fn ast_stmt_v53_2() {
let _ = Stmt::Next.clone();
}
#[test]
fn ast_stmt_v53_3() {
let _ = Stmt::NextFile.clone();
}
#[test]
fn ast_stmt_v53_4() {
let _ = Stmt::Exit(None).clone();
}
#[test]
fn ast_stmt_v53_5() {
let _ = Stmt::Return(None).clone();
}
#[test]
fn ast_stmt_v53_6() {
let _ = Stmt::If {
cond: Expr::Number(1.0),
then_: vec![],
else_: vec![],
}
.clone();
}
#[test]
fn ast_stmt_v53_7() {
let _ = Stmt::While {
cond: Expr::Number(1.0),
body: vec![],
}
.clone();
}
#[test]
fn ast_stmt_v53_8() {
let _ = Stmt::ForC {
init: None,
cond: None,
iter: None,
body: vec![],
}
.clone();
}
#[test]
fn ast_stmt_v53_9() {
let _ = Stmt::ForIn {
var: "k".into(),
arr: "a".into(),
body: vec![],
}
.clone();
}
#[test]
fn ast_stmt_v53_10() {
let _ = Stmt::Block(vec![]).clone();
}
#[test]
fn ast_stmt_v53_11() {
let _ = Stmt::Expr(Expr::Number(1.0)).clone();
}
#[test]
fn ast_stmt_v53_12() {
let _ = Stmt::Print {
args: vec![],
redir: None,
}
.clone();
}
#[test]
fn ast_stmt_v53_13() {
let _ = Stmt::Printf {
args: vec![],
redir: None,
}
.clone();
}
#[test]
fn ast_stmt_v53_14() {
let _ = Stmt::Delete {
name: "a".into(),
indices: None,
}
.clone();
}
#[test]
fn ast_stmt_v53_15() {
let _ = Stmt::Switch {
expr: Expr::Number(1.0),
arms: vec![],
}
.clone();
}
#[test]
fn ast_pattern_v53_0() {
let _ = Pattern::Begin.clone();
}
#[test]
fn ast_pattern_v53_1() {
let _ = Pattern::End.clone();
}
#[test]
fn ast_pattern_v53_2() {
let _ = Pattern::BeginFile.clone();
}
#[test]
fn ast_pattern_v53_3() {
let _ = Pattern::EndFile.clone();
}
#[test]
fn ast_pattern_v53_4() {
let _ = Pattern::Empty.clone();
}
#[test]
fn ast_pattern_v53_5() {
let _ = Pattern::Regexp("a".into()).clone();
}
#[test]
fn ast_pattern_v53_6() {
let _ = Pattern::Range(Box::new(Pattern::Begin), Box::new(Pattern::End)).clone();
}
}