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) => {
51 if state.effect != TextEffect::None {
52 state.effect = TextEffect::None;
53 } else {
54 state.effect = eff
55 }
56 }
57 Tag::End => state.end = true,
58 Tag::Say(expr) => {
59 let val = eval_expr(expr, state);
60 let s = val_to_string(&val);
63 return Some(Word::Text(s, state.effect));
64 }
65 Tag::DrwT(id) => return Some(Word::Tile(id)),
66 Tag::DrwS(id) => return Some(Word::Sprite(id)),
67 Tag::DrwI(id) => return Some(Word::Item(id)),
68 Tag::Pal(pal) => state.palette = pal,
69 Tag::Ava(id) => state.avatar = id,
70 Tag::Exit(room, x, y) => {
71 state.room = room;
72 state.pos_x = x;
73 state.pos_y = y;
74 }
75 Tag::Set(name, expr) => {
76 let val = eval_expr(expr, state);
77 state.vars.set(name, val);
78 }
79 Tag::Unknown(_, _) => {}
80 };
81 None
82}
83
84fn handle_close_tag(tag: Tag, state: &mut State) -> Option<Word> {
85 if let Tag::Eff(_) = tag {
86 state.effect = TextEffect::None
87 };
88 None
89}
90
91fn eval_expr(expr: Expr, state: &mut State) -> Val {
92 match expr {
93 Expr::SimpleExpr(expr) => eval_simple_expr(expr, state),
94 Expr::BinOp(op, lhs, rhs) => {
95 let lhs = eval_simple_expr(lhs, state);
96 let rhs = eval_simple_expr(rhs, state);
97 eval_bin_op(op, lhs, rhs)
98 }
99 }
100}
101
102fn eval_simple_expr(expr: SimpleExpr, state: &mut State) -> Val {
103 match expr {
104 SimpleExpr::Var(name) => state.vars.get(&name).clone(),
105 SimpleExpr::Item(name) => Val::I(state.inventory.get(&name) as i16),
106 SimpleExpr::Val(val) => val,
107 }
108}
109
110fn eval_bin_op(op: BinOp, lhs: Val, rhs: Val) -> Val {
111 match op {
112 BinOp::Mul => match (lhs, rhs) {
113 (Val::I(a), Val::I(b)) => Val::I(a * b),
114 (Val::I(a), Val::F(b)) => Val::F(a as f32 * b),
115 (Val::F(a), Val::I(b)) => Val::F(a * b as f32),
116 (Val::F(a), Val::F(b)) => Val::F(a * b),
117 (Val::Undef, b) => b,
118 (a, _) => a,
119 },
120 BinOp::Div => match (lhs, rhs) {
121 (Val::I(a), Val::I(b)) => Val::I(a / b),
122 (Val::I(a), Val::F(b)) => Val::F(a as f32 / b),
123 (Val::F(a), Val::I(b)) => Val::F(a / b as f32),
124 (Val::F(a), Val::F(b)) => Val::F(a / b),
125 (Val::Undef, b) => b,
126 (a, _) => a,
127 },
128 BinOp::Add => match (lhs, rhs) {
129 (Val::I(a), Val::I(b)) => Val::I(a + b),
130 (Val::I(a), Val::F(b)) => Val::F(a as f32 + b),
131 (Val::F(a), Val::I(b)) => Val::F(a + b as f32),
132 (Val::S(a), Val::S(b)) => Val::S(alloc::format!("{a}{b}")),
133 (Val::F(a), Val::F(b)) => Val::F(a + b),
134 (a, Val::Undef) => a,
135 (_, b) => b,
136 },
137 BinOp::Sub => match (lhs, rhs) {
138 (Val::I(a), Val::I(b)) => Val::I(a - b),
139 (Val::I(a), Val::F(b)) => Val::F(a as f32 - b),
140 (Val::F(a), Val::I(b)) => Val::F(a - b as f32),
141 (Val::F(a), Val::F(b)) => Val::F(a - b),
142 (Val::Undef, b) => b,
143 (a, _) => a,
144 },
145 BinOp::Lt => {
146 let res = match (lhs, rhs) {
147 (Val::I(a), Val::I(b)) => a < b,
148 (Val::I(a), Val::F(b)) => (a as f32) < b,
149 (Val::F(a), Val::I(b)) => a < b as f32,
150 (Val::F(a), Val::F(b)) => a < b,
151 _ => false,
152 };
153 Val::I(if res { 1 } else { 0 })
154 }
155 BinOp::Gt => {
156 let res = match (lhs, rhs) {
157 (Val::I(a), Val::I(b)) => a > b,
158 (Val::I(a), Val::F(b)) => a as f32 > b,
159 (Val::F(a), Val::I(b)) => a > b as f32,
160 (Val::F(a), Val::F(b)) => a > b,
161 _ => false,
162 };
163 Val::I(if res { 1 } else { 0 })
164 }
165 BinOp::Lte => {
166 let res = match (lhs, rhs) {
167 (Val::I(a), Val::I(b)) => a <= b,
168 (Val::I(a), Val::F(b)) => a as f32 <= b,
169 (Val::F(a), Val::I(b)) => a <= b as f32,
170 (Val::F(a), Val::F(b)) => a <= b,
171 _ => false,
172 };
173 Val::I(if res { 1 } else { 0 })
174 }
175 BinOp::Gte => {
176 let res = match (lhs, rhs) {
177 (Val::I(a), Val::I(b)) => a >= b,
178 (Val::I(a), Val::F(b)) => a as f32 >= b,
179 (Val::F(a), Val::I(b)) => a >= b as f32,
180 (Val::F(a), Val::F(b)) => a >= b,
181 _ => false,
182 };
183 Val::I(if res { 1 } else { 0 })
184 }
185 BinOp::Eq => {
186 let res = match (lhs, rhs) {
187 (Val::I(a), Val::I(b)) => a == b,
188 (Val::I(a), Val::F(b)) => a as f32 == b,
189 (Val::F(a), Val::I(b)) => a == b as f32,
190 (Val::F(a), Val::F(b)) => a == b,
191 _ => false,
192 };
193 Val::I(if res { 1 } else { 0 })
194 }
195 }
196}
197
198fn val_to_string(val: &Val) -> String {
199 match val {
200 Val::Undef => "0".to_string(),
201 Val::I(i) => format!("{i}"),
202 Val::S(s) => s.to_string(),
203 Val::F(f) => format!("{f}"),
204 }
205}