diff --git a/CHANGELOG.md b/CHANGELOG.md index 50a3f6b4a..c65096d13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,12 @@ In addition to original Keep-a-Changelog, we use following rules: - This will be checked by GitHub Actions - Each Pull Request MAY correspond to one or more lines in this file +## Unreleased + +### Fixed + +- Fixes to support parsing of ISO13399 database plib. https://github.com/ricosjp/ruststep/pull/251 + ## 0.4.0 - 2024-09-20 ### Added diff --git a/ruststep/src/parser/exchange/parameter.rs b/ruststep/src/parser/exchange/parameter.rs index d374ffd3d..04d57f6be 100644 --- a/ruststep/src/parser/exchange/parameter.rs +++ b/ruststep/src/parser/exchange/parameter.rs @@ -6,8 +6,8 @@ use nom::{branch::alt, combinator::value, Parser}; /// list = `(` \[ [parameter] { `,` [parameter] } \] `)` . pub fn list(input: &str) -> ParseResult { - tuple_((char_('('), comma_separated(parameter), char_(')'))) - .map(|(_open, params, _close)| Parameter::List(params)) + tuple_((char_('('), opt_(comma_separated(parameter)), char_(')'))) + .map(|(_open, params, _close)| Parameter::List(params.unwrap_or_default())) .parse(input) } @@ -66,4 +66,25 @@ mod tests { assert_eq!(res, ""); assert_eq!(record, Parameter::real(2.0)); } + + #[test] + fn parameter_list() { + let (res, record) = super::untyped_parameter("(1, 2, 3)").finish().unwrap(); + assert_eq!(res, ""); + assert_eq!( + record, + Parameter::List(vec![ + Parameter::Integer(1), + Parameter::Integer(2), + Parameter::Integer(3), + ]) + ); + } + + #[test] + fn empty_parameter_list() { + let (res, record) = super::untyped_parameter("()").finish().unwrap(); + assert_eq!(res, ""); + assert_eq!(record, Parameter::List(vec![])); + } } diff --git a/ruststep/src/parser/token.rs b/ruststep/src/parser/token.rs index 005af3ecb..f886e3aeb 100644 --- a/ruststep/src/parser/token.rs +++ b/ruststep/src/parser/token.rs @@ -4,6 +4,8 @@ use crate::{ ast::*, parser::{basic::*, combinator::*}, }; +use nom::bytes::complete::tag; +use nom::combinator::map; use nom::{ branch::alt, character::complete::{char, digit0, digit1, multispace0, none_of, satisfy}, @@ -68,7 +70,12 @@ pub fn real(input: &str) -> ParseResult { /// string = `'` { [special] | [digit] | [space] | [lower] | [upper] | high_codepoint | [apostrophe] [apostrophe] | [reverse_solidus] [reverse_solidus] | control_directive } `'` . pub fn string(input: &str) -> ParseResult { - tuple((char('\''), many0(none_of("'")), char('\''))) + let escaped_char = map(tag("''"), |_| '\''); // Parse '' as a single ' + let normal_char = none_of("'"); // Parse any character except ' + + let string_content = many0(escaped_char.or(normal_char.map(|c| c))); + + tuple((char('\''), string_content, char('\''))) .map(|(_start, s, _end)| s.iter().collect()) .parse(input) } @@ -259,6 +266,13 @@ mod tests { assert_eq!(s, "vim"); } + #[test] + fn escaped_string() { + let (res, s) = super::string("'vim''s'").finish().unwrap(); + assert_eq!(res, ""); + assert_eq!(s, "vim's"); + } + #[test] fn instance_name() { let (res, s) = super::entity_instance_name("#18446744073709551615" /* u64::MAX */)