(Arne Babenhauserheide)
2015-02-15: merge merge
diff --git a/.bugs/bugs b/.bugs/bugs --- a/.bugs/bugs +++ b/.bugs/bugs @@ -1,28 +1,39 @@ -testsuite: to pass, the tree-il has to match, not the emitted string. This allows for reader-only implementations. | owner:, open:True, id:00b74a730bbf076e73166e817ca7b0a273b376d4, time:1408224636.42 +testsuite: to pass, the tree-il has to match, not the emitted string. This allows for reader-only implementations. | owner:, open:False, id:00b74a730bbf076e73166e817ca7b0a273b376d4, time:1408224636.42 +wisp-scheme: unescape \_ and \: | owner:, open:False, id:086f61a06e16f1ef56e9917453bbd55b5879d15d, time:1415121255.99 fails when I add stuff at the end of end of example.w | owner:, open:False, id:08c68e1ce0c9798184c01806d2661a3220bff3cd, time:1363789693.79 wisp-mode in quoted lists only the first item is colorized as data, but all words up to the last paren should be colorized. | owner:, open:True, id:1675ca3f894ed8470fa292149a476a2fa0d17140, time:1397196957.45 add a testsuite for wisp parsers. | owner:, open:False, id:1c05d27ac916e1a823b8985a094947907c3c19af, time:1379064922.74 wisp-mode: export wisp to html fails in org-mode: font-lock-fontify-keywords-region: Invalid regexp | owner:, open:False, id:1e46d8c05580c961c37a32d36c987a5dd1d34943, time:1389371020.39 an empty line with : should start with double parens | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:2e188ddf44d36e4605030d3c58607ebfa97d189e, time:1390328674.43 wisp-in-wisp: remove the leading . for continuation lines after inferring the brackets. | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:2e42e5b64622f0cc383eb8acc3d510912e925bf0, time:1377476687.79 +'() gives REPR-QUOTE-... | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:30c42de75c137f483245898e2a62af1e65cf19a6, time:1415060388.34 +multiple escaped initial underscores must be unescaped. | owner:, open:True, id:314e45488da4c7c8298c4c64ece03359918d057b, time:1415959749.14 wisp: handle general paren prefixes like quote, quasiquote, etc. | owner:, open:False, id:323ff94b5be635742619467e1cb44f4c0d96f63f, time:1379047798.47 throw an exception when reducing indentation to an unknown indentation level. | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:424186bd85f186b7279c5c59e2bd42f847284719, time:1376003568.91 wisp-in-wisp: only parses the first 272 lines, for some reason. | owner:, open:False, id:4cb6c556d7136609e2da9ab3fc045a39847f1ef3, time:1377014682.98 +adjust runtests.sh to use testrunner.w | owner:, open:False, id:4d4e76343fe09f0ec72a3e5eb0077bd16e12f9d5, time:1415127234.43 +wisp-scheme: REPL: sometimes the output of a command is only shown after typing the next non-empty line. | owner:, open:True, id:56d2f81e9c89accb0b0bc668ddc8feed3b60e9b2, time:1416584789.23 implement wisp in wisp | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:6299306916706410702029289bf32edab1e7f17c, time:1367113341.49 support other types of brackets, like square brackets. | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:6749f3abcb9455eac9271efd8265797bce114239, time:1389134151.98 linebreaks in parens still break | owner:, open:False, id:6797987c7834a53358fb4ebbd8b9b36c2c4a8f01, time:1379004764.14 wisp-guile.w does not yet remove the leading . which signifies a continuation. | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:7075096a323933493f42a3751da5f75a45d5d699, time:1377381700.17 inline ' : should be '( | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:72d534a8b23b4cb168017f1bb7d8816f0ea170c4, time:1366497335.26 failing test tests/shebang.w | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:74a851f83af8996465a7b24d8453161beb0f0fd5, time:1379106761.57 -non-nested multiline comments with #! !#. Requires restructuring. | owner:, open:True, id:7a57614fa920b2ddad002d044b144d0bb7c34f84, time:1389364108.01 -support nested multi-line comments with #| ... |#: multiline comments (srfi-30). Requires restructuring. | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:8cf6202873d4454f57813dd17cf60432059f7c62, time:1389569421.6 -the repl does not require 3 returns when you use a single char as function, or rather only does so every second time | owner:, open:True, id:9cedd0bdbf4a3b17add4bfe86ad5a23e500cfc6c, time:1379064870.78 +non-nested multiline comments with #! !#. Requires restructuring. | owner:, open:False, id:7a57614fa920b2ddad002d044b144d0bb7c34f84, time:1389364108.01 +wisp-scheme: interpret , : as ,() similar to : , | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:85e150dcb10c49d8f51db525e07d24e83bdba0f1, time:1416432201.21 +wisp-guile: support nested multi-line comments with #| ... |#: multiline comments (srfi-30). Requires restructuring. | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:8cf6202873d4454f57813dd17cf60432059f7c62, time:1389569421.6 +wisp-scheme: Does not recognize the . #!curly-infix request for curly-infix or other reader syntax. | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:91f27adb7d4e378e034b3408b6e4616f707f9587, time:1418162368.88 +wisp-guile: the repl does not require 3 returns when you use a single char as function, or rather only does so every second time | owner:, open:True, id:9cedd0bdbf4a3b17add4bfe86ad5a23e500cfc6c, time:1379064870.78 wisp-guile.w breaks on ";" and complex brackets with bracket char literals. See wisp-guile.w::91 | owner:, open:False, id:9d8b6f87fa5365733fc8655614dbf2a9ba5bd054, time:1377533321.27 +wisp-scheme: treat quote quasiquote syntax quasisyntax and so on similar to the dot. | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:9e587f38115099c0825c13a2159605e5f560aeec, time:1413623986.49 FIX regression: empty line with only : does not remove the :. It transforms to (:, it should transform to ( | owner:, open:False, id:a2323d347612425bc5af577c939916c8b60ec1c9, time:1389631450.78 wisp-mode: handle lines starting with underscores: currently sees the underscores as function call. | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:b2c3755e1deb8355655a334d569679e2e62d2836, time:1376612093.55 -parens in comments can throw off the parser. | owner:, open:True, id:ce28d6c0d1f9894c9b946e56b17934473800edfe, time:1408224406.79 +wisp-scheme: curly braces should use read. | owner:, open:False, id:c0e62db4dcfdf4f1cf84f1871e439d055dacbefa, time:1415121781.25 +wisp-guile: parens in strings can throw off the parser | owner:, open:True, id:ce28d6c0d1f9894c9b946e56b17934473800edfe, time:1408224406.79 make this work: let : : origfile ( open-file : nth 1 : command-line ) r | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:d6de2074a5017f1f29f34d142ce797981ed270a0, time:1366529287.67 wisp.py breaks on \ - quote, escaped backslash, quote. Ignored, because wisp.py is only needed for bootstrapping. | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:d75a93ca58ade5b3e3e51f1e7ee9782e743ac131, time:1377424552.02 comments containing a closing parenthesis can break the parser. | owner:, open:False, id:d9147504868960e5fbc2648474d48ce5c9bd1a02, time:1374838747.22 breaks on empty files | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:e40fa7a93eb2c497dca1af7eed22ad5ed5cfbe7f, time:1390325470.91 +wisp-scheme: breaks on lines with only underscores. These should be treated as empty lines. | owner:, open:False, id:e464b5ce49deb14a80f67d50c6d70043ca9bde25, time:1415124488.16 quote as only char in a line gets parenthized instead of becoming a paren-prefix. | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:eb7468387e90bb5d13f5a5d81c6f4a704f2ca0fb, time:1390326369.6 +in the REPL output can be delayed by one line: Appears only when submitting the next command. | owner:, open:True, id:f1e42bbd4c17a2dec886c26d9c14e770bcff66d2, time:1415972414.48 diff --git a/.bugs/details/4d4e76343fe09f0ec72a3e5eb0077bd16e12f9d5.txt b/.bugs/details/4d4e76343fe09f0ec72a3e5eb0077bd16e12f9d5.txt new file mode 100644 --- /dev/null +++ b/.bugs/details/4d4e76343fe09f0ec72a3e5eb0077bd16e12f9d5.txt @@ -0,0 +1,28 @@ +# Lines starting with '#' and sections without content +# are not displayed by a call to 'details' +# +[paths] +# Paths related to this bug. +# suggested format: REPO_PATH:LINENUMBERS + + +[details] +# Additional details +after the fix: +wisp-scheme now passes the testsuite, tested by a testrunner which checks the code-tree, not the string-representation. + + +[expected] +# The expected result + + +[actual] +# What happened instead + + +[reproduce] +# Reproduction steps + + +[comments] +# Comments and updates - leave your name diff --git a/.hgsigs b/.hgsigs --- a/.hgsigs +++ b/.hgsigs @@ -8,3 +8,12 @@ 1d95b99da08b25917847702a382c691b5bd1de69 a41ca7bf033667a8dfeacd48be5caf315fabb020 0 iJwEAAEIAAYFAlL2Z+gACgkQ3M8NswvBBUisDgQAiHKSfcOdlWoin7wpHDVlyKhAxAIg5D9xwAGDj2CIVEu4cpw5HdZ8t8fjyrP6lMsAkHnCVNUlRjprdo7PR4al1uxNmz4H0mQMlDLxG4Sfj2x01w3DDgiNOfV/65lwNY9BNxULCjwBlHN5qzv9toLwZ29SLEZXvshuZBxe8qSfBy8= a2ae0f4d637ff5d615acc91d82d21259b0ec3b94 0 iJwEAAEIAAYFAlMJPXwACgkQ3M8NswvBBUjSEAP/bvPcy52p1mq4LuEkYxvj3UYnknT6g3yDCCXNEa2vuy6rkekZvbl6h9U2/FM37JEw2sgeqcp2P7epJzlxSpd9jIH+5/xT7R1FViOibLBumZ/5cQoMsthQyyrB2NhQbxtUf6fH5TnqZU/z9jdAZqBLABNaNeufetjGXbYmn4W7zk4= 4e9a5aef2eb1307e082d4536afa5d4f47840b6ec 0 iQEcBAABAgAGBQJTIGw4AAoJEFyD82SnDaCeQw4IAKt5CZS8Jx4qyL3Zb8z0xjop461uDnEXyg0m+QL2fUgv3kpsZM5CqgZRm8mF3bnRTtmPwwvtD+mjkz+xCUhAWkqCMH+VusLnwfVAeOxAAvvXT+z8quh/Xt9qZ8J8VaWh6L1CrYl8xJFDJlymCe/2pcOn9OnWF3QeNuLswWllebGRXFHpeUs+JZKVxXhwSyGnfKOiboXfpkrW4VoyCuWR4Mz/KczohAj8dZYhD+gRjTUGLS64TJbaevmTnffexgqvM3KYj8hvwx4m1Iz95QLxcb09fRA9BoRPNvaOHUNMsPSlpoDEMI/pBBfWx0ALadaYTmJvG/jGeyYDCWQMAXUjMIs= +a321c87fec27f184407da6a410c482a944074b7e 0 iQEcBAABAgAGBQJTw8CwAAoJEFyD82SnDaCeb/sH/374MNTwjx2LqBDAaK0jMHsFabm1/vZ99hlzNo0d7TPbl6/KkeicnluTpB+HVYtssMwHEFGiIWAY1xmX3rZKrYDpvCr2r15UZqqtyyeJxdDkqTQfsI7qwQy4FhZAfI9o948zYQ3z32TtsjPoyS6JDRZ1D0rBcU8/+K9AaYwl3QVsyxuvVwJK2Wb/Afn8CbG8xn0JtGNRbosfAAcgQDnV4MqA1p5MSDX3UaImWuVuBM9ejIvcyiBXxpwUb2DiEfFF8agsJoHQ/Vjy1j+IPE/mIa6nfV9I4Czb9wpItDXJe56wrsmGHEVVstnzys4DPiEWH57tG+iFgHXuw3gBJfySi2g= +922c4eca67c5a4d01a584377d52aab3152a69564 0 iQEcBAABAgAGBQJT47YpAAoJEFyD82SnDaCefVUH/ioHISgEgJ7N0kWss+V3KMenaolt3GDTiUaR+ntzkdx0UmX48JcyMj3wgCeh1zMh76B/umJVqUAgB2Z/aw5nE654RRwMtE8EGZ1G9WvdArFG97GaGyWoJLHu4zzCPSKMT9PpACMWKR46jd7qKl7dcTL04Vd1oLJ6uV2+17SYRY222RKrgMH3CEcf5i457wEGb5qAM0T5Ap56SPrhsi+rBU7lPTtF2jKd5DJ8smIuwimHhE7JlHcl8/HzJICp1cJERRmV9ztfZxdpCIKpYpWByB7fNAjRiGo/pBq55TK9mAQ+ZqXYNtixMPtPdui+I1vhmjH/ZmWmKl6kD6x7Lm10Cgo= +cd97a1e91fcdd700835270841a7e0d43a820eb02 0 iJwEAAEIAAYFAlQGH1QACgkQ3M8NswvBBUivrgP+MX9WKW2TYgEG1X/TKr/+mBpGmC/Ji8pX/nrD1gFv34Jcf+y2pm+zV8VMduHhc53AiLuT7FIZy0ZktqqFztHgxGwdVaVlaPg1jK4c4rKaIWPFvuRs8Vv+Cs7S913VJ6rd8x4E5GwAPbY+vyQ/Xw2gMuzw5VpuERwh+kRO1SooMqo= +60707024df8a4e281791bca863552fcbaa3e534a 0 iJwEAAEIAAYFAlQGIGQACgkQ3M8NswvBBUimkgP/SXQY7JmLyRBJZNke3T9vfqj1vfNL2GSvRnRvWCetFtl6Uu4zt+nLrJOokuxGKPL6inJGhvB282vqAMu7CAPjk7XwJQr06tKsdoDwJOZ0JV1tgp7vP0L2mkCl5ClLA4d17hhuKITwr6PyXLBaCBrN51z1uFrJRv/ppKbL9QHtYAU= +c9aaed7fd8345e6f1248bb62f40a7ae7f2d08f2b 0 iJwEAAEIAAYFAlQGIZsACgkQ3M8NswvBBUgpowP+KWBfE5CH0kXEYHNc65Zus5OyZl5hLGm7pOmmgfPhWVZiUJo503ZVQv9WTxECs6ZxERz1kwq03QB8AwjRAUDbWK6N1dSvuPYOWNLF1nzTb/6Sq1CFMv7X5ZGapyLncSc+h8iU8aesa/kAqf8FmB64xiAagjHgOHe0L8bvlQHYyaU= +32659321b29470b5198827eda494d9824cc161ee 0 iQEcBAABAgAGBQJUP+rWAAoJEFyD82SnDaCe9McH/0v4rc0G78jS6jDxi4uo0snaJ+t4RhJi79+HqMBE4P8FLZgRgq7iL4KIt11oyaMzcQdlwRNrIdtdK93Q9WNr0wWGEhlkIGe5weLGpJDN8HZv0mzKiZqAspHySq8d/PPXEjbwl5OMXGiZl7Iw6IzCOqJw4BbnIzMRYN+ov/Icqxng6VfbcguUx3+NP2I15X7jEQS53zOxq+fi0LAJcycXRBSX4n5+v7/v6Qwm/YYKGq56qq/DDULGAGI97ANI/e2etvyzPixTVFTsZ0ZAQeYJgJWv0xJwr8yWnaEBT9lH9xhENbmsCTbpuqvURv/48py0JFgoysC1NMrab6sr8zxfyjQ= +eaf23f42b01382e4ab255abcd34e031b043e1f56 0 iQEcBAABAgAGBQJUP+zuAAoJEFyD82SnDaCeXRkH/iZOiyKj8VcuNJdpSZKqIvzNRMz5JhIiF3G04zzHs8jDxrJiGVVHWPYNXR0p7pChMsq5JanjrnQn2IGcGt7blB1fmjzhq6bwbru+sD2moisP/zFM1HOSKx0j7xsNwB8wd08l0GVbNzgffRZjwQbJkCov8Uvl60OLUHgH5Pro8CRkKwV8/6pG8a9TtGEMlnhdhw/L5wkeSkifFTgg2R/CCHAJDhgfSAUZfjQzPgvtLUMHe+0Og/hwgnMqpI/TMoxAyOSBHbAGiZGDUb3v+sXB84k7kd9gm59A3s805L1PEeqlhTE2FWAGBV8se7NeNIygnUfmXgPFclrZSB2QF1qguz4= +695e3f4ff4bd2512e2d963c5b21385415c3b6dc3 0 iJsEAAEIAAYFAlRb4xsACgkQ3M8NswvBBUiRugP41O3ZOBViEjB0y4smTiU/yju4b/xJczLBhbNM1ExKu/EB3oQkAPpZhnBQcOPz43TMl2Kk8QKJgFcgeHKQlT+ZyMxZ0j7/GOSBxTH2Q1x5SXwJlnJAdmSH7UE2i5btEsemjkqAuqOlkX+z7QIswFSv7yHoBVh/Qs9AvcY0cCKFYw== +fed7f4d46a41b0814c81eb08dcdb506b38321c61 0 iQEcBAABAgAGBQJUbMOkAAoJEKMv031G/7TThsYIALXZAJY4Z4n5Be6mTE/CRXE7g3GlDEBPwstnvUBNzXiM5dAQbLHUt71yRx+d2WxxRHxUfuWG8PgrO/beITdjWhwoaM0fhknPRIOZ3Sc3RSrtleTm9gx1DS6CW5sCQvmqRSdyYJlqS30oHiq/gPftmFq2CllrSZWblL+t+/BfBLfG26DN4jy/b0IN5J1qeoi4gP/FwQ3e8A1lUIznjzQa57BVGBc/kKA+pAy/yFAlFvukAOG0BbFGRe0K3Gj6xITLdxfrmndH/688jgefUp+7JhLZZkfIoFAWBosPRQ5a2zaB1YRtUMEKgvvA05UiyTLQdlME2d52X1sSKrS9p69sTUU= diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -16,3 +16,12 @@ bb1c4165b8a6d12929625e6518a5b1c727c75942 0e1335f015a83c6c6616019189c665b3849269ce v0.5.10 07ec05365e84d29d24ce5f476654f9542931ed2d v0.5.11 9af37e8efa7a2674caec07c7d2339f136f380d37 wisp-mode-0.2 +5475d743562512c44d2cdd0bf534c78c88efb0f8 v0.6.0 +64745a296d569849de536000b636c100e3e0d30c v0.6.1 +7089c2ba36f5b3f1eeafde42be4ca4e4df1d6544 v0.6.2 +fc3d17fe770257a5e700c912844cee14668aa431 v0.6.3 +1c63ac211fe4275a00f7e206c7f44051e0d7cd81 v0.6.4 +42ab97d010efa7883240f5e5254ea46fd9423239 v0.6.5 +b7441736af4dc8f1a7df860d1b064e080a45e1a5 v0.6.6 +0e702c268e6fdc9c52f034b6553c940b09c16400 v0.8.0 +8eaf023f5d3bc20ad4b795cde3a92e3b5c242dba v0.8.1 diff --git a/Makefile.am b/Makefile.am --- a/Makefile.am +++ b/Makefile.am @@ -1,8 +1,11 @@ -wisp = wisp.scm language/wisp/spec.scm -wisp_SOURCES = wisp-guile.w wisp-reader.w -EXTRA_DIST = $(wisp_SOURCES) $(wisp_DATA) bootstrap.sh wisp.py examples tests runtests.sh wisp-repl-guile.sh +wisp = wisp.scm wisp-scheme.scm language/wisp/spec.scm +wisp_SOURCES = wisp-guile.w wisp-reader.w wisp-scheme.w +EXTRA_DIST = $(wisp_SOURCES) $(wisp_DATA) bootstrap.sh wisp.py examples tests wisp-repl-guile.sh testrunner.w CLEANFILES = ${wisp} ChangeLog -DISTCLEANFILES = ${CLEANFILES} @abs_top_builddir@/1 @abs_top_builddir@/2 @abs_top_builddir@/test.sh +DISTCLEANFILES = ${CLEANFILES} @abs_top_builddir@/1 @abs_top_builddir@/2 @abs_top_builddir@/syntaxtests.sh @abs_top_builddir@/syntaxtestsreader.sh +# don't spout out lots of stuff at each distcheck. Disable for debugging. +AM_DISTCHECK_CONFIGURE_FLAGS="--quiet" + all : ${wisp} @@ -14,12 +17,18 @@ ChangeLog : .INTERMEDIATE: input.in.intermediate input.in.intermediate: ${wisp_SOURCES} - @abs_top_srcdir@/bootstrap.sh @abs_top_srcdir@ @guile@ @python3@ + @abs_top_srcdir@/bootstrap.sh @abs_top_srcdir@ @guile@ @python3@ 2>&1 | sed "s/^;;;.*//" 2>&1 | grep . 1>&2 ; test ! $$? -eq 0 # grep did not find anything -.PHONY: test.sh -test.sh : wisp.scm runtests.sh - echo '#!/bin/bash' > @abs_top_builddir@/test.sh - echo @abs_top_srcdir@/runtests.sh @abs_top_srcdir@ @abs_top_builddir@ >> @abs_top_builddir@/test.sh - chmod +x @abs_top_builddir@/test.sh +.PHONY: syntaxtests.sh +syntaxtests.sh : wisp.scm tests/runtests-scheme-preprocessor.sh + echo '#!/bin/bash' > @abs_top_builddir@/$@ + echo @abs_top_srcdir@/tests/runtests-scheme-preprocessor.sh @abs_top_srcdir@ @abs_top_builddir@ >> @abs_top_builddir@/$@ + chmod +x @abs_top_builddir@/$@ -TESTS=test.sh +.PHONY: syntaxtestsreader.sh +syntaxtestsreader.sh : wisp.scm tests/runtests-scheme-reader.sh + echo '#!/bin/bash' > @abs_top_builddir@/$@ + echo @abs_top_srcdir@/tests/runtests-scheme-reader.sh @abs_top_srcdir@ @abs_top_builddir@ >> @abs_top_builddir@/$@ + chmod +x @abs_top_builddir@/$@ + +TESTS=syntaxtests.sh syntaxtestsreader.sh diff --git a/NEWS b/NEWS --- a/NEWS +++ b/NEWS @@ -1,3 +1,37 @@ +wisp 0.8.0 (2014-11-03): +- the testsuite is defined in terms of the code-tree, not in terms of + the readable file. Implemented in testrunner.w +- wisp-scheme passes the wisp testsuite +- wisp uses curly-infix by default (srfi-105) +- this is the first full featured release of wisp-scheme: wisp which + defers all complex parsing to the scheme reader (and match). + +wisp 0.6.6 (2014-10-16): +- fix boostrap. + +wisp 0.6.5 (2014-10-16): +- use wisp-scheme in the REPL. +- safe dot representation for reading a literal dot (.) for creating improper lists. + +wisp 0.6.4 (2014-09-02): +- an actually working wisp implementation for scheme (only) which uses the guile reader. This should be actually correct for scheme. And match-magic ☺ +- polishing. + +wisp 0.6.1 (2014-08-05): +- simpler unicode handling +- honor --quiet in bootstrapping + +wisp 0.6.0 (2014-07-14): +- Better performance +- Support for SRFI-105 +- Working syntax highlighting in export via wisp-mode.el +- Wisp can now execute wisp-files directly via `guile -L . --language=wisp file.w`. +- Icosahedric Advection-Diffusion example: examples/d20world.w +- Draft for an SRFI +- Presentatien: Why Wisp? +- Working autoreconf -i; ./configure; make distcheck +- Real Testsuite (./runtests.sh . .) + wisp 0.5.3 (2014-01-08): Started to use autotools to get make distcheck. wisp 0.5.2 (2014-01-07): Support general paren-prefixes for macros. @@ -14,4 +48,4 @@ wisp 0.5 (2013-09-13): Wisp now has a RE Voilà, you have wisp at the REPL! Caveeat: the wisp-parser is still experimental and contains known bugs. Use it for testing, but please do not rely on it for important stuff, yet. -wisp 0.4 (2013-09-10): wisp-guile.w can now parse itself! Bootstrapping: The magical feeling of seeing a language (dialect) grow up to live by itself: python3 wisp.py wisp-guile.w > 1 && guile 1 wisp-guile.w > 2 && guile 2 wisp-guile.w > 3 && diff 2 3. Starting today, wisp is implemented in wisp. \ No newline at end of file +wisp 0.4 (2013-09-10): wisp-guile.w can now parse itself! Bootstrapping: The magical feeling of seeing a language (dialect) grow up to live by itself: python3 wisp.py wisp-guile.w > 1 && guile 1 wisp-guile.w > 2 && guile 2 wisp-guile.w > 3 && diff 2 3. Starting today, wisp is implemented in wisp. diff --git a/README b/README --- a/README +++ b/README @@ -4,18 +4,21 @@ Wisp: Whitespace to Lisp define : hello (define (hello) display "Hello World" ⇒ (display "Hello World")) +<a name="fibonacci"></a> define : fibonacci n (define (fibonacci n) let rek : (i 0) (u 1) (v 1) (let rek ((i 0) (u 1) (v 1)) - if : >= i : - n 2 ⇒ (if (>= i (- n 2)) + if : >= i {n - 2} ⇒ (if (>= i (- n 2)) . v v - rek (+ i 1) v (+ u v) (rek (+ i 1) v (+ u v))))) + rek {i + 1} v {u + v} (rek (+ i 1) v (+ u v))))) -Wisp turns indentation based syntax into Lisp. The conversion is homoiconic[^h], generic[^g], and backwards-compatible[^b]. It is inspired by [project readable][], but tries to keep itself simple (and stupid: just a preprocessor). More information on the [wisp-website][] and code in the [wisp-repository][]. +Wisp turns indentation based syntax into Lisp. The conversion is homoiconic[^h], generic[^g], and backwards-compatible[^b]. It is inspired by [project readable][], but tries to keep itself simple (and stupid: just add parens for indentation). More information is available on the [wisp-website][], and code in the [wisp-repository][]. For a short presentation, see [Why Wisp?](why-wisp.html) +Note that this is full-fledged scheme, with all its capabilities like hygienic macros (programmable syntax!) and full tail recursion. + [wisp-website]: http://draketo.de/light/english/wisp-lisp-indentation-preprocessor "wisp: Whitespace to Lisp: An indentation to parentheses preprocessor to get more readable Lisp" [wisp-repository]: http://draketo.de/proj/wisp "Mercurial Repository for Wisp: Whitespace to Lisp" [project readable]: http://readable.sourceforge.net/ "Readable Lisp S-expressions Project" @@ -40,24 +43,15 @@ Usage Wisp and curly infix (SRFI-105) ------------------------------- -Wisp treats braces "{}" the same as parentheses "()" and square brackets "[]", so you can use it with curly infix ([SRFI-105](http://srfi.schemers.org/srfi-105/srfi-105.html)) to get more customary math expressions. In Guile Scheme with Wisp you can activate curly infix using the following line `. #!curly-infix ` (with a final space!) - -<a name="fibonacci"></a>By combining curly-infix and wisp, the well-known Fibonacci sequence can be defined as follows: - - . #!curly-infix - define : fibonacci n - let rek : (i 0) (u 1) (v 1) - if {i >= {n - 2}} - . v - rek {i + 1} v {u + v} - -Note that this is full-fledged scheme, with all its capabilities like hygienic macros (programmable syntax!) and full tail recursion. +Wisp treats braces "{}" the same as parentheses "()" and square brackets "[]", so you can use it with curly infix ([SRFI-105](http://srfi.schemers.org/srfi-105/srfi-105.html)) to get more customary math expressions. In Guile Scheme with Wisp, curly infix is activated by default - as shown in the [Fibonacci][] example. If you want to use a curly-infix expression starting a line, you have to prefix it with a dot: . {1 + 1} ; = 2 +[Fibonacci]: #fibonacci "Generation of the fibonacci sequence in wisp and s-expressions" + Notes ----- diff --git a/bootstrap.sh b/bootstrap.sh --- a/bootstrap.sh +++ b/bootstrap.sh @@ -9,7 +9,7 @@ fi # Bootstrap wisp-guile with wisp.py if [[ x"$2" == x"" ]]; then - guile="guile" + guile='guile' else guile="$2" fi @@ -26,12 +26,21 @@ if [[ ! x"${diff}" == x"success" ]]; the echo "failed to bootstrap wisp.scm. diff: " ${diff} exit 1 fi -echo "successfully bootstrapped wisp.scm" -echo preparing the reader: wisp at the REPL -echo parsing the spec file... +# put all output into stderr via 1>&2 and prefix it with ;;; to make it possible to kill it alongside the auto-compile output from guile with one sed. +echo ";;;" "successfully bootstrapped wisp.scm" 1>&2 mkdir -p language/wisp + +echo ";;;" preparing the reader: wisp at the REPL 1>&2 + +echo ";;;" parsing wisp-scheme.w with the parser for the REPL 1>&2 +${guile} wisp.scm ${srcdir}/wisp-scheme.w 2>/dev/null > wisp-scheme.scm \ + && echo ";;;" ...precompiling the parser... 1>&2 \ + && ${guile} -s wisp-scheme.scm 2>/dev/null \ + && echo ";;;" ...succeeded 1>&2 \ + +echo ";;;" parsing the spec file... 1>&2 ${guile} wisp.scm ${srcdir}/wisp-reader.w 2>/dev/null > language/wisp/spec.scm \ - && echo ...precompiling the spec file... \ + && echo ";;;" ...precompiling the spec file... 1>&2 \ && ${guile} -L . -s language/wisp/spec.scm \ - && echo ...succeeded \ - && echo to use wisp at the REPL, run '`'${guile} -L . --language=wisp'`' + && echo ";;;" ...succeeded 1>&2 \ + && echo ";;;" to use wisp at the REPL, run '`'${guile} -L . --language=wisp'`' 1>&2 diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -1,14 +1,14 @@ dnl run `autoreconf -i` to generate a configure script. dnl Then run ./configure to generate a Makefile. dnl Finally run make to generate the project. -AC_INIT([wisp], [0.5.9], +AC_INIT([wisp], [0.8.1], [arne_bab@web.de]) # Check for programs I need for my build AC_CANONICAL_TARGET -AC_ARG_VAR([guile], [How to call GNU Guile.]) -AC_CHECK_TARGET_TOOL([guile], [guile], [no]) +AC_ARG_VAR([guile], [How to call GNU Guile 2.0.x.]) +AC_CHECK_TARGET_TOOL([guile], [guile-2.0], [no]) AS_IF([test "x$guile" = "xno"], - [AC_MSG_ERROR([cannot find GNU Guile.])]) + [AC_MSG_ERROR([cannot find GNU Guile 2.0 or later.])]) AC_ARG_VAR([python3], [How to call Python 3.]) AC_CHECK_TARGET_TOOL([python3], [python3], [no]) AS_IF([test "x$python3" = "xno"], @@ -21,4 +21,4 @@ AS_IF([test "x$python3" = "xno"], AM_INIT_AUTOMAKE([gnu]) AM_MAINTAINER_MODE([enable]) AC_CONFIG_FILES([Makefile]) -AC_OUTPUT \ No newline at end of file +AC_OUTPUT diff --git a/docs/srfi-from-template.html b/docs/srfi-from-template.html new file mode 100644 --- /dev/null +++ b/docs/srfi-from-template.html @@ -0,0 +1,732 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<html> + <head> + <title>SRFI ?: wisp: simpler indentation-sensitive scheme</title> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> + </head> + <body> + +<H1>Title</H1> + +wisp: simpler indentation-sensitive scheme + +<H1>Author</H1> + +<ul> +<li>Arne Babenhauserheide +</li> +</ul> + +<h3>Acknowledgments</h3> +<ul> +<li>Thanks for many constructive discussions goes to Alan Manuel K. Gloria and David A. Wheeler. +</li> +<li>Also thanks to Mark Weaver for his help with the wisp parser and the guile integration - including a 20x speedup. +</li> +</ul> + +<H1>Abstract</H1> + +<p> +This SRFI describes a simple syntax which allows making scheme easier to read for newcomers while keeping the simplicity, generality and elegance of s-expressions. Similar to <a href="http://srfi.schemers.org/srfi-110/srfi-110.html">SRFI 110</a>, <a href="http://srfi.schemers.org/srfi-49/srfi-49.html">SRFI 49</a> and Python it uses indentation to group expressions. Like <a href="http://srfi.schemers.org/srfi-110/srfi-110.html">SRFI 110</a> wisp is general and homoiconic. +</p> + +<p> +Different from its predecessors, wisp only uses the absolute minimum of additional syntax-elements which are required for writing and exchanging arbitrary code-structures. As syntax elements it only uses a colon surrounded by whitespace, the period followed by whitespace as first code-character on the line and optional underscores followed by whitespace at the beginning of the line. +</p> + +<p> +It resolves a limitation of <a href="http://srfi.schemers.org/srfi-110/srfi-110.html">SRFI 110</a> and <a href="http://srfi.schemers.org/srfi-49/srfi-49.html">SRFI 49</a>, both of which force the programmer to use a single argument per line if the arguments to a procedure need to be continued after a procedure-call. +</p> + +<p> +Wisp expressions can include any s-expressions and as such provide backwards compatibility. +</p> + +<table><tr><th>wisp</th><th>s-exp</th></tr><tr><td> +<pre><b>define</b> : <i>hello</i> who + <i>format</i> #t "~A ~A!\n" + . "Hello" who +<i>hello</i> "Wisp" +</pre> +</td><td> +<pre>(<b>define</b> (<i>hello</i> who) + (<i>format</i> #t "~A ~A!\n" + "Hello" who)) +(<i>hello</i> "S-exp") +</pre> +</td></tr></table> + +<H1>Issues</H1> + +<ul> +<li>wisp-scheme: REPL: sometimes the output of a command is only shown after typing the next non-empty line.</li></ul> + +<H1>Rationale</H1> + +<p>A big strength of Scheme and other lisp-like languages is their minimalistic syntax. By using only the most common characters like the period, the comma, the quote and quasiquote, the hash, the semicolon and the parens for the syntax (<code>.,"'`#;()</code><!--"-->), they are very close to natural language.<a href="#common-letters" name="common-letters-reference">⁽¹⁾</a> Along with the minimal list-structure of the code, this gives these languages a timeless elegance.</p> + +<p>But as <a href="http://srfi.schemers.org/srfi-110/srfi-110.html">SRFI 110</a> explains very thoroughly (which we need not repeat here), the parentheses at the beginning of lines hurt readability and scare away newcomers. Additionally using indentation to mark the structure of the code follows naturally from the observation that most programmers use indentation, with many programmers letting their editor indent code automatically to fit the structure. Indentation is an important way how programmers understand code and using it directly to define the structure avoids errors due to mismatches between indentation and actual meaning.</p> + +<p>As a solution to this, <a href="http://srfi.schemers.org/srfi-49/srfi-49.html">SRFI 49</a> and <a href="http://srfi.schemers.org/srfi-110/srfi-110.html">SRFI 110</a> provide a way to write whitespace sensitive scheme, but both have their share of issues.</p> + +<p>As noted in <a href="http://srfi.schemers.org/srfi-110/srfi-110.html">SRFI 110</a>, there are a number of implementation-problems in <a href="http://srfi.schemers.org/srfi-49/srfi-49.html">SRFI 49</a>, as well as specification shortcomings like choosing the name “group” for the construct which is necessary to represent double parentheses. In addition to the problems named in <a href="http://srfi.schemers.org/srfi-110/srfi-110.html">SRFI 110</a>, <a href="http://srfi.schemers.org/srfi-49/srfi-49.html">SRFI 49</a> is not able to continue the arguments to a procedure on one line, if a prior argument was a procedure call. The following example shows the difference between wisp and <a href="http://srfi.schemers.org/srfi-49/srfi-49.html">SRFI 49</a> for a very simple code snippet:</p> + +<table><tr><th>wisp</th><th><a href="http://srfi.schemers.org/srfi-49/srfi-49.html">SRFI 49</a></th></tr><tr><td> +<pre> + <i>*</i> 5 + <i>+</i> 4 3 + . 2 1 +</pre> +</td><td> +<pre> + <i>*</i> 5 + <i>+</i> 4 3 + 2 + 1 +</pre> +</td></tr></table> + +<p>Here wisp uses the leading period to mark a line as continuing the argument list.<a href="#period-concept" name="period-concept-reference">⁽²⁾</a></p> + +<p><a href="http://srfi.schemers.org/srfi-110/srfi-110.html">SRFI 110</a> improves a lot over <a href="http://srfi.schemers.org/srfi-49/srfi-49.html">SRFI 49</a>. It resolves the group-naming and reduces the need to continue the argument-list by introducing 3 different grouping syntax forms (<code>$</code>, <code>\\</code> and <code><* *></code>). These additional syntax-elements however hurt readability for newcomers (obviously the authors of <a href="http://srfi.schemers.org/srfi-110/srfi-110.html">SRFI 110</a> disagree with this assertion. Their view is discussed in <a href="http://srfi.schemers.org/srfi-110/srfi-110.html">SRFI 110</a> in the section about wisp). The additional syntax elements lead to structures like the following (taken from examples from the readable project):</p> + + +<table><tr><th><a href="http://srfi.schemers.org/srfi-110/srfi-110.html">SRFI 110</a> / readable</th></tr><tr><td> +<pre> + <i>myprocedure</i> + x: \\ original-x + y: \\ <i>calculate-y</i> original-y +</pre> +</td></tr><tr><td> +<pre> + <i>a</i> b $ <i>c</i> d e $ <i>f</i> g +</pre> +</td></tr><tr><td> +<pre> + let <* <i>x</i> <i>getx</i>() \\ <i>y</i> <i>gety</i>() *> + ! {{x * x} + {y * y}} +</pre> +</td></tr></table> + +<p>This is not only hard to read, but also makes it harder to work with the code, because the programmer has to learn these additional syntax elements and keep them in mind before being able to understand the code.</p> + +<p>Like <a href="http://srfi.schemers.org/srfi-49/srfi-49.html">SRFI 49</a> <a href="http://srfi.schemers.org/srfi-110/srfi-110.html">SRFI 110</a> also cannot continue the argument-list without resorting to single-element lines, though it reduces this problem by the above grouping syntax forms and advertising the use of neoteric expressions from <a href="http://srfi.schemers.org/srfi-105/srfi-105.html">SRFI 105</a>.</p> + +<h2>Wisp example</h2> + +Since an example speaks more than a hundred explanations, the following shows wisp exploiting all its features - including curly-infix from <a href="http://srfi.schemers.org/srfi-105/srfi-105.html">SRFI 105</a>: + +<blockquote> +<pre> +<b>define</b> : <i>factorial</i> n +__ <b>if</b> : <i>zero?</i> n +____ . 1 +____ <i>*</i> n : <i>factorial</i> {n - 1} + +<i>display</i> : <i>factorial</i> 5 +<i>newline</i> +</pre> +</blockquote> + +<h2>Advantages of Wisp</h2> + +<p>Wisp draws on the strength of <a href="http://srfi.schemers.org/srfi-110/srfi-110.html">SRFI 110</a> but avoids its complexities. It was conceived and improved in the discussions within the readable-project which preceded <a href="http://srfi.schemers.org/srfi-110/srfi-110.html">SRFI 110</a> and there is a comparison between readable in wisp in <a href="http://srfi.schemers.org/srfi-110/srfi-110.html">SRFI 110</a>.</p> + +<p>Like <a href="http://srfi.schemers.org/srfi-110/srfi-110.html">SRFI 110</a>, wisp is general and homoiconic and interacts nicely with <a href="http://srfi.schemers.org/srfi-105/srfi-105.html">SRFI 105</a> (neoteric expressions and curly infix). Like <a href="http://srfi.schemers.org/srfi-110/srfi-110.html">SRFI 110</a>, the expressions are the same in the REPL and in code-files. Like <a href="http://srfi.schemers.org/srfi-110/srfi-110.html">SRFI 110</a>, wisp has been used for implementing multiple smaller programs, though the biggest program in wisp is still its implementations (written in wisp and bootstrapped via a simpler wisp preprocessor).</p> + +<p>But unlike <a href="http://srfi.schemers.org/srfi-110/srfi-110.html">SRFI 110</a>, wisp only uses the minimum of additional syntax-elements which are necessary to support arbitrary code-structures with indentation-sensitive code which is intended to be shared over the internet. To realize these syntax-elements, it generalizes existing syntax and draws on the most common non-letter non-math characters in prose. This allows keeping the actual representation of the code elegant and inviting to newcomers.</p> + +<p>Wisp expressions are not as sweet as <a href="http://readable.sf.net">readable</a>, but they KISS.</p> + +<h2>Disadvantages of Wisp</h2> + +<p>Using the colon as syntax element keeps the code very close to written prose, but it can interfere with type definitions as for example used in Typed Racket.<a href="#typed-racket" name="typed-racket-reference">⁽³⁾</a> This can be mitigated in let- and lambda-forms by using the parenthesized form. When doing so, wisp avoids the double-paren for type-declarations and as such makes them easier to catch by eye. For procedure definitions (the only <code>define</code> call where type declarations are needed in typed-racket), a <code>declare</code> macro directly before the <code>define</code> should work well.</p> + +<p>Using the period to continue the argument list is unusual compared to other languages and as such can lead to errors when trying to return a variable from a procedure and forgetting the period.</p> + + +<h2>Related SRFIs</h2> +<ul> +<li><a href="http://srfi.schemers.org/srfi-49/srfi-49.html">SRFI 49</a> (Indentation-sensitive syntax): superseded by this SRFI, +</li> +<li><a href="http://srfi.schemers.org/srfi-110/srfi-110.html">SRFI 110</a> (Sweet-expressions (t-expressions)): alternative to this SRFI, +</li> +<li><a href="http://srfi.schemers.org/srfi-105/srfi-105.html">SRFI 105</a> (neoteric expressions and curly infix): supported in this SRFI by treating curly braces like brackets and parentheses. Curly infix is required by the implementation and the testsuite. +</li> +<li><a href="http://srfi.schemers.org/srfi-30/srfi-30.html">SRFI 30</a> (Nested Multi-line comments): complex interaction. Should be avoided at the beginning of lines, because it can make the indentation hard to distinguish for humans. <a href="http://srfi.schemers.org/srfi-110/srfi-110.html">SRFI 110</a> includes them, so there might be value in adding them. The wisp reference implementation does not treat them specially, though, which might create arbitrary complications. +</li> +</ul> + + +<h2>Footnotes</h2> + +<ul><li><a name="common-letters" href="#common-letters-reference">⁽¹⁾</a> The most common non-letter, non-math characters in prose are <code>.,":'_#?!;</code><!--"-->, in the given order as derived from newspapers and other sources (for the ngram assembling scripts, see the <a href="http://bitbucket.org/ArneBab/evolve-keyboard-layout">evolve keyboard layout project</a>).</li> + <li><a name="period-concept" href="#period-concept-reference">⁽²⁾</a> Conceptually, continuing the argument list with a period uses syntax to mark the rare case of not calling a procedure as opposed to marking the common case of calling a procedure. To back the claim, that calling a procedure is actually the common case in scheme-code, grepping the the modules in the Guile source code shows over 27000 code-lines which start with a paren and only slightly above 10000 code-lines which start with a non-paren, non-comment character. Since wisp-syntax mostly follows the regular scheme indentation guidelines (as realized for example by Emacs), the whitespace in front of lines does not need to change.</li> + <li><a name="typed-racket" href="#typed-racket-reference">⁽³⁾</a> Typed Racket uses calls of the form <code>(: x Number)</code> to declare types. These forms can still be used directly in parenthesized form, but in wisp-form the colon has to be replaced with <code>\:</code>. In most cases type-declarations are not needed in typed racket, since the type can be inferred. See <a href="http://docs.racket-lang.org/ts-guide/more.html?q=typed#%28part._when-annotations~3f%29">When do you need type annotations?</a></li> +</ul> + +<H1>Specification</H1> + +<p>The specification is separated into four parts: A general overview of the syntax, a more detailed description, justifications for each added syntax element and clarifications for technical details.</p> + +<h2>Overview</h2> + +<p>The basics of wisp syntax can be defined in 4 rules, each of which emerges directly from a requirement:</p> + +<h3>Wisp syntax 1/4: procedure calls</h3> + +<p>Indentation:</p> + +<pre> +<i>display</i> + + 3 4 5 +<i>newline</i> +</pre> + +<p>becomes</p> + +<pre> +(<i>display</i> + (+ 3 4 5)) +(<i>newline</i>) +</pre> + +<p><i>requirement: call procedure without parenthesis.</i></p> + +<h3>Wisp syntax 2/4: Continue Argument list</h3> + +<p>The period:</p> + +<pre> +<i>+</i> 5 + <i>*</i> 4 3 + . 2 1 +</pre> + +<p>becomes</p> + +<pre> +(<i>+</i> 5 + (<i>*</i> 4 3) + 2 1) +</pre> + +<p>This also works with just one argument after the period. To start a line without a procedure call, you have to prefix it with a period followed by whitespace.</p> + +<p><i>requirement: continue the argument list of a procedure after an intermediate call to another procedure.</i></p> + +<h3>Wisp syntax 3/4: Double Parens</h3> + +<p>The colon:</p> + +<pre> +<b>let</b> + : x 1 + y 2 + z 3 + <i>body</i> +</pre> + +<p>becomes</p> + +<pre> +(<b>let</b> + ((x 1) + (y 2) + (z 3)) + (<i>body</i>)) +</pre> + +<p><i>requirement: represent code with two adjacent blocks in double-parentheses.</i></p> + +<h3>Wisp syntax 4/4: Resilient Indentation</h3> + +<p>The underscore (optional):</p> + +<pre> +<b>let</b> +_ : x 1 +__ y 2 +__ z 3 +_ <i>body</i> +</pre> + +<p>becomes</p> + +<pre> +(<b>let</b> + ((x 1) + (y 2) + (z 3)) + (<i>body</i>)) +</pre> + +<p><i>requirement: share code in environments which do not preserve whitespace.</i></p> + +<h3>Summary</h3> + +<p>The syntax shown here is the minimal syntax required for the goal of wisp: indentation-based, general lisp with a simple preprocessor, and code which can be shared easily on the internet:</p> + +<ul><li><code>.</code> to continue the argument list</li> + <li><code>:</code> for double parens</li> + <li><code>_</code> to survive HTML</li></ul> + + +<h3>More detailed: Wisp syntax rules</h3> + + +<h4>Unindented line</h4> + +<p> +<b>A line without indentation is a procedure call</b>, just as if it would start with a parenthesis. +</p> + + + +<pre><i>display</i> "Hello World!" ; (<i>display</i> "Hello World!") +</pre> + + + +<h4>Sibling line</h4> + +<p> +<b>A line which is more indented than the previous line is a sibling to that line</b>: It opens a new parenthesis. +</p> + + + +<pre><i>display</i> ; (<i>display</i> + <i>string-append</i> "Hello " "World!" ; (<i>string-append</i> "Hello " "World!")) +</pre> + + + +<h4>Closing line</h4> + +<p> +<b>A line which is not more indented than previous line(s) closes the parentheses of all previous lines which have higher or equal indentation</b>. You should only reduce the indentation to indentation levels which were already used by parent lines, else the behaviour is undefined. +</p> + + + +<pre><i>display</i> ; (<i>display</i> + <i>string-append</i> "Hello " "World!" ; (<i>string-append</i> "Hello " "World!")) +<i>display</i> "Hello Again!" ; (<i>display</i> "Hello Again!") +</pre> + + + + + +<h4>Prefixed line</h4> + +<p> +<b>To add any of ' , ` #' #, #` or #@, to the first parenthesis on a line, just prefix the line with that symbol</b> followed by at least one space. Implementations are free to add more prefix symbols. +</p> + + + +<pre>' "Hello World!" ; '("Hello World!") +</pre> + + + + + + +<h4>Continuing line</h4> + +<p> +<b>A line whose first non-whitespace characters is a dot followed by a space (". ") does not open a new parenthesis: it is treated as simple continuation of the first less indented previous line</b>. In the first line this means that this line does not start with a parenthesis and does not end with a parenthesis, just as if you had directly written it in lisp without the leading ". ". +</p> + + + +<pre><i>string-append</i> "Hello" ; (<i>string-append</i> "Hello" + <i>string-append</i> " " "World" ; (<i>string-append</i> " " "World") + . "!" ; "!") +</pre> + + + + + + +<h4>Empty indentation level</h4> + +<p> +<b>A line which contains only whitespace and a colon (":") defines an indentation level at the indentation of the colon</b>. It opens a parenthesis which gets closed by the next line which has less or equal indentation. If you need to use a colon by itself. you can escape it as "\:". +</p> + + + +<pre><b>let</b> ; (<b>let</b> + : ; ( + <i>msg</i> "Hello World!" ; (<i>msg</i> "Hello World!")) + <i>display</i> msg ; (<i>display</i> msg)) +</pre> + + + + + + +<h4>Inline Colon</h4> + +<p> +<b>A colon surrounded by whitespace (" : ") starts a parenthesis which gets closed at the end of the line</b>. +</p> + + + +<pre><b>define</b> : <i>hello</i> who ; (<b>define</b> (<i>hello</i> who) + <i>display </i> ; (<i>display</i> + <i>string-append</i> "Hello " who "!" ; (<i>string-append</i> "Hello " who "!"))) +</pre> + + +<p> +If the colon starts a line which also contains other non-whitespace characters, it starts a parenthesis which gets closed at the end of the line <b>and</b> defines an indentation level at the position of the colon. +</p> + +<p> +If the colon is the last non-whitespace character on a line, it represents an empty pair of parentheses: +</p> + + + +<pre><b>let</b> : ; (<b>let</b> () + <i>display</i> "Hello" ; (<i>display</i> "Hello")) +</pre> + + + + + +<h4>Initial Underscores</h4> + +<p> +<b>You can replace any number of consecutive initial spaces by underscores</b>, as long as at least one whitespace is left between the underscores and any following character. You can escape initial underscores by prefixing the first one with \ ("\___ a" → "(_ a)"), if you have to use them as procedure names. +</p> + + + +<pre><b>define</b> : <i>hello</i> who ; (<b>define</b> (<i>hello</i> who) +_ <i>display</i> ; (<i>display</i> +___ <i>string-append</i> "Hello " who "!" ; (<i>string-append</i> "Hello " who "!"))) +</pre> + + + + + +<h4>Parens and Strings</h4> + +<p> +<b>Linebreaks inside parentheses and strings are not considered linebreaks</b> for parsing indentation. To use parentheses at the beginning of a line without getting double parens, prefix the line with a period. +</p> + + + +<pre><b>define</b> : <i>stringy</i> s + <i>string-append</i> s " reversed and capitalized: + " ; linebreaks in strings do not affect wisp parsing + . (<i>string-capitalize</i> ; same for linebreaks in parentheses + (<i>string-reverse</i> s)) +</pre> + + +<p> +Effectively code in parentheses and strings is interpreted directly as Scheme. This way you can simply copy a thunk of scheme into wisp. The following is valid wisp: +</p> + + + +<pre><b>define</b> foo (<i>+</i> 1 + (<i>*</i> 2 3)) ; defines foo as 7 +</pre> + + + + + + +<h3>Clarifications</h3> + +<ul> +<li>Code-blocks end after 2 empty lines followed by a newline. Indented non-empty lines after 2 empty lines should be treated as error. A line is empty if it only contains whitespace. A line with a comment is never empty. +</li> + +<li>Inside parentheses, wisp parsing is disabled. Consequently linebreaks inside parentheses are not considered linebreaks for wisp-parsing. For the parser everything which happens inside parentheses is treated as a black box. +</li> + +<li>Square brackets and curly braces should be treated the same way as parentheses: They stop the indentation processing until they are closed. +</li> + +<li>Likewise linebreaks inside strings are not considered linebreaks for wisp-parsing. +</li> + +<li>A colon (:) at the beginning of a line adds an extra open parentheses that gets closed at end-of-line <b>and</b> defines an indentation level. +</li> + +<li>Using a quote to escape a symbol separated from it by whitespace is forbidden. This would make the meaning of quoted lines ambiguous. +</li> + +<li>Curly braces should be treated as curly-infix following <a href="http://srfi.schemers.org/srfi-105/srfi-105.html">SRFI 105</a>. This makes most math look natural to newcomers. +</li> + +<li>Neoteric expressions from <a href="http://srfi.schemers.org/srfi-105/srfi-105.html">SRFI 105</a> are not required because they create multiple ways to represent the same code. In wisp they add much less advantages than in sweet expressions from <a href="http://srfi.schemers.org/srfi-110/srfi-110.html">SRFI 110</a>, because wisp can continue the arguments to a procedure after a procedure call (with the leading period) and the inline colon provides most of the benefits neoteric expressions give to sweet. However implementations providing wisp should give users the option to activate neoteric expressions as by <a href="http://srfi.schemers.org/srfi-105/srfi-105.html">SRFI 105</a> to allow experimentation and evolution (<a href="http://sourceforge.net/p/readable/mailman/message/33068104/">discussion</a>). +</li> + +<li>It is possible to write code which is at the same time valid wisp and sweet. The readable mailing list <a href="http://sourceforge.net/p/readable/mailman/message/33058992/">contains details</a>. +</li> + +<li>The suggested suffix for files using wisp-syntax is <code>.w</code>. + +</ul> + + +<h2>Syntax justification</h2> + +<p> +<i>I do not like adding any unnecessary syntax element to lisp. So I want to show explicitly why the syntax elements are required.</i> +</p> + +<p> +<small> +See also <a href="http://draketo.de/light/english/wisp-lisp-indentation-preprocessor#sec-4">http://draketo.de/light/english/wisp-lisp-indentation-preprocessor#sec-4</a> +</small> +</p> + + + +<h3> . (the dot)</h3> +<p> +To represent general code trees, we have to be able to represent continuation of the arguments of a procedure with an intermediate call to another (or the same) procedure. +</p> + +<p> +The dot at the beginning of the line as marker of the continuation of a variable list is a generalization of using the dot as identity procedure - which is an implementation detail in many lisps. +</p> + +<blockquote> +<p> +<code>(. a)</code> is just <code>a</code> +</p> +</blockquote> + +<p> +So for the single variable case, this would not even need additional parsing: wisp could just parse <code>. a</code> to <code>(. a)</code> and produce the correct result in most lisps. But forcing programmers to always use separate lines for each parameter would be very inconvenient, so the definition of the dot at the beginning of the line is extended to mean “take every element in this line as parameter to the parent procedure”. +</p> + +<blockquote> +<p> +<code>(. a)</code> → <code>a</code> is generalized to <code>(. a b c)</code> → <code>a b c</code>. +</p> +</blockquote> + +<p> +At its core, this dot-rule means that we mark variables in the code instead of procedure calls. We do so, because variables at the beginning of a line are much rarer in Scheme than in other programming languages. +</p> + + + +<h3> : (the colon)</h3> + +<p> +For double parentheses and for some other cases we must have a way to mark indentation levels which do not contain code. Wisp uses the colon, because it is the most common non-alpha-numeric character in normal prose which is not already reserved as syntax by Scheme when it is surrounded by whitespace, and because it already gets used without surrounding whitespace for marking keyword arguments to procedures in Emacs Lisp and Common Lisp, so it does not add completely alien concepts. +</p> + +<p> +The inline procedure call via inline " : " is a limited generalization of using the colon to mark an indentation level: If we add a syntax-element, we should use it as widely as possible to justify adding syntax overhead. +</p> + +<p> +But if you need to use <code>:</code> as variable or procedure name, you can still do so by escaping it with a backslash (<code>\:</code>), so this does not forbid using the character. +</p> + +<p> +For simple cases, the colon could be replaced by clever whitespace parsing, but there are complex cases which make this impossible. The minimal example is a theoretical doublelet which does not require a body. The example uses a double let without action as example for the colon-syntax, even though that does nothing, because that makes it impossible to use later indentation to mark an intermediate indentation-level. Another reason why I would not use later indentation to define whether something earlier is a single or double indent is that this would call for subtle and really hard to find errors. +</p> + + +<pre>(<i>doublelet</i> + ((foo bar)) + ((bla foo))) +</pre> + + +<p> +The wisp version of this is +</p> + +<pre><i>doublelet</i> + : + foo bar + : ; <- this empty back step is the real issue + bla foo +</pre> + + +<p> +or shorter with inline colon (which you can use only if you don’t need further indentation-syntax inside the assignment). +</p> + + + +<pre><i>doublelet</i> + : foo bar + : bla foo +</pre> + + +<p> +The need to be able to represent arbitrary syntax trees which can contain expressions like this is the real reason, why the colon exists. The inline and start-of-line use is only a generalization of that principle (we add a syntax-element, so we should see how far we can push it to reduce the effective cost of introducing the additional syntax). +</p> + + + +<h4>Clever whitespace-parsing which would not work</h4> + +<p> +There are two alternative ways to tackle this issue: deferred level-definition and fixed-width indentation. +</p> + +<p> +Defining intermediate indentation-levels by later elements (deferred definition) would be a problem, because it would create code which is really hard to understand. An example is the following: +</p> + + + +<pre><b>define</b> (<i>flubb</i>) + nubb + hubb + subb + gam +</pre> + + +<p> +would become +</p> + + + +<pre>(<b>define</b> (<i>flubb</i>) + ((nubb)) + ((hubb)) + ((subb)) + (gam)) +</pre> + + +<p> +while +</p> + + + +<pre><b>define</b> (<i>flubb</i>) + nubb + hubb + subb +</pre> + + +<p> +would become +</p> + + + +<pre>(<b>define</b> (<i>flubb</i>) + (nubb) + (hubb) + (subb)) +</pre> + + +<p> +Knowledge of later parts of the code would be necessary to understand the parts a programmer is working on at the moment. This would call for subtle errors which would be hard to track down, because the effect of a change in code would not be localized at the point where the change is done but could propagate backwards. +</p> + +<p> +Fixed indentation width (alternative option to inferring it from later lines) would make it really hard to write readable code. Stuff like this would not be possible: +</p> + + + +<pre><b>when</b> + <i>equal?</i> wrong + <i>isright?</i> stuff + <i>fixstuff</i> +</pre> + + + + + +<h3> _ (the underscore)</h3> + +<p> +In Python the whitespace hostile html already presents problems with sharing code - for example in email list archives and forums. But Python-programmers can mostly infer the indentation by looking at the previous line: If that ends with a colon, the next line must be more indented (there is nothing to clearly mark reduced indentation, though). In wisp we do not have this support, so we need a way to survive in the hostile environment of today's web. +</p> + +<p> +The underscore is commonly used to denote a space in URLs, where spaces are inconvenient, but it is rarely used in Scheme (where the dash ("-") is mostly used instead), so it seems like a a natural choice. +</p> + +<p> +You can still use underscores anywhere but at the beginning of the line, and even at the beginning of the line you simply need to escape it by prefixing the first underscore with a backslash ("\____"). +</p> + + + +<H1>Implementation</H1> + +<p>The reference implementation realizes a specialized parser for Scheme. It uses <a href="https://gnu.org/s/guile" title="GNU Guile: The GNU extension language">GNU Guile</a> and can also be used at the REPL.</p> + +<p>The wisp code also contains a general wisp-preprocessor which can be used for any lisp-like language and can used as an external program which gets called on reading. It does not actually have to understand the code itself.</p> + +<p>To allow for easy re-implementation, the chapter after the implementation itself contains a test-suite with commonly used wisp constructs and parenthesized counterparts.</p> + +<p>The wisp preprocessor implementation can be found in the <a href="http://draketo.de/proj/wisp">wisp code repository</a>. Both implementations are explicitly licensed to allow inclusion in an SRFI.</p> + +<p>The reference implementation linked below generates a syntax tree from wisp which can be executed. It is written in indentation-based wisp-syntax and converted with the preprocessor from the code repository (wisp-guile.w) to parenthesized scheme syntax.</p> + +<ul> + <li><A HREF="http://draketo.de/proj/wisp/srfi-reference.scm">Source for the reference implementation</A>.</li> + <li><A HREF="http://draketo.de/proj/wisp/srfi-testsuite.html">Basic Testsuite for wisp implementations</A>. <br>(a more exhaustive testsuite is available in the <a href="http://draketo.de/proj/wisp">wisp code repository</a>)</li> +</ul> + +<H1>Copyright</H1> +Copyright (C) Arne Babenhauserheide (2014). All Rights Reserved. +<p> +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: +<p> +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +<p> +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. + + <hr> + <address>Editor: <a href="mailto:srfi-editors at srfi dot schemers dot org">Dave Mason</a></address> +<!-- Created: Tue Sep 29 19:20:08 EDT 1998 --> +<!-- hhmts start --> +Last modified: Sun Jan 28 14:21:14 MET 2007 +<!-- hhmts end --> + </body> +</html> diff --git a/docs/srfi-testsuite.html b/docs/srfi-testsuite.html new file mode 100644 --- /dev/null +++ b/docs/srfi-testsuite.html @@ -0,0 +1,957 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" +"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"> +<head> +<title>Test Suite</title> +<!-- 2014-12-23 Di 22:50 --> +<meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> +<meta name="generator" content="Org-mode" /> +<meta name="author" content="Arne Babenhauserheide" /> +<style type="text/css"> + <!--/*--><![CDATA[/*><!--*/ + .title { text-align: center; } + .todo { font-family: monospace; color: red; } + .done { color: green; } + .tag { background-color: #eee; font-family: monospace; + padding: 2px; font-size: 80%; font-weight: normal; } + .timestamp { color: #bebebe; } + .timestamp-kwd { color: #5f9ea0; } + .right { margin-left: auto; margin-right: 0px; text-align: right; } + .left { margin-left: 0px; margin-right: auto; text-align: left; } + .center { margin-left: auto; margin-right: auto; text-align: center; } + .underline { text-decoration: underline; } + #postamble p, #preamble p { font-size: 90%; margin: .2em; } + p.verse { margin-left: 3%; } + pre { + border: 1px solid #ccc; + box-shadow: 3px 3px 3px #eee; + padding: 8pt; + font-family: monospace; + overflow: auto; + margin: 1.2em; + } + pre.src { + position: relative; + overflow: visible; + padding-top: 1.2em; + } + pre.src:before { + display: none; + position: absolute; + background-color: white; + top: -10px; + right: 10px; + padding: 3px; + border: 1px solid black; + } + pre.src:hover:before { display: inline;} + pre.src-sh:before { content: 'sh'; } + pre.src-bash:before { content: 'sh'; } + pre.src-emacs-lisp:before { content: 'Emacs Lisp'; } + pre.src-R:before { content: 'R'; } + pre.src-perl:before { content: 'Perl'; } + pre.src-java:before { content: 'Java'; } + pre.src-sql:before { content: 'SQL'; } + + table { border-collapse:collapse; } + caption.t-above { caption-side: top; } + caption.t-bottom { caption-side: bottom; } + td, th { vertical-align:top; } + th.right { text-align: center; } + th.left { text-align: center; } + th.center { text-align: center; } + td.right { text-align: right; } + td.left { text-align: left; } + td.center { text-align: center; } + dt { font-weight: bold; } + .footpara:nth-child(2) { display: inline; } + .footpara { display: block; } + .footdef { margin-bottom: 1em; } + .figure { padding: 1em; } + .figure p { text-align: center; } + .inlinetask { + padding: 10px; + border: 2px solid gray; + margin: 10px; + background: #ffffcc; + } + #org-div-home-and-up + { text-align: right; font-size: 70%; white-space: nowrap; } + textarea { overflow-x: auto; } + .linenr { font-size: smaller } + .code-highlighted { background-color: #ffff00; } + .org-info-js_info-navigation { border-style: none; } + #org-info-js_console-label + { font-size: 10px; font-weight: bold; white-space: nowrap; } + .org-info-js_search-highlight + { background-color: #ffff00; color: #000000; font-weight: bold; } + /*]]>*/--> +</style> +<script type="text/javascript"> +/* +@licstart The following is the entire license notice for the +JavaScript code in this tag. + +Copyright (C) 2012-2013 Free Software Foundation, Inc. + +The JavaScript code in this tag is free software: you can +redistribute it and/or modify it under the terms of the GNU +General Public License (GNU GPL) as published by the Free Software +Foundation, either version 3 of the License, or (at your option) +any later version. The code is distributed WITHOUT ANY WARRANTY; +without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU GPL for more details. + +As additional permission under GNU GPL version 3 section 7, you +may distribute non-source (e.g., minimized or compacted) forms of +that code without the copy of the GNU GPL normally required by +section 4, provided you include this license notice and a URL +through which recipients can access the Corresponding Source. + + +@licend The above is the entire license notice +for the JavaScript code in this tag. +*/ +<!--/*--><![CDATA[/*><!--*/ + function CodeHighlightOn(elem, id) + { + var target = document.getElementById(id); + if(null != target) { + elem.cacheClassElem = elem.className; + elem.cacheClassTarget = target.className; + target.className = "code-highlighted"; + elem.className = "code-highlighted"; + } + } + function CodeHighlightOff(elem, id) + { + var target = document.getElementById(id); + if(elem.cacheClassElem) + elem.className = elem.cacheClassElem; + if(elem.cacheClassTarget) + target.className = elem.cacheClassTarget; + } +/*]]>*///--> +</script> +</head> +<body> +<div id="content"> +<h1 class="title">Test Suite</h1> +<p> +The wisp test-suite consists of a large number of wisp-snippets and the corresponding scheme-code. +</p> + +<p> +A wisp-implementation may call itself compliant with the wisp test-suite if the code tree parsed from the wisp file is the same as a code tree parsed from the equivalent Scheme file. +</p> + +<p> +A wisp-implementation may call itself a compliant wisp pre-processor if it successfully converts each wisp-snippet into the corresponging scheme-snippet. Blank lines at the end of the file and non-functional white-space in the produced scheme-file do not matter for this purpose. +</p> + +<p> +This test-suite is also available in the <a href="http://draketo.de/proj/wisp">wisp repository</a> along with a script-runner (runtests.sh) which tests the reference wisp-implementation with GNU Guile against this testsuite.<sup><a id="fnr.1" name="fnr.1" class="footref" href="#fn.1">1</a></sup> +</p> + +<div id="outline-container-sec-1" class="outline-2"> +<h2 id="sec-1"><span class="section-number-2">1</span> tests/syntax-underscore.w</h2> +<div class="outline-text-2" id="text-1"> +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">a</span> b c +<span style="color: #0000ff;">_ d</span> e +<span style="color: #0000ff;">___ f</span> +<span style="color: #0000ff;">___</span> g h +<span style="color: #0000ff;">__</span><span style="color: #a020f0;"> . </span>i + +<span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">_</span> +<span style="color: #0000ff;">_ display</span> <span style="color: #8b2252;">"hello\n"</span> + +<span style="color: #0000ff;">\_</span> +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-2" class="outline-2"> +<h2 id="sec-2"><span class="section-number-2">2</span> tests/syntax-underscore.scm</h2> +<div class="outline-text-2" id="text-2"> +<div class="org-src-container"> + +<pre class="src src-scheme">(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">a</span> b c) + (d e + (f) + (g h) + i)) + +(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">_</span>) + (display <span style="color: #8b2252;">"hello\n"</span>)) + +(_) +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-3" class="outline-2"> +<h2 id="sec-3"><span class="section-number-2">3</span> tests/syntax-strings-parens.w</h2> +<div class="outline-text-2" id="text-3"> +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #b22222;">; </span><span style="color: #b22222;">Test linebreaks in strings and brackets</span> + +<span style="color: #a020f0;">. </span><span style="color: #8b2252;">"flubbub</span> + +<span style="color: #8b2252;">flabbab"</span> + +hrug (<span style="color: #0000ff;">nadda</span> +<span style="color: #0000ff;">madda</span> gadda <span style="color: #8b2252;">"shoktom</span> +<span style="color: #8b2252;"> mee"</span> <span style="color: #8b2252;">" sep </span> +<span style="color: #8b2252;">ka"</span> +<span style="color: #0000ff;"> hadda)</span> +<span style="color: #0000ff;"> gom</span> + +<span style="color: #0000ff;">flu</span> + +<span style="color: #0000ff;">sum</span> [foo +<span style="color: #0000ff;">bar]</span> barz {1 + [* <span style="color: #008b8b;">2</span> <span style="color: #008b8b;">2</span>]} + +<span style="color: #0000ff;">mara</span> { +<span style="color: #0000ff;">li</span> +<span style="color: #0000ff;">+</span> +<span style="color: #0000ff;">lo</span> - (<span style="color: #0000ff;">mabba</span>) +<span style="color: #0000ff;">}</span> +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-4" class="outline-2"> +<h2 id="sec-4"><span class="section-number-2">4</span> tests/syntax-strings-parens.scm</h2> +<div class="outline-text-2" id="text-4"> +<div class="org-src-container"> + +<pre class="src src-scheme"><span style="color: #b22222;">; </span><span style="color: #b22222;">Test linebreaks in strings and brackets</span> + +<span style="color: #8b2252;">"flubbub</span> + +<span style="color: #8b2252;">flabbab"</span> + +(hrug (nadda +madda gadda <span style="color: #8b2252;">"shoktom</span> +<span style="color: #8b2252;"> mee"</span> <span style="color: #8b2252;">" sep </span> +<span style="color: #8b2252;">ka"</span> + hadda) + (gom)) + +(flu) + +(sum [foo +bar] barz {1 + [* 2 2]}) + +(mara { +li ++ +lo - (mabba) +}) +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-5" class="outline-2"> +<h2 id="sec-5"><span class="section-number-2">5</span> tests/syntax-indent.w</h2> +<div class="outline-text-2" id="text-5"> +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #483d8b;">define</span> +<span style="color: #0000ff;"> hello</span> who +<span style="color: #0000ff;"> format</span> <span style="color: #008b8b;">#t</span> <span style="color: #8b2252;">"Hello ~A\n"</span> who + +<span style="color: #483d8b;">define</span> + <span style="color: #483d8b;">let</span> +<span style="color: #a020f0;"> :</span> +<span style="color: #0000ff;"> a</span> <span style="color: #008b8b;">1</span> +<span style="color: #0000ff;"> b</span> <span style="color: #008b8b;">2</span> +<span style="color: #0000ff;"> c</span> <span style="color: #008b8b;">3</span> +<span style="color: #0000ff;"> format</span> <span style="color: #008b8b;">#t</span> <span style="color: #8b2252;">"a: ~A, b: ~A, c: ~A"</span> +<span style="color: #0000ff;"> +</span> a <span style="color: #008b8b;">2</span> +<span style="color: #a020f0;"> . </span> b c +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-6" class="outline-2"> +<h2 id="sec-6"><span class="section-number-2">6</span> tests/syntax-indent.scm</h2> +<div class="outline-text-2" id="text-6"> +<div class="org-src-container"> + +<pre class="src src-scheme">(<span style="color: #a020f0;">define</span> + (hello who) + (format #t <span style="color: #8b2252;">"Hello ~A\n"</span> who)) + +(<span style="color: #a020f0;">define</span> + (<span style="color: #a020f0;">let</span> + ( + (a 1) + (b 2) + (c 3)) + (format #t <span style="color: #8b2252;">"a: ~A, b: ~A, c: ~A"</span> + (+ a 2) + b c))) +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-7" class="outline-2"> +<h2 id="sec-7"><span class="section-number-2">7</span> tests/syntax-empty.w</h2> +<div class="outline-text-2" id="text-7"> +<div class="org-src-container"> + +<pre class="src src-wisp"></pre> +</div> +</div> +</div> +<div id="outline-container-sec-8" class="outline-2"> +<h2 id="sec-8"><span class="section-number-2">8</span> tests/syntax-empty.scm</h2> +<div class="outline-text-2" id="text-8"> +<div class="org-src-container"> + +<pre class="src src-scheme"></pre> +</div> +</div> +</div> +<div id="outline-container-sec-9" class="outline-2"> +<h2 id="sec-9"><span class="section-number-2">9</span> tests/syntax-dot.w</h2> +<div class="outline-text-2" id="text-9"> +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">foo</span> +<span style="color: #a020f0;"> . </span><span style="color: #8b2252;">"bar"</span> + +<span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">bar</span> +<span style="color: #0000ff;"> '</span> <span style="color: #008b8b;">1</span> +<span style="color: #a020f0;"> . . </span><span style="color: #008b8b;">2</span> <span style="color: #b22222;">; </span><span style="color: #b22222;">pair</span> + +<span style="color: #0000ff;">display</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">foo</span> +<span style="color: #0000ff;">newline</span> +<span style="color: #0000ff;">display</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">bar</span> +<span style="color: #0000ff;">newline</span> +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-10" class="outline-2"> +<h2 id="sec-10"><span class="section-number-2">10</span> tests/syntax-dot.scm</h2> +<div class="outline-text-2" id="text-10"> +<div class="org-src-container"> + +<pre class="src src-scheme">(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">foo</span>) + <span style="color: #8b2252;">"bar"</span>) + +(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">bar</span>) + '(1 + . 2 ))<span style="color: #b22222;">; </span><span style="color: #b22222;">pair</span> + +(display (foo)) +(newline) +(display (bar)) +(newline) +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-11" class="outline-2"> +<h2 id="sec-11"><span class="section-number-2">11</span> tests/syntax-colon.w</h2> +<div class="outline-text-2" id="text-11"> +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #483d8b;">let</span> +<span style="color: #a020f0;"> :</span> +<span style="color: #0000ff;"> a</span> <span style="color: #008b8b;">1</span> +<span style="color: #0000ff;"> b</span> <span style="color: #008b8b;">2</span> + <span style="color: #483d8b;">let</span> +<span style="color: #a020f0;"> :</span> +<span style="color: #a020f0;"> :</span> +<span style="color: #a020f0;"> . </span>c <span style="color: #008b8b;">3</span> +<span style="color: #0000ff;"> format</span> <span style="color: #008b8b;">#t</span> <span style="color: #8b2252;">"a: ~A, b: ~A, c: ~A"</span> +<span style="color: #a020f0;"> . </span> a b c + +<span style="color: #a020f0;">: </span>a + +<span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">hello</span> +<span style="color: #0000ff;"> display</span> <span style="color: #8b2252;">"hello\n"</span> + +<span style="color: #483d8b;">let</span> +<span style="color: #a020f0;"> : </span><span style="color: #0000ff;">a</span> <span style="color: #008b8b;">1</span> +<span style="color: #0000ff;"> b</span> <span style="color: #008b8b;">2</span> +<span style="color: #0000ff;"> format</span> <span style="color: #008b8b;">#t</span> <span style="color: #8b2252;">"a: ~A, b: ~A"</span> +<span style="color: #a020f0;"> . </span> a b + +<span style="color: #483d8b;">let</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">:</span> a ' : + +<span style="color: #483d8b;">let</span> +<span style="color: #a020f0;"> : </span> <span style="color: #b22222;">; </span><span style="color: #b22222;">foo</span> +<span style="color: #0000ff;"> a</span> + ' + +<span style="color: #a020f0;">:</span> + a + +<span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">\:</span> +<span style="color: #0000ff;"> hello</span> + +<span style="color: #0000ff;">\:</span> +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-12" class="outline-2"> +<h2 id="sec-12"><span class="section-number-2">12</span> tests/syntax-colon.scm</h2> +<div class="outline-text-2" id="text-12"> +<div class="org-src-container"> + +<pre class="src src-scheme">(<span style="color: #a020f0;">let</span> + ( + (a 1) + (b 2)) + (<span style="color: #a020f0;">let</span> + ( + ( + c 3)) + (format #t <span style="color: #8b2252;">"a: ~A, b: ~A, c: ~A"</span> + a b c))) + +((a)) + +(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">hello</span>) + (display <span style="color: #8b2252;">"hello\n"</span>)) + +(<span style="color: #a020f0;">let</span> + ((a 1) + (b 2)) + (format #t <span style="color: #8b2252;">"a: ~A, b: ~A"</span> + a b)) + +(<span style="color: #a020f0;">let</span> ((a '()))) + +(<span style="color: #a020f0;">let</span> + ( <span style="color: #b22222;">; </span><span style="color: #b22222;">foo</span> + (a + '()))) + +( + (a)) + +(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">:</span>) + (hello)) + +(:) +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-13" class="outline-2"> +<h2 id="sec-13"><span class="section-number-2">13</span> tests/sublist.w</h2> +<div class="outline-text-2" id="text-13"> +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #b22222;">; </span><span style="color: #b22222;">sublists allow to start single line function calls with a colon ( : ).</span> + +<span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">a</span> b c + <span style="color: #483d8b;">let</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">:</span> e<span style="color: #a020f0;"> . </span>f +<span style="color: #a020f0;"> . </span>g +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-14" class="outline-2"> +<h2 id="sec-14"><span class="section-number-2">14</span> tests/sublist.scm</h2> +<div class="outline-text-2" id="text-14"> +<div class="org-src-container"> + +<pre class="src src-scheme"><span style="color: #b22222;">; </span><span style="color: #b22222;">sublists allow to start single line function calls with a colon ( : ).</span> + +(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">a</span> b c) + (<span style="color: #a020f0;">let</span> ((e . f)) + g)) +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-15" class="outline-2"> +<h2 id="sec-15"><span class="section-number-2">15</span> tests/hashbang.w</h2> +<div class="outline-text-2" id="text-15"> +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #b22222;">#!/usr/bin/wisp.py # !#</span> +<span style="color: #b22222;">; </span><span style="color: #b22222;">This tests hashbang lines</span> +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-16" class="outline-2"> +<h2 id="sec-16"><span class="section-number-2">16</span> tests/hashbang.scm</h2> +<div class="outline-text-2" id="text-16"> +<div class="org-src-container"> + +<pre class="src src-scheme">#!/usr/bin/wisp.py # !# +<span style="color: #b22222;">; </span><span style="color: #b22222;">This tests hashbang lines</span> +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-17" class="outline-2"> +<h2 id="sec-17"><span class="section-number-2">17</span> tests/readable-tests.w</h2> +<div class="outline-text-2" id="text-17"> +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">fibfast</span> n + <span style="color: #483d8b;">if</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;"><</span> n <span style="color: #008b8b;">2</span> +<span style="color: #a020f0;"> . </span>n +<span style="color: #0000ff;"> fibup</span> n <span style="color: #008b8b;">2</span> <span style="color: #008b8b;">1</span> <span style="color: #008b8b;">0</span> + +<span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">fibup</span> maxnum count n-1 n-2 + <span style="color: #483d8b;">if</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">=</span> maxnum count +<span style="color: #0000ff;"> +</span> n-1 n-2 +<span style="color: #0000ff;"> fibup</span> maxnum +<span style="color: #0000ff;"> +</span> count <span style="color: #008b8b;">1</span> +<span style="color: #0000ff;"> +</span> n-1 n-2 +<span style="color: #a020f0;"> . </span>n-1 + +<span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">factorial</span> n + <span style="color: #483d8b;">if</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;"><=</span> n <span style="color: #008b8b;">1</span> +<span style="color: #a020f0;"> . </span><span style="color: #008b8b;">1</span> +<span style="color: #0000ff;"> *</span> n +<span style="color: #0000ff;"> factorial</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">-</span> n <span style="color: #008b8b;">1</span> + +<span style="color: #483d8b;">define</span> (<span style="color: #0000ff;">gcd</span> x y) + <span style="color: #483d8b;">if</span> (<span style="color: #0000ff;">=</span> y <span style="color: #008b8b;">0</span>) +<span style="color: #a020f0;"> . </span>x +<span style="color: #0000ff;"> gcd</span> y +<span style="color: #0000ff;"> rem</span> x y + +<span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">add-if-all-numbers</span> lst +<span style="color: #0000ff;"> call/cc</span> +<span style="color: #0000ff;"> lambda</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">exit</span> + <span style="color: #483d8b;">let</span> loop +<span style="color: #a020f0;"> : </span> +<span style="color: #0000ff;"> lst</span> lst +<span style="color: #0000ff;"> sum</span> <span style="color: #008b8b;">0</span> + <span style="color: #483d8b;">if</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">null?</span> lst +<span style="color: #a020f0;"> . </span>sum + <span style="color: #483d8b;">if</span><span style="color: #a020f0;"> : </span><span style="color: #483d8b;">not</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">number?</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">car</span> lst +<span style="color: #0000ff;"> exit</span> <span style="color: #008b8b;">#f</span> +<span style="color: #0000ff;"> +</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">car</span> lst +<span style="color: #0000ff;"> loop</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">cdr</span> lst +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-18" class="outline-2"> +<h2 id="sec-18"><span class="section-number-2">18</span> tests/readable-tests.scm</h2> +<div class="outline-text-2" id="text-18"> +<div class="org-src-container"> + +<pre class="src src-scheme">(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">fibfast</span> n) + (<span style="color: #a020f0;">if</span> (< n 2)) + n + (fibup n 2 1 0 )) + +(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">fibup</span> maxnum count n-1 n-2) + (<span style="color: #a020f0;">if</span> (= maxnum count) + (+ n-1 n-2) + (fibup maxnum + (+ count 1 ) + (+ n-1 n-2 ) + n-1))) + +(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">factorial</span> n) + (<span style="color: #a020f0;">if</span> (<= n 1) + 1 + (* n + (factorial (- n 1))))) + +(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">gcd</span> x y) + (<span style="color: #a020f0;">if</span> (= y 0)) + x + (gcd y + (rem x y))) + +(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">add-if-all-numbers</span> lst) + (<span style="color: #a020f0;">call/cc</span> + (<span style="color: #a020f0;">lambda</span> (exit) + (<span style="color: #a020f0;">let</span> <span style="color: #0000ff;">loop</span> + ( + (lst lst ) + (sum 0)) + (<span style="color: #a020f0;">if</span> (null? lst) + sum + (<span style="color: #a020f0;">if</span> (not (number? (car lst))) + (exit #f) + (+ (car lst) + (loop (cdr lst))))))))) +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-19" class="outline-2"> +<h2 id="sec-19"><span class="section-number-2">19</span> tests/quotecolon.w</h2> +<div class="outline-text-2" id="text-19"> +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #b22222;">#!/home/arne/wisp/wisp-multiline.sh </span> +<span style="color: #b22222;">; </span><span style="color: #b22222;">!#</span> +<span style="color: #483d8b;">define</span> a <span style="color: #008b8b;">1</span> <span style="color: #b22222;">; </span><span style="color: #b22222;">test whether ' : correctly gets turned into '(</span> +<span style="color: #b22222;">; </span><span style="color: #b22222;">and whether brackets in commments are treated correctly.</span> + +<span style="color: #483d8b;">define</span> a '<span style="color: #a020f0;"> : </span><span style="color: #0000ff;">1</span> <span style="color: #008b8b;">2</span> <span style="color: #008b8b;">3</span> + +<span style="color: #483d8b;">define</span> +<span style="color: #0000ff;"> a</span> b +<span style="color: #0000ff;"> c</span> +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-20" class="outline-2"> +<h2 id="sec-20"><span class="section-number-2">20</span> tests/quotecolon.scm</h2> +<div class="outline-text-2" id="text-20"> +<div class="org-src-container"> + +<pre class="src src-scheme">#!/home/arne/wisp/wisp-multiline.sh +<span style="color: #b22222;">; </span><span style="color: #b22222;">!#</span> +(<span style="color: #a020f0;">define</span> <span style="color: #0000ff;">a</span> 1 )<span style="color: #b22222;">; </span><span style="color: #b22222;">test whether ' : correctly gets turned into '(</span> +<span style="color: #b22222;">; </span><span style="color: #b22222;">and whether brackets in commments are treated correctly.</span> + +(<span style="color: #a020f0;">define</span> <span style="color: #0000ff;">a</span> '(1 2 3)) + +(<span style="color: #a020f0;">define</span> + (a b) + (c)) +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-21" class="outline-2"> +<h2 id="sec-21"><span class="section-number-2">21</span> tests/namedlet.w</h2> +<div class="outline-text-2" id="text-21"> +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #b22222;">#!/home/arne/wisp/wisp-multiline.sh </span> +<span style="color: #b22222;">; </span><span style="color: #b22222;">!#</span> +<span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">hello</span> who +<span style="color: #0000ff;"> display</span> who + +<span style="color: #483d8b;">let</span> hello +<span style="color: #a020f0;"> : </span><span style="color: #0000ff;">who</span> <span style="color: #008b8b;">0</span> + <span style="color: #483d8b;">if</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">=</span> who <span style="color: #008b8b;">5</span> +<span style="color: #0000ff;"> display</span> who +<span style="color: #0000ff;"> hello</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">+</span> <span style="color: #008b8b;">1</span> who +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-22" class="outline-2"> +<h2 id="sec-22"><span class="section-number-2">22</span> tests/namedlet.scm</h2> +<div class="outline-text-2" id="text-22"> +<div class="org-src-container"> + +<pre class="src src-scheme">#!/home/arne/wisp/wisp-multiline.sh +<span style="color: #b22222;">; </span><span style="color: #b22222;">!#</span> +(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">hello</span> who) + (display who)) + +(<span style="color: #a020f0;">let</span> <span style="color: #0000ff;">hello</span> + ((who 0)) + (<span style="color: #a020f0;">if</span> (= who 5) + (display who) + (hello (+ 1 who)))) +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-23" class="outline-2"> +<h2 id="sec-23"><span class="section-number-2">23</span> tests/flexible-parameter-list.w</h2> +<div class="outline-text-2" id="text-23"> +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #b22222;">; </span><span style="color: #b22222;">Test using a . as first parameter on a line by prefixing it with a second .</span> +<span style="color: #483d8b;">define</span> +<span style="color: #0000ff;"> a</span> i +<span style="color: #a020f0;"> . . </span>b +<span style="color: #0000ff;"> unless</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">>=</span> i<span style="color: #a020f0;"> : </span><span style="color: #0000ff;">length</span> b +<span style="color: #0000ff;"> display</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">number->string</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">length</span> b +<span style="color: #0000ff;"> display</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">list-ref</span> b i +<span style="color: #0000ff;"> newline</span> +<span style="color: #0000ff;"> apply</span> a ( <span style="color: #0000ff;">+</span> i <span style="color: #008b8b;">1</span> ) b + + +<span style="color: #0000ff;">a</span> <span style="color: #008b8b;">0</span> <span style="color: #8b2252;">"123"</span> <span style="color: #8b2252;">"345"</span> <span style="color: #8b2252;">"567"</span> +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-24" class="outline-2"> +<h2 id="sec-24"><span class="section-number-2">24</span> tests/flexible-parameter-list.scm</h2> +<div class="outline-text-2" id="text-24"> +<div class="org-src-container"> + +<pre class="src src-scheme"><span style="color: #b22222;">; </span><span style="color: #b22222;">Test using a . as first parameter on a line by prefixing it with a second .</span> +(<span style="color: #a020f0;">define</span> + (a i + . b) + (unless (>= i (length b)) + (display (number->string (length b ))) + (display (list-ref b i)) + (newline) + (apply a ( + i 1 ) b))) + + +(a 0 <span style="color: #8b2252;">"123"</span> <span style="color: #8b2252;">"345"</span> <span style="color: #8b2252;">"567"</span>) +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-25" class="outline-2"> +<h2 id="sec-25"><span class="section-number-2">25</span> tests/factorial.w</h2> +<div class="outline-text-2" id="text-25"> +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #b22222;">;; </span><span style="color: #b22222;">short version</span> +<span style="color: #b22222;">; </span><span style="color: #b22222;">note: once you use one inline colon, all the following forms on that</span> +<span style="color: #b22222;">; </span><span style="color: #b22222;">line will get closed at the end of the line</span> + +<span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">factorial</span> n + <span style="color: #483d8b;">if</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">zero?</span> n +<span style="color: #a020f0;"> . </span><span style="color: #008b8b;">1</span> +<span style="color: #0000ff;"> *</span> n<span style="color: #a020f0;"> : </span><span style="color: #0000ff;">factorial</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">-</span> n <span style="color: #008b8b;">1</span> + +<span style="color: #0000ff;">display</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">factorial</span> <span style="color: #008b8b;">5</span> + + +<span style="color: #b22222;">;; </span><span style="color: #b22222;">more vertical space, less colons</span> +<span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">factorial</span> n + <span style="color: #483d8b;">if</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">zero?</span> n +<span style="color: #a020f0;"> . </span><span style="color: #008b8b;">1</span> +<span style="color: #0000ff;"> *</span> n +<span style="color: #0000ff;"> factorial</span> +<span style="color: #0000ff;"> -</span> n <span style="color: #008b8b;">1</span> + +<span style="color: #0000ff;">display</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">factorial</span> <span style="color: #008b8b;">5</span> +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-26" class="outline-2"> +<h2 id="sec-26"><span class="section-number-2">26</span> tests/factorial.scm</h2> +<div class="outline-text-2" id="text-26"> +<div class="org-src-container"> + +<pre class="src src-scheme"><span style="color: #b22222;">;; </span><span style="color: #b22222;">short version</span> +<span style="color: #b22222;">; </span><span style="color: #b22222;">note: once you use one inline colon, all the following forms on that</span> +<span style="color: #b22222;">; </span><span style="color: #b22222;">line will get closed at the end of the line</span> + +(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">factorial</span> n) + (<span style="color: #a020f0;">if</span> (zero? n) + 1 + (* n (factorial (- n 1))))) + +(display (factorial 5 )) + + +<span style="color: #b22222;">;; </span><span style="color: #b22222;">more vertical space, less colons</span> +(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">factorial</span> n) + (<span style="color: #a020f0;">if</span> (zero? n) + 1 + (* n + (factorial + (- n 1))))) + +(display (factorial 5 )) +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-27" class="outline-2"> +<h2 id="sec-27"><span class="section-number-2">27</span> tests/example.w</h2> +<div class="outline-text-2" id="text-27"> +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #483d8b;">define</span> (<span style="color: #0000ff;">a</span> b c) + <span style="color: #483d8b;">let</span> +<span style="color: #a020f0;"> : </span> +<span style="color: #0000ff;"> d</span> <span style="color: #8b2252;">"i am a string</span> +<span style="color: #8b2252;">do not break me!"</span> +<span style="color: #a020f0;"> : </span> + <span style="color: #b22222;">; </span><span style="color: #b22222;">comment: 0</span> + f +<span style="color: #b22222;">; </span><span style="color: #b22222;">comment : 1</span> +<span style="color: #0000ff;"> `</span> g <span style="color: #b22222;">; </span><span style="color: #b22222;">comment " : " 2</span> +<span style="color: #a020f0;"> : </span> +<span style="color: #0000ff;"> h</span> (<span style="color: #0000ff;">I</span> am in brackets: +<span style="color: #0000ff;"> do</span> <span style="color: #483d8b;">not</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">change</span> <span style="color: #8b2252;">"me"</span>) +<span style="color: #a020f0;"> . </span>i +<span style="color: #0000ff;"> ,</span><span style="color: #008b8b;"> 'j</span> k + +<span style="color: #a020f0;"> . </span>l + +<span style="color: #b22222;">; </span><span style="color: #b22222;">comment</span> + +<span style="color: #0000ff;"> a</span> c + +<span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">b</span> :n o +<span style="color: #a020f0;"> . </span><span style="color: #8b2252;">"second defun : with a docstring!"</span> +<span style="color: #0000ff;"> message</span> <span style="color: #8b2252;">"I am here"</span> +<span style="color: #a020f0;"> . </span>t + +<span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">c</span> e f +<span style="color: #a020f0;"> : </span><span style="color: #0000ff;">g</span> +<span style="color: #a020f0;"> :</span> +<span style="color: #0000ff;"> h</span> +<span style="color: #0000ff;"> i</span> +<span style="color: #0000ff;"> j</span> +<span style="color: #0000ff;"> '</span> : +<span style="color: #0000ff;"> k</span> +<span style="color: #a020f0;"> . </span>l +<span style="color: #a020f0;"> . </span>: <span style="color: #0000ff;">m</span> + +<span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">_</span> \: +<span style="color: #0000ff;">__</span> +<span style="color: #0000ff;">__</span><span style="color: #a020f0;"> . </span>\: + +<span style="color: #0000ff;">\_</span> b + +<span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">d</span> + <span style="color: #483d8b;">let</span> +<span style="color: #a020f0;"> : </span><span style="color: #0000ff;">a</span> b +<span style="color: #0000ff;"> c</span> d + +<span style="color: #0000ff;">a</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">:</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">c</span> + +<span style="color: #483d8b;">let</span> +<span style="color: #a020f0;"> : </span><span style="color: #0000ff;">a</span> b + c + +<span style="color: #483d8b;">let</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">:</span> a b + +<span style="color: #a020f0;">. </span>a +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-28" class="outline-2"> +<h2 id="sec-28"><span class="section-number-2">28</span> tests/example.scm</h2> +<div class="outline-text-2" id="text-28"> +<div class="org-src-container"> + +<pre class="src src-scheme">(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">a</span> b c) + (<span style="color: #a020f0;">let</span> + ( + (d <span style="color: #8b2252;">"i am a string</span> +<span style="color: #8b2252;">do not break me!"</span>) + ( + <span style="color: #b22222;">; </span><span style="color: #b22222;">comment: 0</span> + (f) +<span style="color: #b22222;">; </span><span style="color: #b22222;">comment : 1</span> + `(g ))<span style="color: #b22222;">; </span><span style="color: #b22222;">comment " : " 2</span> + ( + (h (I am in brackets: + do not : change <span style="color: #8b2252;">"me"</span>)) + i))) + ,('j k) + + l + +<span style="color: #b22222;">; </span><span style="color: #b22222;">comment</span> + + (a c)) + +(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">b</span> <span style="color: #483d8b;">:n</span> o) + <span style="color: #8b2252;">"second defun : with a docstring!"</span> + (message <span style="color: #8b2252;">"I am here"</span>) + t) + +(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">c</span> e f) + ((g)) + ( + (h + (i)) + (j)) + '(()) + (k) + l + (m)) + +(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">_</span> :) + + :) + +(_ b) + +(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">d</span>) + (<span style="color: #a020f0;">let</span> + ((a b) + (c d)))) + +(a (((c)))) + +(<span style="color: #a020f0;">let</span> + ((a b) + (c))) + +(<span style="color: #a020f0;">let</span> ((a b))) + +a +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-29" class="outline-2"> +<h2 id="sec-29"><span class="section-number-2">29</span> tests/continuation.w</h2> +<div class="outline-text-2" id="text-29"> +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #0000ff;">a</span> b c d e +<span style="color: #a020f0;"> . </span>f g h +<span style="color: #a020f0;"> . </span>i j k + +<span style="color: #0000ff;">concat</span> <span style="color: #8b2252;">"I want "</span> +<span style="color: #0000ff;"> getwish</span> from me +<span style="color: #a020f0;"> . </span><span style="color: #8b2252;">" - "</span> username +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-30" class="outline-2"> +<h2 id="sec-30"><span class="section-number-2">30</span> tests/continuation.scm</h2> +<div class="outline-text-2" id="text-30"> +<div class="org-src-container"> + +<pre class="src src-scheme">(a b c d e + f g h + i j k) + +(concat <span style="color: #8b2252;">"I want "</span> + (getwish from me) + <span style="color: #8b2252;">" - "</span> username) +</pre> +</div> +</div> +</div> +<div id="footnotes"> +<h2 class="footnotes">Footnotes: </h2> +<div id="text-footnotes"> + +<div class="footdef"><sup><a id="fn.1" name="fn.1" class="footnum" href="#fnr.1">1</a></sup> <p> +To run the tests in the wisp testsuite with a separately built GNU Guile, you can use any given guile interpreter by adjusting the following command: <code>PATH=~/guile-2.0.11/meta:${PATH} ./runtests.sh</code> +</p></div> + + +</div> +</div></div> +<div id="postamble" class="status"> +<p class="author">Author: Arne Babenhauserheide</p> +<p class="date">Created: 2014-12-23 Di 22:50</p> +<p class="creator"><a href="http://www.gnu.org/software/emacs/">Emacs</a> 24.3.1 (<a href="http://orgmode.org">Org</a> mode 8.2.6)</p> +<p class="validation"><a href="http://validator.w3.org/check?uri=referer">Validate</a></p> +</div> +</body> +</html> diff --git a/docs/srfi.html b/docs/srfi.html new file mode 100644 --- /dev/null +++ b/docs/srfi.html @@ -0,0 +1,1885 @@ +<?xml version="1.0" encoding="utf-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" +"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"> +<head> +<title>SRFI: wisp: simpler indentation-sensitive scheme</title> +<!-- 2014-12-23 Di 17:17 --> +<meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> +<meta name="generator" content="Org-mode" /> +<meta name="author" content="Arne Babenhauserheide" /> +<style type="text/css"> + <!--/*--><![CDATA[/*><!--*/ + .title { text-align: center; } + .todo { font-family: monospace; color: red; } + .done { color: green; } + .tag { background-color: #eee; font-family: monospace; + padding: 2px; font-size: 80%; font-weight: normal; } + .timestamp { color: #bebebe; } + .timestamp-kwd { color: #5f9ea0; } + .right { margin-left: auto; margin-right: 0px; text-align: right; } + .left { margin-left: 0px; margin-right: auto; text-align: left; } + .center { margin-left: auto; margin-right: auto; text-align: center; } + .underline { text-decoration: underline; } + #postamble p, #preamble p { font-size: 90%; margin: .2em; } + p.verse { margin-left: 3%; } + pre { + border: 1px solid #ccc; + box-shadow: 3px 3px 3px #eee; + padding: 8pt; + font-family: monospace; + overflow: auto; + margin: 1.2em; + } + pre.src { + position: relative; + overflow: visible; + padding-top: 1.2em; + } + pre.src:before { + display: none; + position: absolute; + background-color: white; + top: -10px; + right: 10px; + padding: 3px; + border: 1px solid black; + } + pre.src:hover:before { display: inline;} + pre.src-sh:before { content: 'sh'; } + pre.src-bash:before { content: 'sh'; } + pre.src-emacs-lisp:before { content: 'Emacs Lisp'; } + pre.src-R:before { content: 'R'; } + pre.src-perl:before { content: 'Perl'; } + pre.src-java:before { content: 'Java'; } + pre.src-sql:before { content: 'SQL'; } + + table { border-collapse:collapse; } + caption.t-above { caption-side: top; } + caption.t-bottom { caption-side: bottom; } + td, th { vertical-align:top; } + th.right { text-align: center; } + th.left { text-align: center; } + th.center { text-align: center; } + td.right { text-align: right; } + td.left { text-align: left; } + td.center { text-align: center; } + dt { font-weight: bold; } + .footpara:nth-child(2) { display: inline; } + .footpara { display: block; } + .footdef { margin-bottom: 1em; } + .figure { padding: 1em; } + .figure p { text-align: center; } + .inlinetask { + padding: 10px; + border: 2px solid gray; + margin: 10px; + background: #ffffcc; + } + #org-div-home-and-up + { text-align: right; font-size: 70%; white-space: nowrap; } + textarea { overflow-x: auto; } + .linenr { font-size: smaller } + .code-highlighted { background-color: #ffff00; } + .org-info-js_info-navigation { border-style: none; } + #org-info-js_console-label + { font-size: 10px; font-weight: bold; white-space: nowrap; } + .org-info-js_search-highlight + { background-color: #ffff00; color: #000000; font-weight: bold; } + /*]]>*/--> +</style> +<script type="text/javascript"> +/* +@licstart The following is the entire license notice for the +JavaScript code in this tag. + +Copyright (C) 2012-2013 Free Software Foundation, Inc. + +The JavaScript code in this tag is free software: you can +redistribute it and/or modify it under the terms of the GNU +General Public License (GNU GPL) as published by the Free Software +Foundation, either version 3 of the License, or (at your option) +any later version. The code is distributed WITHOUT ANY WARRANTY; +without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU GPL for more details. + +As additional permission under GNU GPL version 3 section 7, you +may distribute non-source (e.g., minimized or compacted) forms of +that code without the copy of the GNU GPL normally required by +section 4, provided you include this license notice and a URL +through which recipients can access the Corresponding Source. + + +@licend The above is the entire license notice +for the JavaScript code in this tag. +*/ +<!--/*--><![CDATA[/*><!--*/ + function CodeHighlightOn(elem, id) + { + var target = document.getElementById(id); + if(null != target) { + elem.cacheClassElem = elem.className; + elem.cacheClassTarget = target.className; + target.className = "code-highlighted"; + elem.className = "code-highlighted"; + } + } + function CodeHighlightOff(elem, id) + { + var target = document.getElementById(id); + if(elem.cacheClassElem) + elem.className = elem.cacheClassElem; + if(elem.cacheClassTarget) + target.className = elem.cacheClassTarget; + } +/*]]>*///--> +</script> +</head> +<body> +<div id="content"> +<h1 class="title">SRFI: wisp: simpler indentation-sensitive scheme</h1> +<div class="abstract"> +<p> +This SRFI describes a simple syntax which allows making scheme easier to read for newcomers while keeping the simplicity, generality and elegance of s-expressions. Similar to SRFI-110, SRFI-49 and Python it uses indentation to group expressions. Like SRFI-110 wisp is general and homoiconic. +</p> + +<p> +Different from its precedessors, wisp only uses the absolute minimum of additional syntax-elements which are required for writing and exchanging arbitrary code-structures. As syntax elements it only uses a colon surrounded by whitespace, the period followed by whitespace as first code-character on the line and optional underscores followed by whitespace at the beginning of the line. +</p> + +<p> +It resolves a limitation of SRFI-110 and SRFI-49, both of which force the programmer to use a single argument per line if the arguments to a function need to be continued after a function-call. +</p> + +<p> +Wisp expressions can include any s-expressions and as such provide backwards compatibility. +</p> + +<table><tr><th>wisp</th><th>s-exp</th></tr><tr><td> +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">hello</span> who +<span style="color: #0000ff;"> format</span> <span style="color: #008b8b;">#t</span> <span style="color: #C33;">"~A ~A!\n"</span> +<span style="color: #a020f0;"> . </span><span style="color: #C33;">"Hello"</span> who +<span style="color: #0000ff;">hello</span> <span style="color: #C33;">"Wisp"</span> +</pre> +</div> +</td><td> +<div class="org-src-container"> + +<pre class="src src-scheme">(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">hello</span> who) + (format #t <span style="color: #C33;">"~A ~A!\n"</span> + <span style="color: #C33;">"Hello"</span> who)) +(hello <span style="color: #C33;">"S-exp"</span>) +</pre> +</div> +</td></tr></table> + +</div> + +<div id="table-of-contents"> +<h2>Table of Contents</h2> +<div id="text-table-of-contents"> +<ul> +<li><a href="#sec-1">1. Authors</a> +<ul> +<li><a href="#sec-1-1">1.1. Acknowledgments</a></li> +</ul> +</li> +<li><a href="#sec-2">2. Related SRFIs</a></li> +<li><a href="#sec-3">3. Rationale</a> +<ul> +<li><a href="#sec-3-1">3.1. Wisp example</a></li> +<li><a href="#sec-3-2">3.2. Advantages of Wisp</a></li> +<li><a href="#sec-3-3">3.3. Disadvantages of Wisp</a></li> +</ul> +</li> +<li><a href="#sec-4">4. Specification</a> +<ul> +<li><a href="#sec-4-1">4.1. Overview</a></li> +<li><a href="#sec-4-2">4.2. More detailed: Wisp syntax rules</a></li> +<li><a href="#sec-4-3">4.3. Clarifications</a></li> +</ul> +</li> +<li><a href="#sec-5">5. Syntax justification</a> +<ul> +<li><a href="#sec-5-1">5.1. . (the dot)</a></li> +<li><a href="#sec-5-2">5.2. : (the colon)</a></li> +<li><a href="#sec-5-3">5.3. _ (the underscore)</a></li> +</ul> +</li> +<li><a href="#sec-6">6. Implementation</a> +<ul> +<li><a href="#sec-6-1">6.1. The generic wisp processor (code)</a></li> +<li><a href="#sec-6-2">6.2. Test Suite</a></li> +</ul> +</li> +<li><a href="#sec-7">7. Copyright</a></li> +</ul> +</div> +</div> + +<div id="outline-container-sec-1" class="outline-2"> +<h2 id="sec-1"><span class="section-number-2">1</span> Authors</h2> +<div class="outline-text-2" id="text-1"> +<ul class="org-ul"> +<li>Arne Babenhauserheide +</li> +</ul> +</div> + +<div id="outline-container-sec-1-1" class="outline-3"> +<h3 id="sec-1-1"><span class="section-number-3">1.1</span> Acknowledgments</h3> +<div class="outline-text-3" id="text-1-1"> +<ul class="org-ul"> +<li>Thanks for many constructive discussions goes to Alan Manuel K. Gloria and David A. Wheeler. +</li> +<li>Also thanks to Mark Weaver for his help with the wisp parser and the guile integration - including a 20x speedup. +</li> +</ul> +</div> +</div> +</div> + +<div id="outline-container-sec-2" class="outline-2"> +<h2 id="sec-2"><span class="section-number-2">2</span> Related SRFIs</h2> +<div class="outline-text-2" id="text-2"> +<ul class="org-ul"> +<li>SRFI-49 (Indentation-sensitive syntax): superceded by this SRFI, +</li> +<li>SRFI-110 (Sweet-expressions (t-expressions)): alternative to this SRFI, +</li> +<li>SRFI-105 (neoteric expressions and curly infix): supported in this SRFI by treating curly braces like brackets and parentheses. Curly infix is required by the implementation and the testsuite. +</li> +<li>SRFI-30 (Nested Multi-line comments): complex interaction. Should be avoided at the beginning of lines, because it can make the indentation hard to distinguish for humans. SRFI-110 includes them, so there might be value in adding them. The wisp reference implementation does not treat them specially, though, which might create arbitrary complications. +</li> +</ul> +</div> +</div> + +<div id="outline-container-sec-3" class="outline-2"> +<h2 id="sec-3"><span class="section-number-2">3</span> Rationale</h2> +<div class="outline-text-2" id="text-3"> +<p> +A big strength of Scheme and other lisp-like languages is their minimalistic syntax. By using only the most common characters like the period, the comma, the quote and quasiquote, the hash, the semicolon and the parens for the syntax (<code>.,"'`#;()</code>), they are very close to natural language<sup><a id="fnr.1" name="fnr.1" class="footref" href="#fn.1">1</a></sup>. Along with the minimal list-structure of the code, this gives these languages a timeless elegance. +</p> + +<p> +But as SRFI-110 explains very thoroughly (which we need not repeat here), the parentheses at the beginning of lines hurt readability and scare away newcomers. Additionally using indentation to mark the structure of the code follows naturally from the observation that most programmers use indentation, with many programmers letting their editor indent code automatically to fit the structure. Indentation is an important way how programmers understand code and using it directly to define the structure avoids errors due to mismatches between indentation and actual meaning. +</p> + +<p> +As a solution to this, SRFI-49 and SRFI-110 provide a way to write whitespace sensitive scheme, but both have their share of issues. +</p> + +<p> +As noted in SRFI-110, there are a number of implementation-problems in SRFI-49, as well as specification shortcomings like choosing the name “group” for the construct which is necessary to represent double parentheses. In addition to the problems named in SRFI-110, SRFI-49 is not able to continue the arguments to a function on one line, if a prior argument was a function call. The following example shows the difference between wisp and SRFI-49 for a very simple code snippet: +</p> + +<table><tr><th>wisp</th><th>SRFI-49</th></tr><tr><td> +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #0000ff;">*</span> <span style="color: #008b8b;">5</span> +<span style="color: #0000ff;"> +</span> <span style="color: #008b8b;">4</span> <span style="color: #008b8b;">3</span> +<span style="color: #a020f0;"> . </span><span style="color: #008b8b;">2</span> <span style="color: #008b8b;">1</span> +</pre> +</div> +</td><td> +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #0000ff;">*</span> <span style="color: #008b8b;">5</span> +<span style="color: #0000ff;"> +</span> <span style="color: #008b8b;">4</span> <span style="color: #008b8b;">3</span> +<span style="color: #0000ff;"> 2</span> +<span style="color: #0000ff;"> 1</span> +</pre> +</div> +</td></tr></table> + +<p> +SRFI-110 improves a lot over the implementation of SRFI-49. It resolves the group-naming and reduces the need to continue the argument-list by introducing 3 different grouping syntaxes (<code>$</code>, <code>\\</code> and <code><* *></code>). These additional syntax-elements however hurt readability for newcomers (obviously the authors of SRFI-110 disagree with this assertion. Their view is discussed in SRFI-110 in the section about wisp). The additional syntax elements lead to structures like the following (taken from examples from the readable project): +</p> +<div class="org-src-container"> + +<pre class="src src-scheme">myfunction + x: \\ original-x + y: \\ calculate-y original-y +</pre> +</div> + +<div class="org-src-container"> + +<pre class="src src-scheme">a b $ c d e $ f g +</pre> +</div> + +<div class="org-src-container"> + +<pre class="src src-scheme">let <* x getx() \\ y gety() *> +! {{x * x} + {y * y}} +</pre> +</div> + +<p> +This is not only hard to read, but also makes it harder to work with the code, because the programmer has to learn these additional syntax elements and keep them in mind before being able to understand the code. +</p> + +<p> +Like SRFI-49 SRFI-110 also cannot continue the argument-list without resorting to single-element lines, though it reduces this problem by the above grouping syntaxes and advertising the use of neoteric expressions from SRFI-105. +</p> +</div> + +<div id="outline-container-sec-3-1" class="outline-3"> +<h3 id="sec-3-1"><span class="section-number-3">3.1</span> Wisp example</h3> +<div class="outline-text-3" id="text-3-1"> +<p> +Since an example speaks more than a hundred explanations, the following shows wisp exploiting all its features - including curly-infix from SRFI-105: +</p> + +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">factorial</span> n +<span style="color: #0000ff;">__</span> <span style="color: #483d8b;">if</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">zero?</span> n +<span style="color: #0000ff;">____</span><span style="color: #a020f0;"> . </span><span style="color: #008b8b;">1</span> +<span style="color: #0000ff;">____ *</span> n<span style="color: #a020f0;"> : </span><span style="color: #0000ff;">factorial</span> {n - 1} + +<span style="color: #0000ff;">display</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">factorial</span> <span style="color: #008b8b;">5</span> +<span style="color: #0000ff;">newline</span> +</pre> +</div> +</div> +</div> + +<div id="outline-container-sec-3-2" class="outline-3"> +<h3 id="sec-3-2"><span class="section-number-3">3.2</span> Advantages of Wisp</h3> +<div class="outline-text-3" id="text-3-2"> +<p> +Wisp draws on the strength of SRFI-110 but avoids its complexities. It was conceived and improved in the discussions within the readable-project which preceded SRFI-110 and there is a comparison between readable in wisp in SRFI-110. +</p> + +<p> +Like SRFI-110, wisp is general and homoiconic and interacts nicely with SRFI-105 (neoteric expressions and curly infix). Like SRFI-110, the expressions are the same in the REPL and in code-files. Like SRFI-110, wisp has been used for implementing multiple smaller programs, though the biggest program in wisp is still its implementations (written in wisp and bootstrapped via a simpler wisp preprocessor). +</p> + +<p> +But unlike SRFI-110, wisp only uses the minimum of additional syntax-elements which are necessary to support arbitrary code-structures with indentation-sensitive code which is intended to be shared over the internet. To realize these syntax-elements, it generalizes existing syntax and draws on the most common non-letter non-math characters in prose. This allows keeping the actual representation of the code elegant and inviting to newcomers. +</p> + +<p> +Wisp expressions are not as sweet as <a href="http://readable.sf.net">readable</a>, but they KISS. +</p> +</div> +</div> + +<div id="outline-container-sec-3-3" class="outline-3"> +<h3 id="sec-3-3"><span class="section-number-3">3.3</span> Disadvantages of Wisp</h3> +<div class="outline-text-3" id="text-3-3"> +<p> +Using the colon as syntax element keeps the code very close to written prose, but it can interfere with type definitions as for example used in Typed Racket<sup><a id="fnr.2" name="fnr.2" class="footref" href="#fn.2">2</a></sup>. This can be mitigated in let- and lambda-forms by using the parenthesized form. When doing so, wisp avoids the double-paren for type-declarations and as such makes them easier to catch by eye. For function definitions (the only <code>define</code> call where type declarations are needed in typed-racket<sup><a id="fnr.3" name="fnr.3" class="footref" href="#fn.3">3</a></sup>), a <code>declare</code> macro directly before the <code>define</code> should work well. +</p> + +<p> +Using the period to continue the argument list is unusual compared to other languages and as such can lead to errors when trying to return a variable from a procedure and forgetting the period. +</p> +</div> +</div> +</div> + +<div id="outline-container-sec-4" class="outline-2"> +<h2 id="sec-4"><span class="section-number-2">4</span> Specification</h2> +<div class="outline-text-2" id="text-4"> +<p> +The specification is separated into four parts: A general overview of the syntax, a more detailed description, justifications for each added syntax element and clarifications for technical details. +</p> +</div> + +<div id="outline-container-sec-4-1" class="outline-3"> +<h3 id="sec-4-1"><span class="section-number-3">4.1</span> Overview</h3> +<div class="outline-text-3" id="text-4-1"> +<p> +The basics of wisp syntax can be defined in 4 rules, each of which emerges directly from a requirement: +</p> +</div> + +<div id="outline-container-sec-4-1-1" class="outline-4"> +<h4 id="sec-4-1-1"><span class="section-number-4">4.1.1</span> Wisp syntax 1/4: function calls</h4> +<div class="outline-text-4" id="text-4-1-1"> +<p> +Indentation: +</p> + +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #0000ff;">display</span> +<span style="color: #0000ff;"> +</span> <span style="color: #008b8b;">3</span> <span style="color: #008b8b;">4</span> <span style="color: #008b8b;">5</span> +<span style="color: #0000ff;">newline</span> +</pre> +</div> + +<p> +becomes +</p> + +<div class="org-src-container"> + +<pre class="src src-scheme">(display + (+ 3 4 5)) +(newline) +</pre> +</div> + +<p> +<i>requirement: call functions without parenthesis.</i> +</p> +</div> +</div> + +<div id="outline-container-sec-4-1-2" class="outline-4"> +<h4 id="sec-4-1-2"><span class="section-number-4">4.1.2</span> Wisp syntax 2/4: Continue Argument list</h4> +<div class="outline-text-4" id="text-4-1-2"> +<p> +The period: +</p> + +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #0000ff;">+</span> <span style="color: #008b8b;">5</span> +<span style="color: #0000ff;"> *</span> <span style="color: #008b8b;">4</span> <span style="color: #008b8b;">3</span> +<span style="color: #a020f0;"> . </span><span style="color: #008b8b;">2</span> <span style="color: #008b8b;">1</span> +</pre> +</div> + +<p> +becomes +</p> + +<div class="org-src-container"> + +<pre class="src src-scheme">(+ 5 + (* 4 3) + 2 1) +</pre> +</div> + +<p> +This also works with just one argument after the period. To start a line without a function call, you have to prefix it with a period followed by whitespace.<sup><a id="fnr.4" name="fnr.4" class="footref" href="#fn.4">4</a></sup> +</p> + +<p> +<i>requirement: continue the argument list of a function after an intermediate call to another function.</i> +</p> +</div> +</div> + +<div id="outline-container-sec-4-1-3" class="outline-4"> +<h4 id="sec-4-1-3"><span class="section-number-4">4.1.3</span> Wisp syntax 3/4: Double Parens</h4> +<div class="outline-text-4" id="text-4-1-3"> +<p> +The colon:<sup><a id="fnr.5" name="fnr.5" class="footref" href="#fn.5">5</a></sup> +</p> + +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #483d8b;">let</span> +<span style="color: #a020f0;"> : </span><span style="color: #0000ff;">x</span> <span style="color: #008b8b;">1</span> +<span style="color: #0000ff;"> y</span> <span style="color: #008b8b;">2</span> +<span style="color: #0000ff;"> z</span> <span style="color: #008b8b;">3</span> +<span style="color: #0000ff;"> body</span> +</pre> +</div> + +<p> +becomes +</p> + +<div class="org-src-container"> + +<pre class="src src-scheme">(<span style="color: #a020f0;">let</span> + ((x 1) + (y 2) + (z 3)) + (body)) +</pre> +</div> + +<p> +<i>requirement: represent code with two adjadent blocks in double-parentheses.</i> +</p> +</div> +</div> + +<div id="outline-container-sec-4-1-4" class="outline-4"> +<h4 id="sec-4-1-4"><span class="section-number-4">4.1.4</span> Wisp syntax 4/4: Resilient Indentation</h4> +<div class="outline-text-4" id="text-4-1-4"> +<p> +The underscore (optional): +</p> + +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #483d8b;">let</span> +<span style="color: #a020f0;">_ : </span><span style="color: #0000ff;">x</span> <span style="color: #008b8b;">1</span> +<span style="color: #0000ff;">__ y</span> <span style="color: #008b8b;">2</span> +<span style="color: #0000ff;">__ z</span> <span style="color: #008b8b;">3</span> +<span style="color: #0000ff;">_ body</span> +</pre> +</div> + +<p> +becomes +</p> + +<div class="org-src-container"> + +<pre class="src src-scheme">(<span style="color: #a020f0;">let</span> + ((x 1) + (y 2) + (z 3)) + (body)) +</pre> +</div> + +<p> +<i>requirement: share code in environments which do not preserve whitespace.</i> +</p> +</div> +</div> + +<div id="outline-container-sec-4-1-5" class="outline-4"> +<h4 id="sec-4-1-5"><span class="section-number-4">4.1.5</span> Summary</h4> +<div class="outline-text-4" id="text-4-1-5"> +<p> +The syntax shown here is the minimal syntax required for the goal of wisp: indentation-based, general lisp with a simple preprocessor, and code which can be shared easily on the internet: +</p> + +<ul class="org-ul"> +<li><code>.</code> to continue the argument list +</li> +<li><code>:</code> for double parens +</li> +<li><code>_</code> to survive HTML +</li> +</ul> +</div> +</div> +</div> + +<div id="outline-container-sec-4-2" class="outline-3"> +<h3 id="sec-4-2"><span class="section-number-3">4.2</span> More detailed: Wisp syntax rules</h3> +<div class="outline-text-3" id="text-4-2"> +</div><div id="outline-container-sec-4-2-1" class="outline-4"> +<h4 id="sec-4-2-1"><span class="section-number-4">4.2.1</span> Unindented line</h4> +<div class="outline-text-4" id="text-4-2-1"> +<p> +<b>A line without indentation is a function call</b>, just as if it would start with a parenthesis. +</p> + +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #0000ff;">display</span> <span style="color: #C33;">"Hello World!"</span> <span style="color: #898887;">; </span><span style="color: #898887;">(display "Hello World!")</span> +</pre> +</div> +</div> +</div> + +<div id="outline-container-sec-4-2-2" class="outline-4"> +<h4 id="sec-4-2-2"><span class="section-number-4">4.2.2</span> Sibling line</h4> +<div class="outline-text-4" id="text-4-2-2"> +<p> +<b>A line which is more indented than the previous line is a sibling to that line</b>: It opens a new parenthesis. +</p> + +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #0000ff;">display</span> <span style="color: #898887;">; </span><span style="color: #898887;">(display</span> +<span style="color: #0000ff;"> string-append</span> <span style="color: #C33;">"Hello "</span> <span style="color: #C33;">"World!"</span> <span style="color: #898887;">; </span><span style="color: #898887;">(string-append "Hello " "World!"))</span> +</pre> +</div> +</div> +</div> + +<div id="outline-container-sec-4-2-3" class="outline-4"> +<h4 id="sec-4-2-3"><span class="section-number-4">4.2.3</span> Closing line</h4> +<div class="outline-text-4" id="text-4-2-3"> +<p> +<b>A line which is not more indented than previous line(s) closes the parentheses of all previous lines which have higher or equal indentation</b>. You should only reduce the indentation to indentation levels which were already used by parent lines, else the behaviour is undefined. +</p> + +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #0000ff;">display</span> <span style="color: #898887;">; </span><span style="color: #898887;">(display</span> +<span style="color: #0000ff;"> string-append</span> <span style="color: #C33;">"Hello "</span> <span style="color: #C33;">"World!"</span> <span style="color: #898887;">; </span><span style="color: #898887;">(string-append "Hello " "World!"))</span> +<span style="color: #0000ff;">display</span> <span style="color: #C33;">"Hello Again!"</span> <span style="color: #898887;">; </span><span style="color: #898887;">(display "Hello Again!")</span> +</pre> +</div> +</div> +</div> + +<div id="outline-container-sec-4-2-4" class="outline-4"> +<h4 id="sec-4-2-4"><span class="section-number-4">4.2.4</span> Prefixed line</h4> +<div class="outline-text-4" id="text-4-2-4"> +<p> +<b>To add any of ' , ` #' #, #` or #@, to the first parenthesis on a line, just prefix the line with that symbol</b> followed by at least one space. Implementations are free to add more prefix symbols. +</p> + +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #0000ff;">'</span> <span style="color: #C33;">"Hello World!"</span> <span style="color: #898887;">; </span><span style="color: #898887;">'("Hello World!")</span> +</pre> +</div> +</div> +</div> + + +<div id="outline-container-sec-4-2-5" class="outline-4"> +<h4 id="sec-4-2-5"><span class="section-number-4">4.2.5</span> Continuing line</h4> +<div class="outline-text-4" id="text-4-2-5"> +<p> +<b>A line whose first non-whitespace characters is a dot followed by a space (". ") does not open a new parenthesis: it is treated as simple continuation of the first less indented previous line</b>. In the first line this means that this line does not start with a parenthesis and does not end with a parenthesis, just as if you had directly written it in lisp without the leading ". ". +</p> + +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #0000ff;">string-append</span> <span style="color: #C33;">"Hello"</span> <span style="color: #898887;">; </span><span style="color: #898887;">(string-append "Hello"</span> +<span style="color: #0000ff;"> string-append</span> <span style="color: #C33;">" "</span> <span style="color: #C33;">"World"</span> <span style="color: #898887;">; </span><span style="color: #898887;">(string-append " " "World")</span> +<span style="color: #a020f0;"> . </span><span style="color: #C33;">"!"</span> <span style="color: #898887;">; </span><span style="color: #898887;">"!")</span> +</pre> +</div> +</div> +</div> + + +<div id="outline-container-sec-4-2-6" class="outline-4"> +<h4 id="sec-4-2-6"><span class="section-number-4">4.2.6</span> Empty indentation level</h4> +<div class="outline-text-4" id="text-4-2-6"> +<p> +<b>A line which contains only whitespace and a colon (":") defines an indentation level at the indentation of the colon</b>. It opens a parenthesis which gets closed by the next line which has less or equal indentation. If you need to use a colon by itself. you can escape it as "\:". +</p> + +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #483d8b;">let</span> <span style="color: #898887;">; </span><span style="color: #898887;">(let</span> +<span style="color: #a020f0;"> : </span> <span style="color: #898887;">; </span><span style="color: #898887;">(</span> +<span style="color: #0000ff;"> msg</span> <span style="color: #C33;">"Hello World!"</span> <span style="color: #898887;">; </span><span style="color: #898887;">(msg "Hello World!"))</span> +<span style="color: #0000ff;"> display</span> msg <span style="color: #898887;">; </span><span style="color: #898887;">(display msg))</span> +</pre> +</div> +</div> +</div> + + +<div id="outline-container-sec-4-2-7" class="outline-4"> +<h4 id="sec-4-2-7"><span class="section-number-4">4.2.7</span> Inline Colon</h4> +<div class="outline-text-4" id="text-4-2-7"> +<p> +<b>A colon sourrounded by whitespace (" : ") starts a parenthesis which gets closed at the end of the line</b>. +</p> + +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">hello</span> who <span style="color: #898887;">; </span><span style="color: #898887;">(define (hello who)</span> +<span style="color: #0000ff;"> display</span> <span style="color: #898887;">; </span><span style="color: #898887;">(display </span> +<span style="color: #0000ff;"> string-append</span> <span style="color: #C33;">"Hello "</span> who <span style="color: #C33;">"!"</span> <span style="color: #898887;">; </span><span style="color: #898887;">(string-append "Hello " who "!")))</span> +</pre> +</div> + +<p> +If the colon starts a line which also contains other non-whitespace characters, it starts a parenthesis which gets closed at the end of the line <b>and</b> defines an indentation level at the position of the colon. +</p> + +<p> +If the colon is the last non-whitespace character on a line, it represents an empty pair of parentheses: +</p> + +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #483d8b;">let</span><span style="color: #a020f0;"> : </span> <span style="color: #898887;">; </span><span style="color: #898887;">(let ()</span> +<span style="color: #0000ff;"> display</span> <span style="color: #C33;">"Hello"</span> <span style="color: #898887;">; </span><span style="color: #898887;">(display "Hello"))</span> +</pre> +</div> +</div> +</div> + +<div id="outline-container-sec-4-2-8" class="outline-4"> +<h4 id="sec-4-2-8"><span class="section-number-4">4.2.8</span> Initial Underscores</h4> +<div class="outline-text-4" id="text-4-2-8"> +<p> +<b>You can replace any number of consecutive initial spaces by underscores</b>, as long as at least one whitespace is left between the underscores and any following character. You can escape initial underscores by prefixing the first one with \ ("\___ a" → "(<span class="underline">_</span> a)"), if you have to use them as function names. +</p> + +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">hello</span> who <span style="color: #898887;">; </span><span style="color: #898887;">(define (hello who)</span> +<span style="color: #0000ff;">_ display</span> <span style="color: #898887;">; </span><span style="color: #898887;">(display </span> +<span style="color: #0000ff;">___ string-append</span> <span style="color: #C33;">"Hello "</span> who <span style="color: #C33;">"!"</span> <span style="color: #898887;">; </span><span style="color: #898887;">(string-append "Hello " who "!")))</span> +</pre> +</div> +</div> +</div> + +<div id="outline-container-sec-4-2-9" class="outline-4"> +<h4 id="sec-4-2-9"><span class="section-number-4">4.2.9</span> Parens and Strings</h4> +<div class="outline-text-4" id="text-4-2-9"> +<p> +<b>Linebreaks inside parentheses and strings are not considered linebreaks</b> for parsing indentation. To use parentheses at the beginning of a line without getting double parens, prefix the line with a period. +</p> + +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">stringy</span> s +<span style="color: #0000ff;"> string-append</span> s <span style="color: #C33;">" reversed and capitalized:</span> +<span style="color: #C33;"> "</span> <span style="color: #898887;">; </span><span style="color: #898887;">linebreaks in strings do not affect wisp parsing</span> +<span style="color: #a020f0;"> . </span>(<span style="color: #0000ff;">string-capitalize</span> <span style="color: #898887;">; </span><span style="color: #898887;">same for linebreaks in parentheses</span> +<span style="color: #0000ff;"> (string-reverse</span> s)) +</pre> +</div> + +<p> +Effectively code in parentheses and strings is interpreted directly as Scheme. This way you can simply copy a thunk of scheme into wisp. The following is valid wisp: +</p> + +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #483d8b;">define</span> foo (<span style="color: #0000ff;">+</span> <span style="color: #008b8b;">1</span> +<span style="color: #0000ff;"> (*</span> <span style="color: #008b8b;">2</span> <span style="color: #008b8b;">3</span>)) <span style="color: #898887;">; </span><span style="color: #898887;">defines foo as 7</span> +</pre> +</div> +</div> +</div> +</div> + +<div id="outline-container-sec-4-3" class="outline-3"> +<h3 id="sec-4-3"><span class="section-number-3">4.3</span> Clarifications</h3> +<div class="outline-text-3" id="text-4-3"> +<ul class="org-ul"> +<li>Code-blocks end after 2 empty lines followed by a newline. Indented non-empty lines after 2 empty lines should be treated as error. A line is empty if it only contains whitespace. A line with a comment is never empty. +</li> + +<li>Inside parentheses, wisp parsing is disabled. Consequently linebreaks inside parentheses are not considered linebreaks for wisp-parsing. For the parser everything which happens inside parentheses is treated as a black box. +</li> + +<li>Square brackets and curly braces should be treated the same way as parentheses: They stop the indentation processing until they are closed. +</li> + +<li>Likewise linebreaks inside strings are not considered linebreaks for wisp-parsing. +</li> + +<li>A colon (:) at the beginning of a line adds an extra open parentheses that gets closed at end-of-line (rule 4.2.7) <b>and</b> defines an indentation level. +</li> + +<li>using a quote to escape a symbol separated from it by whitespace is forbidden. This would make the meaning of quoted lines ambigous. +</li> + +<li>Curly braces should be treated as curly-infix following SRFI-105. This makes most math look natural to newcomers. +</li> + +<li>Neoteric expressions from SRFI-105 are not required because they create multiple ways to represent the same code. In wisp they add much less advantages than in sweet expressions from SRFI-110, because wisp can continue the arguments to a function after a function call (with the leading period) and the inline colon provides most of the benefits neoteric expressions give to sweet. However implementations providing wisp should give users the option to activate neoteric expressions as by SRFI-105 to allow experimentation and evolution (<a href="http://sourceforge.net/p/readable/mailman/message/33068104/">discussion</a>). +</li> + +<li>It is possible to write code which is at the same time valid wisp and sweet. The readable mailinglist <a href="http://sourceforge.net/p/readable/mailman/message/33058992/">contains details</a>. +</li> +</ul> +</div> +</div> +</div> + +<div id="outline-container-sec-5" class="outline-2"> +<h2 id="sec-5"><span class="section-number-2">5</span> Syntax justification</h2> +<div class="outline-text-2" id="text-5"> +<p> +<i>I do not like adding any unnecessary syntax element to lisp. So I want to show explicitely why the syntax elements are required.</i> +</p> + +<small> +<p> +See also <a href="http://draketo.de/light/english/wisp-lisp-indentation-preprocessor#sec-4">http://draketo.de/light/english/wisp-lisp-indentation-preprocessor#sec-4</a> +</p> +</small> +</div> + + +<div id="outline-container-sec-5-1" class="outline-3"> +<h3 id="sec-5-1"><span class="section-number-3">5.1</span> . (the dot)</h3> +<div class="outline-text-3" id="text-5-1"> +<p> +To represent general code trees, we have to be able to represent continuation of the arguments of a function with an intermediate call to another (or the same) function. +</p> + +<p> +The dot at the beginning of the line as marker of the continuation of a variable list is a generalization of using the dot as identity function - which is an implementation detail in many lisps. +</p> + +<blockquote> +<p> +<code>(. a)</code> is just <code>a</code> +</p> +</blockquote> + +<p> +So for the single variable case, this would not even need additional parsing: wisp could just parse <code>. a</code> to <code>(. a)</code> and produce the correct result in most lisps. But forcing programmers to always use separate lines for each parameter would be very inconvenient, so the definition of the dot at the beginning of the line is extended to mean “take every element in this line as parameter to the parent function”. +</p> + +<blockquote> +<p> +<code>(. a)</code> → <code>a</code> is generalized to <code>(. a b c)</code> → <code>a b c</code>. +</p> +</blockquote> + +<p> +At its core, this dot-rule means that we mark variables in the code instead of function calls. We do so, because variables at the beginning of a line are much rarer in Scheme than in other programming languages. +</p> +</div> +</div> + +<div id="outline-container-sec-5-2" class="outline-3"> +<h3 id="sec-5-2"><span class="section-number-3">5.2</span> : (the colon)</h3> +<div class="outline-text-3" id="text-5-2"> +<p> +For double parentheses and for some other cases we must have a way to mark indentation levels which do not contain code. Wisp uses the colon, because it is the most common non-alpha-numeric character in normal prose which is not already reserved as syntax by Scheme when it is surrounded by whitespace, and because it already gets used without sourrounding whitespace for marking keyword arguments to functions in Emacs Lisp and Common Lisp, so it does not add completely alien concepts. +</p> + +<p> +The inline function call via inline " : " is a limited generalization of using the colon to mark an indentation level: If we add a syntax-element, we should use it as widely as possible to justify adding syntax overhead. +</p> + +<p> +But if you need to use <code>:</code> as variable or function name, you can still do so by escaping it with a backslash (<code>\:</code>), so this does not forbid using the character. +</p> + +<p> +For simple cases, the colon could be replaced by clever whitespace parsing, but there are complex cases which make this impossible. The minimal example is a theoretical doublelet which does not require a body:<sup><a id="fnr.6" name="fnr.6" class="footref" href="#fn.6">6</a></sup> +</p> + +<div class="org-src-container"> + +<pre class="src src-scheme">(doublelet + ((foo bar)) + ((bla foo))) +</pre> +</div> + +<p> +The wisp version of this is +</p> + +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #0000ff;">doublelet</span> +<span style="color: #a020f0;"> :</span> +<span style="color: #0000ff;"> foo</span> bar +<span style="color: #a020f0;"> : </span><span style="color: #898887;">; </span><span style="color: #898887;"><- this empty backstep is the real issue</span> +<span style="color: #0000ff;"> bla</span> foo +</pre> +</div> + +<p> +or shorter with inline colon (which you can use only if you don’t need further indentation-syntax inside the assignment). +</p> + +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #0000ff;">doublelet</span> +<span style="color: #a020f0;"> : </span><span style="color: #0000ff;">foo</span> bar +<span style="color: #a020f0;"> : </span><span style="color: #0000ff;">bla</span> foo +</pre> +</div> + +<p> +The need to be able to represent arbitrary syntax trees which can contain expressions like this is the real reason, why the colon exists. The inline and start-of-line use is only a generalization of that principle (we add a syntax-element, so we should see how far we can push it to reduce the effective cost of introducing the additional syntax). +</p> +</div> + +<div id="outline-container-sec-5-2-1" class="outline-4"> +<h4 id="sec-5-2-1"><span class="section-number-4">5.2.1</span> Clever whitespace-parsing which would not work</h4> +<div class="outline-text-4" id="text-5-2-1"> +<p> +There are two alternative ways to tackle this issue: deferred level-definition and fixed-width indentation. +</p> + +<p> +Defining intermediate indentation-levels by later elements (deferred definition) would be a problem, because it would create code which is really hard to understand. An example is the following: +</p> + +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #483d8b;">define</span> (<span style="color: #0000ff;">flubb</span>) +<span style="color: #0000ff;"> nubb</span> +<span style="color: #0000ff;"> hubb</span> +<span style="color: #0000ff;"> subb</span> +<span style="color: #0000ff;"> gam</span> +</pre> +</div> + +<p> +would become +</p> + +<div class="org-src-container"> + +<pre class="src src-scheme">(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">flubb</span>) + ((nubb)) + ((hubb)) + ((subb)) + (gam)) +</pre> +</div> + +<p> +while +</p> + +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #483d8b;">define</span> (<span style="color: #0000ff;">flubb</span>) +<span style="color: #0000ff;"> nubb</span> +<span style="color: #0000ff;"> hubb</span> +<span style="color: #0000ff;"> subb</span> +</pre> +</div> + +<p> +would become +</p> + +<div class="org-src-container"> + +<pre class="src src-scheme">(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">flubb</span>) + (nubb) + (hubb) + (subb)) +</pre> +</div> + +<p> +Knowledge of later parts of the code would be necessary to understand the parts a programmer is working on at the moment. This would call for subtle errors which would be hard to track down, because the effect of a change in code would not be localized at the point where the change is done but could propagate backwards. +</p> + +<p> +Fixed indentation width (alternative option to inferring it from later lines) would make it really hard to write readable code. Stuff like this would not be possible: +</p> + +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #483d8b;">when</span> +<span style="color: #0000ff;"> equal?</span> wrong +<span style="color: #0000ff;"> isright?</span> stuff +<span style="color: #0000ff;"> fixstuff</span> +</pre> +</div> +</div> +</div> +</div> + +<div id="outline-container-sec-5-3" class="outline-3"> +<h3 id="sec-5-3"><span class="section-number-3">5.3</span> _ (the underscore)</h3> +<div class="outline-text-3" id="text-5-3"> +<p> +In Python the whitespace hostile html already presents problems with sharing code - for example in email list archives and forums. But Python-programmers can mostly infer the indentation by looking at the previous line: If that ends with a colon, the next line must be more indented (there is nothing to clearly mark reduced indentation, though). In wisp we do not have this support, so we need a way to survive in the hostile environment of todays web. +</p> + +<p> +The underscore is commonly used to denote a space in URLs, where spaces are inconvenient, but it is rarely used in Scheme (where the dash ("-") is mostly used instead), so it seems like a a natural choice. +</p> + +<p> +You can still use underscores anywhere but at the beginning of the line, and even at the beginning of the line you simply need to escape it by prefixing the first underscore with a backslash ("\____"). +</p> +</div> +</div> +</div> + +<div id="outline-container-sec-6" class="outline-2"> +<h2 id="sec-6"><span class="section-number-2">6</span> Implementation</h2> +<div class="outline-text-2" id="text-6"> +<p> +This reference implementation realizes a specialized parser for Scheme. It uses GNU Guile and can also be used at the REPL. +</p> + +<p> +The wisp code also contains a general wisp-preprocessor which can be used for any lisp-like language and can used as an external program which gets called on reading. It does not actually have to understand the code itself. This is not part of this SRFI, though. +</p> + +<p> +To allow for easy re-implementation, the chapter after the implementation itself contains a test-suite with commonly used wisp constructs and parenthesized counterparts. +</p> + +<p> +The wisp preprocessor implementation can be found at <a href="http://draketo.de/proj/wisp">http://draketo.de/proj/wisp</a>. Both implementations are explicitly licensed to allow inclusion in an SRFI. +</p> +</div> + +<div id="outline-container-sec-6-1" class="outline-3"> +<h3 id="sec-6-1"><span class="section-number-3">6.1</span> The generic wisp processor (code)</h3> +<div class="outline-text-3" id="text-6-1"> +<p> +TODO: Include the code from <a href="http://draketo.de/proj/wisp">http://draketo.de/proj/wisp</a> +</p> +</div> +</div> + +<div id="outline-container-sec-6-2" class="outline-3"> +<h3 id="sec-6-2"><span class="section-number-3">6.2</span> Test Suite</h3> +<div class="outline-text-3" id="text-6-2"> +<p> +The wisp test-suite consists of a large number of wisp-snippets and the corresponding scheme-code. +</p> + +<p> +A wisp-implementation may call itself compliant with the wisp test-suite if the code tree parsed from the wisp file is the same as a code tree parsed from the equivalent Scheme file. +</p> + +<p> +A wisp-implementation may call itself a compliant wisp pre-processor if it successfully converts each wisp-snippet into the corresponging scheme-snippet. Blank lines at the end of the file and non-functional white-space in the produced scheme-file do not matter for this purpose. +</p> + +<p> +This test-suite is also available in the <a href="http://draketo.de/proj/wisp">wisp repository</a> along with a script-runner (runtests.sh) which tests the reference wisp-implementation with GNU Guile against this testsuite.<sup><a id="fnr.7" name="fnr.7" class="footref" href="#fn.7">7</a></sup> +</p> +</div> + +<div id="outline-container-sec-6-2-1" class="outline-4"> +<h4 id="sec-6-2-1"><span class="section-number-4">6.2.1</span> tests/syntax-underscore.w</h4> +<div class="outline-text-4" id="text-6-2-1"> +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">a</span> b c +<span style="color: #0000ff;">_ d</span> e +<span style="color: #0000ff;">___ f</span> +<span style="color: #0000ff;">___</span> g h +<span style="color: #0000ff;">__</span><span style="color: #a020f0;"> . </span>i + +<span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">_</span> +<span style="color: #0000ff;">_ display</span> <span style="color: #C33;">"hello\n"</span> + +<span style="color: #0000ff;">\_</span> +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-6-2-2" class="outline-4"> +<h4 id="sec-6-2-2"><span class="section-number-4">6.2.2</span> tests/syntax-underscore.scm</h4> +<div class="outline-text-4" id="text-6-2-2"> +<div class="org-src-container"> + +<pre class="src src-scheme">(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">a</span> b c) + (d e + (f) + (g h) + i)) + +(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">_</span>) + (display <span style="color: #C33;">"hello\n"</span>)) + +(_) +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-6-2-3" class="outline-4"> +<h4 id="sec-6-2-3"><span class="section-number-4">6.2.3</span> tests/syntax-strings-parens.w</h4> +<div class="outline-text-4" id="text-6-2-3"> +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #898887;">; </span><span style="color: #898887;">Test linebreaks in strings and brackets</span> + +<span style="color: #a020f0;">. </span><span style="color: #C33;">"flubbub</span> + +<span style="color: #C33;">flabbab"</span> + +hrug (<span style="color: #0000ff;">nadda</span> +<span style="color: #0000ff;">madda</span> gadda <span style="color: #C33;">"shoktom</span> +<span style="color: #C33;"> mee"</span> <span style="color: #C33;">" sep </span> +<span style="color: #C33;">ka"</span> +<span style="color: #0000ff;"> hadda)</span> +<span style="color: #0000ff;"> gom</span> + +<span style="color: #0000ff;">flu</span> + +<span style="color: #0000ff;">sum</span> [foo +<span style="color: #0000ff;">bar]</span> barz {1 + [* <span style="color: #008b8b;">2</span> <span style="color: #008b8b;">2</span>]} + +<span style="color: #0000ff;">mara</span> { +<span style="color: #0000ff;">li</span> +<span style="color: #0000ff;">+</span> +<span style="color: #0000ff;">lo</span> - (<span style="color: #0000ff;">mabba</span>) +<span style="color: #0000ff;">}</span> +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-6-2-4" class="outline-4"> +<h4 id="sec-6-2-4"><span class="section-number-4">6.2.4</span> tests/syntax-strings-parens.scm</h4> +<div class="outline-text-4" id="text-6-2-4"> +<div class="org-src-container"> + +<pre class="src src-scheme"><span style="color: #898887;">; </span><span style="color: #898887;">Test linebreaks in strings and brackets</span> + +<span style="color: #C33;">"flubbub</span> + +<span style="color: #C33;">flabbab"</span> + +(hrug (nadda +madda gadda <span style="color: #C33;">"shoktom</span> +<span style="color: #C33;"> mee"</span> <span style="color: #C33;">" sep </span> +<span style="color: #C33;">ka"</span> + hadda) + (gom)) + +(flu) + +(sum [foo +bar] barz {1 + [* 2 2]}) + +(mara { +li ++ +lo - (mabba) +}) +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-6-2-5" class="outline-4"> +<h4 id="sec-6-2-5"><span class="section-number-4">6.2.5</span> tests/syntax-indent.w</h4> +<div class="outline-text-4" id="text-6-2-5"> +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #483d8b;">define</span> +<span style="color: #0000ff;"> hello</span> who +<span style="color: #0000ff;"> format</span> <span style="color: #008b8b;">#t</span> <span style="color: #C33;">"Hello ~A\n"</span> who + +<span style="color: #483d8b;">define</span> + <span style="color: #483d8b;">let</span> +<span style="color: #a020f0;"> :</span> +<span style="color: #0000ff;"> a</span> <span style="color: #008b8b;">1</span> +<span style="color: #0000ff;"> b</span> <span style="color: #008b8b;">2</span> +<span style="color: #0000ff;"> c</span> <span style="color: #008b8b;">3</span> +<span style="color: #0000ff;"> format</span> <span style="color: #008b8b;">#t</span> <span style="color: #C33;">"a: ~A, b: ~A, c: ~A"</span> +<span style="color: #0000ff;"> +</span> a <span style="color: #008b8b;">2</span> +<span style="color: #a020f0;"> . </span> b c +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-6-2-6" class="outline-4"> +<h4 id="sec-6-2-6"><span class="section-number-4">6.2.6</span> tests/syntax-indent.scm</h4> +<div class="outline-text-4" id="text-6-2-6"> +<div class="org-src-container"> + +<pre class="src src-scheme">(<span style="color: #a020f0;">define</span> + (hello who) + (format #t <span style="color: #C33;">"Hello ~A\n"</span> who)) + +(<span style="color: #a020f0;">define</span> + (<span style="color: #a020f0;">let</span> + ( + (a 1) + (b 2) + (c 3)) + (format #t <span style="color: #C33;">"a: ~A, b: ~A, c: ~A"</span> + (+ a 2) + b c))) +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-6-2-7" class="outline-4"> +<h4 id="sec-6-2-7"><span class="section-number-4">6.2.7</span> tests/syntax-empty.w</h4> +<div class="outline-text-4" id="text-6-2-7"> +<div class="org-src-container"> + +<pre class="src src-wisp"></pre> +</div> +</div> +</div> +<div id="outline-container-sec-6-2-8" class="outline-4"> +<h4 id="sec-6-2-8"><span class="section-number-4">6.2.8</span> tests/syntax-empty.scm</h4> +<div class="outline-text-4" id="text-6-2-8"> +<div class="org-src-container"> + +<pre class="src src-scheme"></pre> +</div> +</div> +</div> +<div id="outline-container-sec-6-2-9" class="outline-4"> +<h4 id="sec-6-2-9"><span class="section-number-4">6.2.9</span> tests/syntax-dot.w</h4> +<div class="outline-text-4" id="text-6-2-9"> +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">foo</span> +<span style="color: #a020f0;"> . </span><span style="color: #C33;">"bar"</span> + +<span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">bar</span> +<span style="color: #0000ff;"> '</span> <span style="color: #008b8b;">1</span> +<span style="color: #a020f0;"> . . </span><span style="color: #008b8b;">2</span> <span style="color: #898887;">; </span><span style="color: #898887;">pair</span> + +<span style="color: #0000ff;">display</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">foo</span> +<span style="color: #0000ff;">newline</span> +<span style="color: #0000ff;">display</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">bar</span> +<span style="color: #0000ff;">newline</span> +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-6-2-10" class="outline-4"> +<h4 id="sec-6-2-10"><span class="section-number-4">6.2.10</span> tests/syntax-dot.scm</h4> +<div class="outline-text-4" id="text-6-2-10"> +<div class="org-src-container"> + +<pre class="src src-scheme">(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">foo</span>) + <span style="color: #C33;">"bar"</span>) + +(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">bar</span>) + '(1 + . 2 ))<span style="color: #898887;">; </span><span style="color: #898887;">pair</span> + +(display (foo)) +(newline) +(display (bar)) +(newline) +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-6-2-11" class="outline-4"> +<h4 id="sec-6-2-11"><span class="section-number-4">6.2.11</span> tests/syntax-colon.w</h4> +<div class="outline-text-4" id="text-6-2-11"> +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #483d8b;">let</span> +<span style="color: #a020f0;"> :</span> +<span style="color: #0000ff;"> a</span> <span style="color: #008b8b;">1</span> +<span style="color: #0000ff;"> b</span> <span style="color: #008b8b;">2</span> + <span style="color: #483d8b;">let</span> +<span style="color: #a020f0;"> :</span> +<span style="color: #a020f0;"> :</span> +<span style="color: #a020f0;"> . </span>c <span style="color: #008b8b;">3</span> +<span style="color: #0000ff;"> format</span> <span style="color: #008b8b;">#t</span> <span style="color: #C33;">"a: ~A, b: ~A, c: ~A"</span> +<span style="color: #a020f0;"> . </span> a b c + +<span style="color: #a020f0;">: </span>a + +<span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">hello</span> +<span style="color: #0000ff;"> display</span> <span style="color: #C33;">"hello\n"</span> + +<span style="color: #483d8b;">let</span> +<span style="color: #a020f0;"> : </span><span style="color: #0000ff;">a</span> <span style="color: #008b8b;">1</span> +<span style="color: #0000ff;"> b</span> <span style="color: #008b8b;">2</span> +<span style="color: #0000ff;"> format</span> <span style="color: #008b8b;">#t</span> <span style="color: #C33;">"a: ~A, b: ~A"</span> +<span style="color: #a020f0;"> . </span> a b + +<span style="color: #483d8b;">let</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">:</span> a ' : + +<span style="color: #483d8b;">let</span> +<span style="color: #a020f0;"> : </span> <span style="color: #898887;">; </span><span style="color: #898887;">foo</span> +<span style="color: #0000ff;"> a</span> + ' + +<span style="color: #a020f0;">:</span> + a + +<span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">\:</span> +<span style="color: #0000ff;"> hello</span> + +<span style="color: #0000ff;">\:</span> +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-6-2-12" class="outline-4"> +<h4 id="sec-6-2-12"><span class="section-number-4">6.2.12</span> tests/syntax-colon.scm</h4> +<div class="outline-text-4" id="text-6-2-12"> +<div class="org-src-container"> + +<pre class="src src-scheme">(<span style="color: #a020f0;">let</span> + ( + (a 1) + (b 2)) + (<span style="color: #a020f0;">let</span> + ( + ( + c 3)) + (format #t <span style="color: #C33;">"a: ~A, b: ~A, c: ~A"</span> + a b c))) + +((a)) + +(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">hello</span>) + (display <span style="color: #C33;">"hello\n"</span>)) + +(<span style="color: #a020f0;">let</span> + ((a 1) + (b 2)) + (format #t <span style="color: #C33;">"a: ~A, b: ~A"</span> + a b)) + +(<span style="color: #a020f0;">let</span> ((a '()))) + +(<span style="color: #a020f0;">let</span> + ( <span style="color: #898887;">; </span><span style="color: #898887;">foo</span> + (a + '()))) + +( + (a)) + +(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">:</span>) + (hello)) + +(:) +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-6-2-13" class="outline-4"> +<h4 id="sec-6-2-13"><span class="section-number-4">6.2.13</span> tests/sublist.w</h4> +<div class="outline-text-4" id="text-6-2-13"> +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #898887;">; </span><span style="color: #898887;">sublists allow to start single line function calls with a colon ( : ).</span> + +<span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">a</span> b c + <span style="color: #483d8b;">let</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">:</span> e<span style="color: #a020f0;"> . </span>f +<span style="color: #a020f0;"> . </span>g +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-6-2-14" class="outline-4"> +<h4 id="sec-6-2-14"><span class="section-number-4">6.2.14</span> tests/sublist.scm</h4> +<div class="outline-text-4" id="text-6-2-14"> +<div class="org-src-container"> + +<pre class="src src-scheme"><span style="color: #898887;">; </span><span style="color: #898887;">sublists allow to start single line function calls with a colon ( : ).</span> + +(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">a</span> b c) + (<span style="color: #a020f0;">let</span> ((e . f)) + g)) +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-6-2-15" class="outline-4"> +<h4 id="sec-6-2-15"><span class="section-number-4">6.2.15</span> tests/hashbang.w</h4> +<div class="outline-text-4" id="text-6-2-15"> +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #898887;">#!/usr/bin/wisp.py # !#</span> +<span style="color: #898887;">; </span><span style="color: #898887;">This tests hashbang lines</span> +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-6-2-16" class="outline-4"> +<h4 id="sec-6-2-16"><span class="section-number-4">6.2.16</span> tests/hashbang.scm</h4> +<div class="outline-text-4" id="text-6-2-16"> +<div class="org-src-container"> + +<pre class="src src-scheme">#!/usr/bin/wisp.py # !# +<span style="color: #898887;">; </span><span style="color: #898887;">This tests hashbang lines</span> +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-6-2-17" class="outline-4"> +<h4 id="sec-6-2-17"><span class="section-number-4">6.2.17</span> tests/readable-tests.w</h4> +<div class="outline-text-4" id="text-6-2-17"> +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">fibfast</span> n + <span style="color: #483d8b;">if</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;"><</span> n <span style="color: #008b8b;">2</span> +<span style="color: #a020f0;"> . </span>n +<span style="color: #0000ff;"> fibup</span> n <span style="color: #008b8b;">2</span> <span style="color: #008b8b;">1</span> <span style="color: #008b8b;">0</span> + +<span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">fibup</span> maxnum count n-1 n-2 + <span style="color: #483d8b;">if</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">=</span> maxnum count +<span style="color: #0000ff;"> +</span> n-1 n-2 +<span style="color: #0000ff;"> fibup</span> maxnum +<span style="color: #0000ff;"> +</span> count <span style="color: #008b8b;">1</span> +<span style="color: #0000ff;"> +</span> n-1 n-2 +<span style="color: #a020f0;"> . </span>n-1 + +<span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">factorial</span> n + <span style="color: #483d8b;">if</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;"><=</span> n <span style="color: #008b8b;">1</span> +<span style="color: #a020f0;"> . </span><span style="color: #008b8b;">1</span> +<span style="color: #0000ff;"> *</span> n +<span style="color: #0000ff;"> factorial</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">-</span> n <span style="color: #008b8b;">1</span> + +<span style="color: #483d8b;">define</span> (<span style="color: #0000ff;">gcd</span> x y) + <span style="color: #483d8b;">if</span> (<span style="color: #0000ff;">=</span> y <span style="color: #008b8b;">0</span>) +<span style="color: #a020f0;"> . </span>x +<span style="color: #0000ff;"> gcd</span> y +<span style="color: #0000ff;"> rem</span> x y + +<span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">add-if-all-numbers</span> lst +<span style="color: #0000ff;"> call/cc</span> +<span style="color: #0000ff;"> lambda</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">exit</span> + <span style="color: #483d8b;">let</span> loop +<span style="color: #a020f0;"> : </span> +<span style="color: #0000ff;"> lst</span> lst +<span style="color: #0000ff;"> sum</span> <span style="color: #008b8b;">0</span> + <span style="color: #483d8b;">if</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">null?</span> lst +<span style="color: #a020f0;"> . </span>sum + <span style="color: #483d8b;">if</span><span style="color: #a020f0;"> : </span><span style="color: #483d8b;">not</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">number?</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">car</span> lst +<span style="color: #0000ff;"> exit</span> <span style="color: #008b8b;">#f</span> +<span style="color: #0000ff;"> +</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">car</span> lst +<span style="color: #0000ff;"> loop</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">cdr</span> lst +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-6-2-18" class="outline-4"> +<h4 id="sec-6-2-18"><span class="section-number-4">6.2.18</span> tests/readable-tests.scm</h4> +<div class="outline-text-4" id="text-6-2-18"> +<div class="org-src-container"> + +<pre class="src src-scheme">(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">fibfast</span> n) + (<span style="color: #a020f0;">if</span> (< n 2)) + n + (fibup n 2 1 0 )) + +(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">fibup</span> maxnum count n-1 n-2) + (<span style="color: #a020f0;">if</span> (= maxnum count) + (+ n-1 n-2) + (fibup maxnum + (+ count 1 ) + (+ n-1 n-2 ) + n-1))) + +(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">factorial</span> n) + (<span style="color: #a020f0;">if</span> (<= n 1) + 1 + (* n + (factorial (- n 1))))) + +(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">gcd</span> x y) + (<span style="color: #a020f0;">if</span> (= y 0)) + x + (gcd y + (rem x y))) + +(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">add-if-all-numbers</span> lst) + (<span style="color: #a020f0;">call/cc</span> + (<span style="color: #a020f0;">lambda</span> (exit) + (<span style="color: #a020f0;">let</span> <span style="color: #0000ff;">loop</span> + ( + (lst lst ) + (sum 0)) + (<span style="color: #a020f0;">if</span> (null? lst) + sum + (<span style="color: #a020f0;">if</span> (not (number? (car lst))) + (exit #f) + (+ (car lst) + (loop (cdr lst))))))))) +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-6-2-19" class="outline-4"> +<h4 id="sec-6-2-19"><span class="section-number-4">6.2.19</span> tests/quotecolon.w</h4> +<div class="outline-text-4" id="text-6-2-19"> +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #898887;">#!/home/arne/wisp/wisp-multiline.sh </span> +<span style="color: #898887;">; </span><span style="color: #898887;">!#</span> +<span style="color: #483d8b;">define</span> a <span style="color: #008b8b;">1</span> <span style="color: #898887;">; </span><span style="color: #898887;">test whether ' : correctly gets turned into '(</span> +<span style="color: #898887;">; </span><span style="color: #898887;">and whether brackets in commments are treated correctly.</span> + +<span style="color: #483d8b;">define</span> a '<span style="color: #a020f0;"> : </span><span style="color: #0000ff;">1</span> <span style="color: #008b8b;">2</span> <span style="color: #008b8b;">3</span> + +<span style="color: #483d8b;">define</span> +<span style="color: #0000ff;"> a</span> b +<span style="color: #0000ff;"> c</span> +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-6-2-20" class="outline-4"> +<h4 id="sec-6-2-20"><span class="section-number-4">6.2.20</span> tests/quotecolon.scm</h4> +<div class="outline-text-4" id="text-6-2-20"> +<div class="org-src-container"> + +<pre class="src src-scheme">#!/home/arne/wisp/wisp-multiline.sh +<span style="color: #898887;">; </span><span style="color: #898887;">!#</span> +(<span style="color: #a020f0;">define</span> <span style="color: #0000ff;">a</span> 1 )<span style="color: #898887;">; </span><span style="color: #898887;">test whether ' : correctly gets turned into '(</span> +<span style="color: #898887;">; </span><span style="color: #898887;">and whether brackets in commments are treated correctly.</span> + +(<span style="color: #a020f0;">define</span> <span style="color: #0000ff;">a</span> '(1 2 3)) + +(<span style="color: #a020f0;">define</span> + (a b) + (c)) +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-6-2-21" class="outline-4"> +<h4 id="sec-6-2-21"><span class="section-number-4">6.2.21</span> tests/namedlet.w</h4> +<div class="outline-text-4" id="text-6-2-21"> +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #898887;">#!/home/arne/wisp/wisp-multiline.sh </span> +<span style="color: #898887;">; </span><span style="color: #898887;">!#</span> +<span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">hello</span> who +<span style="color: #0000ff;"> display</span> who + +<span style="color: #483d8b;">let</span> hello +<span style="color: #a020f0;"> : </span><span style="color: #0000ff;">who</span> <span style="color: #008b8b;">0</span> + <span style="color: #483d8b;">if</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">=</span> who <span style="color: #008b8b;">5</span> +<span style="color: #0000ff;"> display</span> who +<span style="color: #0000ff;"> hello</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">+</span> <span style="color: #008b8b;">1</span> who +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-6-2-22" class="outline-4"> +<h4 id="sec-6-2-22"><span class="section-number-4">6.2.22</span> tests/namedlet.scm</h4> +<div class="outline-text-4" id="text-6-2-22"> +<div class="org-src-container"> + +<pre class="src src-scheme">#!/home/arne/wisp/wisp-multiline.sh +<span style="color: #898887;">; </span><span style="color: #898887;">!#</span> +(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">hello</span> who) + (display who)) + +(<span style="color: #a020f0;">let</span> <span style="color: #0000ff;">hello</span> + ((who 0)) + (<span style="color: #a020f0;">if</span> (= who 5) + (display who) + (hello (+ 1 who)))) +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-6-2-23" class="outline-4"> +<h4 id="sec-6-2-23"><span class="section-number-4">6.2.23</span> tests/flexible-parameter-list.w</h4> +<div class="outline-text-4" id="text-6-2-23"> +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #898887;">; </span><span style="color: #898887;">Test using a . as first parameter on a line by prefixing it with a second .</span> +<span style="color: #483d8b;">define</span> +<span style="color: #0000ff;"> a</span> i +<span style="color: #a020f0;"> . . </span>b +<span style="color: #0000ff;"> unless</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">>=</span> i<span style="color: #a020f0;"> : </span><span style="color: #0000ff;">length</span> b +<span style="color: #0000ff;"> display</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">number->string</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">length</span> b +<span style="color: #0000ff;"> display</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">list-ref</span> b i +<span style="color: #0000ff;"> newline</span> +<span style="color: #0000ff;"> apply</span> a ( <span style="color: #0000ff;">+</span> i <span style="color: #008b8b;">1</span> ) b + + +<span style="color: #0000ff;">a</span> <span style="color: #008b8b;">0</span> <span style="color: #C33;">"123"</span> <span style="color: #C33;">"345"</span> <span style="color: #C33;">"567"</span> +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-6-2-24" class="outline-4"> +<h4 id="sec-6-2-24"><span class="section-number-4">6.2.24</span> tests/flexible-parameter-list.scm</h4> +<div class="outline-text-4" id="text-6-2-24"> +<div class="org-src-container"> + +<pre class="src src-scheme"><span style="color: #898887;">; </span><span style="color: #898887;">Test using a . as first parameter on a line by prefixing it with a second .</span> +(<span style="color: #a020f0;">define</span> + (a i + . b) + (unless (>= i (length b)) + (display (number->string (length b ))) + (display (list-ref b i)) + (newline) + (apply a ( + i 1 ) b))) + + +(a 0 <span style="color: #C33;">"123"</span> <span style="color: #C33;">"345"</span> <span style="color: #C33;">"567"</span>) +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-6-2-25" class="outline-4"> +<h4 id="sec-6-2-25"><span class="section-number-4">6.2.25</span> tests/factorial.w</h4> +<div class="outline-text-4" id="text-6-2-25"> +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #898887;">;; </span><span style="color: #898887;">short version</span> +<span style="color: #898887;">; </span><span style="color: #898887;">note: once you use one inline colon, all the following forms on that</span> +<span style="color: #898887;">; </span><span style="color: #898887;">line will get closed at the end of the line</span> + +<span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">factorial</span> n + <span style="color: #483d8b;">if</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">zero?</span> n +<span style="color: #a020f0;"> . </span><span style="color: #008b8b;">1</span> +<span style="color: #0000ff;"> *</span> n<span style="color: #a020f0;"> : </span><span style="color: #0000ff;">factorial</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">-</span> n <span style="color: #008b8b;">1</span> + +<span style="color: #0000ff;">display</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">factorial</span> <span style="color: #008b8b;">5</span> + + +<span style="color: #898887;">;; </span><span style="color: #898887;">more vertical space, less colons</span> +<span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">factorial</span> n + <span style="color: #483d8b;">if</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">zero?</span> n +<span style="color: #a020f0;"> . </span><span style="color: #008b8b;">1</span> +<span style="color: #0000ff;"> *</span> n +<span style="color: #0000ff;"> factorial</span> +<span style="color: #0000ff;"> -</span> n <span style="color: #008b8b;">1</span> + +<span style="color: #0000ff;">display</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">factorial</span> <span style="color: #008b8b;">5</span> +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-6-2-26" class="outline-4"> +<h4 id="sec-6-2-26"><span class="section-number-4">6.2.26</span> tests/factorial.scm</h4> +<div class="outline-text-4" id="text-6-2-26"> +<div class="org-src-container"> + +<pre class="src src-scheme"><span style="color: #898887;">;; </span><span style="color: #898887;">short version</span> +<span style="color: #898887;">; </span><span style="color: #898887;">note: once you use one inline colon, all the following forms on that</span> +<span style="color: #898887;">; </span><span style="color: #898887;">line will get closed at the end of the line</span> + +(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">factorial</span> n) + (<span style="color: #a020f0;">if</span> (zero? n) + 1 + (* n (factorial (- n 1))))) + +(display (factorial 5 )) + + +<span style="color: #898887;">;; </span><span style="color: #898887;">more vertical space, less colons</span> +(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">factorial</span> n) + (<span style="color: #a020f0;">if</span> (zero? n) + 1 + (* n + (factorial + (- n 1))))) + +(display (factorial 5 )) +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-6-2-27" class="outline-4"> +<h4 id="sec-6-2-27"><span class="section-number-4">6.2.27</span> tests/example.w</h4> +<div class="outline-text-4" id="text-6-2-27"> +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #483d8b;">define</span> (<span style="color: #0000ff;">a</span> b c) + <span style="color: #483d8b;">let</span> +<span style="color: #a020f0;"> : </span> +<span style="color: #0000ff;"> d</span> <span style="color: #C33;">"i am a string</span> +<span style="color: #C33;">do not break me!"</span> +<span style="color: #a020f0;"> : </span> + <span style="color: #898887;">; </span><span style="color: #898887;">comment: 0</span> + f +<span style="color: #898887;">; </span><span style="color: #898887;">comment : 1</span> +<span style="color: #0000ff;"> `</span> g <span style="color: #898887;">; </span><span style="color: #898887;">comment " : " 2</span> +<span style="color: #a020f0;"> : </span> +<span style="color: #0000ff;"> h</span> (<span style="color: #0000ff;">I</span> am in brackets: +<span style="color: #0000ff;"> do</span> <span style="color: #483d8b;">not</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">change</span> <span style="color: #C33;">"me"</span>) +<span style="color: #a020f0;"> . </span>i +<span style="color: #0000ff;"> ,</span><span style="color: #008b8b;"> 'j</span> k + +<span style="color: #a020f0;"> . </span>l + +<span style="color: #898887;">; </span><span style="color: #898887;">comment</span> + +<span style="color: #0000ff;"> a</span> c + +<span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">b</span> :n o +<span style="color: #a020f0;"> . </span><span style="color: #C33;">"second defun : with a docstring!"</span> +<span style="color: #0000ff;"> message</span> <span style="color: #C33;">"I am here"</span> +<span style="color: #a020f0;"> . </span>t + +<span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">c</span> e f +<span style="color: #a020f0;"> : </span><span style="color: #0000ff;">g</span> +<span style="color: #a020f0;"> :</span> +<span style="color: #0000ff;"> h</span> +<span style="color: #0000ff;"> i</span> +<span style="color: #0000ff;"> j</span> +<span style="color: #0000ff;"> '</span> : +<span style="color: #0000ff;"> k</span> +<span style="color: #a020f0;"> . </span>l +<span style="color: #a020f0;"> . </span>: <span style="color: #0000ff;">m</span> + +<span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">_</span> \: +<span style="color: #0000ff;">__</span> +<span style="color: #0000ff;">__</span><span style="color: #a020f0;"> . </span>\: + +<span style="color: #0000ff;">\_</span> b + +<span style="color: #483d8b;">define</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">d</span> + <span style="color: #483d8b;">let</span> +<span style="color: #a020f0;"> : </span><span style="color: #0000ff;">a</span> b +<span style="color: #0000ff;"> c</span> d + +<span style="color: #0000ff;">a</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">:</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">c</span> + +<span style="color: #483d8b;">let</span> +<span style="color: #a020f0;"> : </span><span style="color: #0000ff;">a</span> b + c + +<span style="color: #483d8b;">let</span><span style="color: #a020f0;"> : </span><span style="color: #0000ff;">:</span> a b + +<span style="color: #a020f0;">. </span>a +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-6-2-28" class="outline-4"> +<h4 id="sec-6-2-28"><span class="section-number-4">6.2.28</span> tests/example.scm</h4> +<div class="outline-text-4" id="text-6-2-28"> +<div class="org-src-container"> + +<pre class="src src-scheme">(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">a</span> b c) + (<span style="color: #a020f0;">let</span> + ( + (d <span style="color: #C33;">"i am a string</span> +<span style="color: #C33;">do not break me!"</span>) + ( + <span style="color: #898887;">; </span><span style="color: #898887;">comment: 0</span> + (f) +<span style="color: #898887;">; </span><span style="color: #898887;">comment : 1</span> + `(g ))<span style="color: #898887;">; </span><span style="color: #898887;">comment " : " 2</span> + ( + (h (I am in brackets: + do not : change <span style="color: #C33;">"me"</span>)) + i))) + ,('j k) + + l + +<span style="color: #898887;">; </span><span style="color: #898887;">comment</span> + + (a c)) + +(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">b</span> <span style="color: #483d8b;">:n</span> o) + <span style="color: #C33;">"second defun : with a docstring!"</span> + (message <span style="color: #C33;">"I am here"</span>) + t) + +(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">c</span> e f) + ((g)) + ( + (h + (i)) + (j)) + '(()) + (k) + l + (m)) + +(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">_</span> :) + + :) + +(_ b) + +(<span style="color: #a020f0;">define</span> (<span style="color: #0000ff;">d</span>) + (<span style="color: #a020f0;">let</span> + ((a b) + (c d)))) + +(a (((c)))) + +(<span style="color: #a020f0;">let</span> + ((a b) + (c))) + +(<span style="color: #a020f0;">let</span> ((a b))) + +a +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-6-2-29" class="outline-4"> +<h4 id="sec-6-2-29"><span class="section-number-4">6.2.29</span> tests/continuation.w</h4> +<div class="outline-text-4" id="text-6-2-29"> +<div class="org-src-container"> + +<pre class="src src-wisp"><span style="color: #0000ff;">a</span> b c d e +<span style="color: #a020f0;"> . </span>f g h +<span style="color: #a020f0;"> . </span>i j k + +<span style="color: #0000ff;">concat</span> <span style="color: #C33;">"I want "</span> +<span style="color: #0000ff;"> getwish</span> from me +<span style="color: #a020f0;"> . </span><span style="color: #C33;">" - "</span> username +</pre> +</div> +</div> +</div> +<div id="outline-container-sec-6-2-30" class="outline-4"> +<h4 id="sec-6-2-30"><span class="section-number-4">6.2.30</span> tests/continuation.scm</h4> +<div class="outline-text-4" id="text-6-2-30"> +<div class="org-src-container"> + +<pre class="src src-scheme">(a b c d e + f g h + i j k) + +(concat <span style="color: #C33;">"I want "</span> + (getwish from me) + <span style="color: #C33;">" - "</span> username) +</pre> +</div> +</div> +</div> +</div> +</div> +<div id="outline-container-sec-7" class="outline-2"> +<h2 id="sec-7"><span class="section-number-2">7</span> Copyright</h2> +<div class="outline-text-2" id="text-7"> +<p> +Copyright (C) Arne Babenhauserheide (2013–2014). All Rights Reserved. +</p> + +<p> +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: +</p> + +<p> +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +</p> + +<p> +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. +</p> +</div> +</div> +<div id="footnotes"> +<h2 class="footnotes">Footnotes: </h2> +<div id="text-footnotes"> + +<div class="footdef"><sup><a id="fn.1" name="fn.1" class="footnum" href="#fnr.1">1</a></sup> <p class="footpara"> +The most common non-letter, non-math characters in prose are <code>.,":'_#?!;</code>, in the given order as derived from newspapers and other sources (for the ngram assembling scripts, see the <a href="http://bitbucket.org/ArneBab/evolve-keyboard-layout">evolve keyboard layout project</a>). +</p></div> + +<div class="footdef"><sup><a id="fn.2" name="fn.2" class="footnum" href="#fnr.2">2</a></sup> <p class="footpara"> +Typed Racket uses calls of the form <code>(: x Number)</code> to declare types. These forms can still be used directly in parenthesized form, but in wisp-form the colon has to be replaced with <code>\:</code>. +</p></div> + +<div class="footdef"><sup><a id="fn.3" name="fn.3" class="footnum" href="#fnr.3">3</a></sup> <p class="footpara"> +In most cases type-declarations are not needed in typed racket, since the type can be inferred. See <a href="http://docs.racket-lang.org/ts-guide/more.html?q=typed#(part._when-annotations~3f)">When do you need type annotations?</a> +</p></div> + +<div class="footdef"><sup><a id="fn.4" name="fn.4" class="footnum" href="#fnr.4">4</a></sup> <p class="footpara"> +Conceptually, continuing the argument list with a period uses syntax to mark the rare case of not calling a function as opposed to marking the common case of calling a function. To back the claim, that calling a function is actually the common case in scheme-code, grepping the the modules in the Guile source code shows over 27000 code-lines which start with a paren and only slightly above 10000 code-lines which start with a non-paren, non-comment character. Since wisp-syntax mostly follows the regular scheme indentation guidelines (as realized for example by emacs), the whitespace in front of lines does not need to change. +</p></div> + +<div class="footdef"><sup><a id="fn.5" name="fn.5" class="footnum" href="#fnr.5">5</a></sup> <p class="footpara"> +This special syntax for double parens cannot be replaced by clever whitespace parsing, because it is required for representing two consecutive forms which start with double parentheses. The only pure-whitespace alternative would be fixed-width indentation levels. +</p></div> + +<div class="footdef"><sup><a id="fn.6" name="fn.6" class="footnum" href="#fnr.6">6</a></sup> <p class="footpara"> +The example uses a double let without action as example for the colon-syntax, even though that does nothing, because that makes it impossible to use later indentation to mark an intermediate indentation-level. Another reason why I would not use later indentation to define whether something earlier is a single or double indent is that this would call for subtle and really hard to find errors. +</p></div> + +<div class="footdef"><sup><a id="fn.7" name="fn.7" class="footnum" href="#fnr.7">7</a></sup> <p class="footpara"> +To run the tests in the wisp testsuite with a separately built GNU Guile, you can use any given guile interpreter by adjusting the following command: <code>PATH=~/guile-2.0.11/meta:${PATH} ./runtests.sh</code> +</p></div> + + +</div> +</div></div> +<div id="postamble" class="status"> +<p class="author">Author: Arne Babenhauserheide</p> +<p class="date">Created: 2014-12-23 Di 17:17</p> +<p class="creator"><a href="http://www.gnu.org/software/emacs/">Emacs</a> 24.4.1 (<a href="http://orgmode.org">Org</a> mode 8.2.6)</p> +<p class="validation"><a href="http://validator.w3.org/check?uri=referer">Validate</a></p> +</div> +</body> +</html> diff --git a/docs/srfi.org b/docs/srfi.org --- a/docs/srfi.org +++ b/docs/srfi.org @@ -1,10 +1,12 @@ -#+title: SRFI: wisp: whitespace-to-lisp preprocessing -#+options: toc:nil num:t +#+title: SRFI: wisp: simpler indentation-sensitive scheme +#+options: toc:nil num:t ^:nil + +# wisp: indentation-based scheme project #+BEGIN_ABSTRACT This SRFI describes a simple syntax which allows making scheme easier to read for newcomers while keeping the simplicity, generality and elegance of s-expressions. Similar to SRFI-110, SRFI-49 and Python it uses indentation to group expressions. Like SRFI-110 wisp is general and homoiconic. -Different from its precedessors, wisp only uses the absolute minimum of additional syntax-elements which are required for writing and exchanging arbitrary code-structures. As syntax elements it only uses a colon surrounded by whitespace, the period as first code-character on the line and underscores at the beginning of the line. +Different from its precedessors, wisp only uses the absolute minimum of additional syntax-elements which are required for writing and exchanging arbitrary code-structures. As syntax elements it only uses a colon surrounded by whitespace, the period followed by whitespace as first code-character on the line and optional underscores followed by whitespace at the beginning of the line. It resolves a limitation of SRFI-110 and SRFI-49, both of which force the programmer to use a single argument per line if the arguments to a function need to be continued after a function-call. @@ -15,17 +17,21 @@ Wisp expressions can include any s-expre define : hello who format #t "~A ~A!\n" . "Hello" who + hello "Wisp" #+END_SRC #+html: </td><td> #+BEGIN_SRC scheme (define (hello who) (format #t "~A ~A!\n" - "Hello" who)) + "Hello" who)) + (hello "S-exp") #+END_SRC #+html: </td></tr></table> #+END_ABSTRACT +# to make indentation-based code safe to share in non-whitespace preserving environments + #+toc: headlines 2 * SRFI process :noexport: @@ -78,31 +84,44 @@ Remember, even if a proposal becomes an - Arne Babenhauserheide +** Acknowledgments + +- Thanks for many constructive discussions goes to Alan Manuel K. Gloria and David A. Wheeler. +- Also thanks to Mark Weaver for his help with the wisp parser and the guile integration - including a 20x speedup. + * Related SRFIs - SRFI-49 (Indentation-sensitive syntax): superceded by this SRFI, -- SRFI-110 (Sweet-expressions (t-expressions)): superceded by this SRFI, -- SRFI-105 (neoteric expressions and curly infix): supported by treating curly braces like brackets and parens, and +- SRFI-110 (Sweet-expressions (t-expressions)): alternative to this SRFI, +- SRFI-105 (neoteric expressions and curly infix): supported in this SRFI by treating curly braces like brackets and parentheses. Curly infix is required by the implementation and the testsuite. - SRFI-30 (Nested Multi-line comments): complex interaction. Should be avoided at the beginning of lines, because it can make the indentation hard to distinguish for humans. SRFI-110 includes them, so there might be value in adding them. The wisp reference implementation does not treat them specially, though, which might create arbitrary complications. * Rationale -A big strength of Scheme and other lisp-like languages is their minimalistic syntax. By using only the most common characters like the period, the comma, the quote and quasiquote, the hash, the semicolon and the parens for the syntax[fn:1], they are very close to natural language. Along with the minimal list-structure of the code, this gives these languages a timeless elegance. +A big strength of Scheme and other lisp-like languages is their minimalistic syntax. By using only the most common characters like the period, the comma, the quote and quasiquote, the hash, the semicolon and the parens for the syntax (=.,"'`#;()=), they are very close to natural language[fn:1]. Along with the minimal list-structure of the code, this gives these languages a timeless elegance. -But as SRFI-110 explains very thoroughly (which we need not repeat here), the parentheses at the beginning of lines hurt readability and scare away newcomers. Additionally using indentation to mark the structure of the code follows naturally from the observation that most programmers use indentation, with many programmers actually letting their editor indent code automatically to fit the structure. Indentation is an important way how programmers understand code and using it directly to define the structure avoids errors due to mismatches between indentation and actual meaning. +But as SRFI-110 explains very thoroughly (which we need not repeat here), the parentheses at the beginning of lines hurt readability and scare away newcomers. Additionally using indentation to mark the structure of the code follows naturally from the observation that most programmers use indentation, with many programmers letting their editor indent code automatically to fit the structure. Indentation is an important way how programmers understand code and using it directly to define the structure avoids errors due to mismatches between indentation and actual meaning. -As a solution to this, SRFI-49 and SRFI-110 provide a way to write whitespace sensitive scheme, but both have their share of problems. +As a solution to this, SRFI-49 and SRFI-110 provide a way to write whitespace sensitive scheme, but both have their share of issues. -As noted in SRFI-110, there are a number of implementation-problems in SRFI-49, as well as specification shortcomings like choosing the name “group” for the construct which is necessary to represent double parentheses. Additionally to the problems named in SRFI-110, SRFI-49 is not able to continue the arguments to a function on one line, if a prior argument was a function call. The example code in the abstract would have to be written in SRFI-49 as follows: +As noted in SRFI-110, there are a number of implementation-problems in SRFI-49, as well as specification shortcomings like choosing the name “group” for the construct which is necessary to represent double parentheses. In addition to the problems named in SRFI-110, SRFI-49 is not able to continue the arguments to a function on one line, if a prior argument was a function call. The following example shows the difference between wisp and SRFI-49 for a very simple code snippet: -#+BEGIN_SRC scheme +#+html: <table><tr><th>wisp</th><th>SRFI-49</th></tr><tr><td> +#+BEGIN_SRC wisp + ,* 5 + + 4 3 + . 2 1 +#+END_SRC +#+html: </td><td> +#+BEGIN_SRC wisp ,* 5 + 4 3 2 1 #+END_SRC +#+html: </td></tr></table> -SRFI-110 improves a lot over the implementation of SRFI-49 and resolves the group-naming by introducing 3 different grouping-syntaxes (=$=, =\\= and =<* *>=). These additional syntax-elements however hurt readability for newcomers a lot. They make some code written in SRFI-110 look quite similar to perl and bash: +SRFI-110 improves a lot over the implementation of SRFI-49. It resolves the group-naming and reduces the need to continue the argument-list by introducing 3 different grouping syntaxes (=$=, =\\= and =<* *>=). These additional syntax-elements however hurt readability for newcomers (obviously the authors of SRFI-110 disagree with this assertion. Their view is discussed in SRFI-110 in the section about wisp). The additional syntax elements lead to structures like the following (taken from examples from the readable project): #+BEGIN_SRC scheme myfunction x: \\ original-x @@ -120,21 +139,45 @@ myfunction This is not only hard to read, but also makes it harder to work with the code, because the programmer has to learn these additional syntax elements and keep them in mind before being able to understand the code. -Like SRFI-49 SRFI-110 also cannot continue the argument-list without resorting to single-element lines, though it reduces this problem by advertising the use of neoteric expressions (SRFI-105). +Like SRFI-49 SRFI-110 also cannot continue the argument-list without resorting to single-element lines, though it reduces this problem by the above grouping syntaxes and advertising the use of neoteric expressions from SRFI-105. -Wisp draws on the strength of SRFI-110 but avoids its complexities. It was actually conceived and improved in the discussions within the readable-project which preceded SRFI-110 and there is a comparison between readable in wisp in SRFI-110. +** Wisp example -Like SRFI-110, wisp is general and homoiconic and interacts nicely with SRFI-105 (neoteric expressions and curly infix). Like SRFI-110, the expressions are the same in the REPL and in code-files. +Since an example speaks more than a hundred explanations, the following shows wisp exploiting all its features - including curly-infix from SRFI-105: + +#+BEGIN_SRC wisp +define : factorial n +__ if : zero? n +____ . 1 +____ * n : factorial {n - 1} + +display : factorial 5 +newline +#+END_SRC + +** Advantages of Wisp + +Wisp draws on the strength of SRFI-110 but avoids its complexities. It was conceived and improved in the discussions within the readable-project which preceded SRFI-110 and there is a comparison between readable in wisp in SRFI-110. + +Like SRFI-110, wisp is general and homoiconic and interacts nicely with SRFI-105 (neoteric expressions and curly infix). Like SRFI-110, the expressions are the same in the REPL and in code-files. Like SRFI-110, wisp has been used for implementing multiple smaller programs, though the biggest program in wisp is still its implementations (written in wisp and bootstrapped via a simpler wisp preprocessor). But unlike SRFI-110, wisp only uses the minimum of additional syntax-elements which are necessary to support arbitrary code-structures with indentation-sensitive code which is intended to be shared over the internet. To realize these syntax-elements, it generalizes existing syntax and draws on the most common non-letter non-math characters in prose. This allows keeping the actual representation of the code elegant and inviting to newcomers. +Wisp expressions are not as sweet as [[http://readable.sf.net][readable]], but they KISS. + +** Disadvantages of Wisp + +Using the colon as syntax element keeps the code very close to written prose, but it can interfere with type definitions as for example used in Typed Racket[fn:6]. This can be mitigated in let- and lambda-forms by using the parenthesized form. When doing so, wisp avoids the double-paren for type-declarations and as such makes them easier to catch by eye. For function definitions (the only =define= call where type declarations are needed in typed-racket[fn:7]), a =declare= macro directly before the =define= should work well. + +Using the period to continue the argument list is unusual compared to other languages and as such can lead to errors when trying to return a variable from a procedure and forgetting the period. + * Specification The specification is separated into four parts: A general overview of the syntax, a more detailed description, justifications for each added syntax element and clarifications for technical details. ** Overview -The basic rules for wisp-code can be defined in 4 rules, each of which emerges directly from a requirement: +The basics of wisp syntax can be defined in 4 rules, each of which emerges directly from a requirement: *** Wisp syntax 1/4: function calls @@ -154,6 +197,8 @@ becomes (newline) #+END_SRC +/requirement: call functions without parenthesis./ + *** Wisp syntax 2/4: Continue Argument list The period: @@ -174,6 +219,8 @@ becomes This also works with just one argument after the period. To start a line without a function call, you have to prefix it with a period followed by whitespace.[fn:2] +/requirement: continue the argument list of a function after an intermediate call to another function./ + *** Wisp syntax 3/4: Double Parens The colon:[fn:3] @@ -196,6 +243,8 @@ becomes (body)) #+END_SRC +/requirement: represent code with two adjadent blocks in double-parentheses./ + *** Wisp syntax 4/4: Resilient Indentation The underscore (optional): @@ -218,39 +267,36 @@ becomes (body)) #+END_SRC +/requirement: share code in environments which do not preserve whitespace./ *** Summary -#+html: <small> -http://draketo.de/light/english/wisp-lisp-indentation-preprocessor#sec-4 -#+html: </small> - -The syntax shown here is the minimal synatx required for the goal of wisp: indentation-based, general lisp with a simple preprocessor, and code which can be shared easily on the internet: +The syntax shown here is the minimal syntax required for the goal of wisp: indentation-based, general lisp with a simple preprocessor, and code which can be shared easily on the internet: - =.= to continue the argument list - =:= for double parens - =_= to survive HTML ** More detailed: Wisp syntax rules + +*** Unindented line -*** *A line without indentation is a function call*, just as if it would start with a bracket. +*A line without indentation is a function call*, just as if it would start with a parenthesis. #+BEGIN_SRC wisp display "Hello World!" ; (display "Hello World!") #+END_SRC - - -*** *A line which is more indented than the previous line is a sibling to that line*: It opens a new bracket. +*** Sibling line +*A line which is more indented than the previous line is a sibling to that line*: It opens a new parenthesis. #+BEGIN_SRC wisp display ; (display string-append "Hello " "World!" ; (string-append "Hello " "World!")) #+END_SRC - - -*** *A line which is not more indented than previous line(s) closes the brackets of all previous lines which have higher or equal indentation*. You should only reduce the indentation to indentation levels which were already used by parent lines, else the behaviour is undefined. +*** Closing line +*A line which is not more indented than previous line(s) closes the parentheses of all previous lines which have higher or equal indentation*. You should only reduce the indentation to indentation levels which were already used by parent lines, else the behaviour is undefined. #+BEGIN_SRC wisp display ; (display @@ -258,17 +304,17 @@ The syntax shown here is the minimal syn display "Hello Again!" ; (display "Hello Again!") #+END_SRC +*** Prefixed line - -*** *To add any of ' , ` #' #, #` or #@, to the first bracket on a line, just prefix the line with that symbol* followed by at least one space. Implementations are free to add more prefix symbols. +*To add any of ' , ` #' #, #` or #@, to the first parenthesis on a line, just prefix the line with that symbol* followed by at least one space. Implementations are free to add more prefix symbols. #+BEGIN_SRC wisp ' "Hello World!" ; '("Hello World!") #+END_SRC - -*** *A line whose first non-whitespace characters are a dot followed by a space (". ") does not open a new bracket: it is treated as simple continuation of the first less indented previous line*. In the first line this means that this line does not start with a bracket and does not end with a bracket, just as if you had directly written it in lisp without the leading ". ". +*** Continuing line +*A line whose first non-whitespace characters is a dot followed by a space (". ") does not open a new parenthesis: it is treated as simple continuation of the first less indented previous line*. In the first line this means that this line does not start with a parenthesis and does not end with a parenthesis, just as if you had directly written it in lisp without the leading ". ". #+BEGIN_SRC wisp string-append "Hello" ; (string-append "Hello" @@ -277,8 +323,8 @@ The syntax shown here is the minimal syn #+END_SRC - -*** *A line which contains only whitespace and a colon (":") defines an indentation level at the indentation of the colon*. It opens a bracket which gets closed by the next less-indented line. If you need to use a colon by itself. you can escape it as "\:". +*** Empty indentation level +*A line which contains only whitespace and a colon (":") defines an indentation level at the indentation of the colon*. It opens a parenthesis which gets closed by the next line which has less or equal indentation. If you need to use a colon by itself. you can escape it as "\:". #+BEGIN_SRC wisp let ; (let @@ -288,8 +334,8 @@ The syntax shown here is the minimal syn #+END_SRC - -*** *A colon sourrounded by whitespace (" : ") starts a bracket which gets closed at the end of the line*. +*** Inline Colon +*A colon sourrounded by whitespace (" : ") starts a parenthesis which gets closed at the end of the line*. #+BEGIN_SRC wisp define : hello who ; (define (hello who) @@ -297,8 +343,17 @@ The syntax shown here is the minimal syn string-append "Hello " who "!" ; (string-append "Hello " who "!"))) #+END_SRC +If the colon starts a line which also contains other non-whitespace characters, it starts a parenthesis which gets closed at the end of the line *and* defines an indentation level at the position of the colon. + +If the colon is the last non-whitespace character on a line, it represents an empty pair of parentheses: + +#+BEGIN_SRC wisp + let : ; (let () + display "Hello" ; (display "Hello")) +#+END_SRC -*** *You can replace any number of consecutive initial spaces by underscores*, as long as at least one whitespace is left between the underscores and any following character. You can escape initial underscores by prefixing the first one with \ ("\___ a" → "(___ a)"), if you have to use them as function names. +*** Initial Underscores +*You can replace any number of consecutive initial spaces by underscores*, as long as at least one whitespace is left between the underscores and any following character. You can escape initial underscores by prefixing the first one with \ ("\___ a" → "(___ a)"), if you have to use them as function names. #+BEGIN_SRC wisp define : hello who ; (define (hello who) @@ -306,36 +361,80 @@ The syntax shown here is the minimal syn ___ string-append "Hello " who "!" ; (string-append "Hello " who "!"))) #+END_SRC +*** Parens and Strings +*Linebreaks inside parentheses and strings are not considered linebreaks* for parsing indentation. To use parentheses at the beginning of a line without getting double parens, prefix the line with a period. + +#+BEGIN_SRC wisp +define : stringy s + string-append s " reversed and capitalized: + " ; linebreaks in strings do not affect wisp parsing + . (string-capitalize ; same for linebreaks in parentheses + (string-reverse s)) +#+END_SRC + +Effectively code in parentheses and strings is interpreted directly as Scheme. This way you can simply copy a thunk of scheme into wisp. The following is valid wisp: + +#+BEGIN_SRC wisp +define foo (+ 1 + (* 2 3)) ; defines foo as 7 +#+END_SRC ** Clarifications -- Code-blocks end after 2 empty lines followed by a newline. Indented non-empty lines after 2 empty lines should be treated as error. A line is empty if it only contains whitespace. +- Code-blocks end after 2 empty lines followed by a newline. Indented non-empty lines after 2 empty lines should be treated as error. A line is empty if it only contains whitespace. A line with a comment is never empty. -- square brackets and curly braces should be treated the same way as parentheses: They stop the indentation processing until they are closed. +- Inside parentheses, wisp parsing is disabled. Consequently linebreaks inside parentheses are not considered linebreaks for wisp-parsing. For the parser everything which happens inside parentheses is treated as a black box. -** Syntax justification +- Square brackets and curly braces should be treated the same way as parentheses: They stop the indentation processing until they are closed. + +- Likewise linebreaks inside strings are not considered linebreaks for wisp-parsing. + +- A colon (:) at the beginning of a line adds an extra open parentheses that gets closed at end-of-line (rule 4.2.7) *and* defines an indentation level. + +- using a quote to escape a symbol separated from it by whitespace is forbidden. This would make the meaning of quoted lines ambigous. + +- Curly braces should be treated as curly-infix following SRFI-105. This makes most math look natural to newcomers. + +- Neoteric expressions from SRFI-105 are not required because they create multiple ways to represent the same code. In wisp they add much less advantages than in sweet expressions from SRFI-110, because wisp can continue the arguments to a function after a function call (with the leading period) and the inline colon provides most of the benefits neoteric expressions give to sweet. However implementations providing wisp should give users the option to activate neoteric expressions as by SRFI-105 to allow experimentation and evolution ([[http://sourceforge.net/p/readable/mailman/message/33068104/][discussion]]). + +- It is possible to write code which is at the same time valid wisp and sweet. The readable mailinglist [[http://sourceforge.net/p/readable/mailman/message/33058992/][contains details]]. + +* Syntax justification /I do not like adding any unnecessary syntax element to lisp. So I want to show explicitely why the syntax elements are required./ -*** . (the dot) +#+html: <small> +See also http://draketo.de/light/english/wisp-lisp-indentation-preprocessor#sec-4 +#+html: </small> + + +** . (the dot) + +To represent general code trees, we have to be able to represent continuation of the arguments of a function with an intermediate call to another (or the same) function. The dot at the beginning of the line as marker of the continuation of a variable list is a generalization of using the dot as identity function - which is an implementation detail in many lisps. -`(. a)` is just `a`. +#+BEGIN_QUOTE +=(. a)= is just =a= +#+END_QUOTE -So for the single variable case, this would not even need additional parsing: wisp could just parse ". a" to "(. a)" and produce the correct result in most lisps. But forcing programmers to always use separate lines for each parameter would be very inconvenient, so the definition of the dot at the beginning of the line is extended to mean “take every element in this line as parameter to the parent function”. +So for the single variable case, this would not even need additional parsing: wisp could just parse =. a= to =(. a)= and produce the correct result in most lisps. But forcing programmers to always use separate lines for each parameter would be very inconvenient, so the definition of the dot at the beginning of the line is extended to mean “take every element in this line as parameter to the parent function”. -Essentially this dot-rule means that we mark variables in the code instead of function calls, since in Lisp variables at the beginning of a line are much rarer than in other programming languages. In lisp assigning a value to a variable is a function call while it is a syntax element in many other languages, so what would be a variable at the beginning of a line in other languages is a function call in lisp.. +#+BEGIN_QUOTE +=(. a)= → =a= is generalized to =(. a b c)= → =a b c=. +#+END_QUOTE -*** : (the colon) +At its core, this dot-rule means that we mark variables in the code instead of function calls. We do so, because variables at the beginning of a line are much rarer in Scheme than in other programming languages. -For double brackets and for some other cases we must have a way to mark indentation levels without any code. I chose the colon, because it is the most common non-alpha-numeric character in normal prose which is not already reserved as syntax by lisp when it is surrounded by whitespace, and because it already gets used for marking keyword arguments to functions in Emacs Lisp, so it does not add completely alien characters. +** : (the colon) + +For double parentheses and for some other cases we must have a way to mark indentation levels which do not contain code. Wisp uses the colon, because it is the most common non-alpha-numeric character in normal prose which is not already reserved as syntax by Scheme when it is surrounded by whitespace, and because it already gets used without sourrounding whitespace for marking keyword arguments to functions in Emacs Lisp and Common Lisp, so it does not add completely alien concepts. The inline function call via inline " : " is a limited generalization of using the colon to mark an indentation level: If we add a syntax-element, we should use it as widely as possible to justify adding syntax overhead. -But if you need to use : as variable or function name, you can still do so by escaping it with a backslash, so this does not forbid using the character. +But if you need to use =:= as variable or function name, you can still do so by escaping it with a backslash (=\:=), so this does not forbid using the character. -For simple cases, the colon could be replaced by clever whitespace parsing, but there are complex cases which make this impossible. A simple example is a theoretical doublelet which does not require a body:[fn:4] +For simple cases, the colon could be replaced by clever whitespace parsing, but there are complex cases which make this impossible. The minimal example is a theoretical doublelet which does not require a body:[fn:4] #+BEGIN_SRC scheme (doublelet @@ -349,7 +448,7 @@ The wisp version of this is doublelet : foo bar - : ; <- this double backstep is the real issue + : ; <- this empty backstep is the real issue bla foo #+END_SRC @@ -361,68 +460,93 @@ doublelet : bla foo #+END_SRC -The need to be able to represent things like this is the real reason, why the colon exists. The inline and start-of-line use is only a generalization of that principle (we add a syntax-element, so we should see how far we can push it to reduce the effective cost of introducing the additional syntax). +The need to be able to represent arbitrary syntax trees which can contain expressions like this is the real reason, why the colon exists. The inline and start-of-line use is only a generalization of that principle (we add a syntax-element, so we should see how far we can push it to reduce the effective cost of introducing the additional syntax). -**** Clever whitespace-parsing which would not work +*** Clever whitespace-parsing which would not work There are two alternative ways to tackle this issue: deferred level-definition and fixed-width indentation. Defining intermediate indentation-levels by later elements (deferred definition) would be a problem, because it would create code which is really hard to understand. An example is the following: #+BEGIN_SRC wisp -defun flubb - +define (flubb) nubb + hubb + subb gam #+END_SRC would become #+BEGIN_SRC scheme -(defun flubb () +(define (flubb) ((nubb)) + ((hubb)) + ((subb)) (gam)) #+END_SRC +while + +#+BEGIN_SRC wisp +define (flubb) + nubb + hubb + subb +#+END_SRC + +would become + +#+BEGIN_SRC scheme +(define (flubb) + (nubb) + (hubb) + (subb)) +#+END_SRC + +Knowledge of later parts of the code would be necessary to understand the parts a programmer is working on at the moment. This would call for subtle errors which would be hard to track down, because the effect of a change in code would not be localized at the point where the change is done but could propagate backwards. + Fixed indentation width (alternative option to inferring it from later lines) would make it really hard to write readable code. Stuff like this would not be possible: #+BEGIN_SRC wisp -if - equals wrong +when + equal? wrong isright? stuff fixstuff #+END_SRC -*** _ (the underscore) +** _ (the underscore) -In Python the whitespace hostile html already presents problems with sharing code - for example in email list archives and forums. But in Python the indentation can mostly be inferred by looking at the previous line: If that ends with a colon, the next line must be more indented (there is nothing to clearly mark reduced indentation, though). In wisp we do not have that help, so we need a way to survive in that hostile environment. +In Python the whitespace hostile html already presents problems with sharing code - for example in email list archives and forums. But Python-programmers can mostly infer the indentation by looking at the previous line: If that ends with a colon, the next line must be more indented (there is nothing to clearly mark reduced indentation, though). In wisp we do not have this support, so we need a way to survive in the hostile environment of todays web. -The underscore is commonly used to denote a space in URLs, where spaces are inconvenient, but it is rarely used in lisp (where the dash ("-") is mostly used instead), so it seems like a a natural choice. +The underscore is commonly used to denote a space in URLs, where spaces are inconvenient, but it is rarely used in Scheme (where the dash ("-") is mostly used instead), so it seems like a a natural choice. You can still use underscores anywhere but at the beginning of the line, and even at the beginning of the line you simply need to escape it by prefixing the first underscore with a backslash ("\____"). * Implementation -This reference implementation realizes a general wisp-preprocessor which can be used for any lisp-like language. It contains special syntax-constructs for scheme, though. The reference-preprocessor uses GNU Guile and can also be used at the REPL. Due to being a simple preprocessor, wisp can also be implemented as an external program which gets called on reading. It does not actually have to understand the code itself. +This reference implementation realizes a specialized parser for Scheme. It uses GNU Guile and can also be used at the REPL. -A wisp-preprocessor which is specialiized for scheme should be much easier to realize, though, by using the parsing methods from an existing scheme implementation. +The wisp code also contains a general wisp-preprocessor which can be used for any lisp-like language and can used as an external program which gets called on reading. It does not actually have to understand the code itself. This is not part of this SRFI, though. -Since reference implementation is heavyweight, it would be great to have someone step up and create a more lightweight scheme-specific alternative. To allow for this, the test-suite in the next chapter only contains scheme-specific snippets. +To allow for easy re-implementation, the chapter after the implementation itself contains a test-suite with commonly used wisp constructs and parenthesized counterparts. -** The generic wisp preprocessor (code) +The wisp preprocessor implementation can be found at http://draketo.de/proj/wisp. Both implementations are explicitly licensed to allow inclusion in an SRFI. + +** The generic wisp processor (code) TODO: Include the code from http://draketo.de/proj/wisp ** Test Suite -The wisp test-suite consists of a large number of wisp-snippets and the corresponding scheme-code. A wisp-implementation may call itself compliant to the wisp test-suite if it successfully converts each wisp-snippet into the corresponging scheme-snippet. Blank lines at the end of the file and non-functional white-space in the produced scheme-file do not matter for this purpose. +The wisp test-suite consists of a large number of wisp-snippets and the corresponding scheme-code. + +A wisp-implementation may call itself compliant with the wisp test-suite if the code tree parsed from the wisp file is the same as a code tree parsed from the equivalent Scheme file. + +A wisp-implementation may call itself a compliant wisp pre-processor if it successfully converts each wisp-snippet into the corresponging scheme-snippet. Blank lines at the end of the file and non-functional white-space in the produced scheme-file do not matter for this purpose. This test-suite is also available in the [[http://draketo.de/proj/wisp][wisp repository]] along with a script-runner (runtests.sh) which tests the reference wisp-implementation with GNU Guile against this testsuite.[fn:5] -The test-suite included here only contains scheme-compatible code to allow for scheme-specific wisp-implementations which use existing parsing functions to simplify the code. - -/TODO: Some of the snippets were transformed from emacs lisp to scheme by hand and this might have introduced bugs. They still need to be tested again./ - *** tests/syntax-underscore.w #+begin_src wisp define : a b c @@ -474,7 +598,7 @@ bar] barz {1 + [* 2 2]} mara { li + -lo (mabba) +lo - (mabba) } #+end_src *** tests/syntax-strings-parens.scm @@ -500,7 +624,7 @@ bar] barz {1 + [* 2 2]}) (mara { li + -lo (mabba) +lo - (mabba) }) #+end_src *** tests/syntax-indent.w @@ -658,7 +782,7 @@ define : \: *** tests/sublist.w #+begin_src wisp ; sublists allow to start single line function calls with a colon ( : ). -; + define : a b c let : : e . f . g @@ -673,15 +797,15 @@ define : a b c #+end_src -*** tests/shebang.w +*** tests/hashbang.w #+begin_src wisp #!/usr/bin/wisp.py # !# -; This tests shebang lines +; This tests hashbang lines #+end_src -*** tests/shebang.scm +*** tests/hashbang.scm #+begin_src scheme #!/usr/bin/wisp.py # !# -; This tests shebang lines +; This tests hashbang lines #+end_src @@ -768,61 +892,6 @@ define : add-if-all-numbers lst (loop (cdr lst))))))))) #+end_src -*** tests/range.w -#+begin_src wisp -import : rnrs - -define range - case-lambda - : n ; one-argument syntax - range 0 n 1 - : n0 n ; two-argument syntax - range n0 n 1 - : n0 n s ; three-argument syntax - assert - and - for-all number? : list n0 n s - not : zero? s - let : : cmp : if (positive? s) >= <= - let loop - : i n0 - acc '() - if - cmp i n - reverse acc - loop (+ i s) (cons i acc) - -display : apply string-append "" : map number->string : range 5 -newline -#+end_src -*** tests/range.scm -#+begin_src scheme -(import (rnrs)) - -(define range - (case-lambda - ((n ); one-argument syntax - (range 0 n 1)) - ((n0 n ); two-argument syntax - (range n0 n 1)) - ((n0 n s ); three-argument syntax - (assert - (and - (for-all number? (list n0 n s)) - (not (zero? s)))) - (let ((cmp (if (positive? s) >= <= ))) - (let loop - ((i n0 ) - (acc '())) - (if - (cmp i n ) - (reverse acc) - (loop (+ i s) (cons i acc)))))))) - -(display (apply string-append "" (map number->string (range 5)))) -(newline) - -#+end_src *** tests/quotecolon.w #+begin_src wisp #!/home/arne/wisp/wisp-multiline.sh @@ -879,20 +948,6 @@ let hello #+end_src -*** tests/mtest.w -#+begin_src wisp -#!/home/arne/wisp/wisp-multiline.sh !# - -display 1 -#+end_src -*** tests/mtest.scm -#+begin_src scheme -#!/home/arne/wisp/wisp-multiline.sh !# - -(display 1) - - -#+end_src *** tests/flexible-parameter-list.w #+begin_src wisp ; Test using a . as first parameter on a line by prefixing it with a second . @@ -993,7 +1048,7 @@ do not break me!" h (I am in brackets: do not : change "me") . i - , ' j k + , 'j k . l @@ -1055,7 +1110,7 @@ do not break me!") (h (I am in brackets: do not : change "me")) i))) - ,(' j k) + ,('j k) l @@ -1127,17 +1182,6 @@ concat "I want " #+end_src -*** tests/btest.w -#+begin_src wisp -display "b" -newline -#+end_src -*** tests/btest.scm -#+begin_src scheme -(display "b") -(newline) -#+end_src - * Copyright Copyright (C) Arne Babenhauserheide (2013--2014). All Rights Reserved. @@ -1156,7 +1200,10 @@ newline [fn:3] This special syntax for double parens cannot be replaced by clever whitespace parsing, because it is required for representing two consecutive forms which start with double parentheses. The only pure-whitespace alternative would be fixed-width indentation levels. -[fn:4] I used a double let without action as example for the colon-syntax, even though that does nothing, because that makes it impossible to use later indentation to mark an intermediate indentation-level. Another reason why I would not use later indentation to define whether something earlier is a single or double indent is that this would call for subtle and really hard to find errors: +[fn:4] The example uses a double let without action as example for the colon-syntax, even though that does nothing, because that makes it impossible to use later indentation to mark an intermediate indentation-level. Another reason why I would not use later indentation to define whether something earlier is a single or double indent is that this would call for subtle and really hard to find errors. [fn:5] To run the tests in the wisp testsuite with a separately built GNU Guile, you can use any given guile interpreter by adjusting the following command: =PATH=~/guile-2.0.11/meta:${PATH} ./runtests.sh= - + +[fn:6] Typed Racket uses calls of the form =(: x Number)= to declare types. These forms can still be used directly in parenthesized form, but in wisp-form the colon has to be replaced with =\:=. + +[fn:7] In most cases type-declarations are not needed in typed racket, since the type can be inferred. See [[http://docs.racket-lang.org/ts-guide/more.html?q=typed#%28part._when-annotations~3f%29][When do you need type annotations?]] diff --git a/docs/why-wisp.org b/docs/why-wisp.org --- a/docs/why-wisp.org +++ b/docs/why-wisp.org @@ -155,7 +155,7 @@ myfunction /This breaks elegance 1/ -/Also the problems of SRFI-49 are preserved/ +/The problems of SRFI-49 are preserved, but their impact reduced./ * Summary: Why wisp? @@ -184,7 +184,7 @@ becomes (newline) #+END_SRC -* Wisp syntax 2/4: Continue Argument list +* Wisp syntax 2/4: Continue Arguments ** The dot diff --git a/examples/d20world.w b/examples/d20world.w --- a/examples/d20world.w +++ b/examples/d20world.w @@ -66,8 +66,8 @@ let loop : : relationships neighbors-hel else let* : cur : car relationships - idx : 1- : car cur - vec : cdr cur + idx : 1- : car cur + vec : cdr cur vector-set! world idx : 1+ idx vector-set! neighbors idx : make-vector 3 let setidx : : idxtoset '(0 1 2) diff --git a/examples/ensemble-estimation.w b/examples/ensemble-estimation.w new file mode 100755 --- /dev/null +++ b/examples/ensemble-estimation.w @@ -0,0 +1,237 @@ +#!/usr/bin/env sh +exec guile -L $(dirname $(dirname $(realpath "$0"))) --language=wisp -e '(@@ (examples ensemble-estimation) main)' -s "$0" "$@" +; !# + +;; Simple Ensemble Square Root Filter to estimate function parameters +;; based on measurements. + +;; Provide first guess parameters x^b and measurements y⁰ to get +;; optimized parameters x^a. + +;; Method +;; x^b = '(…) ; first guess of the parameters +;; P = '((…) (…) …) ; parameter covariance +;; y⁰ = '(…) ; observations +;; R = '((…) (…) …) ; observation covariance +;; H: H(x) → y ; provide modelled observations for the given parameters. Just run the function. +;; with N ensemble members (i=1, … N) drawn from the state x^b: +;; For each measurement y⁰_j: +;; x'^b: X = 1/√(N-1)(x'b_1, …, x'b_N)^T +;; with P = XX^T ; in the simplest case x'^b are gaussian +;; distributed with standard distribution from +;; square root of the diagonals. +;; x_i = x^b + x'^b_i +;; H(x^b_i) = H(x^b + x'^b_i) +;; H(x^b) = (1/N)·Σ H(x^b + x'^b_i) +;; H(x'^b_i) = H(x^b + x'_i) - H(x^b) +;; HPHt = 1/(N-1)(H(x'_1), …, H(x'_N))(H(x'1), …, H(x'N))T +;; PHt = 1/(N-1)(x'_1, …, x'_N)(H(x'1), …, H(x'N))T +;; K = PHt*(HPHt + R)⁻¹ +;; x^a = x^b + K(y⁰_j - H(x^b)) +;; α = (1 + √(R/(HPHt+R)))⁻¹ +;; x'^a = x'^b - αK·H(x'^b) + +define-module : examples ensemble-estimation +use-modules : srfi srfi-42 ; list-ec +use-modules + : ice-9 popen + . #:select : open-output-pipe close-pipe + +; seed the random number generator +set! *random-state* : random-state-from-platform + +define : make-diagonal-matrix-with-trace trace + let : : dim : length trace + list-ec (: i dim) + list-ec (: j dim) + if : = i j + list-ref trace i + . 0.0 + +define : make-covariance-matrix-from-standard-deviations stds + make-diagonal-matrix-with-trace : map (lambda (x) (expt x 2)) stds + +define : mean l + . "Calculate the average value of l (numbers)." + / : apply + l + length l + + +define : standard-deviation l + . "Calculate the standard deviation of list l (numbers)." + let : : l_mean : mean l + sqrt + / : sum-ec (: i l) : expt {i - l_mean} 2 + . {(length l) - 1} + +define : standard-deviation-from-deviations . l + . "Calculate the standard deviation from a list of deviations (x - x_mean)." + sqrt + / : sum-ec (: i l) : expt i 2 + . {(length l) - 1} + +define* : write-multiple . x + . "Helper to avoid suffering from write-newline-typing." + map : lambda (x) (write x) (newline) + . x + +;; Start with the simple case: One variable and independent observations (R diagonal) +;; First define a truth +define x^seed '(0.5 0.6 7 0.1 0.7 0.9 0.8 0.4) +define x^true : append-ec (: i (length x^seed)) : list-ec (: j x^seed) : * j : list-ref x^seed i +;; And add an initial guess of the parameters +define x^b : append-ec (: i (length x^seed)) '(1 1 1 1 1 1 1 1) ; initial guess +define P : make-covariance-matrix-from-standard-deviations : append-ec (: i (length x^seed)) '(0.5 0.1 0.3 0.1 0.2 0.2 0.2 0.2) + +;; Then generate observations +define y⁰-num 3000 +define y⁰-pos-max 100 +;; At the positions where they are measured. Drawn randomly to avoid +;; giving an undue weight to later values. +define y⁰-pos : list-ec (: i y⁰-num) : * (random:uniform) y⁰-pos-max + +;; We need an observation operator to generate observations from true values +define : H x pos + . "Observation operator. It generates modelled observations from the input. + +x are parameters to be optimized, pos is another input which is not optimized. For plain functions it could be the position of the measurement on the x-axis. We currently assume absolute knowledge about the position. +" + let* + : len : length x + ystretch y⁰-pos-max + x-pos : list-ec (: i len) : * ystretch {{i + 0.5} / {len + 1}} + apply + + list-ec (: i len) + * : list-ref x i + . pos + exp + - + expt + / {pos - (list-ref x-pos i)} {ystretch / 20} + . 2 + + +;; We start with true observations which we will disturb later to get +;; the equivalent of measured observations +define y^true : list-ec (: i y⁰-pos) : H x^true i +;; now we disturb the observations with a fixed standard deviation. This assumes uncorrelated observations. +define y⁰-std 50 +define y⁰ : list-ec (: i y^true) : + i : * y⁰-std : random:normal +;; and define the covariance matrix. This assumes uncorrelated observations. +define R : make-covariance-matrix-from-standard-deviations : list-ec (: i y⁰-num) y⁰-std + +;; Alternative: define observations +;; define y⁰-mean 0.8 +;; The actual observations +;; define y⁰ : list-ec (: i y⁰-num) : + y⁰-mean : * y⁰-std : random:normal + + +define : EnSRT H x P y R y-pos N + . "Observation function H, parameters x, +parameter-covariance P, observations y, observation covariance R +and number of ensemble members N. + +Limitations: y is a single value. R and P are diagonal. +" + let step + : observations-to-process y + observation-variances : list-ec (: i (length y)) : list-ref (list-ref R i) i + observation-positions y-pos + x^b x + x-deviations + list-ec (: i N) + list-ec (: j (length x)) + * : random:normal + sqrt : list-ref (list-ref P j) j ; only for diagonal P! + cond + : null? observations-to-process + list x^b x-deviations + else + ; write : list x^b '± : sqrt : * {1 / {(length x-deviations) - 1}} : sum-ec (: i x-deviations) : expt i 2 + ; newline + let* + : y_cur : car observations-to-process + R_cur : car observation-variances + y-pos_cur : car observation-positions + Hx^b_i + list-ec (: i x-deviations) + H + list-ec (: j (length i)) + + (list-ref x^b j) (list-ref i j) + . y-pos_cur + Hx^b + / : sum-ec (: i Hx^b_i) i + . N + Hx^b-prime + list-ec (: i N) + - : list-ref Hx^b_i i + . Hx^b + HPHt + / : sum-ec (: i Hx^b-prime) {i * i} + . {N - 1} + PHt + list-ec (: j (length x^b)) ; for each x^b_i multiply the state-element and model-deviation for all ensemble members. + * {1 / {N - 1}} + sum-ec (: i N) + * : list-ref (list-ref x-deviations i) j ; FIXME: this currently does not use j because I only do length 1 x + list-ref Hx^b-prime i + K : list-ec (: i PHt) {i / {HPHt + R_cur}} + x^a + list-ec (: j (length x^b)) + + : list-ref x^b j + * : list-ref K j + . {y_cur - Hx^b} + α-weight-sqrt : sqrt {R_cur / {HPHt + R_cur}} + α {1 / {1 + α-weight-sqrt}} + x^a-deviations + list-ec (: i N) ; for each ensemble member + list-ec (: j (length x^b)) ; and each state variable + - : list-ref (list-ref x-deviations i) j + * α + list-ref K j + list-ref Hx^b-prime i + step + cdr observations-to-process + cdr observation-variances + cdr observation-positions + . x^a + . x^a-deviations + + +define : main args + let* + : optimized : EnSRT H x^b P y⁰ R y⁰-pos 30 + x-opt : list-ref optimized 0 + x-deviations : list-ref optimized 1 + ; std : sqrt : * {1 / {(length x-deviations) - 1}} : sum-ec (: i x-deviations) : expt i 2 + format #t "x⁰: ~A ± ~A\nx: ~A ± ~A\nx^t:~A\ny: ~A ± \ny⁰: ~A ± ~A\nnoise: ~A\n" + . x^b + list-ec (: i (length x^b)) : list-ref (list-ref P i) i + . x-opt + list-ec (: i (length x-opt)) + apply standard-deviation-from-deviations : list-ec (: j x-deviations) : list-ref j i + . x^true + * {1 / (length y⁰)} : apply + : map (lambda (x) (H x-opt x)) y⁰-pos + ; apply standard-deviation-from-deviations : map H x-deviations ; FIXME: This only works for trivial H. + mean y⁰ + standard-deviation y⁰ + . y⁰-std + ; now plot the result + let : : port : open-output-pipe "python" + format port "import pylab as pl\n" + format port "y0 = [float(i) for i in '~A'[1:-1].split(' ')]\n" y⁰ + format port "ypos = [float(i) for i in '~A'[1:-1].split(' ')]\n" y⁰-pos + format port "yinit = [float(i) for i in '~A'[1:-1].split(' ')]\n" : list-ec (: i y⁰-pos) : H x^b i + format port "ytrue = [float(i) for i in '~A'[1:-1].split(' ')]\n" : list-ec (: i y⁰-pos) : H x^true i + format port "yopt = [float(i) for i in '~A'[1:-1].split(' ')]\n" : list-ec (: i y⁰-pos) : H x-opt i + format port "pl.plot(*zip(*sorted(zip(ypos, yinit))), label='prior')\n" + format port "pl.plot(*zip(*sorted(zip(ypos, ytrue))), label='true')\n" + format port "pl.plot(*zip(*sorted(zip(ypos, yopt))), label='optimized')\n" + format port "pl.plot(*zip(*sorted(zip(ypos, y0))), marker='+', linewidth=0, label='measurements')\n" + format port "pl.legend()\n" + format port "pl.xlabel('position [arbitrary units]')\n" + format port "pl.ylabel('value [arbitrary units]')\n" + format port "pl.title('ensemble optimization results')\n" + format port "pl.show()\n" + format port "exit()\n" + close-pipe port diff --git a/testrunner.w b/testrunner.w new file mode 100755 --- /dev/null +++ b/testrunner.w @@ -0,0 +1,36 @@ +#!/bin/bash +exec guile -L . --language=wisp -s "$0" "$@" +!# + +when : not : = 3 : length : command-line + format #t "Usage: ~A <wisp file> <scheme file>\n" : list-ref (command-line) 0 + exit + +define wisp-file : list-ref (command-line) 1 +define scheme-file : list-ref (command-line) 2 + +use-modules + srfi srfi-1 + wisp-scheme + + +define : read-all port + let readloop : : res : ' + let : : next : read port + if : eof-object? next + . res + readloop : append res : list next + +let + : + read-scheme + with-input-from-file scheme-file + λ () + read-all : current-input-port + parsed-wisp + with-input-from-file wisp-file + λ () + wisp-scheme-read-all : current-input-port + if : equal? parsed-wisp read-scheme + format #t "Files ~A and ~A have equivalent content.\n" scheme-file wisp-file + format #t "Files ~A and ~A are different!\n\nwisp: ~A\n\nscheme: ~A\n\n\n" scheme-file wisp-file parsed-wisp read-scheme diff --git a/tests/emacs-customization.scm b/tests/emacs-customization.scm --- a/tests/emacs-customization.scm +++ b/tests/emacs-customization.scm @@ -1,7 +1,8 @@ (if (file-directory-p "~/.emacs.d/private/journal/") (setq-default journal-dir "~/.emacs.d/private/journal/")) -(global-set-key [(control meta .)] 'goto-last-change-reverse) +; the following line is not valid scheme and as such would break the scheme tests. +; global-set-key [(control meta .)] 'goto-last-change-reverse (require 'org-latex) (add-to-list 'org-export-latex-packages-alist diff --git a/tests/emacs-customization.w b/tests/emacs-customization.w --- a/tests/emacs-customization.w +++ b/tests/emacs-customization.w @@ -1,7 +1,8 @@ if : file-directory-p "~/.emacs.d/private/journal/" setq-default journal-dir "~/.emacs.d/private/journal/" -global-set-key [(control meta .)] 'goto-last-change-reverse +; the following line is not valid scheme and as such would break the scheme tests. +; global-set-key [(control meta .)] 'goto-last-change-reverse require 'org-latex add-to-list 'org-export-latex-packages-alist @@ -55,4 +56,4 @@ custom-set-variables setq a "x" . b "y" - . c "z" \ No newline at end of file + . c "z" diff --git a/tests/example.scm b/tests/example.scm --- a/tests/example.scm +++ b/tests/example.scm @@ -12,7 +12,7 @@ do not break me!") (h (I am in brackets: do not : change "me")) i))) - ,(' j k) + ,('j k) l diff --git a/tests/example.w b/tests/example.w --- a/tests/example.w +++ b/tests/example.w @@ -12,7 +12,7 @@ do not break me!" h (I am in brackets: do not : change "me") . i - , ' j k + , 'j k . l diff --git a/tests/hello.scm b/tests/hello.scm --- a/tests/hello.scm +++ b/tests/hello.scm @@ -1,5 +1,5 @@ (define (hello who) (format #t "~A ~A!\n" "Hello" who)) +(hello "Wisp") - diff --git a/tests/hello.w b/tests/hello.w --- a/tests/hello.w +++ b/tests/hello.w @@ -1,3 +1,4 @@ define : hello who format #t "~A ~A!\n" . "Hello" who +hello "Wisp" diff --git a/runtests.sh b/tests/runtests-scheme-preprocessor.sh rename from runtests.sh rename to tests/runtests-scheme-preprocessor.sh --- a/runtests.sh +++ b/tests/runtests-scheme-preprocessor.sh @@ -17,6 +17,8 @@ fi failed=0 cd ${srcdir}/tests for i in *.w; do + # skip strangecomments + if test x"${i}" = x"strangecomments.w"; then continue; fi d=$(guile ${builddir}/wisp.scm "$i" > ${builddir}/testtempfoo.scm; diff -wuB ${builddir}/testtempfoo.scm "$(basename "$i" .w)".scm; rm ${builddir}/testtempfoo.scm) if test x"$d" = x""; then continue diff --git a/tests/runtests-scheme-reader.sh b/tests/runtests-scheme-reader.sh new file mode 100755 --- /dev/null +++ b/tests/runtests-scheme-reader.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# Simple test runner for wisp, mainly intended to be run by autotools. + +if [[ x"$1" == x"" || x"$1" == x"." ]]; then + srcdir="$(realpath "$(pwd)")" +else + srcdir="$(realpath "$1")" +fi + +if [[ x"$2" == x"" || x"$2" == x"." ]]; then + builddir="$(realpath $(pwd))" +else + builddir="$(realpath "$2")" +fi + +failed=0 +cd ${builddir} +for i in ${srcdir}/tests/*.w; do + if guile -L . --language=wisp ${srcdir}/testrunner.w "${i}" "${srcdir}/tests/$(basename "${i}" .w).scm" | grep -q "have equivalent content"; then + continue + fi + echo test "$i" failed. Diff: $(guile -L . --language=wisp ${srcdir}/testrunner.w "${i}" "${srcdir}/tests/$(basename "${i}" .w).scm") + failed=$((failed + 1)) +done +cd - >/dev/null # undo dir change +# if test $failed -eq 0; then echo "Tests succeeded"; +# else echo "tests failed: ${failed}"; +# fi +exit $failed diff --git a/tests/self-referencial.scm b/tests/self-referencial.scm new file mode 100644 --- /dev/null +++ b/tests/self-referencial.scm @@ -0,0 +1,21 @@ +; http://stackoverflow.com/questions/23167464/scheme-self-reference-lambda-macro +; because this is as cool as things get +(define-syntax slambda + (lambda (x) + (syntax-case x () + ((slambda formals body0 body1 ...) + (with-syntax + ((self (datum->syntax #'slambda 'self))) + #'(letrec ((self (lambda formals body0 body1 ...))) + self)))))) + + + +( + (slambda (x) (+ x 1)) + 10) + +((slambda () self)) + + + diff --git a/tests/self-referencial.w b/tests/self-referencial.w new file mode 100644 --- /dev/null +++ b/tests/self-referencial.w @@ -0,0 +1,19 @@ +; http://stackoverflow.com/questions/23167464/scheme-self-reference-lambda-macro +; because this is as cool as things get +define-syntax slambda + lambda : x + syntax-case x : + : slambda formals body0 body1 ... + with-syntax + : self : datum->syntax #'slambda 'self + #' letrec : : self : lambda formals body0 body1 ... + . self + + + +: + slambda (x) : + x 1 + . 10 + +: slambda () self + diff --git a/tests/strangecomments.scm b/tests/strangecomments.scm --- a/tests/strangecomments.scm +++ b/tests/strangecomments.scm @@ -1,19 +1,18 @@ +(use-modules (wisp-scheme)) ; works (display - (call-with-input-string " foo ; bar\n ; nop \n\n; nup\n; nup \n \n\n\n foo : moo \"\n\" \n___ . goo . hoo" wisp-scheme-read-chunk)) + (call-with-input-string "foo ; bar\n ; nop \n\n; nup\n; nup \n \n\n\n foo : moo \"\n\" \n___ . goo . hoo" wisp-scheme-read-chunk)) (newline) (display - (call-with-input-string " foo \n___. goo . hoo" wisp-scheme-read-chunk)) + (call-with-input-string "foo \n___ . goo . hoo" wisp-scheme-read-chunk)) (newline) ; broken ; expected: -; ((2 (foo)) (2) (0) (0) (2 foo : moo -; ) (4 #{.}# [goo #{.}# hoo])) (display - (call-with-input-string " (foo) ; bar\n ; nop \n\n; nup\n; nup \n \n\n\n foo : moo \"\n\" \n___ . [goo . hoo]" wisp-scheme-read-chunk)) + (call-with-input-string "(foo) ; bar\n ; nop \n\n; nup\n; nup \n \n\n\n foo : moo \"\n\" \n___ . [goo . hoo]" wisp-scheme-read-chunk)) (newline) (display - (call-with-input-string " foo \n___. [goo . hoo]" wisp-scheme-read-chunk)) + (call-with-input-string "foo \n___ . [goo . hoo]" wisp-scheme-read-chunk)) (newline) diff --git a/tests/strangecomments.w b/tests/strangecomments.w --- a/tests/strangecomments.w +++ b/tests/strangecomments.w @@ -1,18 +1,17 @@ +use-modules : wisp-scheme ; works display - call-with-input-string " foo ; bar\n ; nop \n\n; nup\n; nup \n \n\n\n foo : moo \"\n\" \n___ . goo . hoo" wisp-scheme-read-chunk + call-with-input-string "foo ; bar\n ; nop \n\n; nup\n; nup \n \n\n\n foo : moo \"\n\" \n___ . goo . hoo" wisp-scheme-read-chunk newline display - call-with-input-string " foo \n___. goo . hoo" wisp-scheme-read-chunk + call-with-input-string "foo \n___ . goo . hoo" wisp-scheme-read-chunk newline ; broken ; expected: -; ((2 (foo)) (2) (0) (0) (2 foo : moo -; ) (4 #{.}# [goo #{.}# hoo])) display - call-with-input-string " (foo) ; bar\n ; nop \n\n; nup\n; nup \n \n\n\n foo : moo \"\n\" \n___ . [goo . hoo]" wisp-scheme-read-chunk + call-with-input-string "(foo) ; bar\n ; nop \n\n; nup\n; nup \n \n\n\n foo : moo \"\n\" \n___ . [goo . hoo]" wisp-scheme-read-chunk newline display - call-with-input-string " foo \n___. [goo . hoo]" wisp-scheme-read-chunk + call-with-input-string "foo \n___ . [goo . hoo]" wisp-scheme-read-chunk newline diff --git a/tests/sxml.scm b/tests/sxml.scm new file mode 100644 --- /dev/null +++ b/tests/sxml.scm @@ -0,0 +1,34 @@ +(use-modules (sxml simple)) +(use-modules (ice-9 match)) + +; define a template +(define template + (quote + (html + (head (title "test")) + (body + (h1 "test") + (message "the header") + (p "it " (em "works!") + (br) + (" it actually works!")))))) + +; transform it +(define template2 + (let loop + ((l template)) + (match l + (('message a ...) + `(p (@ (style "margin-left: 2em")) + (strong ,(map loop a)))) + ((a ...) + (map loop a )) + (a + a)))) + +; write xml to the output port +(sxml->xml template2) + +(newline) + + diff --git a/tests/sxml.w b/tests/sxml.w new file mode 100644 --- /dev/null +++ b/tests/sxml.w @@ -0,0 +1,32 @@ +use-modules : sxml simple +use-modules : ice-9 match + +; define a template +define template + quote + html + head : title "test" + body + h1 "test" + message "the header" + p "it " : em "works!" + br + " it actually works!" + +; transform it +define template2 + let loop + : l template + match l + : 'message a ... + ` p : @ : style "margin-left: 2em" + strong ,(map loop a) + : a ... + map loop a + a + . a + +; write xml to the output port +sxml->xml template2 + +newline diff --git a/tests/syntax-strings-parens.scm b/tests/syntax-strings-parens.scm --- a/tests/syntax-strings-parens.scm +++ b/tests/syntax-strings-parens.scm @@ -19,5 +19,5 @@ bar] barz {1 + [* 2 2]}) (mara { li + -lo (mabba) +lo - (mabba) }) diff --git a/tests/syntax-strings-parens.w b/tests/syntax-strings-parens.w --- a/tests/syntax-strings-parens.w +++ b/tests/syntax-strings-parens.w @@ -19,5 +19,5 @@ bar] barz {1 + [* 2 2]} mara { li + -lo (mabba) +lo - (mabba) } diff --git a/tests/websafe-indent.scm b/tests/websafe-indent.scm deleted file mode 100644 --- a/tests/websafe-indent.scm +++ /dev/null @@ -1,7 +0,0 @@ -(defun a (b c) - (d e - (f) - (g h) - i)) - - diff --git a/wisp-guile.w b/wisp-guile.w --- a/wisp-guile.w +++ b/wisp-guile.w @@ -8,12 +8,13 @@ ; we need to be able to replace end-of-line characters in brackets and strings -;; nostringandbracketbreaks INPORT -;; -;; Replace linebreaks within brackets and strings in the INPORT by the -;; placeholders \LINE_BREAK_N and \LINE_BREAK_R. Also identify -;; real comments as ;\REALCOMMENTHERE -;; +;; TODO: Check whether I can offload the string processing to the +;; read-function. That’s a source of endless complications. Required: +;; A kind of unrolling step which appends the string-representation of +;; the read strings back into the code. I would have to process a list +;; of strings instead of one big string. Or rather, each line would be +;; a list of strings. + ;; bootstrap via python3 wisp.py wisp-guile.w > 1 && guile 1 wisp-guile.w > 2 && guile 2 wisp-guile.w > 3 && diff 2 3 ;; ;; -Author: Arne Babenhauserheide diff --git a/wisp-multiline.sh b/wisp-multiline.sh --- a/wisp-multiline.sh +++ b/wisp-multiline.sh @@ -41,7 +41,7 @@ else fi PROGNAME=`basename $0` -ARGS=`getopt --name "$PN" --long help,lisp:,verbose,version,output:,wisp:interactive --options hl:vo:w:i -- "$@"` +ARGS=`getopt --name "$PROGNAME" --long help,lisp:,verbose,version,output:,wisp:interactive --options hl:vo:w:i -- "$@"` if [ $? -ne 0 ]; then exit 1 fi diff --git a/wisp-reader.w b/wisp-reader.w --- a/wisp-reader.w +++ b/wisp-reader.w @@ -10,11 +10,15 @@ ; adapted from spec.scm: https://gitorious.org/nacre/guile-sweet/source/ae306867e371cb4b56e00bb60a50d9a0b8353109:sweet/spec.scm define-module : language wisp spec - . #:use-module : wisp +; . #:use-module : wisp + . #:use-module : wisp-scheme . #:use-module : system base compile . #:use-module : system base language . #:export : wisp +; Set locale to something which supports unicode. Required to avoid using fluids. +setlocale LC_ALL "" + ;;; ;;; Language definition ;;; @@ -28,29 +32,52 @@ define : decompile-scheme x e opts define wisp-pending-port : make-object-property ; Code thanks to Mark Weaver +; define : read-one-wisp-sexp port env +; define : read-wisp-chunk +; if : eof-object? : peek-char port +; read-char port ; return eof: we’re done +; let : : s : wisp2lisp : wisp-chunkreader port +; set! : wisp-pending-port port +; open-input-string s +; try-pending +; define : try-pending +; let : : pending-port : wisp-pending-port port +; if pending-port +; let : : x : read pending-port +; if : eof-object? x +; read-wisp-chunk +; . x +; read-wisp-chunk +; try-pending + + +define wisp-pending-sexps : list + define : read-one-wisp-sexp port env - define : read-wisp-chunk - let : : s : wisp2lisp : wisp-chunkreader port - set! : wisp-pending-port port - open-input-string s - try-pending + define : wisp-scheme-read-chunk-env + cond + : eof-object? : peek-char port + read-char port ; return eof: we’re done + else + set! wisp-pending-sexps + append wisp-pending-sexps : wisp-scheme-read-chunk port + try-pending define : try-pending - let : : pending-port : wisp-pending-port port - if pending-port - let : : x : read pending-port - if : eof-object? x - read-wisp-chunk - . x - read-wisp-chunk + if : null? wisp-pending-sexps + wisp-scheme-read-chunk-env + let : : sexp : car wisp-pending-sexps + set! wisp-pending-sexps : cdr wisp-pending-sexps + . sexp try-pending define-language wisp . #:title "Wisp Scheme Syntax THIS IS EXPERIMENTAL, USE AT YOUR OWN RISK" - . #:reader read-one-wisp-sexp - . #:compilers `((scheme . ,compile-scheme)) ; I do not touch quasiquotes yet. + ; . #:reader read-one-wisp-sexp + . #:reader : lambda (port env) : let ((x (read-one-wisp-sexp port env))) x + . #:compilers `((scheme . ,compile-scheme)) . #:decompilers `((scheme . ,decompile-scheme)) . #:evaluator : lambda (x module) : primitive-eval x - . #:printer write + . #:printer write ; TODO: backtransform to wisp? Use source-properties? . #:make-default-environment lambda : ;; Ideally we'd duplicate the whole module hierarchy so that `set!', diff --git a/wisp-scheme.w b/wisp-scheme.w --- a/wisp-scheme.w +++ b/wisp-scheme.w @@ -1,8 +1,9 @@ -#!/home/arne/wisp/wisp-multiline.sh +#!/bin/bash +exec guile -L . --language=wisp -s "$0" "$@" ; !# ;; Scheme-only implementation of a wisp-preprocessor which output a -;; scheme Tree IL to feed to a scheme interpreter instead of a +;; scheme code tree to feed to a scheme interpreter instead of a ;; preprocessed file. ;; Plan: @@ -21,10 +22,14 @@ define-module : wisp-scheme wisp-scheme-read-file-chunk wisp-scheme-read-file wisp-scheme-read-string) +; use curly-infix by default +read-enable 'curly-infix + use-modules srfi srfi-1 srfi srfi-11 ; for let-values ice-9 rw ; for write-string/partial + ice-9 match ;; Helper functions for the indent-and-symbols data structure: '((indent token token ...) ...) define : line-indent line @@ -42,12 +47,90 @@ define : line-code line ; literal values I need define readcolon - call-with-input-string ":" read -define readdot - call-with-input-string "." read + string->symbol ":" + +define wisp-uuid "e749c73d-c826-47e2-a798-c16c13cb89dd" +; define an intermediate dot replacement with UUID to avoid clashes. +define repr-dot ; . + string->symbol : string-append "REPR-DOT-" wisp-uuid + +; allow using reader additions as the first element on a line to prefix the list +define repr-quote ; ' + string->symbol : string-append "REPR-QUOTE-" wisp-uuid +define repr-unquote ; , + string->symbol : string-append "REPR-UNQUOTE-" wisp-uuid +define repr-quasiquote ; ` + string->symbol : string-append "REPR-QUASIQUOTE-" wisp-uuid +define repr-unquote-splicing ; ,@ + string->symbol : string-append "REPR-UNQUOTESPLICING-" wisp-uuid + +define repr-syntax ; #' + string->symbol : string-append "REPR-SYNTAX-" wisp-uuid +define repr-unsyntax ; #, + string->symbol : string-append "REPR-UNSYNTAX-" wisp-uuid +define repr-quasisyntax ; #` + string->symbol : string-append "REPR-QUASISYNTAX-" wisp-uuid +define repr-unsyntax-splicing ; #,@ + string->symbol : string-append "REPR-UNSYNTAXSPLICING-" wisp-uuid + +; TODO: wrap the reader to return the repr of the syntax reader +; additions + +define : match-charlist-to-repr charlist + let + : chlist : reverse charlist + cond + : equal? chlist : list #\. + . repr-dot + : equal? chlist : list #\' + . repr-quote + : equal? chlist : list #\, + . repr-unquote + : equal? chlist : list #\` + . repr-quasiquote + : equal? chlist : list #\, #\@ + . repr-unquote-splicing + : equal? chlist : list #\# #\' + . repr-syntax + : equal? chlist : list #\# #\, + . repr-unsyntax + : equal? chlist : list #\# #\` + . repr-quasisyntax + : equal? chlist : list #\# #\, #\@ + . repr-unsyntax-splicing + else + . #f + +define : wisp-read port + . "wrap read to catch list prefixes." + let : : prefix-maxlen 4 + let longpeek + : peeked '() + repr-symbol #f + cond + : or (< prefix-maxlen (length peeked)) (eof-object? (peek-char port)) (equal? #\space (peek-char port)) (equal? #\newline (peek-char port)) + if repr-symbol ; found a special symbol, return it. + . repr-symbol + let unpeek + : remaining peeked + cond + : equal? '() remaining + read port ; let read to the work + else + unread-char (car remaining) port + unpeek : cdr remaining + else + let* + : next-char : read-char port + peeked : cons next-char peeked + longpeek + . peeked + match-charlist-to-repr peeked + + define : line-continues? line - equal? readdot : car : line-code line + equal? repr-dot : car : line-code line define : line-only-colon? line and @@ -72,7 +155,7 @@ define : line-strip-continuation line . line define : line-strip-indentation-marker line - ' "Strip the indentation markers from the beginning of the line" + . "Strip the indentation markers from the beginning of the line" cdr line define : indent-level-reduction indentation-levels level select-fun @@ -112,143 +195,129 @@ define : wisp-scheme-read-chunk-lines po currentindent 0 currentsymbols '() emptylines 0 - let : : next-char : peek-char port - cond - : eof-object? next-char - append indent-and-symbols : list : append (list currentindent) currentsymbols - : <= 2 emptylines - . indent-and-symbols - : and inindent : equal? #\space next-char - read-char port ; remove char - loop - . indent-and-symbols - . #t ; inindent - . #f ; inunderscoreindent - . #f ; incomment - 1+ currentindent - . currentsymbols - . emptylines - : and inunderscoreindent : equal? #\_ next-char - read-char port ; remove char - loop - . indent-and-symbols - . #t ; inindent - . #t ; inunderscoreindent - . #f ; incomment - 1+ currentindent - . currentsymbols - . emptylines - ; any char but whitespace *after* underscoreindent is - ; an error. This is stricter than the current wisp - ; syntax definition. TODO: Fix the definition. Better - ; start too strict. - : and inunderscoreindent : not : equal? #\space next-char - throw 'wisp-syntax-error "initial underscores without following whitespace at beginning of the line after" : last indent-and-symbols - : or (equal? #\newline next-char) (equal? #\return next-char) - read-char port ; remove the newline - ; TODO: Check whether when or if should be preferred here. guile 1.8 only has if. - if : and (equal? #\newline next-char) : equal? #\return : peek-char port - read-char port ; remove a full \n\r. Damn special cases... - let* ; distinguish pure whitespace lines and lines - ; with comment by giving the former zero - ; indent. Lines with a comment at zero indent - ; get indent -1 for the same reason - meaning - ; not actually empty. - : - indent - cond - incomment - if : = 0 currentindent ; specialcase - . -1 - . currentindent - : not : null? currentsymbols ; pure whitespace - . currentindent - else - . 0 - parsedline : append (list indent) currentsymbols - ; TODO: If the line is empty. Either do it here and do not add it, just - ; increment the empty line counter, or strip it later. Replace indent - ; -1 by indent 0 afterwards. + if : <= 2 emptylines ; the chunk end has to be checked + ; before we look for new chars in the + ; port to make execution in the REPL + ; after two empty lines work + ; (otherwise it shows one more line). + . indent-and-symbols + let : : next-char : peek-char port + cond + : eof-object? next-char + append indent-and-symbols : list : append (list currentindent) currentsymbols + : and inindent : equal? #\space next-char + read-char port ; remove char loop - append indent-and-symbols : list parsedline + . indent-and-symbols . #t ; inindent - equal? #\_ : peek-char port + . #f ; inunderscoreindent . #f ; incomment - . 0 - . '() - if : line-empty? parsedline - 1+ emptylines + 1+ currentindent + . currentsymbols + . emptylines + : and inunderscoreindent : equal? #\_ next-char + read-char port ; remove char + loop + . indent-and-symbols + . #t ; inindent + . #t ; inunderscoreindent + . #f ; incomment + 1+ currentindent + . currentsymbols + . emptylines + ; any char but whitespace *after* underscoreindent is + ; an error. This is stricter than the current wisp + ; syntax definition. TODO: Fix the definition. Better + ; start too strict. FIXME: breaks on lines with only + ; underscores which should empty lines. + : and inunderscoreindent : and (not (equal? #\space next-char)) (not (equal? #\newline next-char)) + throw 'wisp-syntax-error "initial underscores without following whitespace at beginning of the line after" : last indent-and-symbols + : equal? #\newline next-char + read-char port ; remove the newline + ; The following two lines would break the REPL by requiring one char too many. + ; if : and (equal? #\newline next-char) : equal? #\return : peek-char port + ; read-char port ; remove a full \n\r. Damn special cases... + let* ; distinguish pure whitespace lines and lines + ; with comment by giving the former zero + ; indent. Lines with a comment at zero indent + ; get indent -1 for the same reason - meaning + ; not actually empty. + : + indent + cond + incomment + if : = 0 currentindent ; specialcase + . -1 + . currentindent + : not : null? currentsymbols ; pure whitespace + . currentindent + else + . 0 + parsedline : append (list indent) currentsymbols + emptylines + if : not : line-empty? parsedline + . 0 + 1+ emptylines + ; TODO: If the line is empty. Either do it here and do not add it, just + ; increment the empty line counter, or strip it later. Replace indent + ; -1 by indent 0 afterwards. + loop + append indent-and-symbols : list parsedline + . #t ; inindent + if : <= 2 emptylines + . #f ; chunk ends here + equal? #\_ : peek-char port ; are we in underscore indent? + . #f ; incomment . 0 - : equal? #t incomment - read-char port ; remove one comment character - loop - . indent-and-symbols - . #f ; inindent - . #f ; inunderscoreindent - . #t ; incomment - . currentindent - . currentsymbols - . emptylines - : or (equal? #\space next-char) (equal? #\tab next-char) ; remove whitespace when not in indent - read-char port ; remove char - loop - . indent-and-symbols - . #f ; inindent - . #f ; inunderscoreindent - . #f ; incomment - . currentindent - . currentsymbols - . emptylines - ; | cludge to appease the former wisp parser - ; | which had a prblem with the literal comment - ; v char. - : equal? (string-ref ";" 0) next-char - loop - . indent-and-symbols - . #f ; inindent - . #f ; inunderscoreindent - . #t ; incomment - . currentindent - . currentsymbols - . emptylines - else ; use the reader - loop - . indent-and-symbols - . #f ; inindent - . #f ; inunderscoreindent - . #f ; incomment - . currentindent - ; this also takes care of the hashbang and leading comments. - ; TODO: If used from Guile, activate curly infix via read-options. - append currentsymbols : list : read port - . emptylines - -define : line-append-n-parens n line - . "Append N parens at the end of the line" - let loop : (rest n) (l line) - cond - : = 0 rest - . l - else - loop (1- rest) (append l '(")")) - -define : line-prepend-n-parens n line - . "Prepend N parens at the beginning of the line, but after the indentation-marker" - let loop : (rest n) (l line) - cond - : = 0 rest - . l - else - loop - 1- rest - append - list : car l - . '("(") - cdr l + . '() + . emptylines + : equal? #t incomment + read-char port ; remove one comment character + loop + . indent-and-symbols + . #f ; inindent + . #f ; inunderscoreindent + . #t ; incomment + . currentindent + . currentsymbols + . emptylines + : or (equal? #\space next-char) (equal? #\tab next-char) (equal? #\return next-char) ; remove whitespace when not in indent + read-char port ; remove char + loop + . indent-and-symbols + . #f ; inindent + . #f ; inunderscoreindent + . #f ; incomment + . currentindent + . currentsymbols + . emptylines + ; | cludge to appease the former wisp parser + ; | which had a problem with the literal comment + ; v char. + : equal? (string-ref ";" 0) next-char + loop + . indent-and-symbols + . #f ; inindent + . #f ; inunderscoreindent + . #t ; incomment + . currentindent + . currentsymbols + . emptylines + else ; use the reader + loop + . indent-and-symbols + . #f ; inindent + . #f ; inunderscoreindent + . #f ; incomment + . currentindent + ; this also takes care of the hashbang and leading comments. + ; TODO: If used from Guile, activate curly infix via read-options. + append currentsymbols : list : wisp-read port + . emptylines define : line-code-replace-inline-colons line - ' "Replace inline colons by opening parens which close at the end of the line" + . "Replace inline colons by opening parens which close at the end of the line" ; format #t "replace inline colons for line ~A\n" line let loop : processed '() @@ -412,7 +481,7 @@ define : wisp-scheme-indentation-to-pare define : wisp-scheme-replace-inline-colons lines - ' "Replace inline colons by opening parens which close at the end of the line" + . "Replace inline colons by opening parens which close at the end of the line" let loop : processed '() unprocessed lines @@ -424,7 +493,7 @@ define : wisp-scheme-replace-inline-colo define : wisp-scheme-strip-indentation-markers lines - ' "Strip the indentation markers from the beginning of the lines" + . "Strip the indentation markers from the beginning of the lines" let loop : processed '() unprocessed lines @@ -434,76 +503,125 @@ define : wisp-scheme-strip-indentation-m append processed : cdr : car unprocessed cdr unprocessed -define : wisp-scheme-recreate-incomeplete-lists expressions +define : wisp-unescape-underscore-and-colon code + . "replace \\_ and \\: by _ and :" + match code + : a ... + map wisp-unescape-underscore-and-colon a + '\_ + . '_ + '\: + . ': + a + . a + + +define : wisp-replace-empty-eof code + . "replace ((#<eof>)) by ()" + ; FIXME: Actually this is a hack which fixes a bug when the + ; parser hits files with only hashbang and comments. + if : and (not (null? code)) (pair? (car code)) (eof-object? (car (car code))) (null? (cdr code)) (null? (cdr (car code))) + list + . code + + +define : wisp-replace-paren-quotation-repr code + . "Replace lists starting with a quotation symbol by + quoted lists." + match code + : 'REPR-QUOTE-e749c73d-c826-47e2-a798-c16c13cb89dd a ... + list 'quote : map wisp-replace-paren-quotation-repr a + : a ... 'REPR-QUOTE-e749c73d-c826-47e2-a798-c16c13cb89dd b ; this is the quoted empty list + append + map wisp-replace-paren-quotation-repr a + list : list 'quote : map wisp-replace-paren-quotation-repr b + : 'REPR-UNQUOTE-e749c73d-c826-47e2-a798-c16c13cb89dd a ... + list 'unquote : map wisp-replace-paren-quotation-repr a + : 'REPR-QUASIQUOTE-e749c73d-c826-47e2-a798-c16c13cb89dd a ... + list 'quasiquote : map wisp-replace-paren-quotation-repr a + : 'REPR-UNQUOTESPLICING-e749c73d-c826-47e2-a798-c16c13cb89dd a ... + list 'unquote-splicing : map wisp-replace-paren-quotation-repr a + : 'REPR-SYNTAX-e749c73d-c826-47e2-a798-c16c13cb89dd a ... + list 'syntax : map wisp-replace-paren-quotation-repr a + : 'REPR-UNSYNTAX-e749c73d-c826-47e2-a798-c16c13cb89dd a ... + list 'unsyntax : map wisp-replace-paren-quotation-repr a + : 'REPR-QUASISYNTAX-e749c73d-c826-47e2-a798-c16c13cb89dd a ... + list 'quasisyntax : map wisp-replace-paren-quotation-repr a + : 'REPR-UNSYNTAXSPLICING-e749c73d-c826-47e2-a798-c16c13cb89dd a ... + list 'unsyntax-splicing : map wisp-replace-paren-quotation-repr a + : a ... + map wisp-replace-paren-quotation-repr a + a + . a + +define : wisp-make-improper code . "Turn (a #{.}# b) into the correct (a . b). read called on a single dot creates a variable named #{.}# (|.| in r7rs). Due to parsing the indentation before the list -structure is known, the reader cannot create incomplete lists +structure is known, the reader cannot create improper lists when it reads a dot. So we have to take another pass over the -code to recreate the incomplete lists. +code to recreate the improper lists. -Traverse each list and sublist backwards, and if it contains a -readdot, cons every element in the list on the last element. +Match is awesome!" + let + : + improper + match code + : a ... b 'REPR-DOT-e749c73d-c826-47e2-a798-c16c13cb89dd c + append (map wisp-make-improper a) + cons (wisp-make-improper b) (wisp-make-improper c) + : a ... + map wisp-make-improper a + a + . a + define : syntax-error li msg + throw 'wisp-syntax-error (format #f "incorrect dot-syntax #{.}# in code: ~A: ~A" msg li) + if #t + . improper + let check + : tocheck improper + match tocheck + ; lists with only one member + : 'REPR-DOT-e749c73d-c826-47e2-a798-c16c13cb89dd + syntax-error tocheck "list with the period as only member" + ; list with remaining dot. + : a ... + if : and (member repr-dot a) + syntax-error tocheck "leftover period in list" + map check a + ; simple pair - this and the next do not work when parsed from wisp-scheme itself. Why? + : 'REPR-DOT-e749c73d-c826-47e2-a798-c16c13cb89dd . c + syntax-error tocheck "dot as first element in already improper pair" + ; simple pair, other way round + : a . 'REPR-DOT-e749c73d-c826-47e2-a798-c16c13cb89dd + syntax-error tocheck "dot as last element in already improper pair" + ; more complex pairs + : ? pair? a + let + : head : drop-right a 1 + tail : last-pair a + cond + : equal? repr-dot : car tail + syntax-error tocheck "equal? repr-dot : car tail" + : equal? repr-dot : cdr tail + syntax-error tocheck "equal? repr-dot : cdr tail" + : member repr-dot head + syntax-error tocheck "member repr-dot head" + else + . a + a + . a -TODO: Find out how I can do that, when the second element is a -function call (a list). Problem: (cons 1 '(2)) -> '(1 2). - -TODO: Find out whether this would actually be legal scheme code. - (write (1 . (+ 1 2))) -> error - (write . (+ 1 2)) -> strange - (write (list 1 . (+ 1 2))) -> (1 #<procedure + (#:optional _ _ . _)> 1 2) ??? - (list 1 . (list 2 3)) -> (1 #<procedure list _> 2 3) - (list . (list 2 3)) -> (#<procedure list _> 2 3) == (list list 2 3)" - ; FIXME: Implement recreating incomplete lists! - let loop - : processed '() - unprocessed-reversed expressions - cond - : null? unprocessed-reversed - . processed - : not : list? unprocessed-reversed - ; FIXME: This requires unlimited amounts of memory. - cons unprocessed-reversed processed - : not : member readdot unprocessed-reversed - cond - : list? : car unprocessed-reversed - loop - cons - loop '() : car unprocessed-reversed - . processed - . unprocessed-reversed - else - loop - cons (car unprocessed-reversed) processed - cdr unprocessed-reversed - else ; cons unprocessed on its tail - let conser - : proc-reversed : car unprocessed-reversed - unproc : cdr unprocessed-reversed - cond - : null? unproc - ; back to the main loop - loop - . processed - . proc-reversed - : equal? readdot : car unproc ; just skip the dot. It is why we cons. - conser - . proc-reversed - cdr unproc - else - conser - cons (car unproc) proc-reversed - cdr unproc define : wisp-scheme-read-chunk port . "Read and parse one chunk of wisp-code" let : : lines : wisp-scheme-read-chunk-lines port - ; display lines - ; newline - ; FIXME: incmoplete list recreation does not work yet - ; wisp-scheme-recreate-incomeplete-lists - wisp-scheme-indentation-to-parens lines + wisp-make-improper + wisp-replace-empty-eof + wisp-unescape-underscore-and-colon + wisp-replace-paren-quotation-repr + wisp-scheme-indentation-to-parens lines define : wisp-scheme-read-all port . "Read all chunks from the given port" @@ -511,7 +629,6 @@ define : wisp-scheme-read-all port : tokens '() cond : eof-object? : peek-char port - ; TODO: Join as string. . tokens else loop @@ -526,30 +643,77 @@ define : wisp-scheme-read-file-chunk pat define : wisp-scheme-read-string str call-with-input-string str wisp-scheme-read-all +define : wisp-scheme-read-string-chunk str + call-with-input-string str wisp-scheme-read-chunk -; TODO: Recreate incomplete lists. -write - wisp-scheme-read-string "foo . bar" -newline -write - wisp-scheme-read-string "foo . - . bar" -newline -write - wisp-scheme-read-string "foo - . . bar" -newline -write - wisp-scheme-read-string "moo - foo - . . bar -baz waz" -newline -; systax error -write - wisp-scheme-read-string "foo . - . . bar" -newline + +;;;; Test special syntax +; ;; quote the list +; write +; wisp-scheme-read-string "moo +; foo +; ' bar +; baz waz" +; newline +; ;; quote the symbol - in wisp, whitespace after quote is not allowed! +; write +; wisp-scheme-read-string "moo +; foo +; 'bar +; baz waz" +; newline +; ; ;; quote the list with colon +; write +; wisp-scheme-read-string "moo : ' foo +; foo +; ' bar bah +; baz waz" +; newline +; ; ;; syntax the list +; write +; wisp-scheme-read-string "moo : #' foo +; foo +; #' bar bah +; baz waz" +; newline +; +;;;; Test improper lists +;;;; Good cases +; write +; wisp-scheme-read-string "foo . bar" +; newline +; write +; wisp-scheme-read-string "foo . +; . bar" +; newline +; write +; wisp-scheme-read-string "foo +; . . bar" +; newline +; write +; wisp-scheme-read-string "moo +; foo +; . . bar +; baz waz" +; newline +;;;; Syntax Error cases +; write +; wisp-scheme-read-string "foo +; . . ." +; newline +; write +; wisp-scheme-read-string "moo : . . bar" +; write +; wisp-scheme-read-string "foo . +; . . bar" +; newline +; write +; wisp-scheme-read-string "moo +; foo +; . . bar baz +; baz waz" +; newline +;;;; stranger stuff ; write ; wisp-scheme-read-string "foo ; bar\n ; nop \n\n; nup\n; nup \n \n\n\nfoo : moo \"\n\" \n___ . goo . hoo" ; newline @@ -558,13 +722,14 @@ newline ; newline ; write : wisp-scheme-read-file-chunk "wisp-scheme.w" ; newline -; run all chunks in wisp-guile.w as parsed by wisp-scheme.w. Give wisp-guile.w to parse as argument. -; map primitive-eval : wisp-scheme-read-file "wisp-guile.w" ; call-with-output-file "wisp-guile.scm" ; lambda : port ; map ; lambda : chunk ; write chunk port ; wisp-scheme-read-file "wisp-guile.w" -; pipe the output into 1, then compare it with the output of wisp.scm. If it is equal, this parser works! +; run all chunks in wisp-guile.w as parsed by wisp-scheme.w. Give wisp-guile.w to parse as argument. +; map primitive-eval : wisp-scheme-read-file "wisp-guile.w" ; actually runs wisp-guile.w with the arguments supplied to this script. +; uncomment the previous line, then run the next line in the shell. If 1 and 2 are equal, this parser works! ; guile wisp.scm wisp-scheme.w > wisp-scheme.scm; guile wisp-scheme.scm wisp-guile.w > 1; guile wisp.scm wisp-guile.w > 2; diff 1 2 +