SEAM
Symbolic Expressions As Markup.
Why
Because all markup is terrible, especially XML/SGML and derivatives.
But mainly, for easier static markup code generation, such as with macros, code includes and such.
Try it out
This may be used as a library, such as from within a server,
generating HTML (or any other supported markup) before it is served to the
client. Personally, I am currently just using the seam binary to statically
generate some personal and project websites.
Read the USAGE.md file for code examples and documentation.
Current Formats
- XML (
--xml; including: SVG, MathML) - HTML (
--html; SGML) - CSS (
--css) - SExp (
--sexp; S-expression, basically a macro expansion utility) - Plain Text (
--text; renders escaped strings to text)
Installation
You may clone the repo, then build and install
Or install it from crates.io
Either way, you'll need the Rust (nightly) compiler and along
with it, comes cargo.
Using The Binary
You may use it by doing
test.sex contains your symbolic-expressions, which is used to generate
HTML, saved in test.html.
Likewise, you may read from STDIN
# Which is the same as
|
You may also very well use here-strings and here-docs, if your shell supports it.
#stdout:
# <!DOCTYPE html>
# <html>
# <head></head>
# <body>
# <p>Hello World</p>
# </body>
# </html>
#stdout:
# <p>Hello World</p>
#stdout:
# <?xml version="1.0" encoding="UTF-8" ?>
# <para>Today is a day in November, year 2020.</para>
#stdout:
# (hello world)
Checklist
- User
(%error msg)macro for aborting compilation. - Pattern-matching
(%match expr (pat1 ...) (pat2 ...))macro. Pattern matching is already implemented for%defineinternally. - The trailing keyword-matching operator.
&&restmatches excess keyword. Extracting a value from a map(:a 1 :b 2 :c 3)is done with:(%match %h ((:b default &&_) %b)). -
%getmacro:(%get b (:a 1 :b 2))becomes2;(%get 0 (a b c))becomesa. -
(%yaml "..."),(%toml "...")and(%json "...")converts whichever config-lang definition into a seam%define-definition. -
(%do ...)which just expands to the...; the identity function. - Catch expansion errors:
(%try :catch index-error (%do code-to-try) :error the-error (%do caught-error %the-error)). - Implement
(%strip ...)which evaluates to the...without any of the leading whitespace. - Implement splat operation:
(%splat (a b c))becomesa b c. -
(%define x %body)evaluates%bodyeagerly (at definition), while(%define (y) %body)only evaluates%bodyper call-site(%y). - Namespace macro
(%namespace ns (%include "file.sex"))will prefix all definitions in its body withns/, e.g.%ns/defn. Allows for a customizable separator, e.g.(%namespace ns :separator "-" ...)will allow for writing%ns-defn. Otherwise, the macro leaves the content produced by the body completely unchanged. - Command line
-Iinclude directory. - First argument in a macro invocation should have its whitespace stripped.
-
(%os/env ENV_VAR)environment variable macro. - Lazy evaluation for user macros (like in
ifdef) with use of new(%eval ...)macro. -
(%apply name x y z)macro which is equivalent to(%name x y z). -
(%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)becomesy x -
(%string ...),(%join ...),(%map ...),(%filter ...)macros. -
(%concat ...)which is just(%join "" ...). -
(%basename ),(%dirname)and(%extension)macro for paths. - Add options to
%globfor sorting by type, date(s), name, etc. -
(%format "{}")macro with Rust'sformatsyntax. e.g.(%format "Hello {}, age {age:0>2}" "Sam" :age 9) - Add
(%raw ...)macro which takes a string and leaves it unchanged in the final output. -
(%formatter/text ...)can take any seam (sexp) 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?).
-
(%embed "/path")macro, like%include, but just returns the file contents as a string. - Variadic arguments via
&restsyntax. - Type-checking facilities for user macros.
-
%listmacro which expands from(%list %a %b %c)to( %a %b %c )but without calling%aas a macro with%band%cas argument. -
%for-loop macro, iterating over%lists. -
%globwhich returns a list of files/directories matching a glob. -
%markdownrenders Markdown given to it as%rawhtml-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.). - Allow for arbitrary embedding of code with their REPLs, that can be run by
a LISP interpreter (or any other language), for example. (e.g.
(%chez (+ 1 2))executes(+ 1 2)with Chez-Scheme LISP, and places the result in the source (i.e.3).