Skip to main content

rpic_core/
ast.rs

1//! Abstract syntax tree for the pic language.
2//!
3//! Mirrors the structure of dpic's `grammar.txt`. The current parser populates
4//! the drawing core (pictures, primitives + attributes, positions, expressions,
5//! blocks, assignments). Control constructs (`if`/`for`/`define`/`print`/…) have
6//! AST slots reserved but are wired up in a later milestone.
7
8use crate::token::{
9    Arrow, Color, Corner, Dir, EnvVar, Func1, Func2, LineType, Param, Prim, TextPos,
10};
11
12/// A complete picture: optional `.PS <w> <h>` dimensions plus a list of elements.
13#[derive(Debug, Clone, PartialEq)]
14pub struct Picture {
15    pub width: Option<Expr>,
16    pub height: Option<Expr>,
17    pub stmts: Vec<Stmt>,
18}
19
20/// A label with an optional `[subscript]` suffix.
21#[derive(Debug, Clone, PartialEq)]
22pub struct Label {
23    pub name: String,
24    pub subscript: Option<Expr>,
25}
26
27/// A top-level element.
28#[derive(Debug, Clone, PartialEq)]
29pub enum Stmt {
30    /// A drawn object, optionally labelled (`Start: box …`).
31    Object {
32        label: Option<Label>,
33        object: Object,
34    },
35    /// `Label: position` — names a point without drawing.
36    Place { label: Label, pos: Position },
37    /// One or more comma-separated assignments.
38    Assign(Vec<Assignment>),
39    /// A bare direction change (`up` / `down` / `left` / `right`).
40    Direction(Dir),
41    /// `{ … }` grouping block (local scope, no bounding object).
42    Group(Vec<Stmt>),
43    /// rpic animation directive (extension; see [`Animate`]).
44    Animate(Animate),
45    /// `if <cond> then { … } [else { … }]`.
46    If {
47        cond: Expr,
48        then_body: Vec<Stmt>,
49        else_body: Option<Vec<Stmt>>,
50    },
51    /// `for v = from to to [by [*] step] do { … }`.
52    For {
53        var: String,
54        from: Expr,
55        to: Expr,
56        by: Expr,
57        /// `by *` multiplies instead of adds.
58        mult: bool,
59        body: Vec<Stmt>,
60    },
61    /// `print …` (evaluated for diagnostics; no drawing effect).
62    Print(PrintItem),
63    /// `reset` (all) or `reset a, b, …` — restore environment variables.
64    Reset(Vec<EnvVar>),
65}
66
67#[derive(Debug, Clone, PartialEq)]
68pub enum PrintItem {
69    Str(StringExpr),
70    Expr(Expr),
71}
72
73/// `animate <target> with "<effect>" [for <dur>] [at <t> | after <ref>] [delay <d>]`.
74#[derive(Debug, Clone, PartialEq)]
75pub struct Animate {
76    pub target: Place,
77    pub effect: StringExpr,
78    pub duration: Option<Expr>,
79    pub timing: Timing,
80    pub delay: Option<Expr>,
81}
82
83/// When an animation starts.
84#[derive(Debug, Clone, PartialEq)]
85pub enum Timing {
86    /// After the previously declared animation ends (default).
87    Sequential,
88    /// At an absolute time (seconds).
89    At(Expr),
90    /// After the named object's animation ends.
91    After(Place),
92}
93
94/// A single assignment `target op value`.
95#[derive(Debug, Clone, PartialEq)]
96pub struct Assignment {
97    pub target: AssignTarget,
98    pub op: AssignOp,
99    pub value: Expr,
100}
101
102#[derive(Debug, Clone, PartialEq)]
103pub enum AssignTarget {
104    Var(String, Option<Expr>),
105    Env(EnvVar),
106}
107
108#[derive(Debug, Clone, Copy, PartialEq, Eq)]
109pub enum AssignOp {
110    Set, // =  or  :=
111    Add, // +=
112    Sub, // -=
113    Mul, // *=
114    Div, // /=
115    Rem, // %=
116}
117
118/// A drawable object: a base plus a chain of attributes.
119#[derive(Debug, Clone, PartialEq)]
120pub struct Object {
121    pub kind: ObjectKind,
122    pub attrs: Vec<Attr>,
123}
124
125#[derive(Debug, Clone, PartialEq)]
126pub enum ObjectKind {
127    Primitive(Prim),
128    Block(Vec<Stmt>),
129    /// `[]` empty-block reference.
130    Empty,
131    /// A bare quoted string places a text-only object.
132    Text,
133}
134
135/// An object attribute (applied left to right).
136#[derive(Debug, Clone, PartialEq)]
137pub enum Attr {
138    Dim(DimKind, Expr),
139    Direction(Dir, Option<Expr>),
140    LineStyle(LineType, Option<Expr>),
141    Chop(Option<Expr>),
142    Fill(Option<Expr>),
143    Arrowhead(Arrow, Option<Expr>),
144    Then,
145    Cw,
146    Ccw,
147    Same,
148    Continue,
149    Text(StringExpr),
150    TextPos(TextPos),
151    From(Position),
152    To(Position),
153    At(Position),
154    By(Position),
155    With { anchor: WithAnchor, at: Position },
156    Color(Color, StringExpr),
157}
158
159#[derive(Debug, Clone, Copy, PartialEq, Eq)]
160pub enum DimKind {
161    Ht,
162    Wid,
163    Rad,
164    Diam,
165    Thick,
166    Scaled,
167}
168
169/// The reference point on an object used by `with … at …`.
170#[derive(Debug, Clone, PartialEq)]
171pub enum WithAnchor {
172    Corner(Corner),
173    Pair(Expr, Expr),
174    Plain,
175}
176
177/// A position (point) expression.
178#[derive(Debug, Clone, PartialEq)]
179pub enum Position {
180    /// Explicit `x , y`.
181    Pair(Expr, Expr),
182    /// A location plus zero or more `± location` shifts.
183    Place(Location, Vec<Shift>),
184    /// `frac [of the way] between A and B`.
185    Between {
186        frac: Box<Expr>,
187        a: Box<Position>,
188        b: Box<Position>,
189        of_the_way: bool,
190    },
191}
192
193#[derive(Debug, Clone, PartialEq)]
194pub struct Shift {
195    pub sign: Sign,
196    pub loc: Location,
197}
198
199#[derive(Debug, Clone, Copy, PartialEq, Eq)]
200pub enum Sign {
201    Plus,
202    Minus,
203}
204
205/// A point-valued location.
206#[derive(Debug, Clone, PartialEq)]
207pub enum Location {
208    Place(Place),
209    /// `( position )`.
210    Paren(Box<Position>),
211    /// `( position , position )` — x of the first, y of the second.
212    ParenPair(Box<Position>, Box<Position>),
213}
214
215/// A named place in the drawing.
216#[derive(Debug, Clone, PartialEq)]
217pub enum Place {
218    /// A label, optionally subscripted.
219    Name {
220        name: String,
221        subscript: Option<Box<Expr>>,
222    },
223    /// `last box`, `2nd last circle`, etc.
224    Nth {
225        count: Nth,
226        obj: PrimObj,
227    },
228    /// `place . corner` (e.g. `A.ne`).
229    Corner(Box<Place>, Corner),
230    /// `corner of place` / `corner place` (e.g. `top of A`).
231    CornerOf(Corner, Box<Place>),
232    /// `place . place` (block sub-label, e.g. `B.A`).
233    Member(Box<Place>, Box<Place>),
234    Here,
235}
236
237#[derive(Debug, Clone, PartialEq)]
238pub enum Nth {
239    Last,
240    /// `count`-th object; `from_last` true for `… last`.
241    Count(Box<Expr>, bool),
242}
243
244#[derive(Debug, Clone, PartialEq)]
245pub enum PrimObj {
246    Prim(Prim),
247    Block,
248    Str(String),
249    EmptyBrack,
250}
251
252/// A string-valued expression.
253#[derive(Debug, Clone, PartialEq)]
254pub enum StringExpr {
255    Lit(String),
256    Concat(Box<StringExpr>, Box<StringExpr>),
257    Sprintf(Box<StringExpr>, Vec<Expr>),
258    Arg(u32),
259}
260
261/// A scalar (numeric / boolean) expression. pic treats booleans as numbers.
262#[derive(Debug, Clone, PartialEq)]
263pub enum Expr {
264    Num(f64),
265    Var(String),
266    Env(EnvVar),
267    Unary(UnOp, Box<Expr>),
268    Bin(BinOp, Box<Expr>, Box<Expr>),
269    Func1(Func1, Box<Expr>),
270    Func2(Func2, Box<Expr>, Box<Expr>),
271    Rand(Option<Box<Expr>>),
272    DotX(Location),
273    DotY(Location),
274    PlaceAttr(Place, Param),
275}
276
277#[derive(Debug, Clone, Copy, PartialEq, Eq)]
278pub enum UnOp {
279    Neg,
280    Pos,
281    Not,
282}
283
284#[derive(Debug, Clone, Copy, PartialEq, Eq)]
285pub enum BinOp {
286    Add,
287    Sub,
288    Mul,
289    Div,
290    Mod,
291    Pow,
292    Eq,
293    Ne,
294    Lt,
295    Le,
296    Gt,
297    Ge,
298    And,
299    Or,
300}