305 lines
11 KiB
Groff
305 lines
11 KiB
Groff
.TH UNSWEETEN 1 local
|
|
.SH NAME
|
|
unsweeten \- filter to translate Lisp/Scheme sweet-expressions to s-expressions
|
|
.SH SYNOPSIS
|
|
.ll +8
|
|
.B unsweeten [-C | --common-lisp] [file]...
|
|
.ll -8
|
|
.br
|
|
.SH DESCRIPTION
|
|
.PP
|
|
.I unsweeten
|
|
translates Lisp/Scheme sweet-expressions (t-expressions) into s-expressions.
|
|
Without a filename it takes input from standard input
|
|
and outputs to standard output.
|
|
If a list of one or more files is provided,
|
|
those files are processed in order, sending all results to standard output.
|
|
.PP
|
|
Sweet-expressions are a way to represent Lisp/Scheme data and programs
|
|
that adds additional abbreviations beyond those in traditional s-expressions.
|
|
Well-formatted S-expressions should work as-is, but
|
|
sweet-expressions are intended to be easier for humans to understand.
|
|
Unlike most past efforts to make Lisp more readable, the
|
|
sweet-expression approach is
|
|
.I generic
|
|
(the notation does not depend on an underlying semantic) and
|
|
.I homoiconic
|
|
(the underlying data structure is clear from the syntax).
|
|
.PP
|
|
Sweet-expressions are defined in SRFI-110, and are
|
|
actually the top tier of three tiers of notation:
|
|
|
|
.IP 1. 4
|
|
\fICurly-infix-expressions\fR (\fIc-expressions\fR):
|
|
Curly braces {...} contain an \fIinfix list\fR. A \fIsimple infix list\fR has
|
|
(1) an odd number of parameters, (2) at least 3 parameters, and (3)
|
|
all even parameters are the same symbol; it maps to "(even-parameter
|
|
odd-parameters)". The empty {} maps to (), escaping {e} maps to e,
|
|
unary-op {e1 e2} maps to (e1 e2), and curly-infix lists beginning
|
|
with the symbol "." are unspecified. Other infix lists map to "($nfx$
|
|
parameters)". By intent, there is no precedence and you \fImust\fR use
|
|
another {...} for an embedded infix list. Inside a curly-infix-expression
|
|
is a list of neoteric-expressions (below).
|
|
.RS 6
|
|
.IP \(bu 2
|
|
Example: {n <= 2} maps to (<= n 2)
|
|
.IP \(bu 2
|
|
Example: {2 * 3 * 4} maps to (* 2 3 4)
|
|
.IP \(bu 2
|
|
Example: {2 + 3 * 4} maps to ($nfx$ 2 + 3 * 4)
|
|
.IP \(bu 2
|
|
Example: {2 + {3 * 4}} maps to (+ 2 (* 3 4))
|
|
.RE
|
|
.IP 2. 4
|
|
\fINeoteric-expressions\fR (\fIn-expressions\fR): This includes curly-infix-expressions, and adds special meanings to some prefixed symbols. An e(...) maps to (e ...); an e{} maps to (e) and otherwise e{...} maps to (e {...}); and an e[...] maps to ($bracket-apply$ e ...). In all cases, "e" is any expression. There must be no whitespace between e and the open parenthesis. Also, an unprefixed "( . e)" must evaluate as "e".
|
|
.RS 6
|
|
.IP \(bu 2
|
|
Example: f(1 2) maps to (f 1 2)
|
|
.IP \(bu 2
|
|
Example: f{n - 1} maps to f({n - 1}) which maps to (f (- n 1))
|
|
.IP \(bu 2
|
|
Example: f{n - 1}(x) maps to (f {n - 1})(x) which maps to (f (- n 1))(x) which maps to ((f (- n 1)) x)
|
|
.RE
|
|
.IP 3. 4
|
|
\fISweet-expressions\fR (\fIt-expressions\fR): Includes neoteric-expressions, and deduces parentheses from indentation. Basic rules:
|
|
.RS 6
|
|
.IP \(bu 2
|
|
An indented line is a parameter of its parent.
|
|
.IP \(bu 2
|
|
Later terms on a line are parameters of the first term.
|
|
.IP \(bu 2
|
|
A line with exactly one term, and no child lines, is simply that term; multiple terms are wrapped into a list.
|
|
.IP \(bu 2
|
|
An empty line ends the expression; empty lines \fIbefore\fR expressions are ignored.
|
|
.IP \(bu 2
|
|
Indentation processing does not occur inside ( ), [ ], and { }, whether they are prefixed or not; they're just neoteric-expressions.
|
|
.RE
|
|
.IP "" ""
|
|
Sweet-expression rule refinements:
|
|
.RS 6
|
|
.IP \(bu 2
|
|
Lines with only a ;-comment are completely ignored - even their indentation (if any) is irrelevant.
|
|
.IP \(bu 2
|
|
A \\\\ (aka SPLIT) starts a new line at the current indentation. If it's immediately after indentation (aka GROUP in that case), it represents no symbol at all (at that indentation) - this is useful for lists of lists.
|
|
.IP \(bu 2
|
|
A $ (aka SUBLIST) in the middle of list restarts list processing; the right-hand-side (including its sub-blocks) is the last parameter of the left-hand-side (on the line).
|
|
If there is no left-hand-side, the right-hand-side is put in a list.
|
|
.IP \(bu 2
|
|
A leading traditional abbreviation (quote, comma, backquote, or comma-at), followed by space or tab, is that operator applied to the sweet-expression starting at the same line.
|
|
.IP \(bu 2
|
|
A <*...*> (aka collecting list) surrounds a new list, which restarts the indent level inside.
|
|
.IP \(bu 2
|
|
You can indent using one-or-more space, tab, and/or exclamation point (!) characters.
|
|
.IP \(bu 2
|
|
A line with only indentation is an empty line.
|
|
.IP \(bu 2
|
|
If an expression \fIstarts\fR indented, then indentation is completely ignored (that line switches to neoteric-expressions).
|
|
.RE
|
|
|
|
.PP
|
|
Sweet-expression examples are shown below.
|
|
|
|
.PP
|
|
Only a group of semicolon comments starting from either the file's very beginning, or after a blank line, are copied to the output. Such semicolon comments will have indentation (if any) removed. Block comments and inside a datum are never copied. Semicolon comments immediately after a datum aren't copied either (the reader has to consume them to see if it's reached the end of the datum).
|
|
.PP
|
|
Unsweeten also has some special substitutions. If it is outside of reading an expression, and a semicolon begins a line, the next character may cause it to do something special. If line begins with ";#" or ";!", the line is copied back without the leading semicolon. If a line begins with ";_", then the line is copied back without either of those first two characters.
|
|
If the semicolon is followed by whitespace or semicolon, the whole line is copied as-is; users who intend for a semicolon in the first column to begin a real comment should follow the semicolon with whitespace or another semicolon.
|
|
|
|
.PP
|
|
For more information, see
|
|
http://readable.sourceforge.net.
|
|
|
|
|
|
.SH OPTIONS
|
|
|
|
.TP 6
|
|
.BI -C
|
|
Process as Common Lisp.
|
|
|
|
|
|
.\" .SH "ENVIRONMENT"
|
|
.\" .PP
|
|
|
|
.SH BUGS/LIMITATIONS
|
|
.PP
|
|
Unsweeten implements its own reader, so it does not support some of the
|
|
nonstandard reader extensions supported by some other readers.
|
|
|
|
.PP
|
|
Unsweeten is primarily designed to read Scheme-formatted expressions.
|
|
The -C (Common Lisp) option invokes some changes that make it work
|
|
with many Common Lisp expressions, but with limitations.
|
|
Note that:
|
|
.RS 6
|
|
.IP \(bu 2
|
|
It works just fine when you use the (large) notational subset
|
|
common between Scheme and Common Lisp, including lists, improper lists,
|
|
integers, most floating point numbers, characters constants (#\\...),
|
|
and strings without escaped characters.
|
|
.IP \(bu 2
|
|
In practice, most symbols just work.
|
|
Any symbol that meets both Scheme and Common Lisp requirements
|
|
will, of course, work just fine.
|
|
As an extension, in unsweeten anything
|
|
beginning with a digit, plus, or minus is read until a delimiter;
|
|
it's then considered a number if it can be by Scheme, else it is a symbol.
|
|
As a result, you \fIcan\fR use symbols that begin with a digit like "1+",
|
|
as well as symbols that begin with a minus like "-v".
|
|
However, as a special case, the sequences +i and -i are
|
|
numbers (these are positive and negative square root of -1).
|
|
.IP \(bu 2
|
|
You can use quote ('), quasiquote (\`), comma (,),
|
|
and comma-at (,@).
|
|
Internally unsweeten represents them the same way as Scheme does,
|
|
but it then prints them back out in a way
|
|
that Common Lisp accepts, so this generally works just fine.
|
|
Note: If you create a two-element list where the first element is
|
|
one of those symbols (quote, quasiquote, command, and comma-at),
|
|
it will be unfortunately printed as these abbreviations.
|
|
In practice this does not seem to be a problem.
|
|
.IP \(bu 2
|
|
The sequence #'name for (function\ name) is supported.
|
|
Also, the sequences #.datum, #+datum, #-datum, and #:datum are passed through
|
|
and should work.
|
|
.IP \(bu 2
|
|
Symbols surrounded by vertical bars |...| will sometimes work and sometimes
|
|
fail due to interactions within the implementation.
|
|
.IP \(bu 2
|
|
Many other sequences beginning with # (sharpsign)
|
|
are not supported; check those carefully.
|
|
See the Common Lisp hyperspec
|
|
http://www.lispworks.com/documentation/HyperSpec/Body/02_dh.htm
|
|
if you are not sure what they do.
|
|
.RE
|
|
|
|
.PP
|
|
It can be used for other Lisp-based languages
|
|
if the input is limited to the notation in common between them.
|
|
|
|
.SH EXAMPLES
|
|
.PP
|
|
Here is an example of the kind of data that can be sent into unsweeten:
|
|
|
|
.PP
|
|
define fibfast(n) ; Typical function notation
|
|
if {n < 2} ; Indentation, infix {...}
|
|
n ; Single expr = no new list
|
|
fibup n 2 1 0 ; Simple function calls
|
|
|
|
.PP
|
|
The unsweeten tool will translate that input into this traditional
|
|
s-expression (which is a valid Scheme program):
|
|
|
|
.PP
|
|
(define (fibfast n)
|
|
(if (< n 2)
|
|
n
|
|
(fibup n 2 1 0)))
|
|
|
|
|
|
.PP
|
|
Here's another example of a t-expression:
|
|
|
|
.PP
|
|
define factorial(n)
|
|
if {n <= 1}
|
|
1
|
|
{n * factorial{n - 1}}
|
|
|
|
.PP
|
|
Here's an example of what it might translate to:
|
|
.PP
|
|
(define (factorial n)
|
|
(if (<= n 1)
|
|
1
|
|
(* n (factorial (- n 1)))))
|
|
|
|
|
|
|
|
.PP
|
|
You can use this tool to process files, say, via a makefile. Then you can
|
|
use sweet-expressions to write your code, and have it quickly translated
|
|
to s-expressions. The following portable makefile snippet translates all
|
|
".sscm" (Sweet Scheme) files into ".scm" (Scheme) files; be sure the
|
|
first character is TAB on the rule command with $(UNSWEETEN):
|
|
|
|
UNSWEETEN = unsweeten
|
|
\.sscm\.scm:
|
|
$(UNSWEETEN) $< > $@
|
|
# You *must* set .SUFFIXES for the suffix rule to work:
|
|
\.SUFFIXES: \.sscm \.scm
|
|
|
|
|
|
.PP
|
|
You can also use this tool as a front-end for interactive uses.
|
|
For example, you can use it to interact with scsh (Scheme shell):
|
|
|
|
unsweeten | scsh
|
|
|
|
.PP
|
|
Then you can enter Scheme shell commands using sweet-expressions
|
|
(be sure to type Enter Enter to end an expression):
|
|
|
|
run $ grep jar README
|
|
|
|
exit()
|
|
|
|
.PP
|
|
You can even use unsweeten to work with other Lisps, such as Common Lisp.
|
|
The "-C" (--common-lisp) option helps make this work much better
|
|
(but see the BUGS/LIMITATIONS section!).
|
|
For example, you can use unsweeten interactively with clisp
|
|
(a Common Lisp implementation) just by running:
|
|
|
|
unsweeten -C | clisp
|
|
|
|
.PP
|
|
Here's an example of what the Common Lisp example of the factorial
|
|
in sweet-expressions would look like:
|
|
.PP
|
|
defun factorial (n)
|
|
if {n <= 1}
|
|
1
|
|
{n * factorial{n - 1}}
|
|
|
|
.PP
|
|
Here's an example of what it might translate to:
|
|
.PP
|
|
(defun factorial (n)
|
|
(if (<= n 1)
|
|
1
|
|
(* n (factorial (- n 1)))))
|
|
|
|
.SH "SEE ALSO"
|
|
.PP
|
|
.IR diff-s-sweet(1) ,
|
|
.IR sweeten(1) ,
|
|
and
|
|
.IR sweet-run(1) .
|
|
|
|
|
|
.SH "COPYRIGHT NOTICE"
|
|
.PP
|
|
Copyright \(co 2012-2013 David A. Wheeler
|
|
.PP
|
|
This software (including the documentation)
|
|
is released as open source software under the "MIT" license:
|
|
.PP
|
|
Permission is hereby granted, free of charge, to any person obtaining a
|
|
copy of this software and associated documentation files (the "Software"),
|
|
to deal in the Software without restriction, including without limitation
|
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
and/or sell copies of the Software, and to permit persons to whom the
|
|
Software is furnished to do so, subject to the following conditions:
|
|
.PP
|
|
The above copyright notice and this permission notice shall be included
|
|
in all copies or substantial portions of the Software.
|
|
.PP
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
OTHER DEALINGS IN THE SOFTWARE.
|
|
|