fork of https://github.com/tree-sitter/tree-sitter-graph
at main 6.1 kB view raw
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}