#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SourcePosition {
pub offset: usize,
pub line: usize,
pub column: usize,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SourceSpan {
pub start: SourcePosition,
pub end: SourcePosition,
}
impl SourceSpan {
pub fn contains_offset(&self, offset: usize) -> bool {
self.start.offset <= offset && offset < self.end.offset
}
}
#[derive(Clone, Debug)]
pub enum Atom {
External(String),
Ssa(String),
BlockParam(String),
Varnode(String),
AddressOf(String),
Int(u64),
Bool(bool),
}
#[derive(Clone, Debug)]
pub struct TypedAtom {
pub size_bytes: Option<usize>,
pub atom: Atom,
pub span: SourceSpan,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Callee {
Named(String),
Minted(u32),
}
#[derive(Clone, Debug)]
pub struct TupleField {
pub name: Option<String>,
pub value: TypedAtom,
}
#[derive(Clone, Debug)]
pub enum ExtractField {
Name(String),
Index(u64),
}
#[derive(Clone, Debug)]
pub enum GepField {
Name(String),
Offset(u64),
}
#[derive(Clone, Debug)]
pub enum StructFieldType {
Int(usize),
StructPtr(String),
}
#[derive(Clone, Debug)]
pub struct StructFieldDecl {
pub name: String,
pub ty: StructFieldType,
}
impl StructFieldDecl {
pub fn is_padding(&self) -> bool {
self.name == "_"
}
}
#[derive(Clone, Debug)]
pub struct StructDecl {
pub name: String,
pub fields: Vec<StructFieldDecl>,
pub span: SourceSpan,
}
#[derive(Clone, Debug)]
pub enum ExprNode {
Atom(TypedAtom),
Unop {
op: String,
src: TypedAtom,
},
Binary {
lhs: TypedAtom,
op: String,
rhs: TypedAtom,
},
Cast {
op: CastOp,
size_bytes: usize,
src: TypedAtom,
},
Load {
space: String,
size_bytes: usize,
ptr: TypedAtom,
},
Store {
space: String,
size_bytes: usize,
ptr: TypedAtom,
src: TypedAtom,
},
FuncCall {
op: String,
args: Vec<TypedAtom>,
},
Intrinsic {
name: String,
args: Vec<TypedAtom>,
},
Apply {
target: Callee,
args: Vec<TypedAtom>,
},
Map {
body: Callee,
src: TypedAtom,
captures: Vec<TypedAtom>,
},
Scan {
body: Callee,
init: TypedAtom,
src: TypedAtom,
captures: Vec<TypedAtom>,
},
Tuple {
fields: Vec<TupleField>,
},
Extract {
agg: TypedAtom,
field: ExtractField,
},
Gep {
base: TypedAtom,
field: GepField,
},
Range {
src: TypedAtom,
start: Option<u64>,
end: Option<u64>,
},
}
#[derive(Clone, Copy, Debug)]
pub enum CastOp {
Zext,
Sext,
IntToFloat,
FloatToFloat,
Trunc,
}
#[derive(Clone, Debug)]
pub struct BlockParamDecl {
pub name: String,
pub size_bytes: Option<usize>,
}
#[derive(Clone, Debug)]
pub enum Label {
Named {
name: String,
params: Vec<BlockParamDecl>,
span: SourceSpan,
},
Address { value: u64, span: SourceSpan },
}
impl Label {
pub fn span(&self) -> &SourceSpan {
match self {
Self::Named { span, .. } | Self::Address { span, .. } => span,
}
}
pub fn name(&self) -> Option<&str> {
match self {
Self::Named { name, .. } => Some(name),
Self::Address { .. } => None,
}
}
}
pub type BlockArgs = Vec<(String, TypedAtom)>;
pub type SwitchCase = (u64, Label, BlockArgs);
#[derive(Clone, Debug)]
pub enum Statement {
LocalDecl {
name: String,
name_span: SourceSpan,
display_name: String,
size_bytes: usize,
span: SourceSpan,
},
Assign {
name: String,
name_span: SourceSpan,
expr: ExprNode,
decl_struct_ptr: Option<String>,
span: SourceSpan,
},
Expr(ExprNode),
LabelDecl {
label: Label,
span: SourceSpan,
},
Branch {
target: Label,
args: BlockArgs,
span: SourceSpan,
},
BranchInd {
ptr: TypedAtom,
targets: Vec<Label>,
span: SourceSpan,
},
Switch {
scrutinee: TypedAtom,
cases: Vec<SwitchCase>,
default: Option<(Label, BlockArgs)>,
span: SourceSpan,
},
CBranch {
condition: TypedAtom,
target: Label,
target_args: BlockArgs,
fallthrough: Label,
fallthrough_args: BlockArgs,
span: SourceSpan,
},
Call {
target: Callee,
tail: bool,
args: BlockArgs,
targets: Vec<Label>,
span: SourceSpan,
},
CallInd {
ptr: TypedAtom,
args: Vec<TypedAtom>,
targets: Vec<Label>,
span: SourceSpan,
},
Return {
ptr: TypedAtom,
value: Option<TypedAtom>,
span: SourceSpan,
},
ReturnValue {
value: TypedAtom,
span: SourceSpan,
},
BadInsn {
span: SourceSpan,
},
Assert {
condition: TypedAtom,
span: SourceSpan,
},
Commented {
comment: String,
inner: Box<Statement>,
},
}
impl Statement {
pub fn inner(&self) -> &Statement {
match self {
Self::Commented { inner, .. } => inner.inner(),
other => other,
}
}
}
#[derive(Clone, Debug)]
pub struct FnDecl {
pub kind: FnKind,
pub name: String,
pub name_span: SourceSpan,
pub span: SourceSpan,
pub statements: Vec<Statement>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum FnKind {
Machine,
Lambda,
}
#[derive(Clone, Debug)]
pub struct Program {
pub structs: Vec<StructDecl>,
pub kind: ProgramKind,
}
#[derive(Clone, Debug)]
pub enum ProgramKind {
Statements(Vec<Statement>),
Functions {
varnodes: Vec<Statement>,
fns: Vec<FnDecl>,
},
}