1use crate::error::error_msgs;
2use crate::{
3 CommandExpression, Compilable, Parser, ParserError, Value, VariableKind, COMMAND_SEPARATOR,
4};
5use crate::{VAR_CONST, VAR_LET};
6use std::fmt;
7
8pub static CMD_DCLR_VAR: char = '\x51';
9pub static CMD_ASGN_VAR: char = '\x52';
10pub static CMD_PUTS: char = '\x53';
11pub static CMD_EVAL: char = '\x54';
12pub static CMD_SCOPE: char = '\x55';
13pub static CMD_LOOP: char = '\x56';
14pub static CMD_COND: char = '\x57';
15pub static CMD_BREAK: char = '\x58';
16
17#[derive(Debug, Clone, PartialEq)]
18pub enum Command {
19 Break,
20 AssignVariable {
21 name: Value,
22 value: CommandExpression,
23 },
24 Conditional {
25 condition: CommandExpression,
26 body: Vec<Command>,
27 otherwise: Option<Vec<Command>>,
28 },
29 DeclareVariable {
30 kind: VariableKind,
31 name: Value,
32 value: CommandExpression,
33 },
34 Evaluate {
35 expr: CommandExpression,
36 },
37 Loop {
38 body: Vec<Command>,
39 },
40 Puts {
41 value: CommandExpression,
42 },
43 Scope {
44 body: Vec<Command>,
45 },
46}
47
48impl Command {
49 pub fn get_kind(&self) -> char {
50 match self {
51 Self::AssignVariable { .. } => CMD_ASGN_VAR,
52 Self::DeclareVariable { .. } => CMD_DCLR_VAR,
53 Self::Evaluate { .. } => CMD_EVAL,
54 Self::Puts { .. } => CMD_PUTS,
55 Self::Scope { .. } => CMD_SCOPE,
56 Self::Loop { .. } => CMD_LOOP,
57 Self::Conditional { .. } => CMD_COND,
58 Self::Break { .. } => CMD_BREAK,
59 }
60 }
61
62 pub fn visit_asgn(parser: &mut Parser) -> Result<Self, ParserError> {
63 let name = Value::visit(parser)?;
64 let value = CommandExpression::visit(parser)?;
65
66 Ok(Command::AssignVariable { name, value })
67 }
68
69 pub fn visit_var(parser: &mut Parser) -> Result<Self, ParserError> {
70 let kind = parser.consume().ok_or_else(|| {
71 parser.error_corrupt(
72 error_msgs::ERROR_INVALID_CMD_DECL,
73 "Can't get variable kind",
74 1,
75 )
76 })?;
77 let kind = match kind {
78 b if b == VAR_CONST => VariableKind::Const,
79 b if b == VAR_LET => VariableKind::Let,
80 b => {
81 return Err(parser.error_corrupt(
82 error_msgs::ERROR_UNKNOWN_VAR_KIND,
83 format!("{b:?}"),
84 1,
85 ))
86 }
87 };
88
89 let name = Value::visit(parser)?;
90 let value = CommandExpression::visit(parser)?;
91
92 Ok(Command::DeclareVariable { name, kind, value })
93 }
94
95 fn visit_scope(parser: &mut Parser) -> Result<Vec<Self>, ParserError> {
96 let mut body: Vec<Command> = vec![];
97 loop {
98 if parser.peek(0) == Some(COMMAND_SEPARATOR) {
99 parser.pointer += 1;
100 break;
101 }
102
103 let cmd = Command::visit(parser)?;
104 body.push(cmd);
105 }
106
107 Ok(body)
108 }
109
110 pub fn visit(parser: &mut Parser) -> Result<Self, ParserError> {
111 let b = parser.consume().ok_or_else(|| {
112 parser.error_corrupt(
113 error_msgs::ERROR_INVALID_CMD_DECL,
114 "Can't get command kind",
115 1,
116 )
117 })?;
118
119 match b {
120 b if b == CMD_BREAK => Ok(Command::Break),
121 b if b == CMD_ASGN_VAR => Self::visit_asgn(parser),
122 b if b == CMD_DCLR_VAR => Self::visit_var(parser),
123 b if b == CMD_PUTS => Ok(Command::Puts {
124 value: CommandExpression::visit(parser)?,
125 }),
126 b if b == CMD_SCOPE => Ok(Command::Scope {
127 body: Self::visit_scope(parser)?,
128 }),
129 b if b == CMD_LOOP => Ok(Command::Loop {
130 body: Self::visit_scope(parser)?,
131 }),
132 b if b == CMD_COND => Ok(Command::Conditional {
133 condition: CommandExpression::visit(parser)?,
134 body: Self::visit_scope(parser)?,
135 otherwise: if parser.peek(0) != Some(COMMAND_SEPARATOR) {
136 Some(Self::visit_scope(parser)?)
137 } else {
138 let _ = parser.consume();
139 None
140 },
141 }),
142 _ => Err(parser.error_corrupt(
143 error_msgs::ERROR_INVALID_CMD_DECL,
144 format!("Unknown command {:02x?}", b as u8),
145 1,
146 )),
147 }
148 }
149}
150impl Compilable for Command {
151 fn compile_bytecode(&self) -> Box<str> {
152 match self {
153 Self::DeclareVariable { name, value, kind } => {
154 if !name.is_string() {
155 panic!("Variable name should be string");
156 }
157 let kind = kind.compile_bytecode();
158 let name = name.compile_bytecode();
159 let value = value.compile_bytecode();
160
161 Box::from(format!("{CMD_DCLR_VAR}{kind}{name}{value}"))
162 }
163 Self::AssignVariable { name, value } => {
164 if !name.is_string() {
165 panic!("Variable name should be string");
166 }
167 let name = name.compile_bytecode();
168 let value = value.compile_bytecode();
169 Box::from(format!("{CMD_ASGN_VAR}{name}{value}"))
170 }
171 Self::Puts { value } => {
172 let value = value.compile_bytecode();
173 Box::from(format!("{CMD_PUTS}{value}"))
174 }
175 Self::Scope { body } => {
176 let value = body.compile_bytecode();
177 Box::from(format!("{CMD_SCOPE}{value}{COMMAND_SEPARATOR}"))
178 }
179 Self::Loop { body } => {
180 let value = body.compile_bytecode();
181 Box::from(format!("{CMD_LOOP}{value}{COMMAND_SEPARATOR}"))
182 }
183 Self::Conditional {
184 condition,
185 body,
186 otherwise,
187 } => {
188 let condition = condition.compile_bytecode();
189 let body = body.compile_bytecode();
190 let otherwise = if let Some(otherwise) = otherwise {
191 let otherwise = otherwise.compile_bytecode();
192 format!("{otherwise}{COMMAND_SEPARATOR}")
193 } else {
194 COMMAND_SEPARATOR.to_string()
195 };
196
197 Box::from(format!(
198 "{CMD_COND}{condition}{body}{COMMAND_SEPARATOR}{otherwise}"
199 ))
200 }
201 Self::Break => Box::from(CMD_BREAK.to_string()),
202 _ => todo!("{self:#?}"),
203 }
204 }
205}
206
207impl fmt::Display for Command {
208 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
209 fn fmt_body(f: &mut fmt::Formatter, body: &Vec<Command>) -> fmt::Result {
210 for (i, cmd) in body.iter().enumerate() {
211 let ib = format!("\x1b[32m{i:03x}\x1b[0m");
212 let cmd = format!("{cmd}");
213 let mut cmd = cmd
214 .split('\n')
215 .map(|c| format!(".{ib}{c}\n"))
216 .collect::<String>();
217
218 if i == body.len() - 1 {
219 cmd.pop();
220 }
221 f.write_str(&cmd)?;
222 }
223
224 Ok(())
225 }
226
227 match self {
228 Self::Break => f.write_str(": Break"),
229 Self::AssignVariable { name, value } => {
230 f.write_fmt(format_args!(": AssignVariable({name}, {value})"))
231 }
232 Self::DeclareVariable { name, value, kind } => {
233 f.write_fmt(format_args!(": DeclareVariable({kind}, {name}, {value})"))
234 }
235 Self::Evaluate { expr } => f.write_fmt(format_args!(": Evaluate({expr})")),
236 Self::Puts { value } => f.write_fmt(format_args!(": Puts({value})")),
237 Self::Scope { body } => {
238 f.write_str(": Scope:\n")?;
239
240 fmt_body(f, body)
241 }
242 Self::Loop { body } => {
243 f.write_str(": Loop:\n")?;
244
245 fmt_body(f, body)
246 }
247 Self::Conditional {
248 condition,
249 body,
250 otherwise,
251 } => {
252 f.write_fmt(format_args!(": Conditional({condition}):\n"))?;
253
254 fmt_body(f, body)?;
255
256 if let Some(otherwise) = otherwise {
257 f.write_str("\n: Else:\n")?;
258 fmt_body(f, otherwise)?;
259 }
260
261 Ok(())
262 }
263 }
264 }
265}