Skip to main content

workshop_rs/wir/
action.rs

1//! Canonical Workshop action forms.
2
3use crate::core::source::Span;
4
5use super::{ActionId, GlobalVarId, PlayerVarId, SubroutineId, ValueId};
6
7/// A workshop action.
8#[derive(Debug, Clone)]
9pub enum Action {
10    SetGlobalVariable {
11        variable: GlobalVarId,
12        value: ValueId,
13        span: Option<Span>,
14        /// The exact span of the assigned variable identifier.
15        target_span: Option<Span>,
16    },
17    ModifyGlobalVariable {
18        variable: GlobalVarId,
19        op: ModifyOp,
20        value: ValueId,
21        span: Option<Span>,
22        /// The exact span of the modified variable identifier.
23        target_span: Option<Span>,
24    },
25    SetPlayerVariable {
26        player: ValueId,
27        variable: PlayerVarId,
28        value: ValueId,
29        span: Option<Span>,
30        /// The exact span of the assigned variable identifier.
31        target_span: Option<Span>,
32    },
33    ModifyPlayerVariable {
34        player: ValueId,
35        variable: PlayerVarId,
36        op: ModifyOp,
37        value: ValueId,
38        span: Option<Span>,
39        /// The exact span of the modified variable identifier.
40        target_span: Option<Span>,
41    },
42    /// Assignment to a canonical Workshop member-access target, optionally
43    /// indexed. This is not a builtin catalog action; the emitter preserves
44    /// the native member-assignment syntax.
45    AssignMember {
46        target: ValueId,
47        op: Option<ModifyOp>,
48        value: ValueId,
49        span: Option<Span>,
50    },
51    CallSubroutine {
52        subroutine: SubroutineId,
53        span: Option<Span>,
54        /// The exact span of the callee identifier occurrence.
55        callee_span: Option<Span>,
56    },
57    If {
58        branches: Vec<IfBranch>,
59        else_body: Option<Vec<ActionId>>,
60        span: Option<Span>,
61    },
62    While {
63        condition: ValueId,
64        body: Vec<ActionId>,
65        span: Option<Span>,
66    },
67    ForGlobalVariable {
68        variable: GlobalVarId,
69        start: ValueId,
70        stop: ValueId,
71        step: ValueId,
72        body: Vec<ActionId>,
73        span: Option<Span>,
74        /// The exact span of the loop variable identifier.
75        target_span: Option<Span>,
76    },
77    /// `For Player Variable(player, name, start, stop, step)`: the
78    /// per-player loop form (frontend-neutral; parsed from reference
79    /// evidence, not emitted by Wright's own lowering, which models
80    /// foreach counters as globals under the declared #119 contract).
81    ForPlayerVariable {
82        player: ValueId,
83        variable: PlayerVarId,
84        start: ValueId,
85        stop: ValueId,
86        step: ValueId,
87        body: Vec<ActionId>,
88        span: Option<Span>,
89    },
90    /// Any other action call with side effects.
91    Call {
92        name: String,
93        args: Vec<ValueId>,
94        span: Option<Span>,
95    },
96}
97
98impl Action {
99    /// The source span of this action, if any.
100    pub fn span(&self) -> Option<Span> {
101        match self {
102            Action::SetGlobalVariable { span, .. }
103            | Action::ModifyGlobalVariable { span, .. }
104            | Action::SetPlayerVariable { span, .. }
105            | Action::ModifyPlayerVariable { span, .. }
106            | Action::AssignMember { span, .. }
107            | Action::CallSubroutine { span, .. }
108            | Action::If { span, .. }
109            | Action::While { span, .. }
110            | Action::ForGlobalVariable { span, .. }
111            | Action::ForPlayerVariable { span, .. }
112            | Action::Call { span, .. } => *span,
113        }
114    }
115}
116
117/// One condition/body pair of an `If` action.
118#[derive(Debug, Clone)]
119pub struct IfBranch {
120    pub condition: ValueId,
121    pub body: Vec<ActionId>,
122}
123
124/// The modify operators of the v0.1 surface.
125#[derive(Debug, Clone, Copy, PartialEq, Eq)]
126pub enum ModifyOp {
127    Add,
128    Subtract,
129    Multiply,
130    Divide,
131    Modulo,
132    Min,
133    Max,
134    RaiseToPower,
135    AppendToArray,
136    RemoveFromArray,
137    RemoveFromArrayByIndex,
138}
139
140impl ModifyOp {
141    /// A short canonical name for dumps and diagnostics.
142    pub fn as_str(self) -> &'static str {
143        match self {
144            ModifyOp::Add => "Add",
145            ModifyOp::Subtract => "Subtract",
146            ModifyOp::Multiply => "Multiply",
147            ModifyOp::Divide => "Divide",
148            ModifyOp::Modulo => "Modulo",
149            ModifyOp::Min => "Min",
150            ModifyOp::Max => "Max",
151            ModifyOp::RaiseToPower => "RaiseToPower",
152            ModifyOp::AppendToArray => "AppendToArray",
153            ModifyOp::RemoveFromArray => "RemoveFromArray",
154            ModifyOp::RemoveFromArrayByIndex => "RemoveFromArrayByIndex",
155        }
156    }
157
158    /// The canonical catalog identity for this modification operation.
159    pub fn catalog_id(self) -> &'static str {
160        match self {
161            ModifyOp::Add => "add",
162            ModifyOp::Subtract => "subtract",
163            ModifyOp::Multiply => "multiply",
164            ModifyOp::Divide => "divide",
165            ModifyOp::Modulo => "modulo",
166            ModifyOp::Min => "min",
167            ModifyOp::Max => "max",
168            ModifyOp::RaiseToPower => "raiseToPower",
169            ModifyOp::AppendToArray => "appendToArray",
170            ModifyOp::RemoveFromArray => "removeFromArray",
171            ModifyOp::RemoveFromArrayByIndex => "removeFromArrayByIndex",
172        }
173    }
174}