1use crate::ast::{ExprType, Value};
19use crate::reader::LineCol;
20use crate::syms::SymbolKey;
21
22pub type Address = usize;
24
25#[derive(Debug, PartialEq)]
27#[cfg_attr(test, derive(Clone))]
28pub struct DimISpan {
29 pub name: SymbolKey,
31
32 pub shared: bool,
34
35 pub vtype: ExprType,
37}
38
39#[derive(Debug, PartialEq)]
41#[cfg_attr(test, derive(Clone))]
42pub struct DimArrayISpan {
43 pub name: SymbolKey,
45
46 pub name_pos: LineCol,
48
49 pub shared: bool,
51
52 pub dimensions: usize,
54
55 pub subtype: ExprType,
57
58 pub subtype_pos: LineCol,
60}
61
62#[derive(Debug, Eq, PartialEq)]
64pub struct JumpISpan {
65 pub addr: Address,
67}
68
69#[cfg_attr(test, derive(Debug, Eq, PartialEq))]
71pub struct JumpIfDefinedISpan {
72 pub var: SymbolKey,
74
75 pub addr: Address,
77}
78
79#[derive(Clone, Copy)]
81#[cfg_attr(test, derive(Debug, Eq, PartialEq))]
82pub enum ErrorHandlerISpan {
83 Jump(Address),
85
86 None,
88
89 ResumeNext,
91}
92
93#[cfg_attr(test, derive(Debug, Eq, PartialEq))]
95pub struct UnsetISpan {
96 pub name: SymbolKey,
98
99 pub pos: LineCol,
101}
102
103#[cfg_attr(test, derive(Debug, PartialEq))]
105pub enum Instruction {
106 LogicalAnd(LineCol),
108
109 LogicalOr(LineCol),
111
112 LogicalXor(LineCol),
114
115 LogicalNot(LineCol),
117
118 BitwiseAnd(LineCol),
120
121 BitwiseOr(LineCol),
123
124 BitwiseXor(LineCol),
126
127 BitwiseNot(LineCol),
129
130 ShiftLeft(LineCol),
132
133 ShiftRight(LineCol),
135
136 EqualBooleans(LineCol),
138
139 NotEqualBooleans(LineCol),
141
142 EqualDoubles(LineCol),
144
145 NotEqualDoubles(LineCol),
147
148 LessDoubles(LineCol),
150
151 LessEqualDoubles(LineCol),
153
154 GreaterDoubles(LineCol),
156
157 GreaterEqualDoubles(LineCol),
159
160 EqualIntegers(LineCol),
162
163 NotEqualIntegers(LineCol),
165
166 LessIntegers(LineCol),
168
169 LessEqualIntegers(LineCol),
171
172 GreaterIntegers(LineCol),
174
175 GreaterEqualIntegers(LineCol),
177
178 EqualStrings(LineCol),
180
181 NotEqualStrings(LineCol),
183
184 LessStrings(LineCol),
186
187 LessEqualStrings(LineCol),
189
190 GreaterStrings(LineCol),
192
193 GreaterEqualStrings(LineCol),
195
196 AddDoubles(LineCol),
198
199 SubtractDoubles(LineCol),
201
202 MultiplyDoubles(LineCol),
204
205 DivideDoubles(LineCol),
207
208 ModuloDoubles(LineCol),
210
211 PowerDoubles(LineCol),
213
214 NegateDouble(LineCol),
216
217 AddIntegers(LineCol),
219
220 SubtractIntegers(LineCol),
222
223 MultiplyIntegers(LineCol),
225
226 DivideIntegers(LineCol),
228
229 ModuloIntegers(LineCol),
231
232 PowerIntegers(LineCol),
234
235 NegateInteger(LineCol),
237
238 ConcatStrings(LineCol),
240
241 ArrayAssignment(SymbolKey, LineCol, usize),
243
244 ArrayLoad(SymbolKey, LineCol, usize),
246
247 Assign(SymbolKey),
249
250 BuiltinCall(SymbolKey, LineCol, usize),
255
256 Call(JumpISpan),
258
259 FunctionCall(SymbolKey, ExprType, LineCol, usize),
261
262 Dim(DimISpan),
264
265 DimArray(DimArrayISpan),
267
268 End(bool),
271
272 EnterScope,
274
275 DoubleToInteger,
277
278 IntegerToDouble,
280
281 Jump(JumpISpan),
283
284 JumpIfDefined(JumpIfDefinedISpan),
286
287 JumpIfTrue(Address),
289
290 JumpIfNotTrue(Address),
292
293 LeaveScope,
295
296 LoadBoolean(SymbolKey, LineCol),
298
299 LoadDouble(SymbolKey, LineCol),
301
302 LoadInteger(SymbolKey, LineCol),
304
305 LoadString(SymbolKey, LineCol),
307
308 LoadRef(SymbolKey, ExprType, LineCol),
310
311 Nop,
313
314 PushBoolean(bool, LineCol),
316
317 PushDouble(f64, LineCol),
319
320 PushInteger(i32, LineCol),
322
323 PushString(String, LineCol),
325
326 Return(LineCol),
328
329 SetErrorHandler(ErrorHandlerISpan),
331
332 Unset(UnsetISpan),
334}
335
336impl Instruction {
337 pub fn repr(&self) -> (&'static str, Option<String>) {
339 match self {
340 Instruction::BitwiseAnd(_pos) => ("AND%", None),
341 Instruction::BitwiseOr(_pos) => ("OR%", None),
342 Instruction::BitwiseXor(_pos) => ("XOR%", None),
343 Instruction::BitwiseNot(_pos) => ("NOT%", None),
344
345 Instruction::LogicalAnd(_pos) => ("AND?", None),
346 Instruction::LogicalOr(_pos) => ("OR?", None),
347 Instruction::LogicalXor(_pos) => ("XOR?", None),
348 Instruction::LogicalNot(_pos) => ("NOT?", None),
349
350 Instruction::ShiftLeft(_pos) => ("SHL%", None),
351 Instruction::ShiftRight(_pos) => ("SHR%", None),
352
353 Instruction::EqualBooleans(_pos) => ("CMPE?", None),
354 Instruction::NotEqualBooleans(_pos) => ("CMPNE?", None),
355
356 Instruction::EqualDoubles(_pos) => ("CMPE#", None),
357 Instruction::NotEqualDoubles(_pos) => ("CMPNE#", None),
358 Instruction::LessDoubles(_pos) => ("CMPL#", None),
359 Instruction::LessEqualDoubles(_pos) => ("CMPLE#", None),
360 Instruction::GreaterDoubles(_pos) => ("CMPG#", None),
361 Instruction::GreaterEqualDoubles(_pos) => ("CMPGE#", None),
362
363 Instruction::EqualIntegers(_pos) => ("CMPE%", None),
364 Instruction::NotEqualIntegers(_pos) => ("CMPNE%", None),
365 Instruction::LessIntegers(_pos) => ("CMPL%", None),
366 Instruction::LessEqualIntegers(_pos) => ("CMPLE%", None),
367 Instruction::GreaterIntegers(_pos) => ("CMPG%", None),
368 Instruction::GreaterEqualIntegers(_pos) => ("CMPGE%", None),
369
370 Instruction::EqualStrings(_pos) => ("CMPE$", None),
371 Instruction::NotEqualStrings(_pos) => ("CMPNE$", None),
372 Instruction::LessStrings(_pos) => ("CMPL$", None),
373 Instruction::LessEqualStrings(_pos) => ("CMPLE$", None),
374 Instruction::GreaterStrings(_pos) => ("CMPG$", None),
375 Instruction::GreaterEqualStrings(_pos) => ("CMPGE$", None),
376
377 Instruction::AddDoubles(_pos) => ("ADD#", None),
378 Instruction::SubtractDoubles(_pos) => ("SUB#", None),
379 Instruction::MultiplyDoubles(_pos) => ("MUL#", None),
380 Instruction::DivideDoubles(_pos) => ("DIV#", None),
381 Instruction::ModuloDoubles(_pos) => ("MOD#", None),
382 Instruction::PowerDoubles(_pos) => ("POW#", None),
383 Instruction::NegateDouble(_pos) => ("NEG#", None),
384
385 Instruction::AddIntegers(_pos) => ("ADD%", None),
386 Instruction::SubtractIntegers(_pos) => ("SUB%", None),
387 Instruction::MultiplyIntegers(_pos) => ("MUL%", None),
388 Instruction::DivideIntegers(_pos) => ("DIV%", None),
389 Instruction::ModuloIntegers(_pos) => ("MOD%", None),
390 Instruction::PowerIntegers(_pos) => ("POW%", None),
391 Instruction::NegateInteger(_pos) => ("NEG%", None),
392
393 Instruction::ConcatStrings(_pos) => ("CONCAT$", None),
394
395 Instruction::ArrayAssignment(key, _pos, nargs) => {
396 ("SETA", Some(format!("{}, {}", key, nargs)))
397 }
398
399 Instruction::ArrayLoad(key, _pos, nargs) => {
400 ("LOADA", Some(format!("{}, {}", key, nargs)))
401 }
402
403 Instruction::Assign(key) => ("SETV", Some(key.to_string())),
404
405 Instruction::BuiltinCall(key, _pos, nargs) => {
406 ("CALLB", Some(format!("{}, {}", key, nargs)))
407 }
408
409 Instruction::Call(span) => ("CALLA", Some(format!("{:04x}", span.addr))),
410
411 Instruction::FunctionCall(key, etype, _pos, nargs) => {
412 let opcode = match etype {
413 ExprType::Boolean => "CALLF?",
414 ExprType::Double => "CALLF#",
415 ExprType::Integer => "CALLF%",
416 ExprType::Text => "CALLF$",
417 };
418 (opcode, Some(format!("{}, {}", key, nargs)))
419 }
420
421 Instruction::Dim(span) => {
422 let opcode = match (span.shared, span.vtype) {
423 (false, ExprType::Boolean) => "DIMV?",
424 (false, ExprType::Double) => "DIMV#",
425 (false, ExprType::Integer) => "DIMV%",
426 (false, ExprType::Text) => "DIMV$",
427 (true, ExprType::Boolean) => "DIMSV?",
428 (true, ExprType::Double) => "DIMSV#",
429 (true, ExprType::Integer) => "DIMSV%",
430 (true, ExprType::Text) => "DIMSV$",
431 };
432 (opcode, Some(format!("{}", span.name)))
433 }
434
435 Instruction::DimArray(span) => {
436 let opcode = match (span.shared, span.subtype) {
437 (false, ExprType::Boolean) => "DIMA?",
438 (false, ExprType::Double) => "DIMA#",
439 (false, ExprType::Integer) => "DIMA%",
440 (false, ExprType::Text) => "DIMA$",
441 (true, ExprType::Boolean) => "DIMSA?",
442 (true, ExprType::Double) => "DIMSA#",
443 (true, ExprType::Integer) => "DIMSA%",
444 (true, ExprType::Text) => "DIMSA$",
445 };
446 (opcode, Some(format!("{}, {}", span.name, span.dimensions)))
447 }
448
449 Instruction::End(has_code) => ("END", Some(format!("{}", has_code))),
450
451 Instruction::EnterScope => ("ENTER", None),
452
453 Instruction::DoubleToInteger => ("#TO%", None),
454 Instruction::IntegerToDouble => ("%TO#", None),
455
456 Instruction::Jump(span) => ("JMP", Some(format!("{:04x}", span.addr))),
457 Instruction::JumpIfDefined(span) => {
458 ("JMPVD", Some(format!("{}, {:04x}", span.var, span.addr)))
459 }
460 Instruction::JumpIfTrue(addr) => ("JMPT", Some(format!("{:04x}", addr))),
461 Instruction::JumpIfNotTrue(addr) => ("JMPNT", Some(format!("{:04x}", addr))),
462
463 Instruction::LeaveScope => ("LEAVE", None),
464
465 Instruction::LoadBoolean(key, _pos) => ("LOAD?", Some(key.to_string())),
466 Instruction::LoadDouble(key, _pos) => ("LOAD#", Some(key.to_string())),
467 Instruction::LoadInteger(key, _pos) => ("LOAD%", Some(key.to_string())),
468 Instruction::LoadString(key, _pos) => ("LOAD$", Some(key.to_string())),
469
470 Instruction::LoadRef(key, _etype, _pos) => ("LOADR", Some(key.to_string())),
471
472 Instruction::Nop => ("NOP", None),
473
474 Instruction::PushBoolean(b, _pos) => ("PUSH?", Some(format!("{}", b))),
475 Instruction::PushDouble(d, _pos) => ("PUSH#", Some(format!("{}", d))),
476 Instruction::PushInteger(i, _pos) => ("PUSH%", Some(format!("{}", i))),
477 Instruction::PushString(s, _pos) => ("PUSH$", Some(format!("\"{}\"", s))),
478
479 Instruction::Return(_pos) => ("RET", None),
480
481 Instruction::SetErrorHandler(span) => match span {
482 ErrorHandlerISpan::Jump(addr) => ("SEHA", Some(format!("{:04x}", addr))),
483 ErrorHandlerISpan::None => ("SEHN", None),
484 ErrorHandlerISpan::ResumeNext => ("SEHRN", None),
485 },
486
487 Instruction::Unset(span) => ("UNSETV", Some(format!("{}", span.name))),
488 }
489 }
490
491 pub fn pos(&self) -> Option<LineCol> {
495 match self {
496 Instruction::BitwiseAnd(pos) => Some(*pos),
497 Instruction::BitwiseOr(pos) => Some(*pos),
498 Instruction::BitwiseXor(pos) => Some(*pos),
499 Instruction::BitwiseNot(pos) => Some(*pos),
500
501 Instruction::LogicalAnd(pos) => Some(*pos),
502 Instruction::LogicalOr(pos) => Some(*pos),
503 Instruction::LogicalXor(pos) => Some(*pos),
504 Instruction::LogicalNot(pos) => Some(*pos),
505
506 Instruction::ShiftLeft(pos) => Some(*pos),
507 Instruction::ShiftRight(pos) => Some(*pos),
508
509 Instruction::EqualBooleans(pos) => Some(*pos),
510 Instruction::NotEqualBooleans(pos) => Some(*pos),
511
512 Instruction::EqualDoubles(pos) => Some(*pos),
513 Instruction::NotEqualDoubles(pos) => Some(*pos),
514 Instruction::LessDoubles(pos) => Some(*pos),
515 Instruction::LessEqualDoubles(pos) => Some(*pos),
516 Instruction::GreaterDoubles(pos) => Some(*pos),
517 Instruction::GreaterEqualDoubles(pos) => Some(*pos),
518
519 Instruction::EqualIntegers(pos) => Some(*pos),
520 Instruction::NotEqualIntegers(pos) => Some(*pos),
521 Instruction::LessIntegers(pos) => Some(*pos),
522 Instruction::LessEqualIntegers(pos) => Some(*pos),
523 Instruction::GreaterIntegers(pos) => Some(*pos),
524 Instruction::GreaterEqualIntegers(pos) => Some(*pos),
525
526 Instruction::EqualStrings(pos) => Some(*pos),
527 Instruction::NotEqualStrings(pos) => Some(*pos),
528 Instruction::LessStrings(pos) => Some(*pos),
529 Instruction::LessEqualStrings(pos) => Some(*pos),
530 Instruction::GreaterStrings(pos) => Some(*pos),
531 Instruction::GreaterEqualStrings(pos) => Some(*pos),
532
533 Instruction::AddDoubles(pos) => Some(*pos),
534 Instruction::SubtractDoubles(pos) => Some(*pos),
535 Instruction::MultiplyDoubles(pos) => Some(*pos),
536 Instruction::DivideDoubles(pos) => Some(*pos),
537 Instruction::ModuloDoubles(pos) => Some(*pos),
538 Instruction::PowerDoubles(pos) => Some(*pos),
539 Instruction::NegateDouble(pos) => Some(*pos),
540
541 Instruction::AddIntegers(pos) => Some(*pos),
542 Instruction::SubtractIntegers(pos) => Some(*pos),
543 Instruction::MultiplyIntegers(pos) => Some(*pos),
544 Instruction::DivideIntegers(pos) => Some(*pos),
545 Instruction::ModuloIntegers(pos) => Some(*pos),
546 Instruction::PowerIntegers(pos) => Some(*pos),
547 Instruction::NegateInteger(pos) => Some(*pos),
548
549 Instruction::ConcatStrings(pos) => Some(*pos),
550
551 Instruction::ArrayAssignment(_, pos, _) => Some(*pos),
552 Instruction::ArrayLoad(_, pos, _) => Some(*pos),
553 Instruction::Assign(_) => None,
554 Instruction::BuiltinCall(_, pos, _) => Some(*pos),
555 Instruction::Call(_) => None,
556 Instruction::FunctionCall(_, _, pos, _) => Some(*pos),
557 Instruction::Dim(_) => None,
558 Instruction::DimArray(span) => Some(span.name_pos),
559 Instruction::End(_) => None,
560 Instruction::EnterScope => None,
561 Instruction::DoubleToInteger => None,
562 Instruction::IntegerToDouble => None,
563 Instruction::Jump(_) => None,
564 Instruction::JumpIfDefined(_) => None,
565 Instruction::JumpIfTrue(_) => None,
566 Instruction::JumpIfNotTrue(_) => None,
567 Instruction::LeaveScope => None,
568 Instruction::LoadBoolean(_, pos) => Some(*pos),
569 Instruction::LoadDouble(_, pos) => Some(*pos),
570 Instruction::LoadInteger(_, pos) => Some(*pos),
571 Instruction::LoadString(_, pos) => Some(*pos),
572 Instruction::LoadRef(_, _, pos) => Some(*pos),
573 Instruction::Nop => None,
574 Instruction::PushBoolean(_, pos) => Some(*pos),
575 Instruction::PushDouble(_, pos) => Some(*pos),
576 Instruction::PushInteger(_, pos) => Some(*pos),
577 Instruction::PushString(_, pos) => Some(*pos),
578 Instruction::Return(pos) => Some(*pos),
579 Instruction::SetErrorHandler(_) => None,
580 Instruction::Unset(span) => Some(span.pos),
581 }
582 }
583
584 pub(crate) fn is_statement(&self) -> bool {
590 match self {
591 Instruction::LogicalAnd(_)
592 | Instruction::LogicalOr(_)
593 | Instruction::LogicalXor(_)
594 | Instruction::LogicalNot(_)
595 | Instruction::BitwiseAnd(_)
596 | Instruction::BitwiseOr(_)
597 | Instruction::BitwiseXor(_)
598 | Instruction::BitwiseNot(_)
599 | Instruction::ArrayLoad(_, _, _)
600 | Instruction::ShiftLeft(_)
601 | Instruction::ShiftRight(_)
602 | Instruction::EqualBooleans(_)
603 | Instruction::NotEqualBooleans(_)
604 | Instruction::EqualDoubles(_)
605 | Instruction::NotEqualDoubles(_)
606 | Instruction::LessDoubles(_)
607 | Instruction::LessEqualDoubles(_)
608 | Instruction::GreaterDoubles(_)
609 | Instruction::GreaterEqualDoubles(_)
610 | Instruction::EqualIntegers(_)
611 | Instruction::NotEqualIntegers(_)
612 | Instruction::LessIntegers(_)
613 | Instruction::LessEqualIntegers(_)
614 | Instruction::GreaterIntegers(_)
615 | Instruction::GreaterEqualIntegers(_)
616 | Instruction::EqualStrings(_)
617 | Instruction::NotEqualStrings(_)
618 | Instruction::LessStrings(_)
619 | Instruction::LessEqualStrings(_)
620 | Instruction::GreaterStrings(_)
621 | Instruction::GreaterEqualStrings(_)
622 | Instruction::AddDoubles(_)
623 | Instruction::SubtractDoubles(_)
624 | Instruction::MultiplyDoubles(_)
625 | Instruction::DivideDoubles(_)
626 | Instruction::ModuloDoubles(_)
627 | Instruction::PowerDoubles(_)
628 | Instruction::NegateDouble(_)
629 | Instruction::AddIntegers(_)
630 | Instruction::SubtractIntegers(_)
631 | Instruction::MultiplyIntegers(_)
632 | Instruction::DivideIntegers(_)
633 | Instruction::ModuloIntegers(_)
634 | Instruction::PowerIntegers(_)
635 | Instruction::NegateInteger(_)
636 | Instruction::ConcatStrings(_)
637 | Instruction::FunctionCall(_, _, _, _)
638 | Instruction::DoubleToInteger
639 | Instruction::IntegerToDouble
640 | Instruction::LoadBoolean(_, _)
641 | Instruction::LoadDouble(_, _)
642 | Instruction::LoadInteger(_, _)
643 | Instruction::LoadString(_, _)
644 | Instruction::LoadRef(_, _, _)
645 | Instruction::PushBoolean(_, _)
646 | Instruction::PushDouble(_, _)
647 | Instruction::PushInteger(_, _)
648 | Instruction::PushString(_, _)
649 | Instruction::EnterScope
650 | Instruction::LeaveScope => false,
651
652 Instruction::ArrayAssignment(_, _, _)
653 | Instruction::Assign(_)
654 | Instruction::BuiltinCall(_, _, _)
655 | Instruction::Call(_)
656 | Instruction::Dim(_)
657 | Instruction::DimArray(_)
658 | Instruction::End(_)
659 | Instruction::Jump(_)
660 | Instruction::JumpIfDefined(_)
661 | Instruction::JumpIfTrue(_)
662 | Instruction::JumpIfNotTrue(_)
663 | Instruction::Nop
664 | Instruction::Return(_)
665 | Instruction::SetErrorHandler(_)
666 | Instruction::Unset(_) => true,
667 }
668 }
669}
670
671#[cfg_attr(test, derive(Debug, PartialEq))]
673pub struct Image {
674 pub instrs: Vec<Instruction>,
678
679 pub data: Vec<Option<Value>>,
681}