1use crate::*;
2use alloc::format;
3use alloc::string::String;
4use alloc::string::ToString;
5
6#[derive(Debug, PartialEq)]
7pub enum Word {
8 Text(String, TextEffect),
9 Sprite(ID),
10 Tile(ID),
11 Item(ID),
12 LineBreak,
13 PageBreak,
14}
15
16pub struct Interpreter<'a, T: Iterator<Item = Token>> {
17 pub tokens: T,
18 pub state: &'a mut State,
19}
20
21impl<'a, T: Iterator<Item = Token>> Iterator for Interpreter<'a, T> {
22 type Item = Word;
23
24 fn next(&mut self) -> Option<Self::Item> {
25 interpret(&mut self.tokens, self.state)
26 }
27}
28
29pub fn interpret<T>(tokens: &mut T, state: &mut State) -> Option<Word>
30where
31 T: Iterator<Item = Token>,
32{
33 for token in tokens.by_ref() {
34 let maybe_word = match token {
35 Token::OpenTag(tag) => handle_open_tag(tag, state),
36 Token::CloseTag(tag) => handle_close_tag(tag, state),
37 Token::Word(t) => Some(Word::Text(t, state.effect)),
38 };
39 if let Some(word) = maybe_word {
40 return Some(word);
41 }
42 }
43 None
44}
45
46fn handle_open_tag(tag: Tag, state: &mut State) -> Option<Word> {
47 match tag {
48 Tag::Br => return Some(Word::LineBreak),
49 Tag::Pg => return Some(Word::PageBreak),
50 Tag::Eff(eff) => state.effect = eff,
51 Tag::End => state.end = true,
52 Tag::Say(expr) => {
53 let val = eval_expr(expr, state);
54 let s = val_to_string(&val);
57 return Some(Word::Text(s, state.effect));
58 }
59 Tag::DrwT(id) => return Some(Word::Tile(id)),
60 Tag::DrwS(id) => return Some(Word::Sprite(id)),
61 Tag::DrwI(id) => return Some(Word::Item(id)),
62 Tag::Pal(pal) => state.palette = pal,
63 Tag::Ava(id) => state.avatar = id,
64 Tag::Exit(room, x, y) => {
65 state.room = room;
66 state.pos_x = x;
67 state.pos_y = y;
68 }
69 Tag::Set(name, expr) => {
70 let val = eval_expr(expr, state);
71 state.vars.set(name, val);
72 }
73 Tag::Unknown(_, _) => {}
74 };
75 None
76}
77
78fn handle_close_tag(tag: Tag, state: &mut State) -> Option<Word> {
79 if let Tag::Eff(_) = tag {
80 state.effect = TextEffect::None
81 };
82 None
83}
84
85fn eval_expr(expr: Expr, state: &mut State) -> Val {
86 match expr {
87 Expr::SimpleExpr(expr) => eval_simple_expr(expr, state),
88 Expr::BinOp(op, lhs, rhs) => {
89 let lhs = eval_simple_expr(lhs, state);
90 let rhs = eval_simple_expr(rhs, state);
91 eval_bin_op(op, lhs, rhs)
92 }
93 }
94}
95
96fn eval_simple_expr(expr: SimpleExpr, state: &mut State) -> Val {
97 match expr {
98 SimpleExpr::Var(name) => state.vars.get(&name).clone(),
99 SimpleExpr::Item(name) => Val::I(state.inventory.get(&name) as i16),
100 SimpleExpr::Val(val) => val,
101 }
102}
103
104fn eval_bin_op(op: BinOp, lhs: Val, rhs: Val) -> Val {
105 match op {
106 BinOp::Mul => match (lhs, rhs) {
107 (Val::I(a), Val::I(b)) => Val::I(a * b),
108 (Val::I(a), Val::F(b)) => Val::F(a as f32 * b),
109 (Val::F(a), Val::I(b)) => Val::F(a * b as f32),
110 (Val::F(a), Val::F(b)) => Val::F(a * b),
111 (Val::Undef, b) => b,
112 (a, _) => a,
113 },
114 BinOp::Div => match (lhs, rhs) {
115 (Val::I(a), Val::I(b)) => Val::I(a / b),
116 (Val::I(a), Val::F(b)) => Val::F(a as f32 / b),
117 (Val::F(a), Val::I(b)) => Val::F(a / b as f32),
118 (Val::F(a), Val::F(b)) => Val::F(a / b),
119 (Val::Undef, b) => b,
120 (a, _) => a,
121 },
122 BinOp::Add => match (lhs, rhs) {
123 (Val::I(a), Val::I(b)) => Val::I(a + b),
124 (Val::I(a), Val::F(b)) => Val::F(a as f32 + b),
125 (Val::F(a), Val::I(b)) => Val::F(a + b as f32),
126 (Val::S(a), Val::S(b)) => Val::S(alloc::format!("{a}{b}")),
127 (Val::F(a), Val::F(b)) => Val::F(a + b),
128 (a, Val::Undef) => a,
129 (_, b) => b,
130 },
131 BinOp::Sub => match (lhs, rhs) {
132 (Val::I(a), Val::I(b)) => Val::I(a - b),
133 (Val::I(a), Val::F(b)) => Val::F(a as f32 - b),
134 (Val::F(a), Val::I(b)) => Val::F(a - b as f32),
135 (Val::F(a), Val::F(b)) => Val::F(a - b),
136 (Val::Undef, b) => b,
137 (a, _) => a,
138 },
139 BinOp::Lt => {
140 let res = match (lhs, rhs) {
141 (Val::I(a), Val::I(b)) => a < b,
142 (Val::I(a), Val::F(b)) => (a as f32) < b,
143 (Val::F(a), Val::I(b)) => a < b as f32,
144 (Val::F(a), Val::F(b)) => a < b,
145 _ => false,
146 };
147 Val::I(if res { 1 } else { 0 })
148 }
149 BinOp::Gt => {
150 let res = match (lhs, rhs) {
151 (Val::I(a), Val::I(b)) => a > b,
152 (Val::I(a), Val::F(b)) => a as f32 > b,
153 (Val::F(a), Val::I(b)) => a > b as f32,
154 (Val::F(a), Val::F(b)) => a > b,
155 _ => false,
156 };
157 Val::I(if res { 1 } else { 0 })
158 }
159 BinOp::Lte => {
160 let res = match (lhs, rhs) {
161 (Val::I(a), Val::I(b)) => a <= b,
162 (Val::I(a), Val::F(b)) => a as f32 <= b,
163 (Val::F(a), Val::I(b)) => a <= b as f32,
164 (Val::F(a), Val::F(b)) => a <= b,
165 _ => false,
166 };
167 Val::I(if res { 1 } else { 0 })
168 }
169 BinOp::Gte => {
170 let res = match (lhs, rhs) {
171 (Val::I(a), Val::I(b)) => a >= b,
172 (Val::I(a), Val::F(b)) => a as f32 >= b,
173 (Val::F(a), Val::I(b)) => a >= b as f32,
174 (Val::F(a), Val::F(b)) => a >= b,
175 _ => false,
176 };
177 Val::I(if res { 1 } else { 0 })
178 }
179 BinOp::Eq => {
180 let res = match (lhs, rhs) {
181 (Val::I(a), Val::I(b)) => a == b,
182 (Val::I(a), Val::F(b)) => a as f32 == b,
183 (Val::F(a), Val::I(b)) => a == b as f32,
184 (Val::F(a), Val::F(b)) => a == b,
185 _ => false,
186 };
187 Val::I(if res { 1 } else { 0 })
188 }
189 }
190}
191
192fn val_to_string(val: &Val) -> String {
193 match val {
194 Val::Undef => "0".to_string(),
195 Val::I(i) => format!("{i}"),
196 Val::S(s) => s.to_string(),
197 Val::F(f) => format!("{f}"),
198 }
199}