use std::{cmp::Ordering, fmt, hash::Hasher};
use crate::{
decl_engine::parsed_id::ParsedDeclId,
engine_threading::{
DebugWithEngines, DisplayWithEngines, EqWithEngines, HashWithEngines, OrdWithEngines,
OrdWithEnginesContext, PartialEqWithEngines, PartialEqWithEnginesContext,
},
language::{parsed::CodeBlock, *},
type_system::TypeBinding,
Engines, TypeArgument, TypeId,
};
use sway_error::handler::ErrorEmitted;
use sway_types::{ident::Ident, Span, Spanned};
mod asm;
mod match_branch;
mod method_name;
mod scrutinee;
pub(crate) use asm::*;
pub(crate) use match_branch::MatchBranch;
pub use method_name::MethodName;
pub use scrutinee::*;
use sway_ast::intrinsics::Intrinsic;
use super::{FunctionDeclaration, StructDeclaration};
#[derive(Debug, Clone)]
pub struct Expression {
pub kind: ExpressionKind,
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct FunctionApplicationExpression {
pub call_path_binding: TypeBinding<CallPath>,
pub resolved_call_path_binding:
Option<TypeBinding<ResolvedCallPath<ParsedDeclId<FunctionDeclaration>>>>,
pub arguments: Vec<Expression>,
}
impl EqWithEngines for FunctionApplicationExpression {}
impl PartialEqWithEngines for FunctionApplicationExpression {
fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
self.call_path_binding.eq(&other.call_path_binding, ctx)
&& self.arguments.eq(&other.arguments, ctx)
}
}
#[derive(Debug, Clone)]
pub struct LazyOperatorExpression {
pub op: LazyOp,
pub lhs: Box<Expression>,
pub rhs: Box<Expression>,
}
impl EqWithEngines for LazyOperatorExpression {}
impl PartialEqWithEngines for LazyOperatorExpression {
fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
self.op == other.op && self.lhs.eq(&other.lhs, ctx) && self.rhs.eq(&other.rhs, ctx)
}
}
#[derive(Debug, Clone)]
pub struct TupleIndexExpression {
pub prefix: Box<Expression>,
pub index: usize,
pub index_span: Span,
}
impl EqWithEngines for TupleIndexExpression {}
impl PartialEqWithEngines for TupleIndexExpression {
fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
self.prefix.eq(&other.prefix, ctx)
&& self.index == other.index
&& self.index_span == other.index_span
}
}
#[derive(Debug, Clone)]
pub struct ArrayExpression {
pub contents: Vec<Expression>,
pub length_span: Option<Span>,
}
impl EqWithEngines for ArrayExpression {}
impl PartialEqWithEngines for ArrayExpression {
fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
self.contents.eq(&other.contents, ctx) && self.length_span == other.length_span
}
}
#[derive(Debug, Clone)]
pub struct StructExpression {
pub resolved_call_path_binding:
Option<TypeBinding<ResolvedCallPath<ParsedDeclId<StructDeclaration>>>>,
pub call_path_binding: TypeBinding<CallPath>,
pub fields: Vec<StructExpressionField>,
}
impl EqWithEngines for StructExpression {}
impl PartialEqWithEngines for StructExpression {
fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
self.call_path_binding.eq(&other.call_path_binding, ctx)
&& self.fields.eq(&other.fields, ctx)
}
}
#[derive(Debug, Clone)]
pub struct IfExpression {
pub condition: Box<Expression>,
pub then: Box<Expression>,
pub r#else: Option<Box<Expression>>,
}
impl EqWithEngines for IfExpression {}
impl PartialEqWithEngines for IfExpression {
fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
self.condition.eq(&other.condition, ctx)
&& self.then.eq(&other.then, ctx)
&& self.r#else.eq(&other.r#else, ctx)
}
}
#[derive(Debug, Clone)]
pub struct MatchExpression {
pub value: Box<Expression>,
pub branches: Vec<MatchBranch>,
}
impl EqWithEngines for MatchExpression {}
impl PartialEqWithEngines for MatchExpression {
fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
self.value.eq(&other.value, ctx) && self.branches.eq(&other.branches, ctx)
}
}
#[derive(Debug, Clone)]
pub struct MethodApplicationExpression {
pub method_name_binding: TypeBinding<MethodName>,
pub contract_call_params: Vec<StructExpressionField>,
pub arguments: Vec<Expression>,
}
impl EqWithEngines for MethodApplicationExpression {}
impl PartialEqWithEngines for MethodApplicationExpression {
fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
self.method_name_binding.eq(&other.method_name_binding, ctx)
&& self
.contract_call_params
.eq(&other.contract_call_params, ctx)
&& self.arguments.eq(&other.arguments, ctx)
}
}
#[derive(Debug, Clone)]
pub struct SubfieldExpression {
pub prefix: Box<Expression>,
pub field_to_access: Ident,
}
impl EqWithEngines for SubfieldExpression {}
impl PartialEqWithEngines for SubfieldExpression {
fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
self.prefix.eq(&other.prefix, ctx) && self.field_to_access == other.field_to_access
}
}
#[derive(Debug, Clone)]
pub struct AmbiguousSuffix {
pub before: Option<TypeBinding<Ident>>,
pub suffix: Ident,
}
impl EqWithEngines for AmbiguousSuffix {}
impl PartialEqWithEngines for AmbiguousSuffix {
fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
self.before.eq(&other.before, ctx) && self.suffix == other.suffix
}
}
impl Spanned for AmbiguousSuffix {
fn span(&self) -> Span {
if let Some(before) = &self.before {
Span::join(before.span(), &self.suffix.span())
} else {
self.suffix.span()
}
}
}
#[derive(Debug, Clone)]
pub struct QualifiedPathType {
pub ty: TypeArgument,
pub as_trait: TypeId,
pub as_trait_span: Span,
}
impl HashWithEngines for QualifiedPathType {
fn hash<H: Hasher>(&self, state: &mut H, engines: &Engines) {
let QualifiedPathType {
ty,
as_trait,
as_trait_span: _,
} = self;
ty.hash(state, engines);
engines.te().get(*as_trait).hash(state, engines);
}
}
impl EqWithEngines for QualifiedPathType {}
impl PartialEqWithEngines for QualifiedPathType {
fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
let QualifiedPathType {
ty,
as_trait,
as_trait_span: _,
} = self;
ty.eq(&other.ty, ctx)
&& ctx
.engines()
.te()
.get(*as_trait)
.eq(&ctx.engines().te().get(other.as_trait), ctx)
}
}
impl OrdWithEngines for QualifiedPathType {
fn cmp(&self, other: &Self, ctx: &OrdWithEnginesContext) -> Ordering {
let QualifiedPathType {
ty: l_ty,
as_trait: l_as_trait,
as_trait_span: _,
} = self;
let QualifiedPathType {
ty: r_ty,
as_trait: r_as_trait,
as_trait_span: _,
} = other;
l_ty.cmp(r_ty, ctx).then_with(|| {
ctx.engines()
.te()
.get(*l_as_trait)
.cmp(&ctx.engines().te().get(*r_as_trait), ctx)
})
}
}
impl DisplayWithEngines for QualifiedPathType {
fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
write!(
f,
"<{} as {}>",
engines.help_out(self.ty.clone()),
engines.help_out(self.as_trait)
)
}
}
impl DebugWithEngines for QualifiedPathType {
fn fmt(&self, f: &mut fmt::Formatter<'_>, engines: &Engines) -> fmt::Result {
write!(f, "{}", engines.help_out(self),)
}
}
#[derive(Debug, Clone)]
pub struct AmbiguousPathExpression {
pub qualified_path_root: Option<QualifiedPathType>,
pub call_path_binding: TypeBinding<CallPath<AmbiguousSuffix>>,
pub args: Vec<Expression>,
}
impl EqWithEngines for AmbiguousPathExpression {}
impl PartialEqWithEngines for AmbiguousPathExpression {
fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
self.qualified_path_root.eq(&other.qualified_path_root, ctx)
&& PartialEqWithEngines::eq(&self.call_path_binding, &other.call_path_binding, ctx)
&& self.args.eq(&other.args, ctx)
}
}
#[derive(Debug, Clone)]
pub struct DelineatedPathExpression {
pub call_path_binding: TypeBinding<QualifiedCallPath>,
pub args: Option<Vec<Expression>>,
}
impl EqWithEngines for DelineatedPathExpression {}
impl PartialEqWithEngines for DelineatedPathExpression {
fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
self.call_path_binding.eq(&other.call_path_binding, ctx) && self.args.eq(&other.args, ctx)
}
}
#[derive(Debug, Clone)]
pub struct AbiCastExpression {
pub abi_name: CallPath,
pub address: Box<Expression>,
}
impl EqWithEngines for AbiCastExpression {}
impl PartialEqWithEngines for AbiCastExpression {
fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
PartialEqWithEngines::eq(&self.abi_name, &other.abi_name, ctx)
&& self.address.eq(&other.address, ctx)
}
}
#[derive(Debug, Clone)]
pub struct ArrayIndexExpression {
pub prefix: Box<Expression>,
pub index: Box<Expression>,
}
impl EqWithEngines for ArrayIndexExpression {}
impl PartialEqWithEngines for ArrayIndexExpression {
fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
self.prefix.eq(&other.prefix, ctx) && self.index.eq(&other.index, ctx)
}
}
#[derive(Debug, Clone)]
pub struct StorageAccessExpression {
pub namespace_names: Vec<Ident>,
pub field_names: Vec<Ident>,
pub storage_keyword_span: Span,
}
impl EqWithEngines for StorageAccessExpression {}
impl PartialEqWithEngines for StorageAccessExpression {
fn eq(&self, other: &Self, _ctx: &PartialEqWithEnginesContext) -> bool {
self.field_names.eq(&other.field_names)
&& self.storage_keyword_span.eq(&other.storage_keyword_span)
}
}
#[derive(Debug, Clone)]
pub struct IntrinsicFunctionExpression {
pub name: Ident,
pub kind_binding: TypeBinding<Intrinsic>,
pub arguments: Vec<Expression>,
}
impl EqWithEngines for IntrinsicFunctionExpression {}
impl PartialEqWithEngines for IntrinsicFunctionExpression {
fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
self.name.eq(&other.name)
&& self.kind_binding.eq(&other.kind_binding, ctx)
&& self.arguments.eq(&other.arguments, ctx)
}
}
#[derive(Debug, Clone)]
pub struct WhileLoopExpression {
pub condition: Box<Expression>,
pub body: CodeBlock,
}
impl EqWithEngines for WhileLoopExpression {}
impl PartialEqWithEngines for WhileLoopExpression {
fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
self.condition.eq(&other.condition, ctx) && self.body.eq(&other.body, ctx)
}
}
#[derive(Debug, Clone)]
pub struct ForLoopExpression {
pub desugared: Box<Expression>,
}
impl EqWithEngines for ForLoopExpression {}
impl PartialEqWithEngines for ForLoopExpression {
fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
self.desugared.eq(&other.desugared, ctx)
}
}
#[derive(Debug, Clone)]
pub struct ReassignmentExpression {
pub lhs: ReassignmentTarget,
pub rhs: Box<Expression>,
}
impl EqWithEngines for ReassignmentExpression {}
impl PartialEqWithEngines for ReassignmentExpression {
fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
self.lhs.eq(&other.lhs, ctx) && self.rhs.eq(&other.rhs, ctx)
}
}
#[derive(Debug, Clone)]
pub enum ExpressionKind {
Error(Box<[Span]>, ErrorEmitted),
Literal(Literal),
AmbiguousPathExpression(Box<AmbiguousPathExpression>),
FunctionApplication(Box<FunctionApplicationExpression>),
LazyOperator(LazyOperatorExpression),
AmbiguousVariableExpression(Ident),
Variable(Ident),
Tuple(Vec<Expression>),
TupleIndex(TupleIndexExpression),
Array(ArrayExpression),
Struct(Box<StructExpression>),
CodeBlock(CodeBlock),
If(IfExpression),
Match(MatchExpression),
Asm(Box<AsmExpression>),
MethodApplication(Box<MethodApplicationExpression>),
Subfield(SubfieldExpression),
DelineatedPath(Box<DelineatedPathExpression>),
AbiCast(Box<AbiCastExpression>),
ArrayIndex(ArrayIndexExpression),
StorageAccess(StorageAccessExpression),
IntrinsicFunction(IntrinsicFunctionExpression),
WhileLoop(WhileLoopExpression),
ForLoop(ForLoopExpression),
Break,
Continue,
Reassignment(ReassignmentExpression),
ImplicitReturn(Box<Expression>),
Return(Box<Expression>),
Ref(RefExpression),
Deref(Box<Expression>),
}
impl EqWithEngines for Expression {}
impl PartialEqWithEngines for Expression {
fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
self.kind.eq(&other.kind, ctx)
}
}
impl EqWithEngines for ExpressionKind {}
impl PartialEqWithEngines for ExpressionKind {
fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
match (self, other) {
(ExpressionKind::Error(l_span, _), ExpressionKind::Error(r_span, _)) => {
l_span == r_span
}
(ExpressionKind::Literal(l_literal), ExpressionKind::Literal(r_literal)) => {
l_literal == r_literal
}
(
ExpressionKind::AmbiguousPathExpression(lhs),
ExpressionKind::AmbiguousPathExpression(rhs),
) => lhs.eq(rhs, ctx),
(
ExpressionKind::FunctionApplication(lhs),
ExpressionKind::FunctionApplication(rhs),
) => lhs.eq(rhs, ctx),
(ExpressionKind::LazyOperator(lhs), ExpressionKind::LazyOperator(rhs)) => {
lhs.eq(rhs, ctx)
}
(
ExpressionKind::AmbiguousVariableExpression(lhs),
ExpressionKind::AmbiguousVariableExpression(rhs),
) => lhs == rhs,
(ExpressionKind::Variable(lhs), ExpressionKind::Variable(rhs)) => lhs == rhs,
(ExpressionKind::Tuple(lhs), ExpressionKind::Tuple(rhs)) => lhs.eq(rhs, ctx),
(ExpressionKind::TupleIndex(lhs), ExpressionKind::TupleIndex(rhs)) => lhs.eq(rhs, ctx),
(ExpressionKind::Array(lhs), ExpressionKind::Array(rhs)) => lhs.eq(rhs, ctx),
(ExpressionKind::Struct(lhs), ExpressionKind::Struct(rhs)) => lhs.eq(rhs, ctx),
(ExpressionKind::CodeBlock(lhs), ExpressionKind::CodeBlock(rhs)) => lhs.eq(rhs, ctx),
(ExpressionKind::If(lhs), ExpressionKind::If(rhs)) => lhs.eq(rhs, ctx),
(ExpressionKind::Match(lhs), ExpressionKind::Match(rhs)) => lhs.eq(rhs, ctx),
(ExpressionKind::Asm(lhs), ExpressionKind::Asm(rhs)) => lhs.eq(rhs, ctx),
(ExpressionKind::MethodApplication(lhs), ExpressionKind::MethodApplication(rhs)) => {
lhs.eq(rhs, ctx)
}
(ExpressionKind::Subfield(lhs), ExpressionKind::Subfield(rhs)) => lhs.eq(rhs, ctx),
(ExpressionKind::DelineatedPath(lhs), ExpressionKind::DelineatedPath(rhs)) => {
lhs.eq(rhs, ctx)
}
(ExpressionKind::AbiCast(lhs), ExpressionKind::AbiCast(rhs)) => lhs.eq(rhs, ctx),
(ExpressionKind::ArrayIndex(lhs), ExpressionKind::ArrayIndex(rhs)) => lhs.eq(rhs, ctx),
(ExpressionKind::StorageAccess(lhs), ExpressionKind::StorageAccess(rhs)) => {
lhs.eq(rhs, ctx)
}
(ExpressionKind::IntrinsicFunction(lhs), ExpressionKind::IntrinsicFunction(rhs)) => {
lhs.eq(rhs, ctx)
}
(ExpressionKind::WhileLoop(lhs), ExpressionKind::WhileLoop(rhs)) => lhs.eq(rhs, ctx),
(ExpressionKind::ForLoop(lhs), ExpressionKind::ForLoop(rhs)) => lhs.eq(rhs, ctx),
(ExpressionKind::Break, ExpressionKind::Break) => true,
(ExpressionKind::Continue, ExpressionKind::Continue) => true,
(ExpressionKind::Reassignment(lhs), ExpressionKind::Reassignment(rhs)) => {
lhs.eq(rhs, ctx)
}
(ExpressionKind::ImplicitReturn(lhs), ExpressionKind::ImplicitReturn(rhs)) => {
lhs.eq(rhs, ctx)
}
(ExpressionKind::Return(lhs), ExpressionKind::Return(rhs)) => lhs.eq(rhs, ctx),
(ExpressionKind::Ref(lhs), ExpressionKind::Ref(rhs)) => lhs.eq(rhs, ctx),
(ExpressionKind::Deref(lhs), ExpressionKind::Deref(rhs)) => lhs.eq(rhs, ctx),
_ => false,
}
}
}
#[derive(Debug, Clone)]
pub struct RefExpression {
pub to_mutable_value: bool,
pub value: Box<Expression>,
}
impl EqWithEngines for RefExpression {}
impl PartialEqWithEngines for RefExpression {
fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
self.to_mutable_value.eq(&other.to_mutable_value) && self.value.eq(&other.value, ctx)
}
}
#[derive(Debug, Clone)]
pub enum ReassignmentTarget {
ElementAccess(Box<Expression>),
Deref(Box<Expression>),
}
impl EqWithEngines for ReassignmentTarget {}
impl PartialEqWithEngines for ReassignmentTarget {
fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
match (self, other) {
(ReassignmentTarget::ElementAccess(lhs), ReassignmentTarget::ElementAccess(rhs)) => {
lhs.eq(rhs, ctx)
}
(ReassignmentTarget::Deref(lhs), ReassignmentTarget::Deref(rhs)) => lhs.eq(rhs, ctx),
_ => false,
}
}
}
#[derive(Debug, Clone)]
pub struct StructExpressionField {
pub name: Ident,
pub value: Expression,
}
impl EqWithEngines for StructExpressionField {}
impl PartialEqWithEngines for StructExpressionField {
fn eq(&self, other: &Self, ctx: &PartialEqWithEnginesContext) -> bool {
self.name == other.name && self.value.eq(&other.value, ctx)
}
}
impl Spanned for Expression {
fn span(&self) -> Span {
self.span.clone()
}
}
#[derive(Debug)]
pub(crate) struct Op {
pub span: Span,
pub op_variant: OpVariant,
}
impl Op {
pub fn to_var_name(&self) -> Ident {
Ident::new_with_override(self.op_variant.as_str().to_string(), self.span.clone())
}
}
#[derive(Debug)]
pub enum OpVariant {
Add,
Subtract,
Divide,
Multiply,
Modulo,
Or,
And,
Equals,
NotEquals,
Xor,
BinaryOr,
BinaryAnd,
GreaterThan,
LessThan,
GreaterThanOrEqualTo,
LessThanOrEqualTo,
}
impl OpVariant {
fn as_str(&self) -> &'static str {
use OpVariant::*;
match self {
Add => "add",
Subtract => "subtract",
Divide => "divide",
Multiply => "multiply",
Modulo => "modulo",
Or => "$or$",
And => "$and$",
Equals => "eq",
NotEquals => "neq",
Xor => "xor",
BinaryOr => "binary_or",
BinaryAnd => "binary_and",
GreaterThan => "gt",
LessThan => "lt",
LessThanOrEqualTo => "le",
GreaterThanOrEqualTo => "ge",
}
}
}