b2c2_compiler/
utils.rs

1// b2c2-compiler crate::utils
2// author: Leonardone @ NEETSDKASU
3
4use super::*;
5
6// 組み込みルーチンを分離する
7pub fn split_subroutines(
8    mut statements: Vec<casl2::Statement>,
9) -> Vec<(String, Vec<casl2::Statement>)> {
10    let mut indexes: Vec<(String, usize)> = vec![];
11
12    for (i, stmt) in statements.iter().enumerate() {
13        let label = if let casl2::Statement::Code {
14            label: Some(label), ..
15        } = stmt
16        {
17            label
18        } else {
19            continue;
20        };
21        let label = label.as_str();
22        if !(label.chars().count() >= 2
23            && label.starts_with('C')
24            && label.chars().skip(1).all(|ch| ch.is_ascii_digit()))
25        {
26            continue;
27        }
28        let label = label.to_string();
29        if let Some(casl2::Statement::Comment { .. }) = statements.get(i - 1) {
30            indexes.push((label, i - 1));
31        } else {
32            indexes.push((label, i));
33        }
34    }
35
36    let mut ret = Vec::<(String, Vec<casl2::Statement>)>::new();
37
38    while let Some((name_label, i)) = indexes.pop() {
39        let routine = statements.split_off(i);
40        let routine = to_external(&name_label, routine);
41        ret.push((name_label, routine));
42    }
43
44    if !matches!(
45        statements.last(),
46        Some(casl2::Statement::Code {
47            command: casl2::Command::End,
48            ..
49        })
50    ) {
51        statements.code(casl2::Command::End);
52    }
53
54    let program_name = casl2::utils::get_program_name(&statements)
55        .unwrap()
56        .to_string();
57
58    ret.push((program_name, statements));
59
60    ret
61}
62
63// 分割保存対象のサブルーチンのコードの先頭と末尾にSTARTとENDを付与するための処理
64pub fn to_external(name: &str, mut statements: Vec<casl2::Statement>) -> Vec<casl2::Statement> {
65    if !matches!(
66        statements.last(),
67        Some(casl2::Statement::Code {
68            command: casl2::Command::End,
69            ..
70        })
71    ) {
72        statements.code(casl2::Command::End);
73    }
74
75    for stmt in statements.iter_mut() {
76        if let casl2::Statement::Code { label, .. } = stmt {
77            if matches!(label, Some(label) if label.as_str() == name) {
78                *label = None;
79                break;
80            }
81        }
82    }
83
84    statements.insert(
85        0,
86        casl2::Statement::labeled(name, casl2::Command::Start { entry_point: None }),
87    );
88
89    statements
90}