.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.