From 82e5b589e1babe906096b4aef66609ced4cb2933 Mon Sep 17 00:00:00 2001 From: Joscha Date: Sun, 20 Nov 2022 17:28:04 +0100 Subject: [PATCH] Parse string literals --- src/ast/lit.rs | 6 ++---- src/parser/lit.rs | 42 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/src/ast/lit.rs b/src/ast/lit.rs index a659e27..ea87ab7 100644 --- a/src/ast/lit.rs +++ b/src/ast/lit.rs @@ -61,8 +61,6 @@ pub enum StringLitElem { Unicode(char), /// `\\` Backslash, - /// `\'` - SingleQuote, /// `\"'` DoubleQuote, /// `\t` @@ -77,8 +75,8 @@ pub enum StringLitElem { /// - `""` #[derive(Debug, Clone)] pub struct StringLit { - elems: Vec, - span: Span, + pub elems: Vec, + pub span: Span, } impl HasSpan for StringLit { diff --git a/src/parser/lit.rs b/src/parser/lit.rs index 206fb41..a1f11c5 100644 --- a/src/parser/lit.rs +++ b/src/parser/lit.rs @@ -2,7 +2,9 @@ use chumsky::prelude::*; -use crate::ast::{Expr, Ident, Lit, NumLit, NumLitStr, Space, StringLit, TableLit, TableLitElem}; +use crate::ast::{ + Expr, Ident, Lit, NumLit, NumLitStr, Space, StringLit, StringLitElem, TableLit, TableLitElem, +}; use crate::builtin::Builtin; use super::basic::{EParser, Error}; @@ -78,9 +80,43 @@ fn num_lit() -> impl Parser { .map_with_span(|(value, str), span| NumLit { value, str, span }) } +fn string_lit_elem() -> impl Parser { + let plain = filter(|c: &char| !matches!(c, '"' | '\\')) + .repeated() + .at_least(1) + .collect::() + .map(StringLitElem::Plain); + + let unicode_char = num_lit_str_radix(16).try_map(|(n, _), span| { + let msg = "not a valid unicode code point"; + let n: u32 = n.try_into().map_err(|_| Simple::custom(span, msg))?; + let c: char = n.try_into().map_err(|_| Simple::custom(span, msg))?; + Ok(c) + }); + let unicode = just("\\u{") + .ignore_then(unicode_char) + .then_ignore(just('}')) + .map(StringLitElem::Unicode); + let backslash = just("\\\\").to(StringLitElem::Backslash); + let double_quote = just("\\\"").to(StringLitElem::DoubleQuote); + let tab = just("\\t").to(StringLitElem::Tab); + let carriage_return = just("\\r").to(StringLitElem::CarriageReturn); + let newline = just("\\n").to(StringLitElem::Newline); + + plain + .or(unicode) + .or(backslash) + .or(double_quote) + .or(tab) + .or(carriage_return) + .or(newline) +} + fn string_lit() -> impl Parser { - // TODO Parse string literals - filter(|_| false).map(|_| unreachable!()) + string_lit_elem() + .repeated() + .delimited_by(just('"'), just('"')) + .map_with_span(|elems, span| StringLit { elems, span }) } pub fn table_lit_elem(