diff options
| author | Laurenz <laurmaedje@gmail.com> | 2020-10-01 11:32:48 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2020-10-01 11:32:48 +0200 |
| commit | 885bfec5d7524845b41e180fadc9cf5626157eec (patch) | |
| tree | f798e03d101d568a110a5c56f4a9bfa2be892928 /src/syntax | |
| parent | 16f0bd430e0864a3bbd0139803e476be413cb3cb (diff) | |
Make syntax not depend on parse 📩
This would make it possible to split them into two separate crates.
Diffstat (limited to 'src/syntax')
| -rw-r--r-- | src/syntax/lines.rs | 108 | ||||
| -rw-r--r-- | src/syntax/mod.rs | 2 | ||||
| -rw-r--r-- | src/syntax/span.rs | 35 | ||||
| -rw-r--r-- | src/syntax/tree.rs | 43 |
4 files changed, 61 insertions, 127 deletions
diff --git a/src/syntax/lines.rs b/src/syntax/lines.rs deleted file mode 100644 index 6ea223c4..00000000 --- a/src/syntax/lines.rs +++ /dev/null @@ -1,108 +0,0 @@ -//! Conversion of byte positions to line/column locations. - -use std::fmt::{self, Debug, Display, Formatter}; - -use super::Pos; -use crate::parse::{is_newline_char, Scanner}; - -/// Enables conversion of byte position to locations. -pub struct LineMap<'s> { - src: &'s str, - line_starts: Vec<Pos>, -} - -impl<'s> LineMap<'s> { - /// Create a new line map for a source string. - pub fn new(src: &'s str) -> Self { - let mut line_starts = vec![Pos::ZERO]; - let mut s = Scanner::new(src); - - while let Some(c) = s.eat_merging_crlf() { - if is_newline_char(c) { - line_starts.push(s.index().into()); - } - } - - Self { src, line_starts } - } - - /// Convert a byte position to a location. - /// - /// # Panics - /// This panics if the position is out of bounds. - pub fn location(&self, pos: Pos) -> Location { - let line_index = match self.line_starts.binary_search(&pos) { - Ok(i) => i, - Err(i) => i - 1, - }; - - let line_start = self.line_starts[line_index]; - let head = &self.src[line_start.to_usize() .. pos.to_usize()]; - let column_index = head.chars().count(); - - Location { - line: 1 + line_index as u32, - column: 1 + column_index as u32, - } - } -} - -/// One-indexed line-column position in source code. -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] -#[cfg_attr(feature = "serialize", derive(serde::Serialize))] -pub struct Location { - /// The one-indexed line. - pub line: u32, - /// The one-indexed column. - pub column: u32, -} - -impl Location { - /// Create a new location from line and column. - pub fn new(line: u32, column: u32) -> Self { - Self { line, column } - } -} - -impl Debug for Location { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - Display::fmt(self, f) - } -} - -impl Display for Location { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "{}:{}", self.line, self.column) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - const TEST: &str = "äbcde\nf💛g\r\nhi\rjkl"; - - #[test] - fn test_line_map_new() { - let map = LineMap::new(TEST); - assert_eq!(map.line_starts, vec![Pos(0), Pos(7), Pos(15), Pos(18)]); - } - - #[test] - fn test_line_map_location() { - let map = LineMap::new(TEST); - assert_eq!(map.location(Pos(0)), Location::new(1, 1)); - assert_eq!(map.location(Pos(2)), Location::new(1, 2)); - assert_eq!(map.location(Pos(6)), Location::new(1, 6)); - assert_eq!(map.location(Pos(7)), Location::new(2, 1)); - assert_eq!(map.location(Pos(8)), Location::new(2, 2)); - assert_eq!(map.location(Pos(12)), Location::new(2, 3)); - assert_eq!(map.location(Pos(21)), Location::new(4, 4)); - } - - #[test] - #[should_panic] - fn test_line_map_panics_out_of_bounds() { - LineMap::new(TEST).location(Pos(22)); - } -} diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs index f442ba9e..fe887c2f 100644 --- a/src/syntax/mod.rs +++ b/src/syntax/mod.rs @@ -1,11 +1,9 @@ //! Syntax types. -mod lines; mod span; mod token; mod tree; -pub use lines::*; pub use span::*; pub use token::*; pub use tree::*; diff --git a/src/syntax/span.rs b/src/syntax/span.rs index d803eeeb..eb029479 100644 --- a/src/syntax/span.rs +++ b/src/syntax/span.rs @@ -1,6 +1,6 @@ //! Mapping of values to the locations they originate from in source code. -use std::fmt::{self, Debug, Formatter}; +use std::fmt::{self, Debug, Display, Formatter}; #[cfg(test)] use std::cell::Cell; @@ -168,7 +168,7 @@ impl Debug for Span { } } -/// A byte position. +/// A byte position in source code. #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] #[cfg_attr(feature = "serialize", derive(serde::Serialize))] pub struct Pos(pub u32); @@ -203,6 +203,35 @@ impl Offset for Pos { impl Debug for Pos { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - self.0.fmt(f) + Debug::fmt(&self.0, f) + } +} + +/// A one-indexed line-column position in source code. +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[cfg_attr(feature = "serialize", derive(serde::Serialize))] +pub struct Location { + /// The one-indexed line. + pub line: u32, + /// The one-indexed column. + pub column: u32, +} + +impl Location { + /// Create a new location from line and column. + pub fn new(line: u32, column: u32) -> Self { + Self { line, column } + } +} + +impl Debug for Location { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + Display::fmt(self, f) + } +} + +impl Display for Location { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "{}:{}", self.line, self.column) } } diff --git a/src/syntax/tree.rs b/src/syntax/tree.rs index bfbb3706..ee53d476 100644 --- a/src/syntax/tree.rs +++ b/src/syntax/tree.rs @@ -1,6 +1,7 @@ //! The syntax tree. use std::fmt::{self, Debug, Formatter}; +use std::ops::Deref; use unicode_xid::UnicodeXID; @@ -234,7 +235,7 @@ pub struct Ident(pub String); impl Ident { /// Create a new identifier from a string checking that it is a valid. pub fn new(ident: impl AsRef<str> + Into<String>) -> Option<Self> { - if Self::is_ident(ident.as_ref()) { + if is_ident(ident.as_ref()) { Some(Self(ident.into())) } else { None @@ -243,21 +244,21 @@ impl Ident { /// Return a reference to the underlying string. pub fn as_str(&self) -> &str { - self.0.as_str() + self } +} - /// Whether the string is a valid identifier. - pub fn is_ident(string: &str) -> bool { - fn is_ok(c: char) -> bool { - c == '-' || c == '_' - } +impl AsRef<str> for Ident { + fn as_ref(&self) -> &str { + self + } +} - let mut chars = string.chars(); - if matches!(chars.next(), Some(c) if c.is_xid_start() || is_ok(c)) { - chars.all(|c| c.is_xid_continue() || is_ok(c)) - } else { - false - } +impl Deref for Ident { + type Target = str; + + fn deref(&self) -> &Self::Target { + self.0.as_str() } } @@ -267,6 +268,20 @@ impl Debug for Ident { } } +/// Whether the string is a valid identifier. +pub fn is_ident(string: &str) -> bool { + fn is_ok(c: char) -> bool { + c == '-' || c == '_' + } + + let mut chars = string.chars(); + if matches!(chars.next(), Some(c) if c.is_xid_start() || is_ok(c)) { + chars.all(|c| c.is_xid_continue() || is_ok(c)) + } else { + false + } +} + /// A table of expressions. /// /// # Example @@ -307,7 +322,7 @@ pub struct CallExpr { impl CallExpr { /// Evaluate the call expression to a value. pub async fn eval(&self, ctx: &LayoutContext<'_>, f: &mut Feedback) -> Value { - let name = self.name.v.as_str(); + let name = &self.name.v; let span = self.name.span; let args = self.args.eval(ctx, f).await; |
