feat(tazjin/rlox): Add support for scoped environments
Adds scoped environments using a sophisticated structure known as an SRPT, which stands for "shitty parent pointer tree". Change-Id: I62f66aabe6eb32ea01c4cabcca5b03cfefcc28ee Reviewed-on: https://cl.tvl.fyi/c/depot/+/2301 Reviewed-by: tazjin <mail@tazj.in> Tested-by: BuildkiteCI
This commit is contained in:
		
							parent
							
								
									48a54625ce
								
							
						
					
					
						commit
						26ed836e1d
					
				
					 1 changed files with 26 additions and 8 deletions
				
			
		| 
						 | 
				
			
			@ -2,11 +2,14 @@ use crate::errors::{Error, ErrorKind};
 | 
			
		|||
use crate::parser::{self, Declaration, Expr, Literal, Program, Statement};
 | 
			
		||||
use crate::scanner::{self, TokenKind};
 | 
			
		||||
use std::collections::HashMap;
 | 
			
		||||
use std::rc::Rc;
 | 
			
		||||
use std::sync::RwLock;
 | 
			
		||||
 | 
			
		||||
// Tree-walk interpreter
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Default)]
 | 
			
		||||
struct Environment {
 | 
			
		||||
    enclosing: Option<Rc<RwLock<Environment>>>,
 | 
			
		||||
    values: HashMap<String, Literal>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -27,19 +30,34 @@ impl Environment {
 | 
			
		|||
                line: name.0.line,
 | 
			
		||||
                kind: ErrorKind::UndefinedVariable(ident.into()),
 | 
			
		||||
            })
 | 
			
		||||
            .or_else(|err| {
 | 
			
		||||
                if let Some(parent) = &self.enclosing {
 | 
			
		||||
                    parent.read().unwrap().get(name)
 | 
			
		||||
                } else {
 | 
			
		||||
                    Err(err)
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn assign(&mut self, name: &scanner::Token, value: Literal) -> Result<(), Error> {
 | 
			
		||||
        let ident = identifier_str(name)?;
 | 
			
		||||
        let target = self.values
 | 
			
		||||
            .get_mut(ident)
 | 
			
		||||
            .ok_or_else(|| Error {
 | 
			
		||||
                line: name.line,
 | 
			
		||||
                kind: ErrorKind::UndefinedVariable(ident.into()),
 | 
			
		||||
            })?;
 | 
			
		||||
 | 
			
		||||
        *target = value;
 | 
			
		||||
        Ok(())
 | 
			
		||||
        match self.values.get_mut(ident) {
 | 
			
		||||
            Some(target) => {
 | 
			
		||||
                *target = value;
 | 
			
		||||
                Ok(())
 | 
			
		||||
            }
 | 
			
		||||
            None => {
 | 
			
		||||
                if let Some(parent) = &self.enclosing {
 | 
			
		||||
                    return parent.write().unwrap().assign(name, value);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                Err(Error {
 | 
			
		||||
                    line: name.line,
 | 
			
		||||
                    kind: ErrorKind::UndefinedVariable(ident.into()),
 | 
			
		||||
                })
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue