Crates.io | unseemly |
lib.rs | unseemly |
version | 0.0.3 |
source | src |
created_at | 2020-02-02 20:20:22.818905 |
updated_at | 2021-12-03 04:09:37.075441 |
description | A typed macro language |
homepage | https://unseemly.github.io/ |
repository | https://github.com/paulstansifer/unseemly/ |
max_upload_size | |
id | 204304 |
size | 805,587 |
Unseemly typechecks the code that you wrote, not the code your macros wrote. This makes macros feel like part of the language, not something tacked-on.
For a more complete pitch, see http://unseemly.github.io
Unseemly has a bare minimum of forms necessary to bootstrap the implementation of practical languages.
Unseemly is still pretty early-stage, so, while all of the features below exist, there are still a number of things that are janky or incomplete.
match
.List<T>
)'[Expr | … ]'
quotes an expression,
but inside that, ,[Expr | … ],
evaluates its contents and interpolates them)'[Expr | (plus one ,[e1],)]'
is a type error if e1
has the type Expr<String>
)† Except that there are known soundness bugs.
Full-featured REPL, with persistent command history and line editing (courtesy of rustyline
).
Install Rust, if you haven't already:
curl https://sh.rustup.rs -sSf | sh
From your Unseemly repository directory, run an example program:
cargo run --release examples/sum_list.unseemly
(Recommended) Get the default prelude for the Unseemly REPL:
cp examples/.unseemly_prelude ~/
Start the REPL:
cargo run --release
Look at core_language_basics.md for documentation of the language.
Unseemly is most closely based on Romeo, which descends from FreshML. (Romeo is closer to Pure FreshML, but the "Pure" part is not present in Unseemly.) Romeo allowed for manipulation of syntax types with complex binding information, but
SoundX is a language with syntax extensions in which typechecking occurs before expansion. It provides sound language extensions, but
x ∉ dom(E)
.)(TODO: are the extensions themselves statically verified to be type-preserving? I think so, but I don't remember for sure.)
If I understand correctly, Scala's blackbox macros are typechecked before expansion, but they can't do everything that whitebox macros can. Unseemly macros are typechecked before expansion, but are the only macro system needed, because they can (in particular) define new binding forms safely. (TODO: learn more about Scala's macro system)
Wyvern's primary motivating example (write SQL, not strings containing SQL, in your general-purpose code) is a lot like Unseemly's vision of inline syntax extension. Wyvern is a full-fledged language, not a core language. I believe that writing new embedded languages is not as easy as macro definition.
Wyvern also includes a number of features that are outside the scope of Unseemly.
(TODO: learn more about Wyvern)
Terra, from a quick glance (TODO: learn more), appears to be a language with a close relationship to Lua, similar to the relationship that Unseemly-based languages would have.
In this case, it looks like the goal is to marry a high-level and low-level language together, without an FFI and with inline embedding.
MetaOCaml is an extension to OCaml that supports type-safe syntax quotation. Though Unseemly uses "quasiquotation" to describe syntax quotation, it is more similar to MetaOCaml's bracket than to Scheme's quasiquotation, because it respects alpha-equivalence.
Unlike Unseemly, MetaOCaml doesn't use its safe syntax quotation to implement a macro system.
Rust and SweetJS are non-S-expression-based languages with macro systems that allow rich syntax.
Unseemly is implemented in Rust, and it uses lots of macros.