use crate::lexer::token::StrPart;
use crate::span::Span;
#[derive(Debug, Clone, PartialEq)]
pub struct Module<'a> {
pub imports: Vec<Import<'a>>,
pub stmts: Vec<Stmt<'a>>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Import<'a> {
pub source: ImportSource<'a>,
pub alias: &'a str,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub enum ImportSource<'a> {
Registry {
path: &'a str,
version: &'a str,
},
File(&'a str),
Host(&'a str),
}
#[derive(Debug, Clone, PartialEq)]
pub enum Stmt<'a> {
Assign {
name: &'a str,
shadow: bool,
value: Expr<'a>,
span: Span,
},
Property {
key: &'a str,
value: Expr<'a>,
span: Span,
},
Assert {
cond: Expr<'a>,
message: Option<Expr<'a>>,
span: Span,
},
TypeDecl(SchemaDeclaration<'a>),
EnumDecl(EnumDeclaration<'a>),
FuncDecl {
name: &'a str,
params: Vec<&'a str>,
body: Vec<Stmt<'a>>,
public: bool,
span: Span,
},
Block(BlockDeclaration<'a>),
Expr(Expr<'a>),
}
#[derive(Debug, Clone, PartialEq)]
pub struct EnumDeclaration<'a> {
pub name: &'a str,
pub members: Vec<&'a str>,
pub public: bool,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub struct SchemaDeclaration<'a> {
pub name: &'a str,
pub fields: Vec<SchemaField<'a>>,
pub invariants: Vec<SchemaInvariant<'a>>,
pub public: bool,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub struct SchemaInvariant<'a> {
pub cond: Expr<'a>,
pub message: Option<Expr<'a>>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub struct SchemaField<'a> {
pub name: &'a str,
pub ty: TypeName<'a>,
pub default: Option<Expr<'a>>,
pub nullable: bool,
pub ty_span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub enum TypeName<'a> {
String,
Int,
Float,
Bool,
List(Option<Box<TypeName<'a>>>),
Object,
Custom(&'a str),
}
pub const BUILTIN_TYPE_NAMES: &[&str] = &["String", "Int", "Float", "Bool", "List", "Object"];
impl<'a> TypeName<'a> {
pub fn custom_name(&self) -> Option<&'a str> {
match self {
TypeName::Custom(n) => Some(n),
TypeName::List(Some(el)) => el.custom_name(),
_ => None,
}
}
}
impl TypeName<'_> {
pub fn builtin(name: &str) -> Option<TypeName<'static>> {
Some(match name {
"String" => TypeName::String,
"Int" => TypeName::Int,
"Float" => TypeName::Float,
"Bool" => TypeName::Bool,
"List" => TypeName::List(None),
"Object" => TypeName::Object,
_ => return None,
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BlockKind {
Domain,
}
#[derive(Debug, Clone, PartialEq)]
pub struct BlockDeclaration<'a> {
pub kind: BlockKind,
pub label: Expr<'a>,
pub body: Vec<Stmt<'a>>,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub enum LitValue<'a> {
Int(i64),
Float(f64),
Str(&'a str),
InterpStr(Vec<StrPart<'a>>),
Bool(bool),
Null,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UnaryOp {
Neg,
Not,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BinOp {
Add,
Sub,
Mul,
Div,
Rem,
Eq,
Ne,
Lt,
Gt,
Le,
Ge,
And,
Or,
}
#[derive(Debug, Clone, PartialEq)]
pub enum Expr<'a> {
Literal(LitValue<'a>, Span),
Variable(&'a str, Span),
Unary {
op: UnaryOp,
rhs: Box<Expr<'a>>,
span: Span,
},
Binary {
op: BinOp,
lhs: Box<Expr<'a>>,
rhs: Box<Expr<'a>>,
span: Span,
},
Ternary {
cond: Box<Expr<'a>>,
then: Box<Expr<'a>>,
otherwise: Box<Expr<'a>>,
span: Span,
},
Cond {
arms: Vec<(Expr<'a>, Expr<'a>)>,
otherwise: Box<Expr<'a>>,
span: Span,
},
Call {
callee: Box<Expr<'a>>,
args: Vec<Expr<'a>>,
span: Span,
},
MethodCall {
recv: Box<Expr<'a>>,
method: &'a str,
args: Vec<Expr<'a>>,
lambda: Option<Box<Expr<'a>>>,
span: Span,
},
FieldAccess {
recv: Box<Expr<'a>>,
field: &'a str,
span: Span,
},
Index {
recv: Box<Expr<'a>>,
key: Box<Expr<'a>>,
bracket: bool,
span: Span,
},
ObjectLiteral(ObjectBody<'a>),
ListLiteral(Vec<Expr<'a>>, Span),
Lambda {
params: Vec<&'a str>,
body: LambdaBody<'a>,
span: Span,
},
SchemaInstance {
schema: &'a str,
schema_alias: Option<&'a str>,
body: ObjectBody<'a>,
span: Span,
},
}
impl Expr<'_> {
pub fn span(&self) -> Option<Span> {
Some(match self {
Expr::Literal(_, s) | Expr::Variable(_, s) | Expr::ListLiteral(_, s) => *s,
Expr::Unary { span, .. }
| Expr::Binary { span, .. }
| Expr::Ternary { span, .. }
| Expr::Cond { span, .. }
| Expr::Call { span, .. }
| Expr::MethodCall { span, .. }
| Expr::FieldAccess { span, .. }
| Expr::Index { span, .. }
| Expr::Lambda { span, .. }
| Expr::SchemaInstance { span, .. } => *span,
Expr::ObjectLiteral(body) => return body.props.first().map(|(_, _, s)| *s),
})
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct ObjectBody<'a> {
pub props: Vec<(&'a str, Expr<'a>, Span)>,
}
#[derive(Debug, Clone, PartialEq)]
pub enum LambdaBody<'a> {
Expr(Box<Expr<'a>>),
Block(Vec<Stmt<'a>>),
}