use lexer::{ Range, Ranged };
pub type Exp<'a> = Node<ExpKind<'a>>;
pub type Ty<'a> = Node<TyKind<'a>>;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Prog<'a> {
pub items: Vec<Item<'a>>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Node<T> {
pub kind: T,
pub range: Range,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Item<'a> {
StructDecl(StructDecl<'a>),
ClassDecl(ClassDecl<'a>),
EnumDecl(EnumDecl<'a>),
FuncDef(Function<'a>),
Impl(Impl<'a>),
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum ExpKind<'a> {
CondExp(Box<CondExp<'a>>),
BinaryOp(Box<BinaryOp<'a>>),
Cast(Box<Exp<'a>>, Ty<'a>),
UnaryPlus(Box<Exp<'a>>),
UnaryMinus(Box<Exp<'a>>),
LogicNot(Box<Exp<'a>>),
Subscript(Box<Subscript<'a>>),
MemberAccess(MemberAccess<'a>),
QualAccess(QualAccess<'a>),
Call(Call<'a>),
Nil,
Bool(&'a str),
Int(&'a str),
Float(&'a str),
String(&'a str),
Identifier(&'a str),
Tuple(Vec<Exp<'a>>),
Array(Vec<Exp<'a>>),
Struct(Struct<'a>),
If(Box<If<'a>>),
Match(Match<'a>),
Block(Vec<Exp<'a>>),
FuncExp(Box<Function<'a>>),
VarDecl(Box<VarDecl<'a>>),
Semi(Box<Exp<'a>>),
Empty,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum TyKind<'a> {
Pointer(Box<Ty<'a>>),
Optional(Box<Ty<'a>>),
Tuple(Vec<Ty<'a>>),
Array(Box<Ty<'a>>),
Function(FunctionTy<'a>),
Named(&'a str),
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct StructDecl<'a> {
pub range: Range,
pub name: &'a str,
pub fields: Vec<Field<'a>>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ClassDecl<'a> {
pub range: Range,
pub name: &'a str,
pub fields: Vec<Field<'a>>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct RelDecl<'a> {
pub cardinality: &'a str,
pub field: Option<&'a str>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Field<'a> {
pub range: Range,
pub name: &'a str,
pub ty: Ty<'a>,
pub relation: Option<RelDecl<'a>>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct EnumDecl<'a> {
pub range: Range,
pub name: &'a str,
pub variants: Vec<Variant<'a>>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Variant<'a> {
pub range: Range,
pub name: &'a str,
pub ty: Option<Ty<'a>>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Function<'a> {
pub range: Range,
pub name: Option<&'a str>,
pub arguments: Vec<Argument<'a>>,
pub ret_type: Option<Ty<'a>>,
pub body: Exp<'a>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Argument<'a> {
pub range: Range,
pub name: &'a str,
pub ty: Option<Ty<'a>>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Impl<'a> {
pub range: Range,
pub name: &'a str,
pub functions: Vec<Function<'a>>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct CondExp<'a> {
pub condition: Exp<'a>,
pub true_val: Option<Exp<'a>>,
pub false_val: Exp<'a>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct BinaryOp<'a> {
pub op: &'a str,
pub lhs: Exp<'a>,
pub rhs: Exp<'a>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Subscript<'a> {
pub base: Exp<'a>,
pub index: Exp<'a>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct MemberAccess<'a> {
pub base: Box<Exp<'a>>,
pub member: &'a str,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct QualAccess<'a> {
pub base: Box<Exp<'a>>,
pub member: &'a str,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Call<'a> {
pub function: Box<Exp<'a>>,
pub arguments: Vec<Exp<'a>>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Struct<'a> {
pub name: &'a str,
pub fields: Vec<(&'a str, Exp<'a>)>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct If<'a> {
pub condition: Exp<'a>,
pub then_arm: Exp<'a>,
pub else_arm: Option<Exp<'a>>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Match<'a> {
pub discriminant: Box<Exp<'a>>,
pub arms: Vec<(Exp<'a>, Exp<'a>)>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct VarDecl<'a> {
pub name: &'a str,
pub ty: Option<Ty<'a>>,
pub expr: Exp<'a>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct FunctionTy<'a> {
pub arg_types: Vec<Ty<'a>>,
pub ret_type: Box<Ty<'a>>,
}
macro_rules! impl_ranged {
($($name: ident),*) => ($(
impl<'a> Ranged for $name<'a> {
fn range(&self) -> Range {
self.range
}
}
)*);
($($name: ident),+,) => { impl_ranged!($($name),+); };
}
impl_ranged! {
StructDecl,
ClassDecl,
Field,
EnumDecl,
Variant,
Function,
Argument,
Impl,
}
impl<T> Ranged for Node<T> {
fn range(&self) -> Range {
self.range
}
}
impl<'a> Ranged for Item<'a> {
fn range(&self) -> Range {
match *self {
Item::StructDecl(ref s) => s.range,
Item::ClassDecl(ref c) => c.range,
Item::EnumDecl(ref e) => e.range,
Item::FuncDef(ref f) => f.range,
Item::Impl(ref i) => i.range,
}
}
}