Skip to content

Commit

Permalink
Accept colon-prefixed keywords in sexp macro
Browse files Browse the repository at this point in the history
Implementation by @samuel-jimenez in PR #96.

Duplicate of #96, closes #99.
  • Loading branch information
samuel-jimenez authored and Andreas Rottmann committed May 31, 2024
1 parent 1fd8a52 commit 6b7df40
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 2 deletions.
13 changes: 13 additions & 0 deletions lexpr-macros/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,19 @@ impl Parser {
}
_ => Ok(Value::Symbol(c.to_string())),
},
':' => match self.peek() {
Some(TokenTree::Literal(lit)) => {
let name = string_literal(lit)?;
self.eat_token();
Ok(Value::Keyword(name))
}
Some(TokenTree::Ident(ident)) => {
let name = ident.to_string();
self.eat_token();
Ok(Value::Keyword(name))
}
_ => Ok(Value::Symbol(c.to_string())),
},
_ => Ok(Value::Symbol(c.to_string())),
},
}
Expand Down
4 changes: 4 additions & 0 deletions lexpr/NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ Changes:
- The `sexp!` macro is now only included when specifying the
non-default feature `sexp-macro`. This makes the crate a bit more
lightweight for users who don't need that macro.
- The `sexp!` macro now recognizes keywords without a leading
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.

Maintenance-related changes:

Expand Down
18 changes: 16 additions & 2 deletions lexpr/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,8 @@
/// # Symbols and keywords
///
/// Due to syntactic restrictions of Rust's macro system, to use
/// kebab-case, you need to use the `#"..."` syntax.
/// kebab-case, you need to use the `#"..."` (or `#:"...", for
/// keywords) syntax.
///
/// ```
/// # use lexpr_macros::sexp;
Expand All @@ -306,9 +307,22 @@
/// assert!(kebab_kw.is_keyword());
/// ```
///
/// For convenience, since `lexpr` version 0.3.0, keywords can also be
/// written using the Emacs Lisp (or Common Lisp) syntax, leaving off
/// the Scheme-ish octothorpe:
///
/// ```
/// # use lexpr_macros::sexp;
/// let kw = sexp!(:keyword);
/// assert!(kw.is_keyword());
///
/// let kebab_kw = sexp!(#:"kebab-keyword");
/// assert!(kebab_kw.is_keyword());
/// ```
///
/// Since `lexpr` version 0.2.7, symbols following the R7RS (Scheme)
/// syntax, which additionally consist of *only* characters that Rust
/// considers punctuation can be written without quotation:
/// considers punctuation can be written without double quotes:
///
/// ```
/// # use lexpr_macros::sexp;
Expand Down
11 changes: 11 additions & 0 deletions lexpr/tests/sexp-macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ fn test_symbols() {
fn test_keywords() {
assert_eq!(sexp!(#:foo), Value::keyword("foo"));
assert_eq!(sexp!(#:"a-keyword"), Value::keyword("a-keyword"));
assert_eq!(sexp!(:foo), Value::keyword("foo"));
assert_eq!(sexp!(:"a-keyword"), Value::keyword("a-keyword"));
}

#[test]
Expand All @@ -36,6 +38,14 @@ fn test_cons() {
sexp! {((a . 256.0))},
Value::list(vec![Value::cons(Value::symbol("a"), Value::from(256.0))])
);
assert_eq!(
sexp!((#:foo)),
Value::cons(Value::keyword("foo"), Value::Null)
);
assert_eq!(
sexp!((:foo)),
Value::cons(Value::keyword("foo"), Value::Null)
);
}

#[test]
Expand Down Expand Up @@ -68,6 +78,7 @@ fn test_special_tokens() {
assert_eq!(sexp!(...), Value::symbol("..."));
assert_eq!(sexp!(.++), Value::symbol(".++"));
assert_eq!(sexp!(!$%&*+-./:<=>?@^~), Value::symbol("!$%&*+-./:<=>?@^~"));
assert_eq!(sexp!(:!$%&*+-./<=>?@^~), Value::symbol(":!$%&*+-./<=>?@^~"));
assert_eq!(
sexp!((+ 1 2)),
Value::list(vec![Value::symbol("+"), 1.into(), 2.into()])
Expand Down

0 comments on commit 6b7df40

Please sign in to comment.