cleanup and correct string literal content implementation

This commit is contained in:
Moritz Hölting 2024-07-08 15:03:09 +02:00
parent a0a27cda96
commit bc25da6f2c
4 changed files with 67 additions and 18 deletions

View File

@ -27,6 +27,15 @@ impl Default for FsProvider {
} }
} }
impl<P> From<P> for FsProvider
where
P: Into<PathBuf>,
{
fn from(root: P) -> Self {
Self { root: root.into() }
}
}
impl FileProvider for FsProvider { impl FileProvider for FsProvider {
fn read_to_string<P: AsRef<Path>>(&self, path: P) -> Result<String, Error> { fn read_to_string<P: AsRef<Path>>(&self, path: P) -> Result<String, Error> {
let full_path = self.root.join(path); let full_path = self.root.join(path);

View File

@ -1,7 +1,6 @@
//! Module containing structures and implementations for logging messages to the user. //! Module containing structures and implementations for logging messages to the user.
use colored::Colorize; use colored::Colorize;
use path_absolutize::Absolutize;
use std::{fmt::Display, sync::Arc}; use std::{fmt::Display, sync::Arc};
use super::source_file::{Location, SourceFile, Span}; 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 { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let start_location = self.span.start_location(); let start_location = self.span.start_location();
let end_location = self.span.end_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(), "-->".cyan().bold(),
format_args!( format_args!(
"{}:{}:{}", "{}:{}:{}",
self.span self.span.source_file().path().display(),
.source_file()
.path()
.absolutize()
.unwrap_or_else(|_| std::borrow::Cow::Borrowed(self.span.source_file().path()))
.display(),
start_location.line, start_location.line,
start_location.column start_location.column
) )

View File

@ -1,6 +1,6 @@
//! Contains the [`Token`] struct and its related types. //! 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::{ use crate::base::{
source_file::{SourceElement, SourceIterator, Span}, source_file::{SourceElement, SourceIterator, Span},
@ -42,9 +42,9 @@ pub enum KeywordKind {
Import, Import,
} }
impl ToString for KeywordKind { impl Display for KeywordKind {
fn to_string(&self) -> String { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.as_str().to_string() write!(f, "{}", self.as_str())
} }
} }
@ -259,11 +259,22 @@ pub struct StringLiteral {
} }
impl 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] #[must_use]
pub fn str_content(&self) -> &str { pub fn str_content(&self) -> Cow<str> {
let string = self.span.str(); 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(_)));
}
}

View File

@ -89,9 +89,9 @@ impl<'a> Parser<'a> {
// eat the keyword // eat the keyword
self.forward(); self.forward();
let namespace_name = self let namespace_name = self.parse_string_literal(handler).and_then(|name| {
.parse_string_literal(handler) Namespace::validate_str(name.str_content().as_ref()).then_some(name)
.and_then(|name| Namespace::validate_str(name.str_content()).then_some(name))?; })?;
let semicolon = self.parse_punctuation(';', true, handler)?; let semicolon = self.parse_punctuation(';', true, handler)?;