Skip to content

Commit

Permalink
Allow parsing numeric-looking symbols
Browse files Browse the repository at this point in the history
Note that we may want to extend general symbol syntax support as well,
on both parsing and printing, which is currently lacking (at least):

- R6RS/R7RS hex escapes
- R7RS pipe-quoted symbols
- Emacs Lisp escapes
  • Loading branch information
Andreas Rottmann committed Jun 15, 2024
1 parent 3f0b8e6 commit 615b4fd
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 1 deletion.
6 changes: 6 additions & 0 deletions lexpr/NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ New features:

- New parser option `racket_hash_percent_symbols`, implemented in PR
#90 by @andrew-pa.
- New parser option `leading_digit_symbols`, implemented in PR
#FIXME. This should now allow parsing files produced by recent KiCad
versions, thus closing #64.

Changes:

Expand All @@ -14,6 +17,9 @@ Changes:
octothorpe, as in Emacs Lisp and Common Lisp, allowing for a
less-noisy spelling; e.g.: `:foo` instead of `#:foo`. Feature
request (#99) and initial implementation (#96) by @samuel-jimenez.
- The `parser::Options::elisp` constructor now enables the
`leading_digit_symbols` option, as that's what's appropriate for
Emacs Lisp.

Maintenance-related changes:

Expand Down
6 changes: 6 additions & 0 deletions lexpr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@ a feature that is not yet listed here, please [file an issue]!.
- Integer literals with an arbitrary base (radix), are not yet
supported.

### KiCad

- Since version 0.3.0, reading and writing S-expression files produced
by recent versions of KiCad should be supported given the new
`with_leading_digit_symbols` parser option.

## Licensing

The code and documentation in the `lexpr` crate is [free
Expand Down
28 changes: 27 additions & 1 deletion lexpr/src/parse/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ pub struct Options {
string_syntax: StringSyntax,
char_syntax: CharSyntax,
racket_hash_percent_symbols: bool,
leading_digit_symbols: bool,
}

/// Defines the treatment of the symbol `nil`.
Expand Down Expand Up @@ -111,6 +112,7 @@ impl Options {
string_syntax: StringSyntax::R6RS,
char_syntax: CharSyntax::R6RS,
racket_hash_percent_symbols: false,
leading_digit_symbols: false,
}
}

Expand All @@ -122,6 +124,7 @@ impl Options {
.with_brackets(Brackets::Vector)
.with_string_syntax(StringSyntax::Elisp)
.with_char_syntax(CharSyntax::Elisp)
.with_leading_digit_symbols(true)
}

/// Add `syntax` to the recognized keyword syntaxes.
Expand Down Expand Up @@ -178,6 +181,12 @@ impl Options {
self
}

/// Choose whether to allow symbols with leading digits.
pub fn with_leading_digit_symbols(mut self, allow: bool) -> Self {
self.leading_digit_symbols = allow;
self
}

/// Check wether a keyword syntax is enabled.
#[inline]
pub fn keyword_syntax(self, syntax: KeywordSyntax) -> bool {
Expand Down Expand Up @@ -213,6 +222,11 @@ impl Options {
pub fn racket_hash_percent_symbols(self) -> bool {
self.racket_hash_percent_symbols
}

/// Query if symbols with leading digits are allowd.
pub fn leading_digit_symbols(self) -> bool {
self.leading_digit_symbols
}
}

impl Default for Options {
Expand All @@ -231,6 +245,7 @@ impl Default for Options {
string_syntax: StringSyntax::R6RS,
char_syntax: CharSyntax::R6RS,
racket_hash_percent_symbols: false,
leading_digit_symbols: false,
}
}
}
Expand Down Expand Up @@ -529,7 +544,18 @@ impl<'de, R: Read<'de>> Parser<R> {
Token::Number(self.parse_num_literal(10, true)?)
}
}
b'0'..=b'9' => Token::Number(self.parse_num_literal(10, true)?),
b'0'..=b'9' => {
if self.options.leading_digit_symbols {
let symbol = self.parse_symbol()?;
let mut num_parser = Parser::from_slice_custom(symbol.as_bytes(), self.options);
match num_parser.parse_num_literal(10, true) {
Ok(token) => Token::Number(token),
Err(_) => Token::Symbol(symbol.into()),
}
} else {
Token::Number(self.parse_num_literal(10, true)?)
}
}
b'"' => {
self.eat_char();
self.scratch.clear();
Expand Down
20 changes: 20 additions & 0 deletions lexpr/src/parse/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -689,3 +689,23 @@ fn test_racket_hash_percent_symbol() {
assert_eq!(parser.expect_value().unwrap(), Value::symbol("#%symbol"));
parser.expect_end().unwrap();
}

fn parser_recognizes_digit_symbols(options: Options) {
let mut parser = Parser::from_str_custom("55033ea4-52b5-46f6-b909-193ee90f64f8 1234", options);
assert_eq!(
parser.expect_value().unwrap(),
Value::symbol("55033ea4-52b5-46f6-b909-193ee90f64f8")
);
assert_eq!(parser.expect_value().unwrap(), Value::from(1234));
parser.expect_end().unwrap();
}

#[test]
fn test_digit_symbols() {
parser_recognizes_digit_symbols(Options::new().with_leading_digit_symbols(true));
}

#[test]
fn test_digit_symbols_elisp() {
parser_recognizes_digit_symbols(Options::elisp());
}

0 comments on commit 615b4fd

Please sign in to comment.