Scope stuff.

This commit is contained in:
James Harton 2019-02-14 19:08:40 +13:00
parent 447c54ce35
commit 7277510a72
5 changed files with 31 additions and 19 deletions

View file

@ -3,16 +3,17 @@ use crate::symbol::Symbol;
pub struct Context { pub struct Context {
current_pos: usize, current_pos: usize,
globals: Scope,
scope_stack: Vec<Scope>, scope_stack: Vec<Scope>,
} }
impl Context { impl Context {
pub fn globals(&self) -> &Scope { pub fn globals(&self) -> &Scope {
&self.scope_stack[0] &self.globals
} }
pub fn globals_mut(&mut self) -> &mut Scope { pub fn globals_mut(&mut self) -> &mut Scope {
&mut self.scope_stack[0] &mut self.globals
} }
pub fn scope(&self) -> &Scope { pub fn scope(&self) -> &Scope {
@ -39,12 +40,12 @@ impl Context {
} }
} }
pub fn find_symbol(&self, identifier: &str) -> Option<&Symbol> { pub fn reference(&self, identifier: &str) -> Option<&Symbol> {
let mut pos = self.scope_stack.len(); let mut pos = self.scope_stack.len();
while pos > 0 { while pos > 0 {
pos -= 1; pos -= 1;
if self.scope_stack[pos].has_symbol(identifier) { if self.scope_stack[pos].has_symbol(identifier) {
return self.scope_stack[pos].get(identifier); return self.scope_stack[pos].reference(identifier);
} }
} }
None None
@ -55,6 +56,7 @@ impl Default for Context {
fn default() -> Context { fn default() -> Context {
Context { Context {
current_pos: 0, current_pos: 0,
globals: Scope::default(),
scope_stack: vec![Scope::default()], scope_stack: vec![Scope::default()],
} }
} }
@ -70,7 +72,7 @@ mod test {
let symbol = Symbol::r#type("MartyMcFly"); let symbol = Symbol::r#type("MartyMcFly");
assert!(context.globals().is_empty()); assert!(context.globals().is_empty());
context.globals_mut().add(symbol); context.globals_mut().define(symbol);
assert!(!context.globals().is_empty()); assert!(!context.globals().is_empty());
} }
@ -80,7 +82,7 @@ mod test {
let symbol = Symbol::local("marty"); let symbol = Symbol::local("marty");
assert!(context.scope().is_empty()); assert!(context.scope().is_empty());
context.scope_mut().add(symbol); context.scope_mut().define(symbol);
assert!(!context.scope().is_empty()); assert!(!context.scope().is_empty());
} }
@ -90,10 +92,10 @@ mod test {
let symbol0 = Symbol::local("marty"); let symbol0 = Symbol::local("marty");
let symbol1 = Symbol::local("doc"); let symbol1 = Symbol::local("doc");
context.scope_mut().add(symbol0); context.scope_mut().define(symbol0);
assert!(context.scope().has_symbol("marty")); assert!(context.scope().has_symbol("marty"));
context.push_scope(); context.push_scope();
context.scope_mut().add(symbol1); context.scope_mut().define(symbol1);
assert!(context.scope().has_symbol("doc")); assert!(context.scope().has_symbol("doc"));
assert!(!context.scope().has_symbol("marty")); assert!(!context.scope().has_symbol("marty"));
context.pop_scope(); context.pop_scope();
@ -102,14 +104,14 @@ mod test {
} }
#[test] #[test]
fn find_symbol() { fn reference() {
let mut context = Context::default(); let mut context = Context::default();
let symbol0 = Symbol::local("marty"); let symbol0 = Symbol::local("marty");
let symbol1 = Symbol::local("doc"); let symbol1 = Symbol::local("doc");
context.scope_mut().add(symbol0); context.scope_mut().define(symbol0);
context.push_scope(); context.push_scope();
context.scope_mut().add(symbol1); context.scope_mut().define(symbol1);
assert!(context.find_symbol("marty").is_some()); assert!(context.reference("marty").is_some());
} }
} }

View file

@ -6,11 +6,11 @@ pub struct Scope {
} }
impl Scope { impl Scope {
pub fn add(&mut self, symbol: Symbol) { pub fn define(&mut self, symbol: Symbol) {
self.symbols.insert(symbol.identifier().to_string(), symbol); self.symbols.insert(symbol.identifier().to_string(), symbol);
} }
pub fn get(&self, identifier: &str) -> Option<&Symbol> { pub fn reference(&self, identifier: &str) -> Option<&Symbol> {
self.symbols.get(identifier) self.symbols.get(identifier)
} }
@ -41,8 +41,8 @@ mod test {
let symbol = Symbol::local("marty"); let symbol = Symbol::local("marty");
assert!(scope.is_empty()); assert!(scope.is_empty());
assert!(!scope.has_symbol("marty")); assert!(!scope.has_symbol("marty"));
scope.add(symbol.clone()); scope.define(symbol.clone());
assert!(scope.has_symbol("marty")); assert!(scope.has_symbol("marty"));
assert_eq!(scope.get("marty").unwrap(), &symbol); assert_eq!(scope.reference("marty").unwrap(), &symbol);
} }
} }

View file

@ -56,11 +56,11 @@ mod test {
#[test] #[test]
fn it_parses() { fn it_parses() {
let pair = Grammar::parse(Rule::constant, "MartyMcFly") let pair = Grammar::parse(Rule::constant, "Marty.McFly")
.unwrap() .unwrap()
.next() .next()
.unwrap(); .unwrap();
let constant = Constant::from(pair); let constant = Constant::from(pair);
assert_eq!(constant.value(), "MartyMcFly"); assert_eq!(constant.value(), "Marty.McFly");
} }
} }

View file

@ -646,6 +646,15 @@ mod test {
assert_eq!(arguments.len(), 0); assert_eq!(arguments.len(), 0);
} }
#[test]
fn test_method_call_on_constant() {
let terms = Term::input("My.Greeter.hello()").unwrap();
let (method_name, receiver, arguments) = terms[0].method_call().unwrap();
assert_eq!(method_name.value_ref(), "hello");
assert_eq!(receiver.constant().unwrap().value_ref(), "My.Greeter");
assert_eq!(arguments.len(), 0);
}
#[test] #[test]
fn test_string() { fn test_string() {
let terms = Term::input("\"Marty McFly\"").unwrap(); let terms = Term::input("\"Marty McFly\"").unwrap();

View file

@ -44,7 +44,8 @@ array = { "[" ~ (expression ~ ("," ~ expression)*)? ~ "]" }
atom = @{ ":" ~ ident } atom = @{ ":" ~ ident }
constant = @{ 'A'..'Z' ~ ('a'..'z' | 'A'..'Z' | "_")* } constant = @{ constant_name ~ ("." ~ constant_name)* }
constant_name = @{ 'A'..'Z' ~ ('a'..'z' | 'A'..'Z' | "_")* }
float = ${ float_characteristic ~ "." ~ float_mantissa } float = ${ float_characteristic ~ "." ~ float_mantissa }
float_characteristic = { "0" | (('1'..'9') ~ ('0'..'9' | "_")*) } float_characteristic = { "0" | (('1'..'9') ~ ('0'..'9' | "_")*) }