use std::{cmp::Ordering, fmt, hash::Hasher};
use crate::{
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;
#[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 arguments: Vec<Expression>,
}
#[derive(Debug, Clone)]
pub struct LazyOperatorExpression {
pub op: LazyOp,
pub lhs: Box<Expression>,
pub rhs: Box<Expression>,
}
#[derive(Debug, Clone)]
pub struct TupleIndexExpression {
pub prefix: Box<Expression>,
pub index: usize,
pub index_span: Span,
}
#[derive(Debug, Clone)]
pub struct ArrayExpression {
pub contents: Vec<Expression>,
pub length_span: Option<Span>,
}
#[derive(Debug, Clone)]
pub struct StructExpression {
pub call_path_binding: TypeBinding<CallPath>,
pub fields: Vec<StructExpressionField>,
}
#[derive(Debug, Clone)]
pub struct IfExpression {
pub condition: Box<Expression>,
pub then: Box<Expression>,
pub r#else: Option<Box<Expression>>,
}
#[derive(Debug, Clone)]
pub struct MatchExpression {
pub value: Box<Expression>,
pub branches: Vec<MatchBranch>,
}
#[derive(Debug, Clone)]
pub struct MethodApplicationExpression {
pub method_name_binding: TypeBinding<MethodName>,
pub contract_call_params: Vec<StructExpressionField>,
pub arguments: Vec<Expression>,
}
#[derive(Debug, Clone)]
pub struct SubfieldExpression {
pub prefix: Box<Expression>,
pub field_to_access: Ident,
}
#[derive(Debug, Clone)]
pub struct AmbiguousSuffix {
pub before: Option<TypeBinding<Ident>>,
pub suffix: Ident,
}
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>,
}
#[derive(Debug, Clone)]
pub struct DelineatedPathExpression {
pub call_path_binding: TypeBinding<QualifiedCallPath>,
pub args: Option<Vec<Expression>>,
}
#[derive(Debug, Clone)]
pub struct AbiCastExpression {
pub abi_name: CallPath,
pub address: Box<Expression>,
}
#[derive(Debug, Clone)]
pub struct ArrayIndexExpression {
pub prefix: Box<Expression>,
pub index: Box<Expression>,
}
#[derive(Debug, Clone)]
pub struct StorageAccessExpression {
pub field_names: Vec<Ident>,
pub storage_keyword_span: Span,
}
#[derive(Debug, Clone)]
pub struct IntrinsicFunctionExpression {
pub name: Ident,
pub kind_binding: TypeBinding<Intrinsic>,
pub arguments: Vec<Expression>,
}
#[derive(Debug, Clone)]
pub struct WhileLoopExpression {
pub condition: Box<Expression>,
pub body: CodeBlock,
}
#[derive(Debug, Clone)]
pub struct ForLoopExpression {
pub desugared: Box<Expression>,
}
#[derive(Debug, Clone)]
pub struct ReassignmentExpression {
pub lhs: ReassignmentTarget,
pub rhs: Box<Expression>,
}
#[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>),
}
#[derive(Debug, Clone)]
pub struct RefExpression {
pub to_mutable_value: bool,
pub value: Box<Expression>,
}
#[derive(Debug, Clone)]
pub enum ReassignmentTarget {
ElementAccess(Box<Expression>),
Deref(Box<Expression>),
}
#[derive(Debug, Clone)]
pub struct StructExpressionField {
pub name: Ident,
pub value: Expression,
}
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",
}
}
}