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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
use core::fmt;

use crate as rune;
use crate::alloc;
use crate::alloc::prelude::*;
use crate::alloc::{HashMap, String, Vec};
use crate::ast;

/// A synthetic identifier which can be used to reference something in storage.
#[derive(Debug, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[try_clone(copy)]
pub struct SyntheticId(usize);

impl fmt::Display for SyntheticId {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:04x}", self.0)
    }
}

/// The kind of a synthetic token.
#[derive(Debug, Clone, Copy)]
#[non_exhaustive]
pub enum SyntheticKind {
    /// A synthetic label.
    Label,
    /// A synthetic string.
    String,
    /// A synthetic byte string.
    ByteString,
    /// A synthetic identifier,
    Ident,
    /// A synthetic number.
    Number,
}

impl fmt::Display for SyntheticKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            SyntheticKind::Label => "label".fmt(f),
            SyntheticKind::String => "string".fmt(f),
            SyntheticKind::ByteString => "byte string".fmt(f),
            SyntheticKind::Ident => "identifier".fmt(f),
            SyntheticKind::Number => "number".fmt(f),
        }
    }
}

/// Storage for synthetic language items.
#[derive(Default)]
pub(crate) struct Storage {
    /// Stored strings.
    strings: Vec<String>,
    /// Reverse lookup for existing strings.
    strings_rev: HashMap<String, SyntheticId>,
    /// Stored byte strings.
    byte_strings: Vec<Vec<u8>>,
    /// Reverse lookup for existing byte strings.
    byte_strings_rev: HashMap<Vec<u8>, SyntheticId>,
    /// Numbers stored.
    numbers: Vec<ast::Number>,
}

impl Storage {
    /// Construct a new number.
    ///
    /// The number will be stored in this storage, and will be synthetic
    /// (rather than from the source).
    pub(crate) fn insert_number<N>(&mut self, number: N) -> alloc::Result<SyntheticId>
    where
        ast::Number: From<N>,
    {
        let id = SyntheticId(self.numbers.len());
        self.numbers.try_push(number.into())?;
        Ok(id)
    }

    /// Insert the given text into storage and return its id.
    ///
    /// This will reuse old storage slots that already contains the given
    /// string.
    pub(crate) fn insert_str(&mut self, string: &str) -> alloc::Result<SyntheticId> {
        if let Some(id) = self.strings_rev.get(string).copied() {
            return Ok(id);
        }

        let id = SyntheticId(self.strings.len());
        let string = string.try_to_owned()?;
        self.strings.try_push(string.try_clone()?)?;
        self.strings_rev.try_insert(string, id)?;
        Ok(id)
    }

    /// Insert the given owned string into storage and return its id.
    ///
    /// This will reuse old storage slots that already contains the given
    /// string.
    pub(crate) fn insert_string(&mut self, string: String) -> alloc::Result<SyntheticId> {
        if let Some(id) = self.strings_rev.get(&string).copied() {
            return Ok(id);
        }

        let id = SyntheticId(self.strings.len());
        self.strings.try_push(string.try_clone()?)?;
        self.strings_rev.try_insert(string, id)?;
        Ok(id)
    }

    /// Insert the given text into storage and return its id.
    ///
    /// This will reuse old storage slots that already contains the given
    /// byte string.
    pub(crate) fn insert_byte_string(&mut self, bytes: &[u8]) -> alloc::Result<SyntheticId> {
        if let Some(id) = self.byte_strings_rev.get(bytes).copied() {
            return Ok(id);
        }

        let id = SyntheticId(self.byte_strings.len());
        self.byte_strings.try_push(Vec::try_from(bytes)?)?;
        self.byte_strings_rev
            .try_insert(Vec::try_from(bytes)?, id)?;
        Ok(id)
    }

    /// Get the content of the string with the specified id.
    pub(crate) fn get_string(&self, id: SyntheticId) -> Option<&str> {
        self.strings.get(id.0).map(|s| s.as_ref())
    }

    /// Get the content of the byte string with the specified id.
    pub(crate) fn get_byte_string(&self, id: SyntheticId) -> Option<&[u8]> {
        self.byte_strings.get(id.0).map(|b| b.as_ref())
    }

    /// Get the content of the number with the specified id.
    pub(crate) fn get_number(&self, id: SyntheticId) -> Option<&ast::Number> {
        self.numbers.get(id.0)
    }
}