diff --git a/404.html b/404.html index d78bd4a4..d07d8e0d 100644 --- a/404.html +++ b/404.html @@ -4,7 +4,7 @@
..
and .
operators",id:"usage-of-legacy--and--operators",level:5},{value:"Scheme functions",id:"scheme-functions",level:3},{value:"JavaScript functions",id:"javascript-functions",level:3},{value:"Callbacks",id:"callbacks",level:3},{value:"Regular Expressions",id:"regular-expressions",level:3},{value:"Vectors",id:"vectors",level:3},{value:"Object literals",id:"object-literals",level:3},{value:"Automagic async/await",id:"automagic-asyncawait",level:3},{value:"Promise quotation",id:"promise-quotation",level:3},{value:"Promises vs delay expression",id:"promises-vs-delay-expression",level:3},{value:"Exceptions",id:"exceptions",level:3},{value:"JavaScript Generars and iterators",id:"javascript-generars-and-iterators",level:3},{value:"Classes",id:"classes",level:3},{value:"Node.js",id:"nodejs",level:3},{value:"ES Modules",id:"es-modules",level:3},{value:"Finding LIPS Scheme directory",id:"finding-lips-scheme-directory",level:3},{value:"Binary compiler",id:"binary-compiler",level:2},{value:"loading SRFI",id:"loading-srfi",level:2},{value:"Limitations",id:"limitations",level:2}];function d(e){const n={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",h5:"h5",header:"header",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,i.R)(),...e.components};return(0,a.jsxs)(a.Fragment,{children:[(0,a.jsx)(n.header,{children:(0,a.jsx)(n.h1,{id:"core-features",children:"Core features"})}),"\n",(0,a.jsx)(n.h2,{id:"special-constants",children:"Special constants"}),"\n",(0,a.jsxs)(n.p,{children:["LIPS define ",(0,a.jsx)(n.code,{children:"#null"})," and ",(0,a.jsx)(n.code,{children:"#void"})," as Parser constants so they can be used inside quoted expressions:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-scheme",children:"(let ((lst '(#null #void)))\n (write (symbol? (car lst)))\n (newline)\n (write (symbol? (cadr lst)))\n (newline))\n;; ==> #f\n;; ==> #f\n"})}),"\n",(0,a.jsxs)(n.p,{children:[(0,a.jsx)(n.strong,{children:"NOTE"})," ",(0,a.jsx)(n.code,{children:"#null"})," is the same as JavaScript ",(0,a.jsx)(n.code,{children:"null"})," value and it's a false value. Similar to\n",(0,a.jsx)(n.a,{href:"https://www.gnu.org/software/kawa/index.html",children:"Kawa Scheme"})," that use ",(0,a.jsx)(n.code,{children:"#!null"}),"."]}),"\n",(0,a.jsxs)(n.p,{children:[(0,a.jsx)(n.code,{children:"#void"})," constants is the same as result of ",(0,a.jsx)(n.code,{children:"(value)"})," or ",(0,a.jsx)(n.code,{children:"(if #f #f)"}),". In Scheme it's unspecified value,\nbut in LIPS it's JavaScript undefined. ",(0,a.jsx)(n.code,{children:"#void"})," is not false value."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-scheme",children:"(eq? (if #f #f) (values))\n;; ==> #t\n"})}),"\n",(0,a.jsx)(n.h2,{id:"numerical-tower",children:"Numerical tower"}),"\n",(0,a.jsx)(n.p,{children:"LIPS support full numerical tower (not yet 100% unit tested):"}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsx)(n.li,{children:"integers - using BitInt"}),"\n",(0,a.jsx)(n.li,{children:"floats - using JavaScript numbers"}),"\n",(0,a.jsx)(n.li,{children:"rationals"}),"\n",(0,a.jsx)(n.li,{children:"complex numbers (that can use integers, floats, or rationals)"}),"\n"]}),"\n",(0,a.jsx)(n.h2,{id:"print-procedure",children:"Print procedure"}),"\n",(0,a.jsxs)(n.p,{children:["LIPS define helper ",(0,a.jsx)(n.code,{children:"print"})," procedure that display all its arguments with newline after each element."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-scheme",children:"(print 1 2 3)\n;; ==> 1\n;; ==> 2\n;; ==> 3\n"})}),"\n",(0,a.jsx)(n.h2,{id:"emoji",children:"Emoji"}),"\n",(0,a.jsx)(n.p,{children:"LIPS fully supports all Unicode characters, including emoji:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-scheme",children:'(define smiley #\\\ud83d\ude00)\n(define poo #\\\ud83d\udca9)\n(write (string-append (string smiley) " " (string poo)))\n;; ==> "\ud83d\ude00 \ud83d\udca9"\n'})}),"\n",(0,a.jsx)(n.p,{children:"You can also use them as part of symbols (e.g. as variables name):"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-scheme",children:'(define (\u23cf\ufe0f)\n (print "ejecting"))\n(\u23cf\ufe0f)\n;; ==> ejecting\n'})}),"\n",(0,a.jsx)(n.h2,{id:"macros",children:"Macros"}),"\n",(0,a.jsxs)(n.p,{children:["LIPS define both Lisp macros and Scheme hygienic macros (",(0,a.jsx)(n.code,{children:"syntax-rules"}),")."]}),"\n",(0,a.jsx)(n.p,{children:"It also implements:"}),"\n",(0,a.jsxs)(n.ul,{children:["\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.a,{href:"https://srfi.schemers.org/srfi-46/",children:"SRFI-46"})," which allows changing the ellipsis symbol for nested syntax-rules."]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.a,{href:"https://srfi.schemers.org/srfi-139/",children:"SRFI-139"})," which allows defining\n",(0,a.jsx)(n.a,{href:"/docs/scheme-intro/macros#anaphoric-hygienic-macros",children:"anaphoric syntax-rules macros"}),"."]}),"\n",(0,a.jsxs)(n.li,{children:[(0,a.jsx)(n.a,{href:"https://srfi.schemers.org/srfi-147/",children:"SRFI-147"})," which allows defining a new syntax-rules macros to define syntax-rules macros."]}),"\n"]}),"\n",(0,a.jsx)(n.h3,{id:"gensyms",children:"Gensyms"}),"\n",(0,a.jsxs)(n.p,{children:["With lisp macros you can use ",(0,a.jsx)(n.a,{href:"/docs/scheme-intro/macros#gensyms",children:"gensyms"}),", they are special Scheme\nsymbols that use JavaScript symbols behind the scene, so they are proven to be unique. Additionally\nyou can use named gensym if you pass string as first argument:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-scheme",children:'(gensym)\n;; ==> #:g5\n(gensym "sym")\n;; ==> #:sym\n'})}),"\n",(0,a.jsx)(n.h2,{id:"single-argument-eval",children:"Single argument eval"}),"\n",(0,a.jsxs)(n.p,{children:["Eval in LIPS don't require second argument to ",(0,a.jsx)(n.code,{children:"eval"}),". The environment is optional and default\nit's a result of calling ",(0,a.jsx)(n.code,{children:"(interaction-environment)"}),"."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-scheme",children:"(define x 10)\n(eval '(+ x x))\n;; ==> 20\n"})}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-scheme",children:"(define x 10)\n(let ((x 20))\n (eval '(- x)))\n;; ==> -10\n"})}),"\n",(0,a.jsx)(n.p,{children:"But you can also use the second arguments:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-scheme",children:"(define x 10)\n(let ((x 20))\n (eval '(- x) (current-environment)))\n;; ==> -20\n"})}),"\n",(0,a.jsxs)(n.p,{children:["Read more about ",(0,a.jsx)(n.a,{href:"/docs/lips/environments",children:"LIPS environments"}),"."]}),"\n",(0,a.jsx)(n.h2,{id:"procedures",children:"Procedures"}),"\n",(0,a.jsxs)(n.p,{children:["Procedures in LIPS have access additional objects ",(0,a.jsx)(n.code,{children:"arguments"}),", but the have nothing to do with JavaScript.\narguments is an array/vector with calling arguments and it have an object callee which points to the same\nprocedure. So you can create recursive functions with anonymous lambda:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-scheme",children:"((lambda (n)\n (if (<= n 0)\n 1\n (* n (arguments.callee (- n 1))))) 10)\n;; ==> 3628800\n"})}),"\n",(0,a.jsx)(n.p,{children:"This is classic factorial function written as lambda without the name."}),"\n",(0,a.jsx)(n.h3,{id:"length-property",children:"length property"}),"\n",(0,a.jsxs)(n.p,{children:["LIPS functions similarly to JavaScript functions also have ",(0,a.jsx)(n.code,{children:"length"})," property that indicate how many\narguments a function accepts. If function get more or less argumenets it's not an error like in Scheme. More arguments are ignored,\nand if less arguments are passed they are ",(0,a.jsx)(n.code,{children:"undefined"})," (",(0,a.jsx)(n.code,{children:"#void"}),")."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-scheme",children:"(define (sum a b c)\n (+ a b c))\n\n(print sum.length)\n;; ==> 3\n"})}),"\n",(0,a.jsx)(n.p,{children:"It return number of number arguments the rest (dot notation) arguments are ignored."}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-scheme",children:"(define (sum a b . rest)\n (apply + a b rest))\n\n(print sum.length)\n;; ==> 3\n(sum 1 2 3 4 5 6)\n;; ==> 21\n"})}),"\n",(0,a.jsx)(n.h2,{id:"doc-strings",children:"Doc strings"}),"\n",(0,a.jsx)(n.p,{children:"Procedures, macros, and variables can have doc strings."}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-scheme",children:'(define (factorial n)\n "(factorial n)\n\n Calculate factorial of a given number"\n (if (<= n 0)\n 1\n (* n (factorial (- n 1)))))\n'})}),"\n",(0,a.jsxs)(n.p,{children:["You can access doc string with ",(0,a.jsx)(n.code,{children:"help"})," procedure or with ",(0,a.jsx)(n.code,{children:"__doc__"})," property."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-scheme",children:'(write factorial.__doc__)\n"(factorial n)\n\nCalculate factorial of a given number"\n'})}),"\n",(0,a.jsxs)(n.p,{children:["If you define variable or hygienic macro with doc string, the string is hidden (you can access it with ",(0,a.jsx)(n.code,{children:"__doc__"}),"),\nso help is the only way to access it:"]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-scheme",children:'(define-syntax q\n (syntax-rules ()\n ((_ x) \'x))\n "(q expression)\n\n Macro quote the expression")\n\n(write q.__doc__)\n;; ==> #void\n(help q)\n;; ==> (q expression)\n;; ==>\n;; ==> Macro quote the expression\n'})}),"\n",(0,a.jsx)(n.h2,{id:"typechecking",children:"Typechecking"}),"\n",(0,a.jsx)(n.p,{children:"LIPS do typechecking for all scheme procedures."}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-scheme",children:'(+ "hello" 10)\n;; ==> Expecting number got string\n'})}),"\n",(0,a.jsx)(n.p,{children:"You can incorporate typechecking in your own code:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-scheme",children:'(let ((x 10))\n (typecheck "let" x "string" 0))\n;; ==> Expecting string got number in expression `let` (argument 0)\n(let ((x "string"))\n (typecheck "let" x "number"))\n;; ==> Expecting number got string in expression `let`\n'})}),"\n",(0,a.jsx)(n.p,{children:"There is also another function to check type of number:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-scheme",children:'(let ((i 10+10i))\n (typecheck-number "let" i "bigint"))\n;; ==> Expecting bigint got complex in expression `let`\n'})}),"\n",(0,a.jsxs)(n.p,{children:[(0,a.jsx)(n.strong,{children:"NOTE"}),": In LIPS all integers are BigInts."]}),"\n",(0,a.jsxs)(n.p,{children:["The last typecking function is ",(0,a.jsx)(n.code,{children:"typecheck-args"})," that check if all arguments are of same type."]}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-scheme",children:'(let ((number \'(1 10 1/2 10+10i)))\n (typecheck-args "number" "let" number))\n;; ==> #void\n(let ((number \'(1 10 1/2 "string")))\n (typecheck-args "number" "let" number))\n;; ==> Expecting number got string in expression `let` (argument 4)\n'})}),"\n",(0,a.jsx)(n.h2,{id:"integration-with-javascript",children:"Integration with JavaScript"}),"\n",(0,a.jsx)(n.h3,{id:"dot-notation",children:"Dot notation"}),"\n",(0,a.jsx)(n.p,{children:"LIPS allow accessing JavaScript objects with dot notation:"}),"\n",(0,a.jsx)(n.pre,{children:(0,a.jsx)(n.code,{className:"language-scheme",children:"document.querySelector\n;; ==> #