lua_semantics/
label.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
use lua_parser::{Span, SpannedString};

use crate::ProcessError;

/// label information.
#[derive(Debug)]
pub struct LabelInfo {
    pub name: String,

    /// Scope tree of this label.
    /// In goto statement, destination label must be parent (prefix) of current scope.
    pub scope: Option<(Vec<usize>, Span)>,

    /// where `goto` statement is called
    pub from: Vec<(Vec<usize>, Span)>,
}

impl LabelInfo {
    fn check_prefix(prefix: &[usize], target: &[usize]) -> bool {
        if prefix.len() > target.len() {
            return false;
        }
        for i in 0..prefix.len() {
            if prefix[i] != target[i] {
                return false;
            }
        }
        true
    }
    pub fn add_from(&mut self, from: Vec<usize>, goto_span: Span) -> Result<(), ProcessError> {
        if let Some((scope, label_span)) = &self.scope {
            if !Self::check_prefix(scope, &from) {
                return Err(ProcessError::InvalidGotoScope(*label_span, goto_span));
            }
        }
        self.from.push((from, goto_span));
        Ok(())
    }
    pub fn set_label(
        &mut self,
        name: SpannedString,
        scope: Vec<usize>,
        label_span: Span,
    ) -> Result<(), ProcessError> {
        if self.scope.is_some() {
            Err(ProcessError::MultipleLabel(name))
        } else {
            for (from, from_span) in &self.from {
                if !Self::check_prefix(&scope, from) {
                    return Err(ProcessError::InvalidGotoScope(label_span, *from_span));
                }
            }

            self.name = name.string;
            self.scope = Some((scope, label_span));
            Ok(())
        }
    }
}

impl Default for LabelInfo {
    fn default() -> Self {
        Self {
            name: String::new(),
            scope: None,
            from: Vec::new(),
        }
    }
}