use serde::ser::{SerializeMap, SerializeSeq};
use serde::Serialize;
use std::fmt::Debug;
use std::hash::Hash;
use std::ops::Range;
#[derive(Debug, Clone, Serialize, Default)]
pub struct Program {
pub statements: Vec<Span<Stmt>>,
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct Span<T: Debug + Clone + PartialEq>(pub T, pub Range<usize>);
impl<T: Debug + Clone + PartialEq + Serialize + Hash> Eq for Span<T> {}
pub type TypeParams = Span<Vec<Span<String>>>;
#[derive(Debug, Clone, PartialEq)]
pub enum Fields<T: Debug + Clone + PartialEq> {
Named(Vec<(Span<String>, Span<T>)>),
Tuple(Vec<Span<T>>),
Empty,
}
impl<T: Serialize + Debug + Clone + PartialEq> Serialize for Fields<T> {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match self {
Fields::Named(fields) => {
let mut map = serializer.serialize_map(Some(fields.len()))?;
for (name, value) in fields {
map.serialize_entry(name, value)?;
}
map.end()
}
Fields::Tuple(fields) => {
let mut seq = serializer.serialize_seq(Some(fields.len()))?;
for value in fields {
seq.serialize_element(value)?;
}
seq.end()
}
Fields::Empty => serializer.serialize_none(),
}
}
}
impl<T: Debug + Clone + PartialEq> Fields<T> {
pub fn map<U: Debug + Clone + PartialEq>(
&self,
mut f: impl FnMut(&Span<T>) -> Span<U>,
) -> Fields<U> {
match self {
Fields::Named(fields) => Fields::Named(
fields
.iter()
.map(|(name, value)| (name.clone(), f(value)))
.collect(),
),
Fields::Tuple(fields) => Fields::Tuple(fields.iter().map(f).collect()),
Fields::Empty => Fields::Empty,
}
}
}
pub type TypeFields = Fields<TypeSig>;
#[derive(Debug, Clone, PartialEq, Serialize)]
pub enum TypeDeclaration {
Struct {
name: Span<String>,
type_parameters: Option<TypeParams>,
fields: TypeFields,
},
Enum {
name: Span<String>,
type_parameters: Option<TypeParams>,
variants: Vec<(Span<String>, TypeFields)>,
},
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct Function {
pub name: Span<String>,
pub type_parameters: Option<TypeParams>,
pub params: Vec<(Span<String>, Span<TypeSig>)>,
pub return_type: Option<Span<TypeSig>>,
pub body: Span<ExprBlock>,
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub enum Stmt {
Let(Span<String>, Span<Expr>),
Function(Function),
Expr(Span<Expr>),
If {
condition: Span<Expr>,
then_block: Vec<Span<Stmt>>,
else_block: Vec<Span<Stmt>>,
},
For {
iterator_variable: Span<String>,
iterator: Span<Expr>,
body: Vec<Span<Stmt>>,
},
Return(Option<Span<Expr>>),
Import {
ty: Span<ImportType>,
default_import: Option<Span<String>>,
named_imports: Vec<Span<String>>,
path: Span<String>,
},
Type(TypeDeclaration),
Use {
module: Span<String>,
name: Span<String>,
},
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub enum ImportType {
Internal,
External,
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct ExprBlock {
pub stmts: Vec<Span<Stmt>>,
pub end_expr: Option<Box<Span<Expr>>>,
}
pub type ExprFields = Fields<Expr>;
impl ExprFields {
pub fn len(&self) -> usize {
match self {
ExprFields::Tuple(fields) => fields.len(),
ExprFields::Named(fields) => fields.len(),
ExprFields::Empty => 0,
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub enum Expr {
Value(Value),
Variable(String),
PostFix(Box<Span<Expr>>, Span<PostFix>),
Binary(Span<BinaryOp>, Box<Span<Expr>>, Box<Span<Expr>>),
Unary(Span<UnaryOp>, Box<Span<Expr>>),
Struct(Span<String>, ExprFields),
Enum {
enum_name: Span<String>,
variant_name: Span<String>,
fields: ExprFields,
},
If {
condition: Box<Span<Expr>>,
then_block: Span<ExprBlock>,
else_block: Span<ExprBlock>,
},
Match {
expr: Box<Span<Expr>>,
cases: Vec<(Span<MatchCase>, Span<ExprBlock>)>,
},
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct MatchCase {
pub enum_name: Span<String>,
pub variant_name: Span<String>,
pub fields: Option<MatchBindings>,
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub enum MatchBindings {
Tuple(Vec<Span<String>>),
Named(Vec<(Span<String>, Option<Span<String>>)>),
}
impl MatchBindings {
pub fn len(&self) -> usize {
match self {
MatchBindings::Tuple(fields) => fields.len(),
MatchBindings::Named(fields) => fields.len(),
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub enum PostFix {
Field(Span<String>),
Index(Box<Span<Expr>>),
Args(Vec<Span<Expr>>),
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub enum TypeSig {
I32,
F32,
String,
Bool,
Named(Span<String>, Vec<Span<TypeSig>>),
}
impl Eq for TypeSig {}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub enum Value {
I32(i32),
F32(f32),
Bool(bool),
String(String),
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub enum BinaryOp {
Add,
Subtract,
Divide,
Multiply,
GreaterThan,
GreaterThanOrEqual,
LessThan,
LessThanOrEqual,
Equal,
NotEqual,
}
#[derive(Debug, Copy, Clone, PartialEq, Serialize)]
pub enum UnaryOp {
Negate,
Not,
}