Page Not Found | LIPS Scheme
-
+
diff --git a/assets/js/aa178e2b.f31d8ce2.js b/assets/js/aa178e2b.b3cb7e23.js
similarity index 69%
rename from assets/js/aa178e2b.f31d8ce2.js
rename to assets/js/aa178e2b.b3cb7e23.js
index 860e2d2e..489d5e55 100644
--- a/assets/js/aa178e2b.f31d8ce2.js
+++ b/assets/js/aa178e2b.b3cb7e23.js
@@ -1 +1 @@
-"use strict";(self.webpackChunknew_docs=self.webpackChunknew_docs||[]).push([[7868],{3649:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>c,contentTitle:()=>r,default:()=>h,frontMatter:()=>a,metadata:()=>o,toc:()=>l});var i=s(5893),t=s(1151);const a={sidebar_position:6,description:"A way to extends LIPS syntax, not only with macros"},r="Extending LIPS",o={id:"lips/extension",title:"Extending LIPS",description:"A way to extends LIPS syntax, not only with macros",source:"@site/docs/lips/extension.md",sourceDirName:"lips",slug:"/lips/extension",permalink:"/docs/lips/extension",draft:!1,unlisted:!1,editUrl:"https://github.com/jcubic/lips/tree/master/docs/docs/lips/extension.md",tags:[],version:"current",sidebarPosition:6,frontMatter:{sidebar_position:6,description:"A way to extends LIPS syntax, not only with macros"},sidebar:"tutorialSidebar",previous:{title:"Functional and other utils",permalink:"/docs/lips/functional-helpers"},next:{title:"REPL",permalink:"/docs/lips/REPL"}},c={},l=[{value:"Macros",id:"macros",level:2},{value:"Hygienic macros",id:"hygienic-macros",level:3},{value:"Macroexpand",id:"macroexpand",level:3},{value:"Syntax extensions",id:"syntax-extensions",level:2},{value:"Splice syntax extensions",id:"splice-syntax-extensions",level:3},{value:"Symbol syntax extensions",id:"symbol-syntax-extensions",level:3},{value:"Autogensyms",id:"autogensyms",level:3},{value:"String interpolation",id:"string-interpolation",level:3},{value:"Accessing parser",id:"accessing-parser",level:3},{value:"Standard input",id:"standard-input",level:3},{value:"Limitations",id:"limitations",level:3},{value:"New Homoiconic data types",id:"new-homoiconic-data-types",level:2},{value:"Combining with syntax extensions",id:"combining-with-syntax-extensions",level:3}];function d(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,t.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"extending-lips",children:"Extending LIPS"}),"\n",(0,i.jsxs)(n.p,{children:["There are two ways to extend LIPS Scheme, one is through ",(0,i.jsx)(n.a,{href:"#macros",children:"macros"})," and the other ways is with\n",(0,i.jsx)(n.a,{href:"#syntax-extensions",children:"syntax extensions"}),"."]}),"\n",(0,i.jsx)(n.h2,{id:"macros",children:"Macros"}),"\n",(0,i.jsxs)(n.p,{children:["LIPS allow creating Lisp macros and Scheme hygienic macros. Right now the limitations of macros is\nthat they are runtime. There are no expansion time. Macros act like function calls, but they\ntransform the code and the interpreter evaluates the code that is returned by the macro. They ware\nimplemented like this, because this is how I understood the macros when they first got\nimplemented. There is a ",(0,i.jsx)(n.a,{href:"https://github.com/jcubic/lips/issues/169",children:"plan to create proper macro\nexpansion"}),"."]}),"\n",(0,i.jsx)(n.p,{children:"Quasiquote works with object literals, like with vectors:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(let* ((x 10)\n (y 20)\n (obj `&(:x ,x :y ,y)))\n (print obj))\n"})}),"\n",(0,i.jsxs)(n.p,{children:["to define a lisp macro, you use syntax defined in ",(0,i.jsx)(n.a,{href:"/docs/scheme-intro/macros",children:"Scheme Tutorial about Macros"}),"."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-macro (for var start end . body)\n `(for-each (lambda (,var)\n ,@body)\n (range ,start ,(+ end 1))))\n\n(let ((result (vector)))\n (for i 10 20\n (result.push i))\n (print result))\n;; ==> #(10 11 12 13 14 15 16 17 18 19 20)\n"})}),"\n",(0,i.jsx)(n.p,{children:"You can define macro that create shorthand syntax like in JavaScript:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-javascript",children:"const x = 10;\nconst y = 20;\nconst obj = { x, y };\nconsole.log(obj);\n// { x: 10, y: 20 }\n"})}),"\n",(0,i.jsx)(n.p,{children:"You can create macro that will work the same in LIPS Scheme:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(define (symbol->key symbol)\n (string->symbol (string-append ":" (symbol->string symbol))))\n\n(define-macro (expand . args)\n `(object ,@(reduce (lambda (symbol acc)\n (let ((key (symbol->key symbol)))\n (append acc (list key symbol))))\n \'()\n args)))\n(let* ((x 10)\n (y 20)\n (obj (expand x y)))\n (print obj))\n;; ==> &(:x 10 :y 20)\n'})}),"\n",(0,i.jsx)(n.h3,{id:"hygienic-macros",children:"Hygienic macros"}),"\n",(0,i.jsxs)(n.p,{children:["LIPS define hygienic macros in form of standard ",(0,i.jsx)(n.code,{children:"syntax-rules"})," expression. Note that there are know\nbugs in ",(0,i.jsx)(n.code,{children:"syntax-rules"})," see ",(0,i.jsx)(n.a,{href:"https://github.com/jcubic/lips/issues/43",children:"issue #43 on GitHub"})," and ",(0,i.jsx)(n.a,{href:"https://github.com/jcubic/lips/blob/devel/tests/syntax.scm",children:"unit\ntests"})," that have tests marked as\nfailing."]}),"\n",(0,i.jsx)(n.p,{children:"If you find a case of failing macro, don't hessitate to create an issue. You can also check if your\ncase is not already listed on above links. You can also just create a comment on issue #43 with your\nbroken test case."}),"\n",(0,i.jsx)(n.p,{children:"LIPS Scheme define those extensions to syntax-rules macros:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.a,{href:"https://srfi.schemers.org/srfi-46/srfi-46.html",children:"SRFI-46"})," (changing ellipsis symbol: see\n",(0,i.jsx)(n.a,{href:"/docs/scheme-intro/macros#nested-hygienic-macros",children:"Nested Hygienic Macros"})]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.a,{href:"https://srfi.schemers.org/srfi-139/srfi-139.html",children:"SRFI-139"})," see\n",(0,i.jsx)(n.a,{href:"/docs/scheme-intro/macros#anaphoric-hygienic-macros",children:"Syntax Parameters"})]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.a,{href:"https://srfi.schemers.org/srfi-147/srfi-147.html",children:"SRFI 147"})," allow defining new syntax-rules transformers"]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"macroexpand",children:"Macroexpand"}),"\n",(0,i.jsxs)(n.p,{children:["LIPS define ",(0,i.jsx)(n.code,{children:"macroexpand"})," and ",(0,i.jsx)(n.code,{children:"macroexpand-1"})," but they are macros and the expression don't need to be quoted.\nThere is an ",(0,i.jsx)(n.a,{href:"https://github.com/jcubic/lips/issues/323",children:"issue to change those expressions into functions"})," like\nin ",(0,i.jsx)(n.a,{href:"http://clhs.lisp.se/Body/f_mexp_.htm",children:"Common Lisp"}),"."]}),"\n",(0,i.jsx)(n.h2,{id:"syntax-extensions",children:"Syntax extensions"}),"\n",(0,i.jsx)(n.p,{children:"Syntax extensions are a way to add new syntax to LIPS Scheme. They are executed at parse time. Object literals and\nvector literals are added using syntax extensions. Syntax extension modify the Parser and allow to add new behavior at\nparse time."}),"\n",(0,i.jsx)(n.p,{children:"To add syntax extension you use:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(set-special! "##" \'my-function lips.specials.LITERAL)\n'})}),"\n",(0,i.jsx)(n.p,{children:"The syntax extension can point to a macro or a function. When extension is a function it's invoked and the result data\nis returned from the parser:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define (my-function number)\n `(list ,number ,number))\n"})}),"\n",(0,i.jsx)(n.p,{children:"if you define the function like this and execute:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"##10\n;; ==> (10 10)\n"})}),"\n",(0,i.jsxs)(n.p,{children:["To see the expansion of syntax extension you can use ",(0,i.jsx)(n.code,{children:"lips.parse"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(lips.parse "##10")\n;; ==> #((list 10 10))\n'})}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"NOTE"}),": The ",(0,i.jsx)(n.code,{children:"lips.parse"})," function return array/vector of parsed expressions."]}),"\n",(0,i.jsxs)(n.p,{children:["There are 3 types of syntax extensions ",(0,i.jsx)(n.code,{children:"SPLICE"}),", ",(0,i.jsx)(n.code,{children:"LITERAL"}),", and ",(0,i.jsx)(n.code,{children:"SYMBOL"}),". You define them using\nconstants defined in ",(0,i.jsx)(n.code,{children:"lips.specials"})," object."]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"LITERAL"})," - used above pass it's argument as is, with literal syntax extension you can execute it\non any argument. This is default when no constant in ",(0,i.jsx)(n.code,{children:"set-special!"})," is used."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"SPLICE"})," - if you execute syntax ",(0,i.jsx)(n.code,{children:"##(1 2 3)"})," the arguments will be spliced, so the function or a\nmacro needs to use improper list. Or use named arguments if syntax accept fixed amount of arguments."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"SYMBOL"})," - this type of extensions don't accept any arguments and can be used to define parser constants."]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"splice-syntax-extensions",children:"Splice syntax extensions"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(set-special! "##" \'complex lips.specials.SPLICE)\n\n(define (complex real imag)\n (make-rectangular real imag))\n'})}),"\n",(0,i.jsx)(n.p,{children:"This syntax extension will define complex numbers and will work only on lists:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"##(10 20)\n;; ==> 10+20i\n"})}),"\n",(0,i.jsx)(n.p,{children:"Since it's a macro it evaluate at parse time:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(lips.parse "##(10 20)")\n;; ==> #(10+20i)\n'})}),"\n",(0,i.jsxs)(n.p,{children:["With splice syntax extension you can limit the number of arguments (remember that LIPS don't check\n",(0,i.jsx)(n.a,{href:"https://en.wikipedia.org/wiki/Arity",children:"arity"}),")."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(define (complex . args)\n (if (not (= (length args) 2))\n (throw "Invalid invocation of ## syntax extension")\n (apply make-rectangular args)))\n'})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(lips.parse "##(10 20)")\n;; ==> #(10+20i)\n(lips.parse "##(1 2 3)")\n;; ==> Invalid invocation of ## syntax extension\n'})}),"\n",(0,i.jsx)(n.h3,{id:"symbol-syntax-extensions",children:"Symbol syntax extensions"}),"\n",(0,i.jsx)(n.p,{children:"The last type of syntax extensions are symbols they don't accept any arguments and can be used to\ndefine parser constants."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(set-special! \"nil\" 'nil-fn lips.specials.SYMBOL)\n(define (nil-fn) '())\n"})}),"\n",(0,i.jsxs)(n.p,{children:["This will define constant ",(0,i.jsx)(n.code,{children:"#nil"}),". It's different from ",(0,i.jsx)(n.code,{children:"nil"})," variable:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define nil '())\n\n(eq? nil #nil)\n;; ==> #t\n(eq? (car '(nil)) (car '(#nil)))\n;; ==> #f\n(symbol? (car '(nil)))\n;; ==> #f\n(symbol? (car '(#nil)))\n;; ==> #f\n(eq? (car '(#nil)) '())\n;; ==> #t\n"})}),"\n",(0,i.jsx)(n.h3,{id:"autogensyms",children:"Autogensyms"}),"\n",(0,i.jsx)(n.p,{children:"With syntax extensions you can define autogensyms expressions:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(set-special! \"#:\" 'keyword lips.specials.LITERAL)\n\n(define (keyword symbol)\n `(gensym ',symbol))\n\n(let ((x #:foo))\n (write x))\n;; ==> #:foo\n"})}),"\n",(0,i.jsxs)(n.p,{children:["This allow to create named ",(0,i.jsx)(n.a,{href:"/docs/lips/intro#gensyms",children:"gensyms"})," that are unique:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(eq? #:foo #:foo)\n;; ==> #f\n"})}),"\n",(0,i.jsxs)(n.p,{children:["You can use them with lisp macros instead of ",(0,i.jsx)(n.code,{children:"gensym"})," expressions. The autogensyms are actually part\nof the standard library."]}),"\n",(0,i.jsx)(n.h3,{id:"string-interpolation",children:"String interpolation"}),"\n",(0,i.jsx)(n.p,{children:"With syntax extensions you can create string interpolation that expand into a Scheme code:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(set-special! "$" \'interpolate)\n\n(define (interpolate str)\n (typecheck "interpolate" str "string")\n (let* ((re #/(\\$\\{[^\\}]+\\})/)\n (parts (--\x3e str (split re) (filter Boolean))))\n `(string-append ,@(map (lambda (part)\n (if (not (null? (part.match re)))\n (let* ((expr (part.replace #/(^\\$\\{)|(\\}$)/g ""))\n (port (open-input-string expr))\n (value (with-input-from-port port read)))\n `(repr ,value))\n part))\n (vector->list parts)))))\n\n(pprint (macroexpand-1 (let ((x 10)) $"x = ${(+ x 2)}")))\n;; ==> (let ((x 10))\n;; ==> (string-append "x = " (repr (+ x 2))))\n\n(let ((x 10))\n $"x = ${(+ x 2)}")\n;; ==> "x = 12"\n'})}),"\n",(0,i.jsxs)(n.p,{children:["The limitation of this solution is that you can't use strings inside ",(0,i.jsx)(n.code,{children:"${ ... }"}),". It will break the\nLexer. In the future there may be a way to define such syntax extensions (See ",(0,i.jsx)(n.a,{href:"https://github.com/jcubic/lips/issues/321",children:"Add full string\ninterpolation as syntax extension"}),")."]}),"\n",(0,i.jsx)(n.h3,{id:"accessing-parser",children:"Accessing parser"}),"\n",(0,i.jsx)(n.p,{children:"In LIPS syntax extensions you can access the parser instance, so you can implement syntax\nextension that return line number:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(set-special! "#:num" \'line-num lips.specials.SYMBOL)\n\n(define (line-num)\n (let* ((lexer lips.__parser__.__lexer__)\n (token lexer.__token__))\n (write token)\n (newline)\n ;; line number start from 0\n (+ token.line 1)))\n\n(print (list\n #:num\n #:num))\n;; ==> &(:token "#:num" :col 8 :offset 260 :line 11)\n;; ==> &(:token "#:num" :col 10 :offset 274 :line 12)\n;; ==> (12 13)\n'})}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"NOTE"}),": The provided output will be exactly the same, when the code will be put into a single file\nand executed."]}),"\n",(0,i.jsx)(n.h3,{id:"standard-input",children:"Standard input"}),"\n",(0,i.jsxs)(n.p,{children:["In syntax extensions ",(0,i.jsx)(n.code,{children:"current-input-port"})," points into the parser stream. So you can implement\nyour own parser logic. The best way to implement custom syntax extension (that works similar to\ncommon lips reader macros)."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(set-special! "$" \'raw-string lips.specials.SYMBOL)\n\n(define (raw-string)\n (if (char=? (peek-char) #\\")\n (begin\n (read-char)\n (let loop ((result (vector)) (char (peek-char)))\n (read-char)\n (if (char=? char #\\")\n (apply string (vector->list result))\n (loop (vector-append result (vector char)) (peek-char)))))))\n\n(print $"foo \\ bar")\n;; ==> "foo \\\\ bar"\n'})}),"\n",(0,i.jsxs)(n.p,{children:["This extension implements raw string, like in Python, where you don't need to escape the characters that are thread literally.\nSimilarly, you can implement strings that use backticks, you only need to replace ",(0,i.jsx)(n.code,{children:'#\\"'})," with ",(0,i.jsx)(n.code,{children:"#\\`"}),"."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(set-special! "$" \'raw-string lips.specials.SYMBOL)\n\n(define (raw-string)\n (if (char=? (peek-char) #\\`)\n (begin\n (read-char)\n (let loop ((result (vector)) (char (peek-char)))\n (read-char)\n (if (char=? char #\\`)\n (apply string (vector->list result))\n (loop (vector-append result (vector char)) (peek-char)))))))\n\n(print $`foo \\ bar`)\n;; ==> "foo \\\\ bar"\n'})}),"\n",(0,i.jsx)(n.p,{children:"With this feature in hand you can implement full string interpolation (that will probably be part of\nLIPS Scheme in the future)."}),"\n",(0,i.jsx)(n.h3,{id:"limitations",children:"Limitations"}),"\n",(0,i.jsx)(n.p,{children:"The limitation of syntax extensions is that you can't define a variable that starts with the\nsame characters as syntax extension. This may be a benefit and not a limitation:"}),"\n",(0,i.jsx)(n.h2,{id:"new-homoiconic-data-types",children:"New Homoiconic data types"}),"\n",(0,i.jsx)(n.p,{children:"With LIPS, you can define representation of custom data types that are the same when printed and read."}),"\n",(0,i.jsxs)(n.p,{children:["To create custom representation of new data type you can use ",(0,i.jsx)(n.code,{children:"set-repr!"})," expression. It only works\nwith JavaScript classes. But Scheme records in LIPS define new JavaScript class. So you can create\nnew records and create different representation for them."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(define-record-type :Person\n (make-person name age)\n person?\n (name person-name set-name!)\n (age person-age set-age!))\n\n(set-repr! :Person (lambda (obj quot)\n (string-append "(make-person "\n (repr (person-name obj) quot)\n " "\n (repr (person-age obj) quot)\n ")")))\n\n(write (make-person "Mick Jagger" 80))\n;; ==> (make-person "Mick Jagger" 80)\n(display (make-person "Mick Jagger" 80))\n;; ==> (make-person Mick Jagger 80)\n'})}),"\n",(0,i.jsxs)(n.p,{children:["As you can see the ",(0,i.jsx)(n.code,{children:"display"})," don't quote the strings because of ",(0,i.jsx)(n.code,{children:"repr"})," expression that use ",(0,i.jsx)(n.code,{children:"quot"}),"\nargument to the ",(0,i.jsx)(n.code,{children:"set-repr!"})," handler."]}),"\n",(0,i.jsx)(n.h3,{id:"combining-with-syntax-extensions",children:"Combining with syntax extensions"}),"\n",(0,i.jsx)(n.p,{children:"You can combine syntax extensions with custom representation:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(set-special! ":P" \'make-person lips.specials.SPLICE)\n\n(set-repr! :Person (lambda (obj quot)\n (string-append ":P("\n (repr (person-name obj) quot)\n " "\n (repr (person-age obj) quot)\n ")")))\n\n(write :P("Mick Jagger" 80))\n;; ==> :P("Mick Jagger" 80)\n'})})]})}function h(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},1151:(e,n,s)=>{s.d(n,{Z:()=>o,a:()=>r});var i=s(7294);const t={},a=i.createContext(t);function r(e){const n=i.useContext(a);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:r(e.components),i.createElement(a.Provider,{value:n},e.children)}}}]);
\ No newline at end of file
+"use strict";(self.webpackChunknew_docs=self.webpackChunknew_docs||[]).push([[7868],{3649:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>c,contentTitle:()=>r,default:()=>h,frontMatter:()=>a,metadata:()=>o,toc:()=>l});var i=s(5893),t=s(1151);const a={sidebar_position:6,description:"A way to extends LIPS syntax, not only with macros"},r="Extending LIPS",o={id:"lips/extension",title:"Extending LIPS",description:"A way to extends LIPS syntax, not only with macros",source:"@site/docs/lips/extension.md",sourceDirName:"lips",slug:"/lips/extension",permalink:"/docs/lips/extension",draft:!1,unlisted:!1,editUrl:"https://github.com/jcubic/lips/tree/master/docs/docs/lips/extension.md",tags:[],version:"current",sidebarPosition:6,frontMatter:{sidebar_position:6,description:"A way to extends LIPS syntax, not only with macros"},sidebar:"tutorialSidebar",previous:{title:"Functional and other utils",permalink:"/docs/lips/functional-helpers"},next:{title:"REPL",permalink:"/docs/lips/REPL"}},c={},l=[{value:"Macros",id:"macros",level:2},{value:"Hygienic macros",id:"hygienic-macros",level:3},{value:"Macroexpand",id:"macroexpand",level:3},{value:"Syntax extensions",id:"syntax-extensions",level:2},{value:"Splice syntax extensions",id:"splice-syntax-extensions",level:3},{value:"Symbol syntax extensions",id:"symbol-syntax-extensions",level:3},{value:"Autogensyms",id:"autogensyms",level:3},{value:"String interpolation",id:"string-interpolation",level:3},{value:"Accessing parser",id:"accessing-parser",level:3},{value:"Standard input",id:"standard-input",level:3},{value:"Limitations",id:"limitations",level:3},{value:"New Homoiconic data types",id:"new-homoiconic-data-types",level:2},{value:"Combining with syntax extensions",id:"combining-with-syntax-extensions",level:3}];function d(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,t.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"extending-lips",children:"Extending LIPS"}),"\n",(0,i.jsxs)(n.p,{children:["There are two ways to extend LIPS Scheme, one is through ",(0,i.jsx)(n.a,{href:"#macros",children:"macros"})," and the other ways is with\n",(0,i.jsx)(n.a,{href:"#syntax-extensions",children:"syntax extensions"}),"."]}),"\n",(0,i.jsx)(n.h2,{id:"macros",children:"Macros"}),"\n",(0,i.jsxs)(n.p,{children:["LIPS allow creating Lisp macros and Scheme hygienic macros. Right now the limitations of macros is\nthat they are runtime. There are no expansion time. Macros act like function calls, but they\ntransform the code and the interpreter evaluates the code that is returned by the macro. They ware\nimplemented like this, because this is how I understood the macros when they first got\nimplemented. There is a ",(0,i.jsx)(n.a,{href:"https://github.com/jcubic/lips/issues/169",children:"plan to create proper macro\nexpansion"}),"."]}),"\n",(0,i.jsx)(n.p,{children:"Quasiquote works with object literals, like with vectors:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(let* ((x 10)\n (y 20)\n (obj `&(:x ,x :y ,y)))\n (print obj))\n"})}),"\n",(0,i.jsxs)(n.p,{children:["to define a lisp macro, you use syntax defined in ",(0,i.jsx)(n.a,{href:"/docs/scheme-intro/macros",children:"Scheme Tutorial about Macros"}),"."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define-macro (for var start end . body)\n `(for-each (lambda (,var)\n ,@body)\n (range ,start ,(+ end 1))))\n\n(let ((result (vector)))\n (for i 10 20\n (result.push i))\n (print result))\n;; ==> #(10 11 12 13 14 15 16 17 18 19 20)\n"})}),"\n",(0,i.jsx)(n.p,{children:"You can define macro that create shorthand syntax like in JavaScript:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-javascript",children:"const x = 10;\nconst y = 20;\nconst obj = { x, y };\nconsole.log(obj);\n// { x: 10, y: 20 }\n"})}),"\n",(0,i.jsx)(n.p,{children:"You can create macro that will work the same in LIPS Scheme:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(define (symbol->key symbol)\n (string->symbol (string-append ":" (symbol->string symbol))))\n\n(define-macro (expand . args)\n `(object ,@(reduce (lambda (symbol acc)\n (let ((key (symbol->key symbol)))\n (append acc (list key symbol))))\n \'()\n args)))\n(let* ((x 10)\n (y 20)\n (obj (expand x y)))\n (print obj))\n;; ==> &(:x 10 :y 20)\n'})}),"\n",(0,i.jsx)(n.h3,{id:"hygienic-macros",children:"Hygienic macros"}),"\n",(0,i.jsxs)(n.p,{children:["LIPS define hygienic macros in form of standard ",(0,i.jsx)(n.code,{children:"syntax-rules"})," expression. Note that there are know\nbugs in ",(0,i.jsx)(n.code,{children:"syntax-rules"})," see ",(0,i.jsx)(n.a,{href:"https://github.com/jcubic/lips/issues/43",children:"issue #43 on GitHub"})," and ",(0,i.jsx)(n.a,{href:"https://github.com/jcubic/lips/blob/devel/tests/syntax.scm",children:"unit\ntests"})," that have tests marked as\nfailing."]}),"\n",(0,i.jsx)(n.p,{children:"If you find a case of failing macro, don't hessitate to create an issue. You can also check if your\ncase is not already listed on above links. You can also just create a comment on issue #43 with your\nbroken test case."}),"\n",(0,i.jsx)(n.p,{children:"LIPS Scheme define those extensions to syntax-rules macros:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.a,{href:"https://srfi.schemers.org/srfi-46/srfi-46.html",children:"SRFI-46"})," (changing ellipsis symbol: see\n",(0,i.jsx)(n.a,{href:"/docs/scheme-intro/macros#nested-hygienic-macros",children:"Nested Hygienic Macros"})]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.a,{href:"https://srfi.schemers.org/srfi-139/srfi-139.html",children:"SRFI-139"})," see\n",(0,i.jsx)(n.a,{href:"/docs/scheme-intro/macros#anaphoric-hygienic-macros",children:"Syntax Parameters"})]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.a,{href:"https://srfi.schemers.org/srfi-147/srfi-147.html",children:"SRFI 147"})," allow defining new syntax-rules transformers"]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"macroexpand",children:"Macroexpand"}),"\n",(0,i.jsxs)(n.p,{children:["LIPS define ",(0,i.jsx)(n.code,{children:"macroexpand"})," and ",(0,i.jsx)(n.code,{children:"macroexpand-1"})," but they are macros and the expression don't need to be quoted.\nThere is an ",(0,i.jsx)(n.a,{href:"https://github.com/jcubic/lips/issues/323",children:"issue to change those expressions into functions"})," like\nin ",(0,i.jsx)(n.a,{href:"http://clhs.lisp.se/Body/f_mexp_.htm",children:"Common Lisp"}),"."]}),"\n",(0,i.jsx)(n.h2,{id:"syntax-extensions",children:"Syntax extensions"}),"\n",(0,i.jsx)(n.p,{children:"Syntax extensions are a way to add new syntax to LIPS Scheme. They are executed at parse time. Object literals and\nvector literals are added using syntax extensions. Syntax extension modify the Parser and allow to add new behavior at\nparse time."}),"\n",(0,i.jsx)(n.p,{children:"To add syntax extension you use:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(set-special! "##" \'my-function lips.specials.LITERAL)\n'})}),"\n",(0,i.jsx)(n.p,{children:"The syntax extension can point to a macro or a function. When extension is a function it's invoked and the result data\nis returned from the parser:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define (my-function number)\n `(list ,number ,number))\n"})}),"\n",(0,i.jsx)(n.p,{children:"if you define the function like this and execute:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"##10\n;; ==> (10 10)\n"})}),"\n",(0,i.jsxs)(n.p,{children:["To see the expansion of syntax extension you can use ",(0,i.jsx)(n.code,{children:"lips.parse"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(lips.parse "##10")\n;; ==> #((list 10 10))\n'})}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"NOTE"}),": The ",(0,i.jsx)(n.code,{children:"lips.parse"})," function return array/vector of parsed expressions."]}),"\n",(0,i.jsxs)(n.p,{children:["There are 3 types of syntax extensions ",(0,i.jsx)(n.code,{children:"SPLICE"}),", ",(0,i.jsx)(n.code,{children:"LITERAL"}),", and ",(0,i.jsx)(n.code,{children:"SYMBOL"}),". You define them using\nconstants defined in ",(0,i.jsx)(n.code,{children:"lips.specials"})," object."]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"LITERAL"})," - used above pass it's argument as is, with literal syntax extension you can execute it\non any argument. This is default when no constant in ",(0,i.jsx)(n.code,{children:"set-special!"})," is used."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"SPLICE"})," - if you execute syntax ",(0,i.jsx)(n.code,{children:"##(1 2 3)"})," the arguments will be spliced, so the function or a\nmacro needs to use improper list. Or use named arguments if syntax accept fixed amount of arguments."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"SYMBOL"})," - this type of extensions don't accept any arguments and can be used to define parser constants."]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"splice-syntax-extensions",children:"Splice syntax extensions"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(set-special! "##" \'complex lips.specials.SPLICE)\n\n(define (complex real imag)\n (make-rectangular real imag))\n'})}),"\n",(0,i.jsx)(n.p,{children:"This syntax extension will define complex numbers and will work only on lists:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"##(10 20)\n;; ==> 10+20i\n"})}),"\n",(0,i.jsx)(n.p,{children:"Since it's a macro it evaluate at parse time:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(lips.parse "##(10 20)")\n;; ==> #(10+20i)\n'})}),"\n",(0,i.jsxs)(n.p,{children:["With splice syntax extension you can limit the number of arguments (remember that LIPS don't check\n",(0,i.jsx)(n.a,{href:"https://en.wikipedia.org/wiki/Arity",children:"arity"}),")."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(define (complex . args)\n (if (not (= (length args) 2))\n (throw "Invalid invocation of ## syntax extension")\n (apply make-rectangular args)))\n'})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(lips.parse "##(10 20)")\n;; ==> #(10+20i)\n(lips.parse "##(1 2 3)")\n;; ==> Invalid invocation of ## syntax extension\n'})}),"\n",(0,i.jsx)(n.h3,{id:"symbol-syntax-extensions",children:"Symbol syntax extensions"}),"\n",(0,i.jsx)(n.p,{children:"The last type of syntax extensions are symbols they don't accept any arguments and can be used to\ndefine parser constants."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(set-special! \"nil\" 'nil-fn lips.specials.SYMBOL)\n(define (nil-fn) '())\n"})}),"\n",(0,i.jsxs)(n.p,{children:["This will define constant ",(0,i.jsx)(n.code,{children:"#nil"}),". It's different from ",(0,i.jsx)(n.code,{children:"nil"})," variable:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(define nil '())\n\n(eq? nil #nil)\n;; ==> #t\n(eq? (car '(nil)) (car '(#nil)))\n;; ==> #f\n(symbol? (car '(nil)))\n;; ==> #f\n(symbol? (car '(#nil)))\n;; ==> #f\n(eq? (car '(#nil)) '())\n;; ==> #t\n"})}),"\n",(0,i.jsx)(n.h3,{id:"autogensyms",children:"Autogensyms"}),"\n",(0,i.jsx)(n.p,{children:"With syntax extensions you can define autogensyms expressions:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(set-special! \"#:\" 'keyword lips.specials.LITERAL)\n\n(define (keyword symbol)\n `(gensym ',symbol))\n\n(let ((x #:foo))\n (write x))\n;; ==> #:foo\n"})}),"\n",(0,i.jsxs)(n.p,{children:["This allow to create named ",(0,i.jsx)(n.a,{href:"/docs/lips/intro#gensyms",children:"gensyms"})," that are unique:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:"(eq? #:foo #:foo)\n;; ==> #f\n"})}),"\n",(0,i.jsxs)(n.p,{children:["You can use them with lisp macros instead of ",(0,i.jsx)(n.code,{children:"gensym"})," expressions. The autogensyms are actually part\nof the standard library."]}),"\n",(0,i.jsx)(n.h3,{id:"string-interpolation",children:"String interpolation"}),"\n",(0,i.jsx)(n.p,{children:"With syntax extensions you can create string interpolation that expand into a Scheme code:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(set-special! "$" \'interpolate)\n\n(define (interpolate str)\n (typecheck "interpolate" str "string")\n (let* ((re #/(\\$\\{[^\\}]+\\})/)\n (parts (--\x3e str (split re) (filter Boolean))))\n `(string-append ,@(map (lambda (part)\n (if (not (null? (part.match re)))\n (let* ((expr (part.replace #/(^\\$\\{)|(\\}$)/g ""))\n (port (open-input-string expr))\n (value (with-input-from-port port read)))\n `(repr ,value))\n part))\n (vector->list parts)))))\n\n(pprint (macroexpand-1 (let ((x 10)) $"x = ${(+ x 2)}")))\n;; ==> (let ((x 10))\n;; ==> (string-append "x = " (repr (+ x 2))))\n\n(let ((x 10))\n $"x = ${(+ x 2)}")\n;; ==> "x = 12"\n'})}),"\n",(0,i.jsxs)(n.p,{children:["The limitation of this solution is that you can't use strings inside ",(0,i.jsx)(n.code,{children:"${ ... }"}),". It will break the\nLexer. In order to have full string interpolation you need to read the parser stream (See ",(0,i.jsx)(n.a,{href:"#standard-input",children:"Standard\ninput"})," inside syntax extensions)."]}),"\n",(0,i.jsx)(n.h3,{id:"accessing-parser",children:"Accessing parser"}),"\n",(0,i.jsx)(n.p,{children:"In LIPS syntax extensions you can access the parser instance, so you can implement syntax\nextension that return line number:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(set-special! "#:num" \'line-num lips.specials.SYMBOL)\n\n(define (line-num)\n (let* ((lexer lips.__parser__.__lexer__)\n (token lexer.__token__))\n (write token)\n (newline)\n ;; line number start from 0\n (+ token.line 1)))\n\n(print (list\n #:num\n #:num))\n;; ==> &(:token "#:num" :col 8 :offset 260 :line 11)\n;; ==> &(:token "#:num" :col 10 :offset 274 :line 12)\n;; ==> (12 13)\n'})}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.strong,{children:"NOTE"}),": The provided output will be exactly the same, when the code will be put into a single file\nand executed."]}),"\n",(0,i.jsx)(n.h3,{id:"standard-input",children:"Standard input"}),"\n",(0,i.jsxs)(n.p,{children:["In syntax extensions ",(0,i.jsx)(n.code,{children:"current-input-port"})," points into the parser stream. So you can implement\nyour own parser logic. The best way to implement custom syntax extension (that works similar to\ncommon lips reader macros)."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(set-special! "$" \'raw-string lips.specials.SYMBOL)\n\n(define (raw-string)\n (if (char=? (peek-char) #\\")\n (begin\n (read-char)\n (let loop ((result (vector)) (char (peek-char)))\n (read-char)\n (if (char=? char #\\")\n (apply string (vector->list result))\n (loop (vector-append result (vector char)) (peek-char)))))))\n\n(print $"foo \\ bar")\n;; ==> "foo \\\\ bar"\n'})}),"\n",(0,i.jsxs)(n.p,{children:["This extension implements raw string, like in Python, where you don't need to escape the characters that are thread literally.\nSimilarly, you can implement strings that use backticks, you only need to replace ",(0,i.jsx)(n.code,{children:'#\\"'})," with ",(0,i.jsx)(n.code,{children:"#\\`"}),"."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(set-special! "$" \'raw-string lips.specials.SYMBOL)\n\n(define (raw-string)\n (if (char=? (peek-char) #\\`)\n (begin\n (read-char)\n (let loop ((result (vector)) (char (peek-char)))\n (read-char)\n (if (char=? char #\\`)\n (apply string (vector->list result))\n (loop (vector-append result (vector char)) (peek-char)))))))\n\n(print $`foo \\ bar`)\n;; ==> "foo \\\\ bar"\n'})}),"\n",(0,i.jsx)(n.p,{children:"With this feature in hand you can implement full string interpolation (that will probably be part of\nLIPS Scheme in the future)."}),"\n",(0,i.jsx)(n.h3,{id:"limitations",children:"Limitations"}),"\n",(0,i.jsx)(n.p,{children:"The limitation of syntax extensions is that you can't define a variable that starts with the\nsame characters as syntax extension. This may be a benefit and not a limitation:"}),"\n",(0,i.jsx)(n.h2,{id:"new-homoiconic-data-types",children:"New Homoiconic data types"}),"\n",(0,i.jsx)(n.p,{children:"With LIPS, you can define representation of custom data types that are the same when printed and read."}),"\n",(0,i.jsxs)(n.p,{children:["To create custom representation of new data type you can use ",(0,i.jsx)(n.code,{children:"set-repr!"})," expression. It only works\nwith JavaScript classes. But Scheme records in LIPS define new JavaScript class. So you can create\nnew records and create different representation for them."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(define-record-type :Person\n (make-person name age)\n person?\n (name person-name set-name!)\n (age person-age set-age!))\n\n(set-repr! :Person (lambda (obj quot)\n (string-append "(make-person "\n (repr (person-name obj) quot)\n " "\n (repr (person-age obj) quot)\n ")")))\n\n(write (make-person "Mick Jagger" 80))\n;; ==> (make-person "Mick Jagger" 80)\n(display (make-person "Mick Jagger" 80))\n;; ==> (make-person Mick Jagger 80)\n'})}),"\n",(0,i.jsxs)(n.p,{children:["As you can see the ",(0,i.jsx)(n.code,{children:"display"})," don't quote the strings because of ",(0,i.jsx)(n.code,{children:"repr"})," expression that use ",(0,i.jsx)(n.code,{children:"quot"}),"\nargument to the ",(0,i.jsx)(n.code,{children:"set-repr!"})," handler."]}),"\n",(0,i.jsx)(n.h3,{id:"combining-with-syntax-extensions",children:"Combining with syntax extensions"}),"\n",(0,i.jsx)(n.p,{children:"You can combine syntax extensions with custom representation:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-scheme",children:'(set-special! ":P" \'make-person lips.specials.SPLICE)\n\n(set-repr! :Person (lambda (obj quot)\n (string-append ":P("\n (repr (person-name obj) quot)\n " "\n (repr (person-age obj) quot)\n ")")))\n\n(write :P("Mick Jagger" 80))\n;; ==> :P("Mick Jagger" 80)\n'})})]})}function h(e={}){const{wrapper:n}={...(0,t.a)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},1151:(e,n,s)=>{s.d(n,{Z:()=>o,a:()=>r});var i=s(7294);const t={},a=i.createContext(t);function r(e){const n=i.useContext(a);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:r(e.components),i.createElement(a.Provider,{value:n},e.children)}}}]);
\ No newline at end of file
diff --git a/assets/js/runtime~main.59481896.js b/assets/js/runtime~main.f121cbbb.js
similarity index 98%
rename from assets/js/runtime~main.59481896.js
rename to assets/js/runtime~main.f121cbbb.js
index caa69acb..ecc08cae 100644
--- a/assets/js/runtime~main.59481896.js
+++ b/assets/js/runtime~main.f121cbbb.js
@@ -1 +1 @@
-(()=>{"use strict";var e,a,f,c,t,r={},d={};function b(e){var a=d[e];if(void 0!==a)return a.exports;var f=d[e]={exports:{}};return r[e].call(f.exports,f,f.exports,b),f.exports}b.m=r,e=[],b.O=(a,f,c,t)=>{if(!f){var r=1/0;for(i=0;i=t)&&Object.keys(b.O).every((e=>b.O[e](f[o])))?f.splice(o--,1):(d=!1,t0&&e[i-1][2]>t;i--)e[i]=e[i-1];e[i]=[f,c,t]},b.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return b.d(a,{a:a}),a},f=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,b.t=function(e,c){if(1&c&&(e=this(e)),8&c)return e;if("object"==typeof e&&e){if(4&c&&e.__esModule)return e;if(16&c&&"function"==typeof e.then)return e}var t=Object.create(null);b.r(t);var r={};a=a||[null,f({}),f([]),f(f)];for(var d=2&c&&e;"object"==typeof d&&!~a.indexOf(d);d=f(d))Object.getOwnPropertyNames(d).forEach((a=>r[a]=()=>e[a]));return r.default=()=>e,b.d(t,r),t},b.d=(e,a)=>{for(var f in a)b.o(a,f)&&!b.o(e,f)&&Object.defineProperty(e,f,{enumerable:!0,get:a[f]})},b.f={},b.e=e=>Promise.all(Object.keys(b.f).reduce(((a,f)=>(b.f[f](e,a),a)),[])),b.u=e=>"assets/js/"+({53:"935f2afb",81:"2abfd7a8",533:"b2b675dd",743:"7e736cac",1070:"f196f4a4",1113:"e511e452",1208:"3828c8cd",1317:"75505f57",1477:"b2f554cd",1652:"ea13dd3a",1677:"0a637f08",1713:"a7023ddc",2535:"814f3328",2553:"6878938b",2813:"4b1723f1",2822:"35ee46b0",3085:"1f391b9e",3089:"a6aa9e1f",3237:"1df93b7f",3604:"9ede617c",3608:"9e4087bc",4013:"01a85c17",4015:"69aa9e93",4368:"a94703ab",4699:"ab461798",4985:"14a48451",5460:"9abc7bc7",5564:"468f2e1c",5609:"e1902777",5747:"726afaaf",6103:"ccc49370",6143:"1f27c5d1",6296:"c74dcec5",7018:"413466e5",7184:"68243087",7393:"acecf23e",7414:"393be207",7836:"840797c7",7868:"aa178e2b",7903:"db96436e",7918:"17896441",7953:"f724a01c",8071:"f2e31a35",8097:"4f7497d7",8424:"5ad8d976",8518:"a7bd4aaa",8610:"6875c492",9195:"d969d8ea",9242:"c71491fd",9301:"430f917c",9342:"df5a86e1",9661:"5e95c892",9671:"0e384e19",9817:"14eb3368"}[e]||e)+"."+{53:"cc6240be",81:"eaf1209f",533:"7f33185e",743:"41e22d1d",1070:"4d17d4a0",1113:"6dce99c6",1208:"aa6ba2aa",1317:"519f4209",1477:"92ae2c22",1652:"e9dd3f0f",1677:"61ff06c6",1713:"f57aae3f",1772:"205fa78b",2535:"33be7cdd",2553:"62200649",2813:"7994837a",2822:"5499b20c",3085:"6e4b1596",3089:"ca60c0b4",3237:"7bff3f57",3604:"9d811c06",3608:"eb64b0cc",4013:"0d6af7b9",4015:"00e22eaa",4368:"fac9076a",4699:"e445eee8",4985:"b2bb271d",5005:"facea533",5460:"58965eb1",5564:"1eb5cbc8",5609:"c9bdda11",5747:"5e9ff151",6103:"75bf7d8f",6143:"4d1e30de",6296:"2757b8e1",6705:"8d1cee0d",7018:"5b84004c",7184:"0f23da7a",7393:"3caaec2f",7414:"6bb4bbad",7534:"5a903753",7836:"60904e28",7868:"f31d8ce2",7903:"8da5bafb",7918:"af71c726",7953:"087dbc0b",8071:"eff52960",8097:"07ed6383",8424:"f15ddef4",8518:"b2f1f87c",8610:"54a03b73",9195:"6ce6b63f",9242:"11363cc6",9301:"756863bd",9342:"5a8b1f83",9386:"eb7dae53",9661:"daee7819",9671:"4a2ae178",9817:"131961d5"}[e]+".js",b.miniCssF=e=>{},b.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),b.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),c={},t="new-docs:",b.l=(e,a,f,r)=>{if(c[e])c[e].push(a);else{var d,o;if(void 0!==f)for(var n=document.getElementsByTagName("script"),i=0;i{d.onerror=d.onload=null,clearTimeout(s);var t=c[e];if(delete c[e],d.parentNode&&d.parentNode.removeChild(d),t&&t.forEach((e=>e(f))),a)return a(f)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:d}),12e4);d.onerror=l.bind(null,d.onerror),d.onload=l.bind(null,d.onload),o&&document.head.appendChild(d)}},b.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},b.p="/",b.gca=function(e){return e={17896441:"7918",68243087:"7184","935f2afb":"53","2abfd7a8":"81",b2b675dd:"533","7e736cac":"743",f196f4a4:"1070",e511e452:"1113","3828c8cd":"1208","75505f57":"1317",b2f554cd:"1477",ea13dd3a:"1652","0a637f08":"1677",a7023ddc:"1713","814f3328":"2535","6878938b":"2553","4b1723f1":"2813","35ee46b0":"2822","1f391b9e":"3085",a6aa9e1f:"3089","1df93b7f":"3237","9ede617c":"3604","9e4087bc":"3608","01a85c17":"4013","69aa9e93":"4015",a94703ab:"4368",ab461798:"4699","14a48451":"4985","9abc7bc7":"5460","468f2e1c":"5564",e1902777:"5609","726afaaf":"5747",ccc49370:"6103","1f27c5d1":"6143",c74dcec5:"6296","413466e5":"7018",acecf23e:"7393","393be207":"7414","840797c7":"7836",aa178e2b:"7868",db96436e:"7903",f724a01c:"7953",f2e31a35:"8071","4f7497d7":"8097","5ad8d976":"8424",a7bd4aaa:"8518","6875c492":"8610",d969d8ea:"9195",c71491fd:"9242","430f917c":"9301",df5a86e1:"9342","5e95c892":"9661","0e384e19":"9671","14eb3368":"9817"}[e]||e,b.p+b.u(e)},(()=>{var e={1303:0,532:0};b.f.j=(a,f)=>{var c=b.o(e,a)?e[a]:void 0;if(0!==c)if(c)f.push(c[2]);else if(/^(1303|532)$/.test(a))e[a]=0;else{var t=new Promise(((f,t)=>c=e[a]=[f,t]));f.push(c[2]=t);var r=b.p+b.u(a),d=new Error;b.l(r,(f=>{if(b.o(e,a)&&(0!==(c=e[a])&&(e[a]=void 0),c)){var t=f&&("load"===f.type?"missing":f.type),r=f&&f.target&&f.target.src;d.message="Loading chunk "+a+" failed.\n("+t+": "+r+")",d.name="ChunkLoadError",d.type=t,d.request=r,c[1](d)}}),"chunk-"+a,a)}},b.O.j=a=>0===e[a];var a=(a,f)=>{var c,t,r=f[0],d=f[1],o=f[2],n=0;if(r.some((a=>0!==e[a]))){for(c in d)b.o(d,c)&&(b.m[c]=d[c]);if(o)var i=o(b)}for(a&&a(f);n{"use strict";var e,a,f,c,t,r={},d={};function b(e){var a=d[e];if(void 0!==a)return a.exports;var f=d[e]={exports:{}};return r[e].call(f.exports,f,f.exports,b),f.exports}b.m=r,e=[],b.O=(a,f,c,t)=>{if(!f){var r=1/0;for(i=0;i=t)&&Object.keys(b.O).every((e=>b.O[e](f[o])))?f.splice(o--,1):(d=!1,t0&&e[i-1][2]>t;i--)e[i]=e[i-1];e[i]=[f,c,t]},b.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return b.d(a,{a:a}),a},f=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,b.t=function(e,c){if(1&c&&(e=this(e)),8&c)return e;if("object"==typeof e&&e){if(4&c&&e.__esModule)return e;if(16&c&&"function"==typeof e.then)return e}var t=Object.create(null);b.r(t);var r={};a=a||[null,f({}),f([]),f(f)];for(var d=2&c&&e;"object"==typeof d&&!~a.indexOf(d);d=f(d))Object.getOwnPropertyNames(d).forEach((a=>r[a]=()=>e[a]));return r.default=()=>e,b.d(t,r),t},b.d=(e,a)=>{for(var f in a)b.o(a,f)&&!b.o(e,f)&&Object.defineProperty(e,f,{enumerable:!0,get:a[f]})},b.f={},b.e=e=>Promise.all(Object.keys(b.f).reduce(((a,f)=>(b.f[f](e,a),a)),[])),b.u=e=>"assets/js/"+({53:"935f2afb",81:"2abfd7a8",533:"b2b675dd",743:"7e736cac",1070:"f196f4a4",1113:"e511e452",1208:"3828c8cd",1317:"75505f57",1477:"b2f554cd",1652:"ea13dd3a",1677:"0a637f08",1713:"a7023ddc",2535:"814f3328",2553:"6878938b",2813:"4b1723f1",2822:"35ee46b0",3085:"1f391b9e",3089:"a6aa9e1f",3237:"1df93b7f",3604:"9ede617c",3608:"9e4087bc",4013:"01a85c17",4015:"69aa9e93",4368:"a94703ab",4699:"ab461798",4985:"14a48451",5460:"9abc7bc7",5564:"468f2e1c",5609:"e1902777",5747:"726afaaf",6103:"ccc49370",6143:"1f27c5d1",6296:"c74dcec5",7018:"413466e5",7184:"68243087",7393:"acecf23e",7414:"393be207",7836:"840797c7",7868:"aa178e2b",7903:"db96436e",7918:"17896441",7953:"f724a01c",8071:"f2e31a35",8097:"4f7497d7",8424:"5ad8d976",8518:"a7bd4aaa",8610:"6875c492",9195:"d969d8ea",9242:"c71491fd",9301:"430f917c",9342:"df5a86e1",9661:"5e95c892",9671:"0e384e19",9817:"14eb3368"}[e]||e)+"."+{53:"cc6240be",81:"eaf1209f",533:"7f33185e",743:"41e22d1d",1070:"4d17d4a0",1113:"6dce99c6",1208:"aa6ba2aa",1317:"519f4209",1477:"92ae2c22",1652:"e9dd3f0f",1677:"61ff06c6",1713:"f57aae3f",1772:"205fa78b",2535:"33be7cdd",2553:"62200649",2813:"7994837a",2822:"5499b20c",3085:"6e4b1596",3089:"ca60c0b4",3237:"7bff3f57",3604:"9d811c06",3608:"eb64b0cc",4013:"0d6af7b9",4015:"00e22eaa",4368:"fac9076a",4699:"e445eee8",4985:"b2bb271d",5005:"facea533",5460:"58965eb1",5564:"1eb5cbc8",5609:"c9bdda11",5747:"5e9ff151",6103:"75bf7d8f",6143:"4d1e30de",6296:"2757b8e1",6705:"8d1cee0d",7018:"5b84004c",7184:"0f23da7a",7393:"3caaec2f",7414:"6bb4bbad",7534:"5a903753",7836:"60904e28",7868:"b3cb7e23",7903:"8da5bafb",7918:"af71c726",7953:"087dbc0b",8071:"eff52960",8097:"07ed6383",8424:"f15ddef4",8518:"b2f1f87c",8610:"54a03b73",9195:"6ce6b63f",9242:"11363cc6",9301:"756863bd",9342:"5a8b1f83",9386:"eb7dae53",9661:"daee7819",9671:"4a2ae178",9817:"131961d5"}[e]+".js",b.miniCssF=e=>{},b.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),b.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),c={},t="new-docs:",b.l=(e,a,f,r)=>{if(c[e])c[e].push(a);else{var d,o;if(void 0!==f)for(var n=document.getElementsByTagName("script"),i=0;i{d.onerror=d.onload=null,clearTimeout(s);var t=c[e];if(delete c[e],d.parentNode&&d.parentNode.removeChild(d),t&&t.forEach((e=>e(f))),a)return a(f)},s=setTimeout(l.bind(null,void 0,{type:"timeout",target:d}),12e4);d.onerror=l.bind(null,d.onerror),d.onload=l.bind(null,d.onload),o&&document.head.appendChild(d)}},b.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},b.p="/",b.gca=function(e){return e={17896441:"7918",68243087:"7184","935f2afb":"53","2abfd7a8":"81",b2b675dd:"533","7e736cac":"743",f196f4a4:"1070",e511e452:"1113","3828c8cd":"1208","75505f57":"1317",b2f554cd:"1477",ea13dd3a:"1652","0a637f08":"1677",a7023ddc:"1713","814f3328":"2535","6878938b":"2553","4b1723f1":"2813","35ee46b0":"2822","1f391b9e":"3085",a6aa9e1f:"3089","1df93b7f":"3237","9ede617c":"3604","9e4087bc":"3608","01a85c17":"4013","69aa9e93":"4015",a94703ab:"4368",ab461798:"4699","14a48451":"4985","9abc7bc7":"5460","468f2e1c":"5564",e1902777:"5609","726afaaf":"5747",ccc49370:"6103","1f27c5d1":"6143",c74dcec5:"6296","413466e5":"7018",acecf23e:"7393","393be207":"7414","840797c7":"7836",aa178e2b:"7868",db96436e:"7903",f724a01c:"7953",f2e31a35:"8071","4f7497d7":"8097","5ad8d976":"8424",a7bd4aaa:"8518","6875c492":"8610",d969d8ea:"9195",c71491fd:"9242","430f917c":"9301",df5a86e1:"9342","5e95c892":"9661","0e384e19":"9671","14eb3368":"9817"}[e]||e,b.p+b.u(e)},(()=>{var e={1303:0,532:0};b.f.j=(a,f)=>{var c=b.o(e,a)?e[a]:void 0;if(0!==c)if(c)f.push(c[2]);else if(/^(1303|532)$/.test(a))e[a]=0;else{var t=new Promise(((f,t)=>c=e[a]=[f,t]));f.push(c[2]=t);var r=b.p+b.u(a),d=new Error;b.l(r,(f=>{if(b.o(e,a)&&(0!==(c=e[a])&&(e[a]=void 0),c)){var t=f&&("load"===f.type?"missing":f.type),r=f&&f.target&&f.target.src;d.message="Loading chunk "+a+" failed.\n("+t+": "+r+")",d.name="ChunkLoadError",d.type=t,d.request=r,c[1](d)}}),"chunk-"+a,a)}},b.O.j=a=>0===e[a];var a=(a,f)=>{var c,t,r=f[0],d=f[1],o=f[2],n=0;if(r.some((a=>0!==e[a]))){for(c in d)b.o(d,c)&&(b.m[c]=d[c]);if(o)var i=o(b)}for(a&&a(f);nArchive | LIPS Scheme
-
+
diff --git a/blog/emacs-scheme-regex/index.html b/blog/emacs-scheme-regex/index.html
index 22d05634..c6add592 100644
--- a/blog/emacs-scheme-regex/index.html
+++ b/blog/emacs-scheme-regex/index.html
@@ -4,7 +4,7 @@
Scheme Regex literals in Emacs | LIPS Scheme
-
+
diff --git a/blog/index.html b/blog/index.html
index cf96c5d0..dd85d5dc 100644
--- a/blog/index.html
+++ b/blog/index.html
@@ -4,7 +4,7 @@
Blog | LIPS Scheme
-
+
diff --git a/blog/lips-history/index.html b/blog/lips-history/index.html
index e9212f79..095a384a 100644
--- a/blog/lips-history/index.html
+++ b/blog/lips-history/index.html
@@ -4,7 +4,7 @@
LIPS History | LIPS Scheme
-
+
diff --git a/blog/tags/emacs/index.html b/blog/tags/emacs/index.html
index d20c50fc..55bcbdf7 100644
--- a/blog/tags/emacs/index.html
+++ b/blog/tags/emacs/index.html
@@ -4,7 +4,7 @@
One post tagged with "emacs" | LIPS Scheme
-
+
diff --git a/blog/tags/history/index.html b/blog/tags/history/index.html
index ec1788fe..0cd6456e 100644
--- a/blog/tags/history/index.html
+++ b/blog/tags/history/index.html
@@ -4,7 +4,7 @@
One post tagged with "history" | LIPS Scheme
-
+
diff --git a/blog/tags/index.html b/blog/tags/index.html
index fad1ad1f..af6bf799 100644
--- a/blog/tags/index.html
+++ b/blog/tags/index.html
@@ -4,7 +4,7 @@
Tags | LIPS Scheme
-
+
diff --git a/blog/tags/lips/index.html b/blog/tags/lips/index.html
index 74a96957..f1ba9b27 100644
--- a/blog/tags/lips/index.html
+++ b/blog/tags/lips/index.html
@@ -4,7 +4,7 @@
One post tagged with "lips" | LIPS Scheme
-
+
diff --git a/blog/tags/scheme/index.html b/blog/tags/scheme/index.html
index 91d0b735..95d98ce0 100644
--- a/blog/tags/scheme/index.html
+++ b/blog/tags/scheme/index.html
@@ -4,7 +4,7 @@
2 posts tagged with "scheme" | LIPS Scheme
-
+
diff --git a/docs/category/introduction-to-scheme/index.html b/docs/category/introduction-to-scheme/index.html
index 4297e15f..715374c5 100644
--- a/docs/category/introduction-to-scheme/index.html
+++ b/docs/category/introduction-to-scheme/index.html
@@ -4,7 +4,7 @@
Introduction to Scheme | LIPS Scheme
-
+
diff --git a/docs/category/lips-introduction/index.html b/docs/category/lips-introduction/index.html
index ed341bbe..ecc3d446 100644
--- a/docs/category/lips-introduction/index.html
+++ b/docs/category/lips-introduction/index.html
@@ -4,7 +4,7 @@
LIPS introduction | LIPS Scheme
-
+
diff --git a/docs/intro/index.html b/docs/intro/index.html
index 802b6c62..50acd196 100644
--- a/docs/intro/index.html
+++ b/docs/intro/index.html
@@ -4,7 +4,7 @@
Getting Started | LIPS Scheme
-
+
diff --git a/docs/lips/REPL/index.html b/docs/lips/REPL/index.html
index 43e277a4..778b351a 100644
--- a/docs/lips/REPL/index.html
+++ b/docs/lips/REPL/index.html
@@ -4,7 +4,7 @@
REPL | LIPS Scheme
-
+
diff --git a/docs/lips/environments/index.html b/docs/lips/environments/index.html
index f8616061..621ed1dd 100644
--- a/docs/lips/environments/index.html
+++ b/docs/lips/environments/index.html
@@ -4,7 +4,7 @@
Environments | LIPS Scheme
-
+
diff --git a/docs/lips/extension/index.html b/docs/lips/extension/index.html
index 82d5bb9d..3c6ac1e1 100644
--- a/docs/lips/extension/index.html
+++ b/docs/lips/extension/index.html
@@ -4,7 +4,7 @@
Extending LIPS | LIPS Scheme
-
+
@@ -198,8 +198,8 @@
String
;; ==> "x = 12"
The limitation of this solution is that you can't use strings inside ${ ... }. It will break the
-Lexer. In the future there may be a way to define such syntax extensions (See Add full string
-interpolation as syntax extension).
+Lexer. In order to have full string interpolation you need to read the parser stream (See Standard
+input inside syntax extensions).