use crate::span::Span;
#[derive(Debug, Clone)]
pub struct Ident {
pub name: String,
pub span: Span,
}
#[derive(Debug, Clone, Default)]
pub struct Trivia {
pub leading: Vec<String>,
pub trailing: Option<String>,
}
impl Trivia {
pub fn is_empty(&self) -> bool {
self.leading.is_empty() && self.trailing.is_none()
}
}
#[derive(Debug, Clone)]
pub struct Commons {
pub name: QualifiedName,
pub items: Vec<CommonsItem>,
pub uses: Vec<UsesDecl>,
pub documentation: Option<String>,
pub form: CommonsForm,
pub span: Span,
pub trivia: Trivia,
pub trailing_comments: Vec<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CommonsForm {
Brace,
Fragment,
}
#[derive(Debug, Clone)]
pub struct UsesDecl {
pub target: QualifiedName,
pub span: Span,
pub trivia: Trivia,
}
#[derive(Debug, Clone)]
pub struct Context {
pub name: QualifiedName,
pub items: Vec<CommonsItem>,
pub uses: Vec<UsesDecl>,
pub consumes: Vec<ConsumesDecl>,
pub exports: Vec<ExportsDecl>,
pub documentation: Option<String>,
pub form: CommonsForm,
pub span: Span,
pub trivia: Trivia,
pub trailing_comments: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct ConsumesDecl {
pub target: QualifiedName,
pub alias: Option<Ident>,
pub selected: Option<Vec<Ident>>,
pub span: Span,
pub trivia: Trivia,
}
#[derive(Debug, Clone)]
pub struct ExportsDecl {
pub kind: ExportKind,
pub names: Vec<Ident>,
pub span: Span,
pub trivia: Trivia,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ExportKind {
Type(Visibility),
Capability,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Visibility {
Opaque,
Transparent,
}
#[derive(Debug, Clone)]
pub struct AdapterDecl {
pub name: QualifiedName,
pub items: Vec<CommonsItem>,
pub uses: Vec<UsesDecl>,
pub exports: Vec<ExportsDecl>,
pub consumes: Vec<ConsumesDecl>,
pub binding: Option<BindingDecl>,
pub documentation: Option<String>,
pub form: CommonsForm,
pub span: Span,
pub trivia: Trivia,
pub trailing_comments: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct BindingDecl {
pub module: String,
pub module_span: Span,
pub requires: Vec<RequiresDep>,
pub span: Span,
pub trivia: Trivia,
}
#[derive(Debug, Clone)]
pub struct RequiresDep {
pub package: String,
pub range: String,
pub span: Span,
}
#[derive(Debug, Clone)]
pub enum SourceUnit {
Commons(Commons),
Context(Context),
Test(TestDecl),
Integration(IntegrationDecl),
Adapter(AdapterDecl),
}
impl SourceUnit {
pub fn name(&self) -> &QualifiedName {
match self {
SourceUnit::Commons(c) => &c.name,
SourceUnit::Context(c) => &c.name,
SourceUnit::Test(t) => &t.target,
SourceUnit::Integration(i) => &i.name,
SourceUnit::Adapter(a) => &a.name,
}
}
pub fn span(&self) -> Span {
match self {
SourceUnit::Commons(c) => c.span,
SourceUnit::Context(c) => c.span,
SourceUnit::Test(t) => t.span,
SourceUnit::Integration(i) => i.span,
SourceUnit::Adapter(a) => a.span,
}
}
pub fn kind_name(&self) -> &'static str {
match self {
SourceUnit::Commons(_) => "commons",
SourceUnit::Context(_) => "context",
SourceUnit::Test(_) => "test",
SourceUnit::Integration(_) => "integration test",
SourceUnit::Adapter(_) => "adapter",
}
}
}
#[derive(Debug, Clone)]
pub struct TestDecl {
pub target: QualifiedName,
pub uses: Vec<UsesDecl>,
pub mocks: Vec<MockDecl>,
pub cases: Vec<TestCase>,
pub form: CommonsForm,
pub documentation: Option<String>,
pub span: Span,
pub trivia: Trivia,
pub trailing_comments: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct MockDecl {
pub target_name: Ident,
pub impl_name: Ident,
pub ops: Vec<MockOp>,
pub documentation: Option<String>,
pub span: Span,
pub trivia: Trivia,
}
#[derive(Debug, Clone)]
pub struct MockOp {
pub name: Ident,
pub params: Vec<Param>,
pub return_type: TypeRef,
pub body: Block,
pub span: Span,
pub trivia: Trivia,
}
#[derive(Debug, Clone)]
pub struct TestCase {
pub name: String,
pub name_span: Span,
pub body: Block,
pub documentation: Option<String>,
pub span: Span,
pub trivia: Trivia,
}
#[derive(Debug, Clone)]
pub struct IntegrationDecl {
pub suite: String,
pub suite_span: Span,
pub name: QualifiedName,
pub participants: Vec<QualifiedName>,
pub uses: Vec<UsesDecl>,
pub cases: Vec<TestCase>,
pub form: CommonsForm,
pub documentation: Option<String>,
pub span: Span,
pub trivia: Trivia,
pub trailing_comments: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct CapRef {
pub context: Option<QualifiedName>,
pub name: Ident,
pub span: Span,
}
impl CapRef {
pub fn key(&self) -> &str {
&self.name.name
}
pub fn is_cross_context(&self) -> bool {
self.context.is_some()
}
pub fn prefix(&self) -> Option<String> {
self.context.as_ref().map(|q| q.joined())
}
}
#[derive(Debug, Clone)]
pub struct QualifiedName {
pub parts: Vec<Ident>,
pub span: Span,
}
impl QualifiedName {
pub fn joined(&self) -> String {
self.parts
.iter()
.map(|p| p.name.as_str())
.collect::<Vec<_>>()
.join(".")
}
}
#[derive(Debug, Clone)]
pub enum CommonsItem {
Type(TypeDecl),
Fn(FnDecl),
Capability(CapabilityDecl),
Provider(ProviderDecl),
Service(ServiceDecl),
Agent(AgentDecl),
Actor(ActorDecl),
}
impl CommonsItem {
pub fn name(&self) -> &Ident {
match self {
CommonsItem::Type(t) => &t.name,
CommonsItem::Fn(f) => f.name.ident(),
CommonsItem::Capability(c) => &c.name,
CommonsItem::Provider(p) => &p.provider_name,
CommonsItem::Service(s) => &s.name,
CommonsItem::Agent(a) => &a.name,
CommonsItem::Actor(a) => &a.name,
}
}
}
#[derive(Debug, Clone)]
pub struct CapabilityDecl {
pub name: Ident,
pub ops: Vec<CapabilityOp>,
pub documentation: Option<String>,
pub span: Span,
pub trivia: Trivia,
}
#[derive(Debug, Clone)]
pub struct CapabilityOp {
pub name: Ident,
pub params: Vec<Param>,
pub return_type: TypeRef,
pub documentation: Option<String>,
pub span: Span,
pub trivia: Trivia,
}
#[derive(Debug, Clone)]
pub struct ProviderDecl {
pub capability: Ident,
pub provider_name: Ident,
pub given: Vec<CapRef>,
pub ops: Vec<ProviderOp>,
pub external: bool,
pub documentation: Option<String>,
pub span: Span,
pub trivia: Trivia,
}
#[derive(Debug, Clone)]
pub struct ProviderOp {
pub name: Ident,
pub params: Vec<Param>,
pub return_type: TypeRef,
pub body: Block,
pub span: Span,
pub trivia: Trivia,
}
#[derive(Debug, Clone)]
pub struct ServiceDecl {
pub name: Ident,
pub protocol: ServiceProtocol,
pub handlers: Vec<Handler>,
pub documentation: Option<String>,
pub span: Span,
pub trivia: Trivia,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ServiceProtocol {
Call,
Http,
Cron,
Queue { name: String },
}
#[derive(Debug, Clone)]
pub struct AgentDecl {
pub name: Ident,
pub key_name: Ident,
pub key_type: TypeRef,
pub store_fields: Vec<StoreField>,
pub invariants: Vec<Invariant>,
pub handlers: Vec<Handler>,
pub documentation: Option<String>,
pub span: Span,
pub trivia: Trivia,
}
#[derive(Debug, Clone)]
pub struct StoreField {
pub name: Ident,
pub kind: StoreKind,
pub annotations: Vec<Annotation>,
pub init: Option<Expr>,
pub documentation: Option<String>,
pub span: Span,
pub trivia: Trivia,
}
#[derive(Debug, Clone)]
pub struct Annotation {
pub name: Ident,
pub args: Vec<AnnotationArg>,
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct AnnotationArg {
pub label: Option<Ident>,
pub value: Expr,
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct StoreKind {
pub head: Ident,
pub args: Vec<TypeRef>,
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct Invariant {
pub name: Ident,
pub predicate: Expr,
pub documentation: Option<String>,
pub span: Span,
pub trivia: Trivia,
}
#[derive(Debug, Clone)]
pub struct ActorDecl {
pub name: Ident,
pub auth: Option<Ident>,
pub auth_config: Vec<SchemeArg>,
pub identity: Option<TypeRef>,
pub refinement: Option<ActorRefinement>,
pub documentation: Option<String>,
pub span: Span,
pub trivia: Trivia,
}
impl ActorDecl {
pub fn scheme_arg(&self, key: &str) -> Option<&SchemeArg> {
self.auth_config.iter().find(|a| a.key.name == key)
}
}
#[derive(Debug, Clone)]
pub struct SchemeArg {
pub key: Ident,
pub value: SchemeArgValue,
pub span: Span,
}
#[derive(Debug, Clone)]
pub enum SchemeArgValue {
Str(String),
Int(i64),
}
impl SchemeArgValue {
pub fn as_str(&self) -> Option<&str> {
match self {
SchemeArgValue::Str(s) => Some(s),
SchemeArgValue::Int(_) => None,
}
}
pub fn as_int(&self) -> Option<i64> {
match self {
SchemeArgValue::Int(n) => Some(*n),
SchemeArgValue::Str(_) => None,
}
}
}
#[derive(Debug, Clone)]
pub struct ActorRefinement {
pub base: Ident,
pub predicate: Expr,
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct ByClause {
pub binder: Option<Ident>,
pub actors: Vec<Ident>,
pub span: Span,
}
impl ByClause {
pub fn primary(&self) -> &Ident {
&self.actors[0]
}
pub fn is_sum(&self) -> bool {
self.actors.len() > 1
}
}
#[derive(Debug, Clone)]
pub struct Handler {
pub kind: HandlerKind,
pub method_name: Option<Ident>,
pub by_clause: Option<ByClause>,
pub params: Vec<Param>,
pub return_type: TypeRef,
pub given: Vec<CapRef>,
pub body: Block,
pub documentation: Option<String>,
pub span: Span,
pub trivia: Trivia,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum HandlerKind {
Call,
Http { method: HttpMethod, path: String },
Cron { expr: String },
Message,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum HttpMethod {
Get,
Post,
Put,
Patch,
Delete,
}
impl HttpMethod {
pub fn as_str(self) -> &'static str {
match self {
HttpMethod::Get => "GET",
HttpMethod::Post => "POST",
HttpMethod::Put => "PUT",
HttpMethod::Patch => "PATCH",
HttpMethod::Delete => "DELETE",
}
}
pub fn from_ident(s: &str) -> Option<HttpMethod> {
match s {
"GET" => Some(HttpMethod::Get),
"POST" => Some(HttpMethod::Post),
"PUT" => Some(HttpMethod::Put),
"PATCH" => Some(HttpMethod::Patch),
"DELETE" => Some(HttpMethod::Delete),
_ => None,
}
}
pub fn forbids_body(self) -> bool {
matches!(self, HttpMethod::Get | HttpMethod::Delete)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HttpVariantPayload {
None,
Value,
Message,
}
#[derive(Debug, Clone, Copy)]
pub struct HttpVariant {
pub name: &'static str,
pub payload: HttpVariantPayload,
pub status: u16,
}
pub const HTTP_VARIANTS: &[HttpVariant] = &[
HttpVariant {
name: "Ok",
payload: HttpVariantPayload::Value,
status: 200,
},
HttpVariant {
name: "Created",
payload: HttpVariantPayload::Value,
status: 201,
},
HttpVariant {
name: "NoContent",
payload: HttpVariantPayload::None,
status: 204,
},
HttpVariant {
name: "BadRequest",
payload: HttpVariantPayload::Message,
status: 400,
},
HttpVariant {
name: "Unauthorized",
payload: HttpVariantPayload::None,
status: 401,
},
HttpVariant {
name: "Forbidden",
payload: HttpVariantPayload::None,
status: 403,
},
HttpVariant {
name: "NotFound",
payload: HttpVariantPayload::None,
status: 404,
},
HttpVariant {
name: "Conflict",
payload: HttpVariantPayload::Message,
status: 409,
},
HttpVariant {
name: "UnprocessableEntity",
payload: HttpVariantPayload::Message,
status: 422,
},
HttpVariant {
name: "ServerError",
payload: HttpVariantPayload::Message,
status: 500,
},
];
pub fn http_variant(name: &str) -> Option<HttpVariant> {
HTTP_VARIANTS.iter().copied().find(|v| v.name == name)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum QueueVariantPayload {
None,
Message,
}
#[derive(Debug, Clone, Copy)]
pub struct QueueVariant {
pub name: &'static str,
pub payload: QueueVariantPayload,
}
pub const QUEUE_VARIANTS: &[QueueVariant] = &[
QueueVariant {
name: "Ack",
payload: QueueVariantPayload::None,
},
QueueVariant {
name: "Retry",
payload: QueueVariantPayload::Message,
},
];
pub fn queue_variant(name: &str) -> Option<QueueVariant> {
QUEUE_VARIANTS.iter().copied().find(|v| v.name == name)
}
#[derive(Debug, Clone)]
pub struct TypeDecl {
pub name: Ident,
pub body: TypeBody,
pub documentation: Option<String>,
pub span: Span,
pub trivia: Trivia,
}
#[derive(Debug, Clone)]
pub enum TypeBody {
Refined {
base: BaseType,
base_span: Span,
refinement: Option<Refinement>,
},
Record(RecordBody),
Sum(SumBody),
Opaque {
base: BaseType,
base_span: Span,
refinement: Option<Refinement>,
},
}
#[derive(Debug, Clone)]
pub struct RecordBody {
pub fields: Vec<RecordField>,
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct RecordField {
pub name: Ident,
pub type_ref: TypeRef,
pub refinement: Option<Refinement>,
pub init: Option<Expr>,
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct SumBody {
pub variants: Vec<Variant>,
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct Variant {
pub name: Ident,
pub payload: Vec<VariantField>,
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct VariantField {
pub name: Ident,
pub type_ref: TypeRef,
pub span: Span,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BaseType {
Int,
String,
Bool,
Float,
Duration,
Instant,
}
impl BaseType {
pub fn name(self) -> &'static str {
match self {
BaseType::Int => "Int",
BaseType::String => "String",
BaseType::Bool => "Bool",
BaseType::Float => "Float",
BaseType::Duration => "Duration",
BaseType::Instant => "Instant",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DurationUnit {
Milliseconds,
Seconds,
Minutes,
Hours,
Days,
}
impl DurationUnit {
pub fn from_name(name: &str) -> Option<Self> {
Some(match name {
"milliseconds" => DurationUnit::Milliseconds,
"seconds" => DurationUnit::Seconds,
"minutes" => DurationUnit::Minutes,
"hours" => DurationUnit::Hours,
"days" => DurationUnit::Days,
_ => return None,
})
}
pub fn name(self) -> &'static str {
match self {
DurationUnit::Milliseconds => "milliseconds",
DurationUnit::Seconds => "seconds",
DurationUnit::Minutes => "minutes",
DurationUnit::Hours => "hours",
DurationUnit::Days => "days",
}
}
pub fn millis(self) -> i64 {
match self {
DurationUnit::Milliseconds => 1,
DurationUnit::Seconds => 1_000,
DurationUnit::Minutes => 60_000,
DurationUnit::Hours => 3_600_000,
DurationUnit::Days => 86_400_000,
}
}
}
#[derive(Debug, Clone)]
pub struct IntBound {
pub value: i64,
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct FloatBound {
pub value: f64,
pub lexeme: String,
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct Refinement {
pub predicates: Vec<RefinementPred>,
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct RefinementPred {
pub kind: PredKind,
pub span: Span,
}
#[derive(Debug, Clone)]
pub enum PredKind {
Matches(String),
InRange(IntBound, IntBound),
InRangeF(FloatBound, FloatBound),
MinLength(i64),
MaxLength(i64),
Length(i64),
NonNegative,
Positive,
NonEmpty,
}
impl PredKind {
pub fn name(&self) -> &'static str {
match self {
PredKind::Matches(_) => "Matches",
PredKind::InRange(..) | PredKind::InRangeF(..) => "InRange",
PredKind::MinLength(_) => "MinLength",
PredKind::MaxLength(_) => "MaxLength",
PredKind::Length(_) => "Length",
PredKind::NonNegative => "NonNegative",
PredKind::Positive => "Positive",
PredKind::NonEmpty => "NonEmpty",
}
}
}
#[derive(Debug, Clone)]
pub struct TypeParam {
pub name: Ident,
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct LambdaExpr {
pub params: Vec<LambdaParam>,
pub body: Box<Expr>,
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct LambdaParam {
pub name: Ident,
pub type_ref: Option<TypeRef>,
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct FnDecl {
pub type_params: Vec<TypeParam>,
pub name: FnName,
pub params: Vec<Param>,
pub return_type: TypeRef,
pub body: Block,
pub has_self: bool,
pub documentation: Option<String>,
pub span: Span,
pub trivia: Trivia,
}
#[derive(Debug, Clone)]
pub enum FnName {
Free(Ident),
Method {
type_name: Ident,
method_name: Ident,
},
}
impl FnName {
pub fn ident(&self) -> &Ident {
match self {
FnName::Free(id) => id,
FnName::Method { method_name, .. } => method_name,
}
}
pub fn type_name(&self) -> Option<&Ident> {
match self {
FnName::Free(_) => None,
FnName::Method { type_name, .. } => Some(type_name),
}
}
pub fn display(&self) -> String {
match self {
FnName::Free(id) => id.name.clone(),
FnName::Method {
type_name,
method_name,
} => format!("{}.{}", type_name.name, method_name.name),
}
}
}
#[derive(Debug, Clone)]
pub struct Block {
pub statements: Vec<Statement>,
pub tail: Box<Expr>,
pub span: Span,
pub tail_leading_comments: Vec<String>,
}
#[derive(Debug, Clone)]
pub enum Statement {
Let(LetStmt),
EffectLet(LetStmt),
Assert(AssertStmt),
Send(SendStmt),
Assign(AssignStmt),
}
impl Statement {
pub fn span(&self) -> Span {
match self {
Statement::Let(l) | Statement::EffectLet(l) => l.span,
Statement::Assert(a) => a.span,
Statement::Send(s) => s.span,
Statement::Assign(a) => a.span,
}
}
}
#[derive(Debug, Clone)]
pub struct AssertStmt {
pub value: Expr,
pub span: Span,
pub trivia: Trivia,
}
#[derive(Debug, Clone)]
pub struct AssignStmt {
pub target: Ident,
pub value: Expr,
pub span: Span,
pub trivia: Trivia,
}
#[derive(Debug, Clone)]
pub struct LetStmt {
pub name: Ident,
pub type_annot: Option<TypeRef>,
pub value: Expr,
pub span: Span,
pub trivia: Trivia,
}
#[derive(Debug, Clone)]
pub struct SendStmt {
pub value: Expr,
pub span: Span,
pub trivia: Trivia,
}
#[derive(Debug, Clone)]
pub struct Param {
pub name: Ident,
pub type_ref: TypeRef,
pub span: Span,
}
#[derive(Debug, Clone)]
pub enum TypeRef {
Base(BaseType, Span),
Named(Ident),
Result(Box<TypeRef>, Box<TypeRef>, Span),
Option(Box<TypeRef>, Span),
Effect(Box<TypeRef>, Span),
HttpResult(Box<TypeRef>, Span),
QueueResult(Span),
List(Box<TypeRef>, Span),
Map(Box<TypeRef>, Box<TypeRef>, Span),
Query(Box<TypeRef>, Span),
ValidationError(Span),
JsonError(Span),
Unit(Span),
Fn(Vec<TypeRef>, Box<TypeRef>, Span),
}
impl TypeRef {
pub fn span(&self) -> Span {
match self {
TypeRef::Base(_, s) => *s,
TypeRef::Named(id) => id.span,
TypeRef::Result(_, _, s) => *s,
TypeRef::Option(_, s) => *s,
TypeRef::Effect(_, s) => *s,
TypeRef::HttpResult(_, s) => *s,
TypeRef::QueueResult(s) => *s,
TypeRef::List(_, s) => *s,
TypeRef::Map(_, _, s) => *s,
TypeRef::Query(_, s) => *s,
TypeRef::ValidationError(s) => *s,
TypeRef::JsonError(s) => *s,
TypeRef::Unit(s) => *s,
TypeRef::Fn(_, _, s) => *s,
}
}
}
#[derive(Debug, Clone)]
pub struct Expr {
pub kind: ExprKind,
pub span: Span,
}
#[derive(Debug, Clone)]
pub enum ExprKind {
IntLit(i64),
FloatLit {
value: f64,
lexeme: String,
},
DurationLit {
value: i64,
unit: DurationUnit,
millis: i64,
},
StrLit(String),
InterpStr(Vec<InterpPart>),
BoolLit(bool),
Ident(Ident),
Call {
name: Ident,
type_args: Vec<TypeRef>,
args: Vec<Expr>,
},
Lambda(LambdaExpr),
BinOp(BinOp, Box<Expr>, Box<Expr>),
UnaryOp(UnaryOp, Box<Expr>),
Paren(Box<Expr>),
Block(Block),
If {
cond: Box<Expr>,
then_block: Box<Block>,
else_block: Box<Block>,
},
Ok(Box<Expr>),
Err(Box<Expr>),
Question(Box<Expr>),
ConstructorCall {
type_name: Ident,
method: Ident,
args: Vec<Expr>,
},
RecordConstruction {
type_name: Ident,
fields: Vec<FieldInit>,
},
FieldAccess {
receiver: Box<Expr>,
field: Ident,
},
MethodCall {
receiver: Box<Expr>,
method: Ident,
type_args: Vec<TypeRef>,
args: Vec<Expr>,
},
Match {
discriminant: Box<Expr>,
arms: Vec<MatchArm>,
},
Is {
value: Box<Expr>,
pattern: Pattern,
},
Some(Box<Expr>),
None,
UnitLit,
RecordSpread {
type_name: Option<Ident>,
base: Box<Expr>,
overrides: Vec<FieldInit>,
},
EffectPure(Box<Expr>),
Assert(Box<Expr>),
Mock {
type_ref: TypeRef,
args: Vec<Expr>,
},
ListLit(Vec<Expr>),
}
#[derive(Debug, Clone)]
pub enum InterpPart {
Chunk(String),
Hole(Box<Expr>),
}
#[derive(Debug, Clone)]
pub struct FieldInit {
pub name: Ident,
pub value: Option<Expr>,
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct MatchArm {
pub pattern: Pattern,
pub body: MatchBody,
pub span: Span,
}
#[derive(Debug, Clone)]
pub enum MatchBody {
Expr(Expr),
Block(Block),
}
impl MatchBody {
pub fn span(&self) -> Span {
match self {
MatchBody::Expr(e) => e.span,
MatchBody::Block(b) => b.span,
}
}
}
#[derive(Debug, Clone)]
pub enum Pattern {
Wildcard(Span),
Variant {
type_name: Option<Ident>,
variant: Ident,
bindings: Vec<PatternBinding>,
span: Span,
},
}
impl Pattern {
pub fn span(&self) -> Span {
match self {
Pattern::Wildcard(s) => *s,
Pattern::Variant { span, .. } => *span,
}
}
}
#[derive(Debug, Clone)]
pub struct PatternBinding {
pub kind: PatternBindingKind,
pub span: Span,
}
#[derive(Debug, Clone)]
pub enum PatternBindingKind {
Positional { name: Ident },
Named { field: Ident, name: Ident },
}
impl PatternBinding {
pub fn local_name(&self) -> &Ident {
match &self.kind {
PatternBindingKind::Positional { name } => name,
PatternBindingKind::Named { name, .. } => name,
}
}
pub fn is_wildcard(&self) -> bool {
self.local_name().name == "_"
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BinOp {
Implies,
Or,
And,
Eq,
NotEq,
Lt,
LtEq,
Gt,
GtEq,
Add,
Sub,
Mul,
Div,
}
impl BinOp {
pub fn name(self) -> &'static str {
match self {
BinOp::Implies => "implies",
BinOp::Or => "||",
BinOp::And => "&&",
BinOp::Eq => "==",
BinOp::NotEq => "!=",
BinOp::Lt => "<",
BinOp::LtEq => "<=",
BinOp::Gt => ">",
BinOp::GtEq => ">=",
BinOp::Add => "+",
BinOp::Sub => "-",
BinOp::Mul => "*",
BinOp::Div => "/",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UnaryOp {
Neg,
Not,
}
impl UnaryOp {
pub fn name(self) -> &'static str {
match self {
UnaryOp::Neg => "-",
UnaryOp::Not => "!",
}
}
}