readable/man/unsweeten.1
2013-04-07 15:00:04 -04:00

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.