From 8f3efc520de0157320ebb473de04571d07430027 Mon Sep 17 00:00:00 2001 From: Jonathan Johnson Date: Fri, 1 Mar 2024 09:16:36 -0800 Subject: [PATCH] Added fully qualified names --- src/compiler.rs | 9 +++++++- src/symbol.rs | 1 + src/syntax.rs | 9 ++++++++ src/syntax/token.rs | 53 ++++++++++++++++++++++++++++++------------- src/vm.rs | 55 ++++++++++++++++++++++++--------------------- tests/cases/mod.rsn | 13 +++++++++++ tests/harness.rs | 2 +- 7 files changed, 100 insertions(+), 42 deletions(-) diff --git a/src/compiler.rs b/src/compiler.rs index 36b9644..d3fade2 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -191,6 +191,11 @@ impl<'a> Scope<'a> { fn compile_expression(&mut self, expr: &Ranged, dest: OpDestination) { self.compiler.code.set_current_source_range(expr.range()); match &**expr { + Expression::RootModule => { + self.compiler + .code + .resolve(Symbol::sigil_symbol().clone(), dest); + } Expression::Literal(literal) => self.compile_literal(literal, dest), Expression::Lookup(lookup) => { if let Some(base) = &lookup.base { @@ -1371,7 +1376,8 @@ impl<'a> Scope<'a> { | Expression::Binary(_) | Expression::Module(_) | Expression::Function(_) - | Expression::Variable(_) => Err(expr.1), + | Expression::Variable(_) + | Expression::RootModule => Err(expr.1), } } @@ -1617,6 +1623,7 @@ impl<'a> Scope<'a> { | Expression::Loop(_) | Expression::Break(_) | Expression::Continue(_) + | Expression::RootModule | Expression::Return(_) => { ValueOrSource::Stack(self.compile_expression_into_temporary(source)) } diff --git a/src/symbol.rs b/src/symbol.rs index 42a1063..36b2c3a 100644 --- a/src/symbol.rs +++ b/src/symbol.rs @@ -53,6 +53,7 @@ static_symbols!( pub_symbol => "pub", return_symbol => "return", set_symbol => "set", + sigil_symbol => "$", super_symbol => "super", then_symbol => "then", throw_symbol => "throw", diff --git a/src/syntax.rs b/src/syntax.rs index a8dca1e..f553b1e 100644 --- a/src/syntax.rs +++ b/src/syntax.rs @@ -180,6 +180,7 @@ impl From<(SourceId, RangeInclusive)> for SourceRange { #[derive(Debug, Clone, PartialEq)] pub enum Expression { + RootModule, Literal(Literal), Lookup(Box), If(Box), @@ -971,6 +972,7 @@ impl Parselet for Term { | Token::Regex(_) | Token::String(_) | Token::Symbol(_) + | Token::Sigil(_) ) } } @@ -1011,6 +1013,13 @@ impl PrefixParselet for Term { token.1, Expression::Literal(Literal::Symbol(sym)), )), + Token::Sigil(sym) => { + if &sym == Symbol::sigil_symbol() { + Ok(Ranged::new(token.1, Expression::RootModule)) + } else { + todo!("macro!!!!!") + } + } _ => unreachable!("parse called with invalid token"), } } diff --git a/src/syntax/token.rs b/src/syntax/token.rs index 0b6333e..82a180d 100644 --- a/src/syntax/token.rs +++ b/src/syntax/token.rs @@ -16,6 +16,7 @@ pub enum Token { Comment, Identifier(Symbol), Symbol(Symbol), + Sigil(Symbol), Label(Symbol), Int(i64), UInt(u64), @@ -75,7 +76,9 @@ impl Hash for Token { fn hash(&self, state: &mut H) { core::mem::discriminant(self).hash(state); match self { - Token::Identifier(t) | Token::Label(t) | Token::Symbol(t) => t.hash(state), + Token::Identifier(t) | Token::Label(t) | Token::Symbol(t) | Token::Sigil(t) => { + t.hash(state); + } Token::Int(t) => t.hash(state), Token::UInt(t) => t.hash(state), Token::Float(t) => t.to_bits().hash(state), @@ -206,6 +209,7 @@ impl Iterator for Tokens<'_> { } (start, '"') => self.tokenize_string(start), + (start, '$') => Ok(self.tokenize_sigil(start)), (start, '@') if self.chars.peek().map_or(false, unicode_ident::is_xid_start) => { let ch = self.chars.next().expect("just peekend").1; Ok(self.tokenize_label(start, ch)) @@ -229,20 +233,7 @@ impl Iterator for Tokens<'_> { (start, '.') if self.chars.peek().map_or(false, |ch| ch.is_ascii_digit()) => { self.tokenize_number(start, '.') } - (start, '.') if self.chars.peek() == Some('.') => { - self.chars.next(); - match self.chars.peek() { - Some('=') => { - self.chars.next(); - Ok(self.chars.ranged(start.., Token::RangeInclusive)) - } - Some('.') => { - self.chars.next(); - Ok(self.chars.ranged(start.., Token::Ellipses)) - } - _ => Ok(self.chars.ranged(start.., Token::Range)), - } - } + (start, '.') if self.chars.peek() == Some('.') => Ok(self.tokenize_range(start)), (start, '*') if self.chars.peek() == Some('*') => { self.chars.next(); Ok(self.chars.ranged(start.., Token::Power)) @@ -320,6 +311,38 @@ impl<'a> Tokens<'a> { self } + fn tokenize_sigil(&mut self, start: usize) -> Ranged { + let symbol = if let Some(ch) = self + .chars + .peek() + .filter(|ch| unicode_ident::is_xid_start(*ch)) + { + self.chars.next(); + self.tokenize_identifier_symbol(start, ch) + } else { + self.chars.ranged(start.., Symbol::sigil_symbol().clone()) + }; + + symbol.map(Token::Sigil) + } + + fn tokenize_range(&mut self, start: usize) -> Ranged { + let second_dot = self.chars.next(); + debug_assert!(matches!(second_dot, Some((_, '.')))); + + match self.chars.peek() { + Some('=') => { + self.chars.next(); + self.chars.ranged(start.., Token::RangeInclusive) + } + Some('.') => { + self.chars.next(); + self.chars.ranged(start.., Token::Ellipses) + } + _ => self.chars.ranged(start.., Token::Range), + } + } + fn tokenize_number( &mut self, start: usize, diff --git a/src/vm.rs b/src/vm.rs index 6215f23..920396c 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -435,34 +435,39 @@ impl Vm { } pub fn resolve(&mut self, name: &Symbol) -> Result { - if let Some(path) = name.strip_prefix("$.") { + if let Some(path) = name.strip_prefix('$') { let mut module = self.modules[0].clone(); let mut path = path.split('.').peekable(); - let name = loop { - let Some(name) = path.next() else { - return Err(Fault::UnknownSymbol); - }; - let name = Symbol::from(name); - if path.peek().is_some() { - let declarations = module.declarations(); - let value = &declarations.get(&name).ok_or(Fault::UnknownSymbol)?.value; - let Some(inner) = value.as_dynamic::() else { - return Err(Fault::MissingModule); + path.next(); + return if path.peek().is_none() { + Ok(module.to_value()) + } else { + let name = loop { + let Some(name) = path.next() else { + return Err(Fault::UnknownSymbol); }; - drop(declarations); - module = inner; - } else { - // Final path component - break name; - } - }; + let name = Symbol::from(name); + if path.peek().is_some() { + let declarations = module.declarations(); + let value = &declarations.get(&name).ok_or(Fault::UnknownSymbol)?.value; + let Some(inner) = value.as_dynamic::() else { + return Err(Fault::MissingModule); + }; + drop(declarations); + module = inner; + } else { + // Final path component + break name; + } + }; - return Ok(module - .declarations() - .get(&name) - .ok_or(Fault::UnknownSymbol)? - .value - .clone()); + Ok(module + .declarations() + .get(&name) + .ok_or(Fault::UnknownSymbol)? + .value + .clone()) + }; } let current_frame = &self.frames[self.current_frame]; @@ -712,7 +717,7 @@ impl Vm { Ordering::Equal => return Ok(StepResult::Complete), Ordering::Greater => return Err(Fault::InvalidInstructionAddress), }; - // println!("Executing {instruction:?}"); + println!("Executing {instruction:?}"); let next_instruction = StepResult::from(address.checked_add(1)); let result = match instruction { LoadedOp::Return => return Ok(StepResult::Complete), diff --git a/tests/cases/mod.rsn b/tests/cases/mod.rsn index d94d071..e3cdbff 100644 --- a/tests/cases/mod.rsn +++ b/tests/cases/mod.rsn @@ -116,4 +116,17 @@ child_mod_private: { foo.bar.a "#, output: Fault(Exception(Exception { value: Symbol("undefined"), backtrace: [SourceRange { source_id: SourceId(None), start: 106, length: 7 }] })), +} + +sigil_root: { + src: r#" + mod foo { + pub mod bar { + pub fn baz() => $.value; + } + }; + pub let value = 42; + foo.bar.baz() + "#, + output: Int(42), } \ No newline at end of file diff --git a/tests/harness.rs b/tests/harness.rs index b038dc7..06500de 100644 --- a/tests/harness.rs +++ b/tests/harness.rs @@ -17,7 +17,7 @@ use serde::Deserialize; fn main() { let filter = std::env::args().nth(1).unwrap_or_default(); - // let filter = String::from("tuple_remaining"); + // let filter = String::from("sigil_root"); for entry in std::fs::read_dir("tests/cases").unwrap() { let entry = entry.unwrap().path(); if entry.extension().map_or(false, |ext| ext == "rsn") {