use std::ops::{Deref, DerefMut};
use cairo_lang_defs::diagnostic_utils::StableLocation;
use cairo_lang_diagnostics::{DiagnosticNote, Diagnostics};
use cairo_lang_semantic as semantic;
use cairo_lang_semantic::{ConcreteEnumId, ConcreteVariant};
use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
use id_arena::{Arena, Id};
use num_bigint::BigInt;
pub mod blocks;
pub use blocks::BlockId;
use semantic::expr::inference::InferenceResult;
use semantic::items::imp::ImplId;
use self::blocks::FlatBlocks;
use crate::db::LoweringGroup;
use crate::diagnostic::LoweringDiagnostic;
use crate::ids::{FunctionId, LocationId, Signature};
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Location {
pub stable_location: StableLocation,
pub notes: Vec<DiagnosticNote>,
}
impl Location {
pub fn new(stable_location: StableLocation) -> Self {
Self { stable_location, notes: vec![] }
}
pub fn with_note(mut self, note: DiagnosticNote) -> Self {
self.notes.push(note);
self
}
pub fn maybe_with_note(mut self, note: Option<DiagnosticNote>) -> Self {
let Some(note) = note else {
return self;
};
self.notes.push(note);
self
}
pub fn add_note_with_location(
self,
db: &dyn LoweringGroup,
text: &str,
location: LocationId,
) -> Self {
self.with_note(DiagnosticNote::with_location(
text.into(),
location.get(db).stable_location.diagnostic_location(db.upcast()),
))
}
}
pub type VariableId = Id<Variable>;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct VarUsage {
pub var_id: VariableId,
pub location: LocationId,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FlatLowered {
pub diagnostics: Diagnostics<LoweringDiagnostic>,
pub signature: Signature,
pub variables: Arena<Variable>,
pub blocks: FlatBlocks,
pub parameters: Vec<VariableId>,
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct VarRemapping {
pub remapping: OrderedHashMap<VariableId, VarUsage>,
}
impl Deref for VarRemapping {
type Target = OrderedHashMap<VariableId, VarUsage>;
fn deref(&self) -> &Self::Target {
&self.remapping
}
}
impl DerefMut for VarRemapping {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.remapping
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FlatBlock {
pub statements: Vec<Statement>,
pub end: FlatBlockEnd,
}
impl Default for FlatBlock {
fn default() -> Self {
Self { statements: Default::default(), end: FlatBlockEnd::NotSet }
}
}
impl FlatBlock {
pub fn is_set(&self) -> bool {
!matches!(self.end, FlatBlockEnd::NotSet)
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum FlatBlockEnd {
NotSet,
Return(Vec<VarUsage>),
Panic(VarUsage),
Goto(BlockId, VarRemapping),
Match {
info: MatchInfo,
},
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Variable {
pub droppable: InferenceResult<ImplId>,
pub duplicatable: InferenceResult<ImplId>,
pub destruct_impl: InferenceResult<ImplId>,
pub panic_destruct_impl: InferenceResult<ImplId>,
pub ty: semantic::TypeId,
pub location: LocationId,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Statement {
Literal(StatementLiteral),
Call(StatementCall),
StructConstruct(StatementStructConstruct),
StructDestructure(StatementStructDestructure),
EnumConstruct(StatementEnumConstruct),
Snapshot(StatementSnapshot),
Desnap(StatementDesnap),
}
impl Statement {
pub fn inputs(&self) -> Vec<VarUsage> {
match &self {
Statement::Literal(_stmt) => vec![],
Statement::Call(stmt) => stmt.inputs.clone(),
Statement::StructConstruct(stmt) => stmt.inputs.clone(),
Statement::StructDestructure(stmt) => vec![stmt.input],
Statement::EnumConstruct(stmt) => vec![stmt.input],
Statement::Snapshot(stmt) => vec![stmt.input],
Statement::Desnap(stmt) => vec![stmt.input],
}
}
pub fn outputs(&self) -> Vec<VariableId> {
match &self {
Statement::Literal(stmt) => vec![stmt.output],
Statement::Call(stmt) => stmt.outputs.clone(),
Statement::StructConstruct(stmt) => vec![stmt.output],
Statement::StructDestructure(stmt) => stmt.outputs.clone(),
Statement::EnumConstruct(stmt) => vec![stmt.output],
Statement::Snapshot(stmt) => vec![stmt.output_original, stmt.output_snapshot],
Statement::Desnap(stmt) => vec![stmt.output],
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct StatementLiteral {
pub value: BigInt,
pub output: VariableId,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct StatementCall {
pub function: FunctionId,
pub inputs: Vec<VarUsage>,
pub outputs: Vec<VariableId>,
pub location: LocationId,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct StatementEnumConstruct {
pub variant: ConcreteVariant,
pub input: VarUsage,
pub output: VariableId,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct StatementStructConstruct {
pub inputs: Vec<VarUsage>,
pub output: VariableId,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct StatementStructDestructure {
pub input: VarUsage,
pub outputs: Vec<VariableId>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct StatementSnapshot {
pub input: VarUsage,
pub output_original: VariableId,
pub output_snapshot: VariableId,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct StatementDesnap {
pub input: VarUsage,
pub output: VariableId,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MatchArm {
pub variant_id: ConcreteVariant,
pub block_id: BlockId,
pub var_ids: Vec<VariableId>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MatchExternInfo {
pub function: FunctionId,
pub inputs: Vec<VarUsage>,
pub arms: Vec<MatchArm>,
pub location: LocationId,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MatchEnumInfo {
pub concrete_enum_id: ConcreteEnumId,
pub input: VarUsage,
pub arms: Vec<MatchArm>,
pub location: LocationId,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum MatchInfo {
Enum(MatchEnumInfo),
Extern(MatchExternInfo),
}
impl MatchInfo {
pub fn inputs(&self) -> Vec<VarUsage> {
match self {
MatchInfo::Enum(s) => vec![s.input],
MatchInfo::Extern(s) => s.inputs.clone(),
}
}
pub fn arms(&self) -> &Vec<MatchArm> {
match self {
MatchInfo::Enum(s) => &s.arms,
MatchInfo::Extern(s) => &s.arms,
}
}
pub fn location(&self) -> &LocationId {
match self {
MatchInfo::Enum(s) => &s.location,
MatchInfo::Extern(s) => &s.location,
}
}
}