amvm/tokens/
command.rs

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}