From 370fa67e3b9b2b017a8f48fe19d8f3050137001d Mon Sep 17 00:00:00 2001 From: Demonstrandum Date: Wed, 4 Dec 2024 22:49:45 +0000 Subject: [PATCH] release: v0.3.0: new macros, pattern matching, performance. all user macros now do pattern matching on argument, including: - named optional argument that may appear out of order. - matching rigid required values. - variadic arguments with &rest syntax - match against lists containing named arguments (essentially hashmaps) and nested variadic &-syntax. added new macros: - %apply - %lambda - %list - %splat - %strip - %join - %filter - %map - %embed - %namespace - %raw - %string --- .gitignore | 4 +- Cargo.lock | 8 +- README.md | 30 +- crates/seam/Cargo.toml | 4 +- crates/seam/src/assemble/html.rs | 2 +- crates/seam/src/assemble/mod.rs | 2 +- crates/seam/src/parse/expander.rs | 499 ++++++++++++++++++--- crates/seam/src/parse/lexer.rs | 2 +- crates/seam/src/parse/macros.rs | 264 +++++++---- crates/seam/src/parse/parser.rs | 147 +++++- crates/seam/src/parse/tokens.rs | 9 +- crates/seam_argparse_proc_macro/src/lib.rs | 69 +-- 12 files changed, 810 insertions(+), 230 deletions(-) diff --git a/.gitignore b/.gitignore index 640af57..f30168c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ /target/ - **/*.rs.bk +rustc-*.txt +._* +.DS* diff --git a/Cargo.lock b/Cargo.lock index 212a629..56f8142 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -85,9 +85,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "descape" -version = "1.1.3" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "214de5502a2fa31149b291f594c1cc0d3929e93c6f4be6842d3944a16a9ef336" +checksum = "7c1113b908df80c963b107424498e37fba986b424b605729d1492dfbe4b2a630" [[package]] name = "formatx" @@ -260,9 +260,9 @@ checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-width" -version = "0.1.14" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" [[package]] name = "wasm-bindgen" diff --git a/README.md b/README.md index 74f528a..2d6ea21 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,11 @@ seam --sexp <<< '(hello (%define subject world) %subject)' ``` ## Checklist - - [ ] A *splat* operation: `(%splat (a b c))` becomes `a b c`. + - [ ] User `(%error msg)` macro for aborting compilation. + - [ ] Pattern-matching `(%match expr (pat1 ...) (pat2 ...) default)` macro. + Pattern matching is already implemented for `%define` internally. + - [x] Implement `(%strip ...)` which evaluates to the `...` without any of the leading whitespace. + - [x] Implement *splat* operation: `(%splat (a b c))` becomes `a b c`. - [x] `(%define x %body)` evaluates `%body` eagerly (at definition), while `(%define (y) %body)` only evaluates `%body` per call-site `(%y)`. - [x] Namespace macro `(%namespace ns (%include "file.sex"))` will prefix all definitions in its body with `ns/`, e.g. `%ns/defn`. @@ -101,28 +105,23 @@ seam --sexp <<< '(hello (%define subject world) %subject)' - [x] First argument in a macro invocation should have its whitespace stripped. - [x] `(%os/env ENV_VAR)` environment variable macro. - [ ] Lazy evaluation for *user* macros (like in `ifdef`) with use of new `(%eval ...)` macro. - - [ ] `(%string ...)`, `(%join ...)`, `(%map ...)`, `(%filter ...)` macros. - - [ ] Escape evaluating macros with `\%`. + - [x] `(%apply name x y z)` macro which is equivalent to `(%name x y z)`. + - [x] `(%lambda (x y) ...)` macro which just evaluates to an secret symbol, e.g. `__lambda0`. + used by applying `%apply`, e.g. `(%apply (%lambda (a b) b a) x y)` becomes `y x` + - [x] `(%string ...)`, `(%join ...)`, `(%map ...)`, `(%filter ...)` macros. - [x] `(%format "{}")` macro with Rust's `format` syntax. e.g. `(%format "Hello {}, age {age:0>2}" "Sam" :age 9)` - [x] Add `(%raw ...)` macro which takes a string and leaves it unchanged in the final output. - [ ] `(%formatter/text)` can take any other source code, for which it just embeds the expanded code (plain-text formatter). - [ ] `(%formatter/html ...)` etc. which call the respective available formatters. - [ ] Implement lexical scope by letting macros store a copy of the scope they were defined in (or a reference?). - [x] `(%embed "/path")` macro, like `%include`, but just returns the file contents as a string. - - [ ] Variadic arguments via `&rest` syntax. - - [ ] Type-checking facilities for user macros (?). - - [ ] Delayed evaluation of macros by `%(...)` syntax. - [ ] For example `%(f x y)` is the same as `(%f x y)`, so you can have `(%define uneval f x)` and then write `%(%uneval y)`. - - [ ] `%list` macro which expands from `(p (%list a b c))` to `(p a b c)`. - Defined as such: - ```lisp - (%define (list &rest) rest) - ``` + - [x] Variadic arguments via `&rest` syntax. + - [ ] Type-checking facilities for user macros. + - [x] `%list` macro which expands from `(%list %a %b %c)` to `( %a %b %c )` but *without* calling `%a` as a macro with `%b` and `%c` as argument. - [ ] `%for`-loop macro, iterating over `%list`s. - [ ] `%glob` which returns a list of files/directories matching a glob. - - [ ] `%markdown` renders Markdown given to it as html. - - [ ] `%html`, `%xml`, `%css`, etc. macros which goes into the specific rendering mode. - - [ ] Add variadic and keyword macro arguments. + - [ ] `%markdown` renders Markdown given to it as `%raw` html-string. + - [ ] Add keyword macro arguments. - [ ] Caching or checking time-stamps as to not regenerate unmodified source files. - [ ] HTML object `style="..."` object should handle s-expressions well, (e.g. `(p :style (:color red :border none) Hello World)`) - [ ] Add more supported formats (`JSON`, `JS`, `TOML`, &c.). @@ -133,7 +132,6 @@ seam --sexp <<< '(hello (%define subject world) %subject)' (const f (=> (a b) (+ a b)) ((. console log) (== (f y z) x)) ``` - - [ ] Add more helpful/generic macros (e.g. `(%include ...)`, which already exists). - [ ] Allow for arbitrary embedding of code, that can be run by a LISP interpreter (or any other langauge), for example. (e.g. `(%chez (+ 1 2))` executes `(+ 1 2)` with Chez-Scheme LISP, and places the result in the source diff --git a/crates/seam/Cargo.toml b/crates/seam/Cargo.toml index dbe33d7..a4eec06 100644 --- a/crates/seam/Cargo.toml +++ b/crates/seam/Cargo.toml @@ -24,7 +24,7 @@ path = "src/bin.rs" seam_argparse_proc_macro = { path = "../seam_argparse_proc_macro" } colored = "2.1" chrono = "0.4" -unicode-width = "0.1.12" -descape = "1.1.2" +unicode-width = "0.2.0" +descape = "2.0.3" formatx = "0.2.2" regex = "1.10.5" diff --git a/crates/seam/src/assemble/html.rs b/crates/seam/src/assemble/html.rs index 5b81ba4..ee67a97 100644 --- a/crates/seam/src/assemble/html.rs +++ b/crates/seam/src/assemble/html.rs @@ -148,7 +148,7 @@ impl<'a> HTMLFormatter<'a> { // - and contain XML, not HTML; // -
,