tree_sitter_graph/
variables.rs

1// -*- coding: utf-8 -*-
2// ------------------------------------------------------------------------------------------------
3// Copyright © 2022, tree-sitter authors.
4// Licensed under either of Apache License, Version 2.0, or MIT license, at your option.
5// Please see the LICENSE-APACHE or LICENSE-MIT files in this distribution for license details.
6// ------------------------------------------------------------------------------------------------
7
8use std::collections::hash_map::Entry::Occupied;
9use std::collections::hash_map::Entry::Vacant;
10use std::collections::HashMap;
11use thiserror::Error;
12
13use crate::graph::Value;
14use crate::Identifier;
15
16#[derive(Debug, Error)]
17pub enum VariableError {
18    #[error("Cannot assign immutable variable")]
19    CannotAssignImmutableVariable(String),
20    #[error("Variable already defined")]
21    VariableAlreadyDefined(String),
22    #[error("Undefined variable")]
23    UndefinedVariable(String),
24}
25
26/// An environment of named variables
27pub(crate) trait Variables<V> {
28    /// Returns the value of a variable, if it exists in this environment.
29    fn get(&self, name: &Identifier) -> Option<&V>;
30}
31
32pub(crate) trait MutVariables<V>: Variables<V> {
33    /// Adds a new variable to this environment, returning an error if the variable already
34    /// exists.
35    fn add(&mut self, name: Identifier, value: V, mutable: bool) -> Result<(), VariableError>;
36
37    /// Sets the variable, returning an error if it does not exists in this environment.
38    fn set(&mut self, name: Identifier, value: V) -> Result<(), VariableError>;
39}
40
41/// A map-like implementation of an environment of named variables
42pub(crate) struct VariableMap<'a, V> {
43    context: Option<&'a mut dyn MutVariables<V>>,
44    values: HashMap<Identifier, Variable<V>>,
45}
46
47struct Variable<V> {
48    value: V,
49    mutable: bool,
50}
51
52impl<'a, V> VariableMap<'a, V> {
53    /// Creates a new, empty variable environment.
54    pub(crate) fn new() -> Self {
55        Self {
56            context: None,
57            values: HashMap::new(),
58        }
59    }
60
61    /// Creates a nested variable environment, that inherits from the given
62    /// context environment.
63    pub(crate) fn nested(context: &'a mut dyn MutVariables<V>) -> Self {
64        Self {
65            context: Some(context),
66            values: HashMap::new(),
67        }
68    }
69
70    /// Clears this enviroment.
71    pub(crate) fn clear(&mut self) {
72        self.values.clear();
73    }
74}
75
76impl<V> Variables<V> for VariableMap<'_, V> {
77    fn get(&self, name: &Identifier) -> Option<&V> {
78        self.values
79            .get(name)
80            .map(|v| &v.value)
81            .or_else(|| self.context.as_ref().map(|p| p.get(name)).flatten())
82    }
83}
84
85impl<V> MutVariables<V> for VariableMap<'_, V> {
86    fn add(&mut self, name: Identifier, value: V, mutable: bool) -> Result<(), VariableError> {
87        match self.values.entry(name) {
88            Vacant(v) => {
89                let variable = Variable { value, mutable };
90                v.insert(variable);
91                Ok(())
92            }
93            Occupied(o) => Err(VariableError::VariableAlreadyDefined(o.key().to_string())),
94        }
95    }
96
97    fn set(&mut self, name: Identifier, value: V) -> Result<(), VariableError> {
98        match self.values.entry(name) {
99            Vacant(v) => self
100                .context
101                .as_mut()
102                .map(|context| context.set(v.key().clone(), value))
103                .unwrap_or(Err(VariableError::UndefinedVariable(
104                    v.into_key().to_string(),
105                ))),
106            Occupied(mut o) => {
107                let variable = o.get_mut();
108                if variable.mutable {
109                    variable.value = value;
110                    Ok(())
111                } else {
112                    Err(VariableError::CannotAssignImmutableVariable(
113                        o.key().to_string(),
114                    ))
115                }
116            }
117        }
118    }
119}
120
121/// Environment of immutable variables
122pub struct Globals<'a> {
123    context: Option<&'a dyn Variables<Value>>,
124    values: HashMap<Identifier, Value>,
125}
126
127impl<'a> Globals<'a> {
128    /// Creates a new, empty variable environment.
129    pub fn new() -> Self {
130        Self {
131            context: None,
132            values: HashMap::new(),
133        }
134    }
135
136    /// Creates a nested variable environment, that inherits from the given
137    /// context environment.
138    pub fn nested(context: &'a Globals<'a>) -> Self {
139        Self {
140            context: Some(context),
141            values: HashMap::new(),
142        }
143    }
144
145    /// Adds a new variable to this environment, returning an error if the variable already
146    /// exists.
147    pub fn add(&mut self, name: Identifier, value: Value) -> Result<(), VariableError> {
148        match self.values.entry(name) {
149            Vacant(v) => {
150                v.insert(value);
151                Ok(())
152            }
153            Occupied(o) => Err(VariableError::VariableAlreadyDefined(o.key().to_string())),
154        }
155    }
156
157    /// Returns the value of a variable, if it exists in this environment.
158    pub fn get(&self, name: &Identifier) -> Option<&Value> {
159        self.values
160            .get(name)
161            .or_else(|| self.context.as_ref().map(|p| p.get(name)).flatten())
162    }
163
164    /// Remove a variable from this enviroment, if it exists.
165    pub fn remove(&mut self, name: &Identifier) {
166        self.values.remove(name);
167    }
168
169    pub fn is_empty(&self) -> bool {
170        self.values.is_empty()
171    }
172
173    pub fn iter<'b>(&'b self) -> Iter<'b> {
174        Iter(self.values.iter())
175    }
176
177    /// Clears this enviroment.
178    pub fn clear(&mut self) {
179        self.values.clear();
180    }
181}
182
183pub struct Iter<'a>(std::collections::hash_map::Iter<'a, Identifier, Value>);
184
185impl<'a> std::iter::Iterator for Iter<'a> {
186    type Item = (&'a Identifier, &'a Value);
187
188    fn next(&mut self) -> Option<Self::Item> {
189        self.0.next()
190    }
191}
192
193impl Variables<Value> for Globals<'_> {
194    fn get(&self, name: &Identifier) -> Option<&Value> {
195        self.get(name)
196    }
197}