diff --git a/src/base/file_provider.rs b/src/base/file_provider.rs index ca69af9..037a710 100644 --- a/src/base/file_provider.rs +++ b/src/base/file_provider.rs @@ -27,6 +27,15 @@ impl Default for FsProvider { } } +impl

From

for FsProvider +where + P: Into, +{ + fn from(root: P) -> Self { + Self { root: root.into() } + } +} + impl FileProvider for FsProvider { fn read_to_string>(&self, path: P) -> Result { let full_path = self.root.join(path); diff --git a/src/base/log.rs b/src/base/log.rs index 8ae26b6..a7b853e 100644 --- a/src/base/log.rs +++ b/src/base/log.rs @@ -1,7 +1,6 @@ //! Module containing structures and implementations for logging messages to the user. use colored::Colorize; -use path_absolutize::Absolutize; use std::{fmt::Display, sync::Arc}; use super::source_file::{Location, SourceFile, Span}; @@ -74,7 +73,7 @@ impl<'a, T> SourceCodeDisplay<'a, T> { } } -impl<'a, T: std::fmt::Display> Display for SourceCodeDisplay<'a, T> { +impl<'a, T: Display> Display for SourceCodeDisplay<'a, T> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let start_location = self.span.start_location(); let end_location = self.span.end_location(); @@ -100,12 +99,7 @@ impl<'a, T: std::fmt::Display> Display for SourceCodeDisplay<'a, T> { "-->".cyan().bold(), format_args!( "{}:{}:{}", - self.span - .source_file() - .path() - .absolutize() - .unwrap_or_else(|_| std::borrow::Cow::Borrowed(self.span.source_file().path())) - .display(), + self.span.source_file().path().display(), start_location.line, start_location.column ) diff --git a/src/lexical/token.rs b/src/lexical/token.rs index 713d2d3..4415b51 100644 --- a/src/lexical/token.rs +++ b/src/lexical/token.rs @@ -1,6 +1,6 @@ //! Contains the [`Token`] struct and its related types. -use std::{collections::HashMap, str::FromStr, sync::OnceLock}; +use std::{borrow::Cow, collections::HashMap, fmt::Display, str::FromStr, sync::OnceLock}; use crate::base::{ source_file::{SourceElement, SourceIterator, Span}, @@ -42,9 +42,9 @@ pub enum KeywordKind { Import, } -impl ToString for KeywordKind { - fn to_string(&self) -> String { - self.as_str().to_string() +impl Display for KeywordKind { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.as_str()) } } @@ -259,11 +259,22 @@ pub struct StringLiteral { } impl StringLiteral { - /// Returns the string without the leading and trailing double quotes. + /// Returns the string content without escapement characters, leading and trailing double quotes. #[must_use] - pub fn str_content(&self) -> &str { + pub fn str_content(&self) -> Cow { let string = self.span.str(); - &string[1..string.len() - 1] + let string = &string[1..string.len() - 1]; + if string.contains('\\') { + let escaped = string + .replace("\\n", "\n") + .replace("\\r", "\r") + .replace("\\t", "\t") + .replace("\\\"", "\"") + .replace("\\\\", "\\"); + Cow::Owned(escaped) + } else { + Cow::Borrowed(string) + } } } @@ -603,3 +614,38 @@ impl Token { } } } + +#[cfg(test)] +mod tests { + use crate::base::source_file::SourceFile; + use shulkerbox::virtual_fs::{VFile, VFolder}; + use std::path::Path; + + use super::*; + + fn get_span(content: &str) -> Span { + let source_file = VFile::Text(String::from(content)); + let mut vfolder = VFolder::new(); + vfolder.add_file("test.shu", source_file); + let source_file = SourceFile::load(Path::new("test.shu"), &vfolder).unwrap(); + + Span::new(source_file, 0, content.len()).unwrap() + } + + #[test] + fn test_string_literal() { + let span = get_span(r#""Hello, World!""#); + let string_literal = StringLiteral { span }; + + let content = string_literal.str_content(); + assert_eq!(content, "Hello, World!"); + assert!(matches!(content, Cow::Borrowed(_))); + + let escaped_string_literal = StringLiteral { + span: get_span(r#""Hello, \"World\"!""#), + }; + let escaped_content = escaped_string_literal.str_content(); + assert_eq!(escaped_content, "Hello, \"World\"!"); + assert!(matches!(escaped_content, Cow::Owned(_))); + } +} diff --git a/src/syntax/syntax_tree/program.rs b/src/syntax/syntax_tree/program.rs index 6389c77..69ee059 100644 --- a/src/syntax/syntax_tree/program.rs +++ b/src/syntax/syntax_tree/program.rs @@ -89,9 +89,9 @@ impl<'a> Parser<'a> { // eat the keyword self.forward(); - let namespace_name = self - .parse_string_literal(handler) - .and_then(|name| Namespace::validate_str(name.str_content()).then_some(name))?; + let namespace_name = self.parse_string_literal(handler).and_then(|name| { + Namespace::validate_str(name.str_content().as_ref()).then_some(name) + })?; let semicolon = self.parse_punctuation(';', true, handler)?;