#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub enum StringInterpPart {
Literal(String),
Expr(Expr),
}
pub type Body = std::sync::Arc<Vec<Entry>>;
#[derive(Debug, Clone, PartialEq)]
pub struct Annotation {
pub name: String,
pub body: Vec<Entry>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Module {
pub name: Option<String>,
pub amends: Option<String>,
pub extends: Option<String>,
pub imports: Vec<Import>,
pub import_exprs: Vec<String>,
pub annotations: Vec<Annotation>,
pub body: Body,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Import {
pub uri: String,
pub alias: Option<String>,
pub is_glob: bool,
}
#[derive(Debug, Clone, PartialEq)]
pub struct TraceSite {
pub source: String,
pub module: String,
pub line: usize,
}
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub enum Entry {
Property(std::sync::Arc<Property>),
DynProperty(Expr, Expr),
ForGenerator(ForGenerator),
WhenGenerator(WhenGenerator),
Spread(Expr),
Elem(Expr),
Predicate(Expr, Expr),
ClassDef(String, Vec<Modifier>, Option<String>, Body),
TypeAlias(String, TypeExpr),
}
#[derive(Debug, Clone, PartialEq)]
pub struct Property {
pub annotations: Vec<Annotation>,
pub modifiers: Vec<Modifier>,
pub name: String,
pub type_ann: Option<TypeExpr>,
pub value: Option<Expr>,
pub body: Option<Body>,
pub is_method: bool,
}
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub enum Modifier {
Local,
Const,
Fixed,
Hidden,
Abstract,
Open,
External,
}
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub enum TypeExpr {
Named(String),
Nullable(Box<TypeExpr>),
Union(Vec<TypeExpr>),
Generic(String, Vec<TypeExpr>),
Constrained(String, Box<Expr>),
}
pub(super) fn type_expr_runtime_name(ty: &TypeExpr) -> String {
match ty {
TypeExpr::Named(name) => name.clone(),
TypeExpr::Nullable(inner) => format!("{}?", type_expr_runtime_name(inner)),
TypeExpr::Union(_) => "Any".to_string(),
TypeExpr::Generic(name, args) => format!(
"{}<{}>",
name,
args.iter()
.map(type_expr_runtime_name)
.collect::<Vec<_>>()
.join(", ")
),
TypeExpr::Constrained(name, _) => name.clone(),
}
}
pub(super) fn infers_new(ty: &TypeExpr) -> bool {
match ty {
TypeExpr::Generic(name, _) => matches!(name.as_str(), "Mapping" | "Listing"),
TypeExpr::Nullable(inner) => infers_new(inner),
TypeExpr::Constrained(base, _) => {
let base = base.trim_end_matches('?');
matches!(base.split('<').next(), Some("Mapping" | "Listing"))
}
TypeExpr::Named(name) => {
name.starts_with(|c: char| c.is_ascii_uppercase())
&& !matches!(
name.as_str(),
"Dynamic" | "Any" | "Map" | "List" | "Set" | "Object"
)
}
TypeExpr::Union(_) => false,
}
}
pub(crate) fn has_untyped_result_new(expr: &Expr) -> bool {
match expr {
Expr::New(None, _, _) => true,
Expr::If(_, then_expr, else_expr) => {
has_untyped_result_new(then_expr) || has_untyped_result_new(else_expr)
}
Expr::Let(_, _, body) | Expr::Trace(body, _) => has_untyped_result_new(body),
_ => false,
}
}
pub(crate) fn infer_method_return_new(expr: &mut Expr, return_type: &TypeExpr) {
rewrite_untyped_result_new(expr, &mut |entries| {
Expr::InferredNew(return_type.clone(), entries)
});
}
pub(crate) fn rewrite_untyped_result_new(expr: &mut Expr, rewrite: &mut impl FnMut(Body) -> Expr) {
match expr {
Expr::New(None, entries, _) => *expr = rewrite(std::mem::take(entries)),
Expr::If(_, then_expr, else_expr) => {
rewrite_untyped_result_new(then_expr, rewrite);
rewrite_untyped_result_new(else_expr, rewrite);
}
Expr::Let(_, _, body) | Expr::Trace(body, _) => rewrite_untyped_result_new(body, rewrite),
_ => {}
}
}
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub enum Expr {
Null,
Bool(bool),
Int(i64),
Float(f64),
String(std::sync::Arc<str>),
Ident(String),
New(Option<String>, Body, Vec<String>),
InferredNew(TypeExpr, Body),
Field(Box<Expr>, String),
Index(Box<Expr>, Box<Expr>),
Call(Box<Expr>, Vec<Expr>),
If(Box<Expr>, Box<Expr>, Box<Expr>),
Let(String, Box<Expr>, Box<Expr>),
Is(Box<Expr>, TypeExpr),
As(Box<Expr>, TypeExpr),
Binop(BinOp, Box<Expr>, Box<Expr>),
Unop(UnOp, Box<Expr>),
ObjectBody(Body),
StringInterpolation(Vec<StringInterpPart>),
NullSafeField(Box<Expr>, String),
Lambda(std::sync::Arc<[String]>, std::sync::Arc<Expr>),
Throw(Box<Expr>),
Trace(Box<Expr>, std::sync::Arc<TraceSite>),
Read(Box<Expr>, String),
ReadOrNull(Box<Expr>, String),
ReadGlob(Box<Expr>, String),
Import(String, String),
ImportGlob(String, String),
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[non_exhaustive]
pub enum BinOp {
Add,
Sub,
Mul,
Div,
Mod,
IntDiv,
Pow,
Eq,
Ne,
Lt,
Le,
Gt,
Ge,
And,
Or,
NullCoalesce,
Pipe,
}
#[derive(Debug, Clone, Copy, PartialEq)]
#[non_exhaustive]
pub enum UnOp {
Neg,
Not,
NonNull,
}
#[derive(Debug, Clone, PartialEq)]
pub struct ForGenerator {
pub key_var: Option<String>,
pub val_var: String,
pub collection: Expr,
pub body: Body,
}
#[derive(Debug, Clone, PartialEq)]
pub struct WhenGenerator {
pub condition: Expr,
pub body: Body,
pub else_body: Option<Body>,
}