use crate::span::Span;
#[derive(Debug, Clone)]
pub struct File {
pub header: Option<Header>,
pub stmts: Vec<Stmt>,
}
#[derive(Debug, Clone)]
pub struct Header {
pub version: String,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Ident {
pub name: String,
pub span: Span,
}
#[derive(Debug, Clone, Default)]
pub struct Trivia {
pub leading: Vec<String>,
pub trailing: Option<String>,
pub blank_before: bool,
}
#[derive(Debug, Clone)]
pub struct Stmt {
pub kind: StmtKind,
pub span: Span,
pub trivia: Trivia,
}
#[derive(Debug, Clone)]
pub enum StmtKind {
Canvas(Block),
Def(Def),
Group(Group),
Class(Class),
Constrain(Vec<Constraint>),
Pin(Pin),
For(For),
Port(Port),
Prop(Prop),
Node(Node),
Edge(Edge),
}
#[derive(Debug, Clone)]
pub struct Block {
pub stmts: Vec<Stmt>,
pub span: Span,
}
#[derive(Debug, Clone)]
pub struct Def {
pub name: Ident,
pub params: Vec<Ident>,
pub body: Block,
}
#[derive(Debug, Clone)]
pub struct Group {
pub name: Ident,
pub label: Option<StrLit>,
pub body: Block,
}
#[derive(Debug, Clone)]
pub struct Class {
pub name: Ident,
pub body: Block,
}
#[derive(Debug, Clone)]
pub struct Constraint {
pub name: Ident,
pub args: Vec<ConstraintArg>,
pub span: Span,
pub trivia: Trivia,
}
#[derive(Debug, Clone)]
pub enum ConstraintArg {
Path(PathRef),
Num(f64, Span),
}
impl ConstraintArg {
pub fn span(&self) -> Span {
match self {
ConstraintArg::Path(p) => p.span,
ConstraintArg::Num(_, s) => *s,
}
}
}
#[derive(Debug, Clone)]
pub struct Pin {
pub target: PathRef,
pub x: Expr,
pub y: Expr,
}
#[derive(Debug, Clone)]
pub struct For {
pub var: Ident,
pub start: Expr,
pub end: Expr,
pub body: Block,
}
#[derive(Debug, Clone)]
pub struct Port {
pub name: Ident,
pub body: Block,
}
#[derive(Debug, Clone)]
pub struct Prop {
pub key: Vec<Ident>,
pub value: Value,
pub span: Span,
}
#[derive(Debug, Clone)]
pub enum Value {
Str(StrLit),
Num(f64, Span),
Word(Ident),
ThemeToken(Ident),
Color(String, Span),
}
impl Value {
pub fn span(&self) -> Span {
match self {
Value::Str(s) => s.span,
Value::Num(_, s) => *s,
Value::Word(i) | Value::ThemeToken(i) => i.span,
Value::Color(_, s) => *s,
}
}
}
#[derive(Debug, Clone)]
pub struct Node {
pub name: Option<Ident>,
pub kind: NodeKind,
}
#[derive(Debug, Clone)]
pub enum NodeKind {
Plain { body: Block },
Container {
ctype: ContainerType,
ctype_span: Span,
body: Block,
},
Call {
callee: Ident,
args: Vec<Expr>,
body: Option<Block>,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ContainerType {
Row,
Column,
Grid { cols: u32, rows: u32 },
}
#[derive(Debug, Clone)]
pub struct Edge {
pub from: PathRef,
pub op: EdgeOp,
pub op_span: Span,
pub to: PathRef,
pub label: Option<StrLit>,
pub props: Option<Block>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EdgeOp {
Forward,
Bidirectional,
}
#[derive(Debug, Clone)]
pub struct PathRef {
pub segments: Vec<PathSeg>,
pub span: Span,
}
#[derive(Debug, Clone)]
pub enum PathSeg {
Name(Ident),
Index(Expr),
Wildcard(Span),
}
impl PathRef {
pub fn display(&self) -> String {
let mut out = String::new();
for (i, seg) in self.segments.iter().enumerate() {
match seg {
PathSeg::Name(id) => {
if i > 0 {
out.push('.');
}
out.push_str(&id.name);
}
PathSeg::Index(_) => out.push_str("[..]"),
PathSeg::Wildcard(_) => out.push_str("[*]"),
}
}
out
}
}
#[derive(Debug, Clone)]
pub struct StrLit {
pub parts: Vec<StrPart>,
pub span: Span,
}
#[derive(Debug, Clone)]
pub enum StrPart {
Text(String),
Expr(Expr),
}
impl StrLit {
pub fn as_plain(&self) -> Option<String> {
match self.parts.as_slice() {
[] => Some(String::new()),
[StrPart::Text(t)] => Some(t.clone()),
_ => None,
}
}
}
#[derive(Debug, Clone)]
pub struct Expr {
pub kind: ExprKind,
pub span: Span,
}
#[derive(Debug, Clone)]
pub enum ExprKind {
Num(f64),
Str(Box<StrLit>),
Var(Ident),
Unary(UnOp, Box<Expr>),
Binary(BinOp, Box<Expr>, Box<Expr>),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UnOp {
Neg,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BinOp {
Add,
Sub,
Mul,
Div,
Mod,
}
impl BinOp {
pub fn symbol(self) -> &'static str {
match self {
BinOp::Add => "+",
BinOp::Sub => "-",
BinOp::Mul => "*",
BinOp::Div => "/",
BinOp::Mod => "%",
}
}
}