summaryrefslogtreecommitdiff
path: root/src/syntax
diff options
context:
space:
mode:
Diffstat (limited to 'src/syntax')
-rw-r--r--src/syntax/lines.rs108
-rw-r--r--src/syntax/mod.rs2
-rw-r--r--src/syntax/span.rs35
-rw-r--r--src/syntax/tree.rs43
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;