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 BuiltinCallISpan {
29 pub name: SymbolKey,
31
32 pub name_pos: LineCol,
34
35 pub upcall_index: usize,
37
38 pub nargs: usize,
43}
44
45#[derive(Debug, PartialEq)]
47#[cfg_attr(test, derive(Clone))]
48pub struct DimISpan {
49 pub name: SymbolKey,
51
52 pub shared: bool,
54
55 pub vtype: ExprType,
57}
58
59#[derive(Debug, PartialEq)]
61#[cfg_attr(test, derive(Clone))]
62pub struct DimArrayISpan {
63 pub name: SymbolKey,
65
66 pub name_pos: LineCol,
68
69 pub shared: bool,
71
72 pub dimensions: usize,
74
75 pub subtype: ExprType,
77
78 pub subtype_pos: LineCol,
80}
81
82#[derive(Debug, PartialEq)]
84#[cfg_attr(test, derive(Clone))]
85pub struct FunctionCallISpan {
86 pub name: SymbolKey,
88
89 pub name_pos: LineCol,
91
92 pub upcall_index: usize,
94
95 pub return_type: ExprType,
97
98 pub nargs: usize,
100}
101
102#[derive(Debug, Eq, PartialEq)]
104pub struct JumpISpan {
105 pub addr: Address,
107}
108
109#[cfg_attr(test, derive(Debug, Eq, PartialEq))]
111pub struct JumpIfDefinedISpan {
112 pub var: SymbolKey,
114
115 pub addr: Address,
117}
118
119#[derive(Clone, Copy)]
121#[cfg_attr(test, derive(Debug, Eq, PartialEq))]
122pub enum ErrorHandlerISpan {
123 Jump(Address),
125
126 None,
128
129 ResumeNext,
131}
132
133#[cfg_attr(test, derive(Debug, Eq, PartialEq))]
135pub struct UnsetISpan {
136 pub name: SymbolKey,
138
139 pub pos: LineCol,
141}
142
143#[cfg_attr(test, derive(Debug, PartialEq))]
145pub enum Instruction {
146 LogicalAnd(LineCol),
148
149 LogicalOr(LineCol),
151
152 LogicalXor(LineCol),
154
155 LogicalNot(LineCol),
157
158 BitwiseAnd(LineCol),
160
161 BitwiseOr(LineCol),
163
164 BitwiseXor(LineCol),
166
167 BitwiseNot(LineCol),
169
170 ShiftLeft(LineCol),
172
173 ShiftRight(LineCol),
175
176 EqualBooleans(LineCol),
178
179 NotEqualBooleans(LineCol),
181
182 EqualDoubles(LineCol),
184
185 NotEqualDoubles(LineCol),
187
188 LessDoubles(LineCol),
190
191 LessEqualDoubles(LineCol),
193
194 GreaterDoubles(LineCol),
196
197 GreaterEqualDoubles(LineCol),
199
200 EqualIntegers(LineCol),
202
203 NotEqualIntegers(LineCol),
205
206 LessIntegers(LineCol),
208
209 LessEqualIntegers(LineCol),
211
212 GreaterIntegers(LineCol),
214
215 GreaterEqualIntegers(LineCol),
217
218 EqualStrings(LineCol),
220
221 NotEqualStrings(LineCol),
223
224 LessStrings(LineCol),
226
227 LessEqualStrings(LineCol),
229
230 GreaterStrings(LineCol),
232
233 GreaterEqualStrings(LineCol),
235
236 AddDoubles(LineCol),
238
239 SubtractDoubles(LineCol),
241
242 MultiplyDoubles(LineCol),
244
245 DivideDoubles(LineCol),
247
248 ModuloDoubles(LineCol),
250
251 PowerDoubles(LineCol),
253
254 NegateDouble(LineCol),
256
257 AddIntegers(LineCol),
259
260 SubtractIntegers(LineCol),
262
263 MultiplyIntegers(LineCol),
265
266 DivideIntegers(LineCol),
268
269 ModuloIntegers(LineCol),
271
272 PowerIntegers(LineCol),
274
275 NegateInteger(LineCol),
277
278 ConcatStrings(LineCol),
280
281 ArrayAssignment(SymbolKey, LineCol, usize),
283
284 ArrayLoad(SymbolKey, LineCol, usize),
286
287 Assign(SymbolKey),
289
290 BuiltinCall(BuiltinCallISpan),
292
293 Call(JumpISpan),
295
296 FunctionCall(FunctionCallISpan),
298
299 Dim(DimISpan),
301
302 DimArray(DimArrayISpan),
304
305 End(bool),
308
309 EnterScope,
311
312 DoubleToInteger,
314
315 IntegerToDouble,
317
318 Jump(JumpISpan),
320
321 JumpIfDefined(JumpIfDefinedISpan),
323
324 JumpIfTrue(Address),
326
327 JumpIfNotTrue(Address),
329
330 LeaveScope,
332
333 LoadBoolean(SymbolKey, LineCol),
335
336 LoadDouble(SymbolKey, LineCol),
338
339 LoadInteger(SymbolKey, LineCol),
341
342 LoadString(SymbolKey, LineCol),
344
345 LoadRef(SymbolKey, ExprType, LineCol),
347
348 Nop,
350
351 PushBoolean(bool, LineCol),
353
354 PushDouble(f64, LineCol),
356
357 PushInteger(i32, LineCol),
359
360 PushString(String, LineCol),
362
363 Return(LineCol),
365
366 SetErrorHandler(ErrorHandlerISpan),
368
369 Unset(UnsetISpan),
371}
372
373impl Instruction {
374 pub fn repr(&self) -> (&'static str, Option<String>) {
376 match self {
377 Instruction::BitwiseAnd(_pos) => ("AND%", None),
378 Instruction::BitwiseOr(_pos) => ("OR%", None),
379 Instruction::BitwiseXor(_pos) => ("XOR%", None),
380 Instruction::BitwiseNot(_pos) => ("NOT%", None),
381
382 Instruction::LogicalAnd(_pos) => ("AND?", None),
383 Instruction::LogicalOr(_pos) => ("OR?", None),
384 Instruction::LogicalXor(_pos) => ("XOR?", None),
385 Instruction::LogicalNot(_pos) => ("NOT?", None),
386
387 Instruction::ShiftLeft(_pos) => ("SHL%", None),
388 Instruction::ShiftRight(_pos) => ("SHR%", None),
389
390 Instruction::EqualBooleans(_pos) => ("CMPE?", None),
391 Instruction::NotEqualBooleans(_pos) => ("CMPNE?", None),
392
393 Instruction::EqualDoubles(_pos) => ("CMPE#", None),
394 Instruction::NotEqualDoubles(_pos) => ("CMPNE#", None),
395 Instruction::LessDoubles(_pos) => ("CMPL#", None),
396 Instruction::LessEqualDoubles(_pos) => ("CMPLE#", None),
397 Instruction::GreaterDoubles(_pos) => ("CMPG#", None),
398 Instruction::GreaterEqualDoubles(_pos) => ("CMPGE#", None),
399
400 Instruction::EqualIntegers(_pos) => ("CMPE%", None),
401 Instruction::NotEqualIntegers(_pos) => ("CMPNE%", None),
402 Instruction::LessIntegers(_pos) => ("CMPL%", None),
403 Instruction::LessEqualIntegers(_pos) => ("CMPLE%", None),
404 Instruction::GreaterIntegers(_pos) => ("CMPG%", None),
405 Instruction::GreaterEqualIntegers(_pos) => ("CMPGE%", None),
406
407 Instruction::EqualStrings(_pos) => ("CMPE$", None),
408 Instruction::NotEqualStrings(_pos) => ("CMPNE$", None),
409 Instruction::LessStrings(_pos) => ("CMPL$", None),
410 Instruction::LessEqualStrings(_pos) => ("CMPLE$", None),
411 Instruction::GreaterStrings(_pos) => ("CMPG$", None),
412 Instruction::GreaterEqualStrings(_pos) => ("CMPGE$", None),
413
414 Instruction::AddDoubles(_pos) => ("ADD#", None),
415 Instruction::SubtractDoubles(_pos) => ("SUB#", None),
416 Instruction::MultiplyDoubles(_pos) => ("MUL#", None),
417 Instruction::DivideDoubles(_pos) => ("DIV#", None),
418 Instruction::ModuloDoubles(_pos) => ("MOD#", None),
419 Instruction::PowerDoubles(_pos) => ("POW#", None),
420 Instruction::NegateDouble(_pos) => ("NEG#", None),
421
422 Instruction::AddIntegers(_pos) => ("ADD%", None),
423 Instruction::SubtractIntegers(_pos) => ("SUB%", None),
424 Instruction::MultiplyIntegers(_pos) => ("MUL%", None),
425 Instruction::DivideIntegers(_pos) => ("DIV%", None),
426 Instruction::ModuloIntegers(_pos) => ("MOD%", None),
427 Instruction::PowerIntegers(_pos) => ("POW%", None),
428 Instruction::NegateInteger(_pos) => ("NEG%", None),
429
430 Instruction::ConcatStrings(_pos) => ("CONCAT$", None),
431
432 Instruction::ArrayAssignment(key, _pos, nargs) => {
433 ("SETA", Some(format!("{}, {}", key, nargs)))
434 }
435
436 Instruction::ArrayLoad(key, _pos, nargs) => {
437 ("LOADA", Some(format!("{}, {}", key, nargs)))
438 }
439
440 Instruction::Assign(key) => ("SETV", Some(key.to_string())),
441
442 Instruction::BuiltinCall(span) => {
443 ("CALLB", Some(format!("{} ({}), {}", span.upcall_index, span.name, span.nargs)))
444 }
445
446 Instruction::Call(span) => ("CALLA", Some(format!("{:04x}", span.addr))),
447
448 Instruction::FunctionCall(span) => {
449 let opcode = match span.return_type {
450 ExprType::Boolean => "CALLF?",
451 ExprType::Double => "CALLF#",
452 ExprType::Integer => "CALLF%",
453 ExprType::Text => "CALLF$",
454 };
455 (opcode, Some(format!("{} ({}), {}", span.upcall_index, span.name, span.nargs)))
456 }
457
458 Instruction::Dim(span) => {
459 let opcode = match (span.shared, span.vtype) {
460 (false, ExprType::Boolean) => "DIMV?",
461 (false, ExprType::Double) => "DIMV#",
462 (false, ExprType::Integer) => "DIMV%",
463 (false, ExprType::Text) => "DIMV$",
464 (true, ExprType::Boolean) => "DIMSV?",
465 (true, ExprType::Double) => "DIMSV#",
466 (true, ExprType::Integer) => "DIMSV%",
467 (true, ExprType::Text) => "DIMSV$",
468 };
469 (opcode, Some(format!("{}", span.name)))
470 }
471
472 Instruction::DimArray(span) => {
473 let opcode = match (span.shared, span.subtype) {
474 (false, ExprType::Boolean) => "DIMA?",
475 (false, ExprType::Double) => "DIMA#",
476 (false, ExprType::Integer) => "DIMA%",
477 (false, ExprType::Text) => "DIMA$",
478 (true, ExprType::Boolean) => "DIMSA?",
479 (true, ExprType::Double) => "DIMSA#",
480 (true, ExprType::Integer) => "DIMSA%",
481 (true, ExprType::Text) => "DIMSA$",
482 };
483 (opcode, Some(format!("{}, {}", span.name, span.dimensions)))
484 }
485
486 Instruction::End(has_code) => ("END", Some(format!("{}", has_code))),
487
488 Instruction::EnterScope => ("ENTER", None),
489
490 Instruction::DoubleToInteger => ("#TO%", None),
491 Instruction::IntegerToDouble => ("%TO#", None),
492
493 Instruction::Jump(span) => ("JMP", Some(format!("{:04x}", span.addr))),
494 Instruction::JumpIfDefined(span) => {
495 ("JMPVD", Some(format!("{}, {:04x}", span.var, span.addr)))
496 }
497 Instruction::JumpIfTrue(addr) => ("JMPT", Some(format!("{:04x}", addr))),
498 Instruction::JumpIfNotTrue(addr) => ("JMPNT", Some(format!("{:04x}", addr))),
499
500 Instruction::LeaveScope => ("LEAVE", None),
501
502 Instruction::LoadBoolean(key, _pos) => ("LOAD?", Some(key.to_string())),
503 Instruction::LoadDouble(key, _pos) => ("LOAD#", Some(key.to_string())),
504 Instruction::LoadInteger(key, _pos) => ("LOAD%", Some(key.to_string())),
505 Instruction::LoadString(key, _pos) => ("LOAD$", Some(key.to_string())),
506
507 Instruction::LoadRef(key, _etype, _pos) => ("LOADR", Some(key.to_string())),
508
509 Instruction::Nop => ("NOP", None),
510
511 Instruction::PushBoolean(b, _pos) => ("PUSH?", Some(format!("{}", b))),
512 Instruction::PushDouble(d, _pos) => ("PUSH#", Some(format!("{}", d))),
513 Instruction::PushInteger(i, _pos) => ("PUSH%", Some(format!("{}", i))),
514 Instruction::PushString(s, _pos) => ("PUSH$", Some(format!("\"{}\"", s))),
515
516 Instruction::Return(_pos) => ("RET", None),
517
518 Instruction::SetErrorHandler(span) => match span {
519 ErrorHandlerISpan::Jump(addr) => ("SEHA", Some(format!("{:04x}", addr))),
520 ErrorHandlerISpan::None => ("SEHN", None),
521 ErrorHandlerISpan::ResumeNext => ("SEHRN", None),
522 },
523
524 Instruction::Unset(span) => ("UNSETV", Some(format!("{}", span.name))),
525 }
526 }
527
528 pub fn pos(&self) -> Option<LineCol> {
532 match self {
533 Instruction::BitwiseAnd(pos) => Some(*pos),
534 Instruction::BitwiseOr(pos) => Some(*pos),
535 Instruction::BitwiseXor(pos) => Some(*pos),
536 Instruction::BitwiseNot(pos) => Some(*pos),
537
538 Instruction::LogicalAnd(pos) => Some(*pos),
539 Instruction::LogicalOr(pos) => Some(*pos),
540 Instruction::LogicalXor(pos) => Some(*pos),
541 Instruction::LogicalNot(pos) => Some(*pos),
542
543 Instruction::ShiftLeft(pos) => Some(*pos),
544 Instruction::ShiftRight(pos) => Some(*pos),
545
546 Instruction::EqualBooleans(pos) => Some(*pos),
547 Instruction::NotEqualBooleans(pos) => Some(*pos),
548
549 Instruction::EqualDoubles(pos) => Some(*pos),
550 Instruction::NotEqualDoubles(pos) => Some(*pos),
551 Instruction::LessDoubles(pos) => Some(*pos),
552 Instruction::LessEqualDoubles(pos) => Some(*pos),
553 Instruction::GreaterDoubles(pos) => Some(*pos),
554 Instruction::GreaterEqualDoubles(pos) => Some(*pos),
555
556 Instruction::EqualIntegers(pos) => Some(*pos),
557 Instruction::NotEqualIntegers(pos) => Some(*pos),
558 Instruction::LessIntegers(pos) => Some(*pos),
559 Instruction::LessEqualIntegers(pos) => Some(*pos),
560 Instruction::GreaterIntegers(pos) => Some(*pos),
561 Instruction::GreaterEqualIntegers(pos) => Some(*pos),
562
563 Instruction::EqualStrings(pos) => Some(*pos),
564 Instruction::NotEqualStrings(pos) => Some(*pos),
565 Instruction::LessStrings(pos) => Some(*pos),
566 Instruction::LessEqualStrings(pos) => Some(*pos),
567 Instruction::GreaterStrings(pos) => Some(*pos),
568 Instruction::GreaterEqualStrings(pos) => Some(*pos),
569
570 Instruction::AddDoubles(pos) => Some(*pos),
571 Instruction::SubtractDoubles(pos) => Some(*pos),
572 Instruction::MultiplyDoubles(pos) => Some(*pos),
573 Instruction::DivideDoubles(pos) => Some(*pos),
574 Instruction::ModuloDoubles(pos) => Some(*pos),
575 Instruction::PowerDoubles(pos) => Some(*pos),
576 Instruction::NegateDouble(pos) => Some(*pos),
577
578 Instruction::AddIntegers(pos) => Some(*pos),
579 Instruction::SubtractIntegers(pos) => Some(*pos),
580 Instruction::MultiplyIntegers(pos) => Some(*pos),
581 Instruction::DivideIntegers(pos) => Some(*pos),
582 Instruction::ModuloIntegers(pos) => Some(*pos),
583 Instruction::PowerIntegers(pos) => Some(*pos),
584 Instruction::NegateInteger(pos) => Some(*pos),
585
586 Instruction::ConcatStrings(pos) => Some(*pos),
587
588 Instruction::ArrayAssignment(_, pos, _) => Some(*pos),
589 Instruction::ArrayLoad(_, pos, _) => Some(*pos),
590 Instruction::Assign(_) => None,
591 Instruction::BuiltinCall(span) => Some(span.name_pos),
592 Instruction::Call(_) => None,
593 Instruction::FunctionCall(span) => Some(span.name_pos),
594 Instruction::Dim(_) => None,
595 Instruction::DimArray(span) => Some(span.name_pos),
596 Instruction::End(_) => None,
597 Instruction::EnterScope => None,
598 Instruction::DoubleToInteger => None,
599 Instruction::IntegerToDouble => None,
600 Instruction::Jump(_) => None,
601 Instruction::JumpIfDefined(_) => None,
602 Instruction::JumpIfTrue(_) => None,
603 Instruction::JumpIfNotTrue(_) => None,
604 Instruction::LeaveScope => None,
605 Instruction::LoadBoolean(_, pos) => Some(*pos),
606 Instruction::LoadDouble(_, pos) => Some(*pos),
607 Instruction::LoadInteger(_, pos) => Some(*pos),
608 Instruction::LoadString(_, pos) => Some(*pos),
609 Instruction::LoadRef(_, _, pos) => Some(*pos),
610 Instruction::Nop => None,
611 Instruction::PushBoolean(_, pos) => Some(*pos),
612 Instruction::PushDouble(_, pos) => Some(*pos),
613 Instruction::PushInteger(_, pos) => Some(*pos),
614 Instruction::PushString(_, pos) => Some(*pos),
615 Instruction::Return(pos) => Some(*pos),
616 Instruction::SetErrorHandler(_) => None,
617 Instruction::Unset(span) => Some(span.pos),
618 }
619 }
620
621 pub(crate) fn is_statement(&self) -> bool {
627 match self {
628 Instruction::LogicalAnd(_)
629 | Instruction::LogicalOr(_)
630 | Instruction::LogicalXor(_)
631 | Instruction::LogicalNot(_)
632 | Instruction::BitwiseAnd(_)
633 | Instruction::BitwiseOr(_)
634 | Instruction::BitwiseXor(_)
635 | Instruction::BitwiseNot(_)
636 | Instruction::ArrayLoad(_, _, _)
637 | Instruction::ShiftLeft(_)
638 | Instruction::ShiftRight(_)
639 | Instruction::EqualBooleans(_)
640 | Instruction::NotEqualBooleans(_)
641 | Instruction::EqualDoubles(_)
642 | Instruction::NotEqualDoubles(_)
643 | Instruction::LessDoubles(_)
644 | Instruction::LessEqualDoubles(_)
645 | Instruction::GreaterDoubles(_)
646 | Instruction::GreaterEqualDoubles(_)
647 | Instruction::EqualIntegers(_)
648 | Instruction::NotEqualIntegers(_)
649 | Instruction::LessIntegers(_)
650 | Instruction::LessEqualIntegers(_)
651 | Instruction::GreaterIntegers(_)
652 | Instruction::GreaterEqualIntegers(_)
653 | Instruction::EqualStrings(_)
654 | Instruction::NotEqualStrings(_)
655 | Instruction::LessStrings(_)
656 | Instruction::LessEqualStrings(_)
657 | Instruction::GreaterStrings(_)
658 | Instruction::GreaterEqualStrings(_)
659 | Instruction::AddDoubles(_)
660 | Instruction::SubtractDoubles(_)
661 | Instruction::MultiplyDoubles(_)
662 | Instruction::DivideDoubles(_)
663 | Instruction::ModuloDoubles(_)
664 | Instruction::PowerDoubles(_)
665 | Instruction::NegateDouble(_)
666 | Instruction::AddIntegers(_)
667 | Instruction::SubtractIntegers(_)
668 | Instruction::MultiplyIntegers(_)
669 | Instruction::DivideIntegers(_)
670 | Instruction::ModuloIntegers(_)
671 | Instruction::PowerIntegers(_)
672 | Instruction::NegateInteger(_)
673 | Instruction::ConcatStrings(_)
674 | Instruction::FunctionCall(_)
675 | Instruction::DoubleToInteger
676 | Instruction::IntegerToDouble
677 | Instruction::LoadBoolean(_, _)
678 | Instruction::LoadDouble(_, _)
679 | Instruction::LoadInteger(_, _)
680 | Instruction::LoadString(_, _)
681 | Instruction::LoadRef(_, _, _)
682 | Instruction::PushBoolean(_, _)
683 | Instruction::PushDouble(_, _)
684 | Instruction::PushInteger(_, _)
685 | Instruction::PushString(_, _)
686 | Instruction::EnterScope
687 | Instruction::LeaveScope => false,
688
689 Instruction::ArrayAssignment(_, _, _)
690 | Instruction::Assign(_)
691 | Instruction::BuiltinCall(_)
692 | Instruction::Call(_)
693 | Instruction::Dim(_)
694 | Instruction::DimArray(_)
695 | Instruction::End(_)
696 | Instruction::Jump(_)
697 | Instruction::JumpIfDefined(_)
698 | Instruction::JumpIfTrue(_)
699 | Instruction::JumpIfNotTrue(_)
700 | Instruction::Nop
701 | Instruction::Return(_)
702 | Instruction::SetErrorHandler(_)
703 | Instruction::Unset(_) => true,
704 }
705 }
706}
707
708#[cfg_attr(test, derive(Debug, PartialEq))]
710pub struct Image {
711 pub upcalls: Vec<SymbolKey>,
713
714 pub instrs: Vec<Instruction>,
718
719 pub data: Vec<Option<Value>>,
721}