diff --git a/.gitattributes b/.gitattributes index 835d675d..0a600261 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,3 +2,4 @@ .* text eol=lf dist/* binary package-lock.json binary +assets/classDiagram.svg binary diff --git a/CHANGELOG.md b/CHANGELOG.md old mode 100644 new mode 100755 index 8405cf24..e7ec7a24 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,55 @@ +## 1.0.0-beta.12 +### Breaking +* `env` and `dir` now returns symbols instead of strings +* `repr` and `type` of quoted promises now return `#` and `promise` +* numbers and characters properties are immutable +### Features +* create minfied std scheme file for faster bootstrap +* add `list-copy` +* add `define-record-type` +* add `escape-regex` function +* make `apropos` accept symbol as argument +* add doc strings for `**interaction-environment**` and `**internal-env**` +* add `letrec*` that in LIPS is exactly the same as `letrec` +* add `pragma->sxml` macro that define `sxml` macro (default is `h`) +* hide `fs` in internal env +* automatic bootstrapping of `fs` with BrowserFS if exists +* `pprint` in both REPLs now print in color [#33](https://github.com/jcubic/lips/issues/33) +* add `nan?`, `infinite?` and `finite?` functions +* add `+nan.0` and `-nan.0` (R7RS) +* properly handle negative inexact zero +* new `environment?` function +* add `current-directory` and `set-...` from SRFI-170 +* add gensym literals (e.g. `#:foo`) +* fix pretty print of different cases of `let` +* add binary input/output procedures from R7RS +* update vector functions that in R7RS get start and end arguments +* add state props and better repr to quotedPromise +### Bugfix +* fix prism highlighting of names (for new context help) +* fix error when using help in node REPL and there are no doc string +* fix escaping regex operators when using string with `apropos` +* fix typechecking of number operators [#128](https://github.com/jcubic/lips/issues/128) +* fix indent of call-with- (input-file, output-file and port) +* fix eq? and type of NaN [#130](https://github.com/jcubic/lips/issues/130) +* fix number predicates +* fix `real-part` function +* fix parsing complex with 0 inexact imaginary part +* fix option -t --trace in Node REPL +* fix `eqv?` on exact and inexact numbers according to R7RS spec +* fix `exact->inexact` on complex numbers +* fix arithmetic with single complex value +* fix parsing regex that have escape slash and parenthesis (`#/( \\/)/g`) +* fix parsing regex that have single slash in class brackets (`#/\/[^/]+$/`) +* fix division on single argument (now `(/ n)` == `(/ 1 n)`) +* fix complex operation that result in real (e.g. multiplication over conjugation) +* fix `list-ref` according to R7RS errata +* fix formatter (pretty print) on multiline strings and atoms +* fix formatter indent of `let*` +* fix repr of vectors (arrays with empty value) +* fix promise quotation of object macro call [#139](https://github.com/jcubic/lips/issues/139) +* fix unquote-splicing inside direct quasiquote vector [#140](https://github.com/jcubic/lips/issues/140) + ## 1.0.0-beta.11 ### Breaking * remove repr of HTMLElement (it's now default instance of a class) diff --git a/Makefile b/Makefile index 1c25c64a..8e2834e1 100644 --- a/Makefile +++ b/Makefile @@ -29,8 +29,9 @@ MERMAID=./node_modules/.bin/mmdc NPM=npm UGLIFY=./node_modules/.bin/uglifyjs ROLLUP=./node_modules/.bin/rollup +LIPS=./bin/lips.js -ALL: Makefile package.json .$(VERSION) assets/classDiagram.svg dist/lips.js dist/lips.min.js README.md dist/std.scm +ALL: Makefile package.json .$(VERSION) assets/classDiagram.svg dist/lips.js dist/lips.min.js README.md dist/std.min.scm dist/lips.js: src/lips.js .$(VERSION) rollup.config.js $(ROLLUP) -c @@ -45,8 +46,11 @@ dist/lips.js: src/lips.js .$(VERSION) rollup.config.js dist/lips.min.js: dist/lips.js .$(VERSION) $(UGLIFY) -o dist/lips.min.js --comments --mangle -- dist/lips.js -dist/std.scm: lib/bootstrap.scm lib/R5RS.scm lib/byte-vectors.scm lib/R7RS.scm - $(CAT) lib/bootstrap.scm lib/R5RS.scm lib/byte-vectors.scm lib/R7RS.scm > dist/std.scm +dist/std.scm: lib/bootstrap.scm lib/R5RS.scm lib/byte-vectors.scm lib/R7RS.scm lib/srfi.scm + $(CAT) lib/bootstrap.scm lib/R5RS.scm lib/byte-vectors.scm lib/R7RS.scm lib/srfi.scm > dist/std.scm + +dist/std.min.scm: dist/std.scm + $(LIPS) ./scripts/minify.scm dist/std.scm > dist/std.min.scm Makefile: templates/Makefile $(SED) -e "s/{{VER""SION}}/"$(VERSION)"/g" templates/Makefile > Makefile @@ -82,10 +86,10 @@ publish: jest-test: dist/lips.js @$(JEST) --coverage spec/*.spec.js -test: dist/lips.js dist/std.scm +test: dist/lips.js dist/std.min.scm @$(NPM) run test -test-file: dist/lips.js dist/std.scm +test-file: dist/lips.js dist/std.min.scm @$(NPM) run test -- -- -f $(FILE) test-update: dist/lips.js dist/std.scm diff --git a/README.md b/README.md index 6cb15d97..01077d6d 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,14 @@ -![LIPS - Scheme Based Powerful Lisp Language](https://github.com/jcubic/lips/blob/master/assets/lips.svg?raw=true) +![LIPS - Scheme Based Powerful Lisp Language](https://github.com/jcubic/lips/blob/devel/assets/lips.svg?raw=true) [![npm](https://img.shields.io/badge/npm-1.0.0%E2%80%93beta.11-blue.svg)](https://www.npmjs.com/package/@jcubic/lips) ![1.0.0 Complete](https://img.shields.io/github/milestones/progress-percent/jcubic/lips/1?label=1.0.0%20Complete) -[![travis](https://travis-ci.org/jcubic/lips.svg?branch=master&8ee545979e1ab3696ae39b50f89705148478b3a9)](https://travis-ci.org/jcubic/lips) -[![Coverage Status](https://coveralls.io/repos/github/jcubic/lips/badge.svg?branch=master&83772d306416614a34e010475a6264c0)](https://coveralls.io/github/jcubic/lips?branch=master) +[![travis](https://travis-ci.org/jcubic/lips.svg?branch=devel&a2ecde1c90338410808edb4f6f18383b2f90a393)](https://travis-ci.org/jcubic/lips) +[![Coverage Status](https://coveralls.io/repos/github/jcubic/lips/badge.svg?branch=devel&1d824f61301ea2d85162361f0502128a)](https://coveralls.io/github/jcubic/lips?branch=devel) [![Join Gitter Chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/jcubic/lips) [![GitHub license](https://img.shields.io/github/license/jcubic/lips.svg)](https://github.com/jcubic/lips/blob/master/LICENSE) [![GitHub stars](https://img.shields.io/github/stars/jcubic/lips.svg?style=social&label=Star&maxAge=2592000)](https://GitHub.com/jcubic/lips/stargazers/) - Tweet + Tweet ![NPM Download Count](https://img.shields.io/npm/dm/@jcubic/lips) ![JSDelivr Download count](https://img.shields.io/jsdelivr/npm/hm/@jcubic/lips) @@ -143,7 +143,7 @@ npm install -g @jcubic/lips@beta you can run the interpreter from the terminal: -![LIPS: Scheme interactive terminal](https://github.com/jcubic/lips/blob/master/assets/screencast.gif?raw=true) +![LIPS: Scheme interactive terminal](https://github.com/jcubic/lips/blob/devel/assets/screencast.gif?raw=true) You can also run code in a string with: @@ -185,6 +185,24 @@ Executables also return a S-Expression according to SRFI-176 use `lips --version * [Git Repository](https://github.com/jcubic/lips) * [Official Website](https://lips.js.org/) +## Roadmap + +### 1.0 +- [x] Full support for R5RS +- [ ] Full support for R7RS +- [ ] Continuations. +- [ ] Tail Call Optimization (TCO). +- [ ] Fully tested Numerical Tower. +- [ ] R7RS libraries (`import`/`export`/`define-library`). +- [ ] All recursive function in JS don't consume stack. +- [ ] Finish `syntax-rules` (ignore limitations of current approach). + - [ ] Objects. + - [ ] Vectors. + +### 1.1 +- [ ] Proper expansion time for both macro system. +- [ ] Fully working and tested R7RS hygienic Macros (`syntax-rules`). + ## Acknowledgments * Font used in logo is [Telegrafico](https://www.dafont.com/telegrafico.font) by [ficod](https://www.deviantart.com/ficod). * Current parser is inspired by implementation in [BiwaScheme](https://www.biwascheme.org/) by Yutaka HARA (yhara). diff --git a/assets/classDiagram b/assets/classDiagram index 8214a56c..c27bfc22 100644 --- a/assets/classDiagram +++ b/assets/classDiagram @@ -8,6 +8,10 @@ InputPort <|-- InputStringPort InputStringPort <|-- InputFilePort OutputPort <|-- OutputStringPort OutputPort <|-- OutputFilePort +OutputPort <|-- OutputByteVectorPort +InputPort <|-- InputByteVectorPort +InputByteVectorPort <|-- InputBinaryFilePort +OutputFilePort <|-- OutputBinaryFilePort Parser *-- Lexer Macro <|-- Syntax @@ -20,33 +24,34 @@ Formatter *-- Pattern Interpreter *-- Environment class LRational { - LNumber num - LNumber denom + LNumber __num__ + LNumber __denom__ pow() abs() cmp() - valueOf() - toString() mul() div() sub() add() + valueOf() + toString() } class LBigInteger { - BigInt value + BigInt __value__ sqrt() gcd() sqrt() - } + class LFloat { - Number value + Number __value__ toRational() toString() } + class LNumber { - Number value + Number __value__ isFloat() isNumber() isComplex() @@ -63,8 +68,8 @@ class LNumber { isOdd() isEven() cmp() - } + class LComplex { LNumber __im__ LNumber __re__ @@ -82,7 +87,7 @@ class LComplex { } class InputPort { - Function _read + Parser __parser__ read_char() skip_char() read_line() @@ -92,19 +97,84 @@ class InputPort { close() toString() } + class OutputPort { + symbol __type__ + write() is_open() close() toString() } class OutputStringPort { - string[] _buffer + string[] __buffer__ + symbol __type__ + write() + valueOf() + toString() +} + +class InputBinaryFilePort { + string __filename__ + toString() } + +class InputStringPort { + symbol __type__ + char_ready() + toString() +} + +class InputFilePort { + string __filename__ + toStgring() +} + class OutputFilePort { - string _filename - number _fd + string __filename__ + symbol __type__ + fs() + internal() + close() + toString() +} + +class InputByteVectorPort { + symbol __type__ + Uint8Array __vector__ + integer __index__ + toString() + u8_ready() + peek_u8() + skip() + read_u8() + read_u8_vector(integer) +} + +class OutputByteVectorPort { + Uin8Array __buffer__ + symbol __type__ + write(any) + close() + write_u8(byte) + write_u8_vector(Uint8Array) + toString() + valueOf() +} + +class InputByteVectorPort { + string __filename__ + toString() } + +class OutputBinaryFilePort { + string __filename__ + symbol __type__ + write(any) + write_u8(byte) + write_u8_vector(Uint8Array) +} + class Formatter { string __code__ indent(object): number @@ -130,29 +200,61 @@ class LString { clone(): LString fill(LCharacter) } + class Worker { string url Worker worker rpc(method, params): Promise exec(code, [dynamic]): Promise } + class LCharacter { - string __name__ + string __name__ string __char__ toUpperCase(): LCharacter toLowerCase(): LCharacter toString(): string valueOf(): string } + class Lexer { - string _input + string __input__ + token(meta) + peek(meta) + skip() + read_line() + read_rest() + read_string(num) + peek_char() + read_char() + skip_char() + match_rule() + next_token() + static rules } + class Parser { Lexer __lexer__ + Environent __env__ + resolve() + peek() + skip() + read() + is_special(token) + is_builtin(token) + is_open(token) + is_close(token) + read_list() + read_value() + read_object() + is_ccomment(token) + evaluate(code) } + class LSymbol { string __name__ } + class Environment { string __name__ Map __docs__ @@ -173,11 +275,13 @@ class Environment { merge(): Environment toString(): string } + class Values { any[] __values__ valueOf() toString() } + class Macro { string __doc__ string __name__ @@ -187,16 +291,19 @@ class Macro { invoke() toString() } + class Syntax { invoke() toString() } + class QuotedPromise { Promise __promise__ then() catch() valueOf() } + class Pair { any car any cdr @@ -204,14 +311,15 @@ class Pair { length() find(any) clone() - lastPair() - toArray() - toObject() + last_pair() + to_array() + to_object() reduce(Function) reverse(): Pair transform(Function) map(Function) } + class Interpreter { Environment __env__ get(symbol) diff --git a/assets/classDiagram.svg b/assets/classDiagram.svg index c1a48dfe..472ccbab 100644 --- a/assets/classDiagram.svg +++ b/assets/classDiagram.svg @@ -1 +1 @@ -LNumberNumber valueisFloat()isNumber()isComplex()isRational()isNative()isBigInteger()isBN()getType()coerce()op()sqrt()pow()abs()isOdd()isEven()cmp()LBigIntegerBigInt valuesqrt()gcd()sqrt()LRationalLNumber numLNumber denompow()abs()cmp()valueOf()toString()mul()div()sub()add()LFloatNumber valuetoRational()toString()LComplexLNumber __im__LNumber __re__sqrt()toRational()add()factor()modulus()sqrt()div()sub()mul()cmp()toString()InputPortFunction _readread_char()skip_char()read_line()read()char_ready()is_open()close()toString()InputStringPortInputFilePortOutputPortis_open()close()toString()OutputStringPortstring[] _bufferOutputFilePortstring _filenamenumber _fdParserLexer __lexer__Lexerstring _inputMacrostring __doc__string __name__boolean __defmacro__Function __fn__defmacro()invoke()toString()Syntaxinvoke()toString()StringLStringstring __string__number lengthtoString()get(number)cmp(string)lower()upper()set(number, LCharacter)clone()fill(LCharacter)Formatterstring __code__indent(object)exception_shift(token, object)break()format()AheadPatternrule patternstring flagInterpreterEnvironment __env__get(symbol)set(symbol, value)constant(name, value)exec(code, dynamic = false, env = null)Environmentstring __name__Map __docs__Object __env__Environment __parent__list()uset(name)inherit(name, object)doc(name, value = null)get(symbol, options)set(symbol, value, doc = null)constant(name, value)has(string)ref(string)parents()newFrame(Function, args)clone()merge()toString()Workerstring urlWorker workerrpc(method, params)exec(code, [dynamic])LCharacterstring __name__string __char__toUpperCase()toLowerCase()toString()valueOf()LSymbolstring __name__Valuesany[] __values__valueOf()toString()QuotedPromisePromise __promise__then()catch()valueOf()Pairany carany cdrflatten()length()find(any)clone()lastPair()toArray()toObject()reduce(Function)reverse()transform(Function)map(Function) \ No newline at end of file +LNumberNumber __value__isFloat()isNumber()isComplex()isRational()isNative()isBigInteger()isBN()getType()coerce()op()sqrt()pow()abs()isOdd()isEven()cmp()LBigIntegerBigInt __value__sqrt()gcd()sqrt()LRationalLNumber __num__LNumber __denom__pow()abs()cmp()mul()div()sub()add()valueOf()toString()LFloatNumber __value__toRational()toString()LComplexLNumber __im__LNumber __re__sqrt()toRational()add()factor()modulus()sqrt()div()sub()mul()cmp()toString()InputPortParser __parser__read_char()skip_char()read_line()read()char_ready()is_open()close()toString()InputStringPortsymbol __type__char_ready()toString()InputFilePortstring __filename__toStgring()OutputPortsymbol __type__write()is_open()close()toString()OutputStringPortstring[] __buffer__symbol __type__write()valueOf()toString()OutputFilePortstring __filename__symbol __type__fs()internal()close()toString()OutputByteVectorPortUin8Array __buffer__symbol __type__write(any)close()write_u8(byte)write_u8_vector(Uint8Array)toString()valueOf()InputByteVectorPortsymbol __type__Uint8Array __vector__integer __index__string __filename__toString()u8_ready()peek_u8()skip()read_u8()read_u8_vector(integer)toString()InputBinaryFilePortstring __filename__toString()OutputBinaryFilePortstring __filename__symbol __type__write(any)write_u8(byte)write_u8_vector(Uint8Array)ParserLexer __lexer__Environent __env__resolve()peek()skip()read()is_special(token)is_builtin(token)is_open(token)is_close(token)read_list()read_value()read_object()is_ccomment(token)evaluate(code)Lexerstring __input__static rulestoken(meta)peek(meta)skip()read_line()read_rest()read_string(num)peek_char()read_char()skip_char()match_rule()next_token()Macrostring __doc__string __name__boolean __defmacro__Function __fn__defmacro()invoke()toString()Syntaxinvoke()toString()StringLStringstring __string__number lengthtoString()get(number)cmp(string)lower()upper()set(number, LCharacter)clone()fill(LCharacter)Formatterstring __code__indent(object)exception_shift(token, object)break()format()AheadPatternrule patternstring flagInterpreterEnvironment __env__get(symbol)set(symbol, value)constant(name, value)exec(code, dynamic = false, env = null)Environmentstring __name__Map __docs__Object __env__Environment __parent__list()uset(name)inherit(name, object)doc(name, value = null)get(symbol, options)set(symbol, value, doc = null)constant(name, value)has(string)ref(string)parents()newFrame(Function, args)clone()merge()toString()Workerstring urlWorker workerrpc(method, params)exec(code, [dynamic])LCharacterstring __name__string __char__toUpperCase()toLowerCase()toString()valueOf()LSymbolstring __name__Valuesany[] __values__valueOf()toString()QuotedPromisePromise __promise__then()catch()valueOf()Pairany carany cdrflatten()length()find(any)clone()last_pair()to_array()to_object()reduce(Function)reverse()transform(Function)map(Function) \ No newline at end of file diff --git a/benchmarks/regex.scm b/benchmarks/regex.scm index a8945ff2..9957f62f 100755 --- a/benchmarks/regex.scm +++ b/benchmarks/regex.scm @@ -23,7 +23,6 @@ (on "cycle" (lambda (e) (print (string-append ">>> " (String e.target))))) - (on "complete" (lambda (e) (try @@ -34,11 +33,4 @@ (catch (e) (print e))))) - - - (run &(:async true))) - - - - diff --git a/bin/lips.js b/bin/lips.js index ed7db8e7..2fd6320c 100755 --- a/bin/lips.js +++ b/bin/lips.js @@ -54,6 +54,10 @@ function run(code, interpreter, dynamic = false, env = null, stack = false) { code = code.toString(); } return interpreter.exec(code, dynamic, env).catch(function(e) { + if (!e) { + console.log('Error is null'); + return; + } if (!stack) { console.error(e.message); } @@ -165,8 +169,7 @@ var interp = Interpreter('repl', { }); }); }), - __dirname: __dirname, - __filename: __filename, + // ------------------------------------------------------------------------- stdout: OutputPort(function(x) { if (typeof x !== 'string') { x = this.get('repr')(x); @@ -174,6 +177,10 @@ var interp = Interpreter('repl', { newline = !x.match(/\n$/); process.stdout.write(x); }), + // ------------------------------------------------------------------------- + __dirname: __dirname, + __filename: __filename, + // ------------------------------------------------------------------------- 'stack-trace': doc(function() { if (strace) { console.log(strace); @@ -181,17 +188,32 @@ var interp = Interpreter('repl', { }, `(stack-trace) Function display stack trace of last error`), + // ------------------------------------------------------------------------- exit: doc(function(code) { process.exit(code); }, `(exit) (exit error-code) Function exits LIPS script or the REPL.`), + // ------------------------------------------------------------------------- + pprint: doc(function(arg) { + if (arg instanceof Pair) { + arg = new Formatter(arg.toString(true)).break().format(); + this.get('display').call(this, scheme(arg)); + } else { + this.get('write').call(this, scheme(arg)); + } + this.get('newline').call(this); + }, env.get('pprint').__doc__), + // ------------------------------------------------------------------------- help: doc(new Macro('help', function(code, { error }) { var new_code = new Pair(new LSymbol('__help'), code); var doc = evaluate(new_code, { env: this, error }); - console.log(doc.toString()); + if (doc) { + console.log(doc.toString()); + } }), env.get('help').__doc__), + // ------------------------------------------------------------------------- '__help': env.get('help') }); @@ -221,9 +243,9 @@ if (options.version || options.V) { bootstrap(interp).then(function() { const code = options.e || options.eval || options.c || options.code; const dynamic = options.d || options.dynamic; - return run(code, interp, dynamic).then(print); + return run(code, interp, dynamic, null, true).then(print); }); -} else if (options._.length === 1) { +} else if (options._.length >= 1) { // hack for node-gtk const rl = readline.createInterface({ input: process.stdin, @@ -351,7 +373,7 @@ function run_repl(err, rl) { rl.setPrompt(''); rl.pause(); prev_eval = prev_eval.then(function() { - var result = run(code, interp, dynamic); + var result = run(code, interp, dynamic, null, options.t || options.trace); code = ''; return result; }).then(function(result) { diff --git a/dist/lips.js b/dist/lips.js index 6e909ba0..c10c1493 100644 --- a/dist/lips.js +++ b/dist/lips.js @@ -4,7 +4,7 @@ * | | \ \ | | | || . \/ __> | | * | | > \ | |_ | || _/\__ \ | | * | | / ^ \ |___||_||_| <___/ | | - * \_\ /_/ \_\ /_/ v. 1.0.0-beta.11 + * \_\ /_/ \_\ /_/ v. DEV * * LIPS is Pretty Simple - Scheme based Powerful LISP in JavaScript * @@ -31,7 +31,7 @@ * Copyright (c) 2014-present, Facebook, Inc. * released under MIT license * - * build: Sun, 31 Jan 2021 11:47:57 +0000 + * build: Tue, 16 Mar 2021 12:52:41 +0000 */ (function () { 'use strict'; @@ -1234,7 +1234,7 @@ * TODO: consider using exec in env.eval or use different maybe_async code */ - /* global define, jQuery, BigInt, Map, Set, Symbol, importScripts */ + /* global define, jQuery, BigInt, Map, Set, Symbol, importScripts, Uint8Array */ (function (root, factory) { if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. @@ -1330,7 +1330,7 @@ function is_debug() { - return user_env.get('DEBUG', { + return user_env && user_env.get('DEBUG', { throwError: false }); } @@ -1420,7 +1420,7 @@ function gen_complex_re(mnemonic, range) { // [+-]i have (?=..) so it don't match +i from +inf.0 - return "".concat(num_mnemicic_re(mnemonic), "(?:[+-]?(?:").concat(range, "+/").concat(range, "+|").concat(range, "+))?(?:[+-]i|[+-]?(?:").concat(range, "+/").concat(range, "+|").concat(range, "+)i)(?=[()[\\]\\s]|$)"); + return "".concat(num_mnemicic_re(mnemonic), "(?:[+-]?(?:").concat(range, "+/").concat(range, "+|nan.0|inf.0|").concat(range, "+))?(?:[+-]i|[+-]?(?:").concat(range, "+/").concat(range, "+|").concat(range, "+|nan.0|inf.0)i)(?=[()[\\]\\s]|$)"); } function gen_integer_re(mnemonic, range) { @@ -1430,7 +1430,7 @@ var re_re = /^#\/((?:\\\/|[^/]|\[[^\]]*\/[^\]]*\])+)\/([gimyus]*)$/; var float_stre = '(?:[-+]?(?:[0-9]+(?:[eE][-+]?[0-9]+)|(?:\\.[0-9]+|[0-9]+\\.[0-9]+)(?:[eE][-+]?[0-9]+)?)|[0-9]+\\.)'; // TODO: extend to ([+-]1/2|float)([+-]1/2|float) - var complex_float_stre = "(?:#[ie])?(?:[+-]?(?:[0-9]+/[0-9]+|".concat(float_stre, "|[+-]?[0-9]+))?(?:").concat(float_stre, "|[+-](?:[0-9]+/[0-9]+|[0-9]+))i"); + var complex_float_stre = "(?:#[ie])?(?:[+-]?(?:[0-9]+/[0-9]+|nan.0|inf.0|".concat(float_stre, "|[+-]?[0-9]+))?(?:").concat(float_stre, "|[+-](?:[0-9]+/[0-9]+|[0-9]+|nan.0|inf.0))i"); var float_re = new RegExp("^(#[ie])?".concat(float_stre, "$"), 'i'); function make_complex_match_re(mnemonic, range) { @@ -1442,7 +1442,7 @@ fl = '(?:[-+]?(?:[0-9]+(?:[eE][-+]?[0-9]+)|(?:\\.[0-9]+|[0-9]+\\.[0-9]+(?![0-9]))(?:[eE][-+]?[0-9]+)?))'; } - return new RegExp("^((?:(?:".concat(fl, "|[+-]?").concat(range, "+/").concat(range, "+(?!").concat(range, ")|[+-]?").concat(range, "+)").concat(neg, ")?)(").concat(fl, "|[+-]?").concat(range, "+/").concat(range, "+|[+-]?").concat(range, "+|[+-])i$"), 'i'); + return new RegExp("^((?:(?:".concat(fl, "|[-+]?inf.0|[-+]?nan.0|[+-]?").concat(range, "+/").concat(range, "+(?!").concat(range, ")|[+-]?").concat(range, "+)").concat(neg, ")?)(").concat(fl, "|[-+]?inf.0|[-+]?nan.0|[+-]?").concat(range, "+/").concat(range, "+|[+-]?").concat(range, "+|[+-])i$"), 'i'); } var complex_list_re = function () { @@ -1682,6 +1682,14 @@ } return _float; + } else if (n.match(/nan.0$/)) { + return LNumber(NaN); + } else if (n.match(/inf.0$/)) { + if (n[0] === '-') { + return LNumber(Number.NEGATIVE_INFINITY); + } + + return LNumber(Number.POSITIVE_INFINITY); } else { throw new Error('Internal Parser Error'); } @@ -1709,12 +1717,14 @@ if (parts[1]) { re = parse_num(parts[1]); - } else if (im instanceof LFloat) { - re = LFloat(0); } else { re = LNumber(0); } + if (im.cmp(0) === 0 && im.__type__ === 'bigint') { + return re; + } + return LComplex({ im: im, re: re @@ -1855,6 +1865,8 @@ return parse_float(arg); } else if (arg === 'nil') { return nil; + } else if (['+nan.0', '-nan.0'].includes(arg)) { + return LNumber(NaN); } else if (['true', '#t', '#true'].includes(arg)) { return true; } else if (['false', '#f', '#false'].includes(arg)) { @@ -1875,25 +1887,25 @@ function is_symbol_string(str) { - return !(['(', ')'].includes(str) || str.match(re_re) || str.match(/^"[\s\S]*"$/) || str.match(int_re) || str.match(float_re) || str.match(complex_re) || str.match(rational_re) || str.match(char_re) || ['#t', '#f', 'nil', 'true', 'false'].includes(str)); + return !(['(', ')', '[', ']'].includes(str) || str.match(re_re) || str.match(/^"[\s\S]*"$/) || str.match(int_re) || str.match(float_re) || str.match(complex_re) || str.match(rational_re) || str.match(char_re) || ['#t', '#f', 'nil', 'true', 'false'].includes(str)); } // ---------------------------------------------------------------------- var string_re = /"(?:\\[\S\s]|[^"])*"?/g; // ---------------------------------------------------------------------- - /* function escape_regex(str) { - if (typeof str === 'string') { - var special = /([-\\^$[\]()+{}?*.|])/g; - return str.replace(special, '\\$1'); - } - } - */ - // ---------------------------------------------------------------------- + if (typeof str === 'string') { + var special = /([-\\^$[\]()+{}?*.|])/g; + return str.replace(special, '\\$1'); + } + + return str; + } // ---------------------------------------------------------------------- // Stack used in balanced function // TODO: use it in parser // ---------------------------------------------------------------------- + function Stack() { this.data = []; } @@ -2173,30 +2185,87 @@ function QuotedPromise(promise) { - // prevent exception on unhandled rejecting when using - // '>(Promise.reject (new Error "zonk")) in REPL - promise["catch"](function () {}); + var _this = this; + + var internal = { + pending: true, + rejected: false, + fulfilled: false, + reason: undefined$1, + type: undefined$1 + }; // then added to __promise__ is needed otherwise rejection + // will give UnhandledPromiseRejectionWarning in Node.js + + promise = promise.then(function (v) { + internal.type = type(v); + internal.fulfilled = true; + internal.pending = false; + return v; + }); // promise without catch, used for valueOf - for rejecting + // that should throw an error when used with await + + read_only(this, '_promise', promise, { + hidden: true + }); + + if (is_function(promise["catch"])) { + // prevent exception on unhandled rejecting when using + // '>(Promise.reject (new Error "zonk")) in REPL + promise = promise["catch"](function (err) { + internal.rejected = true; + internal.pending = false; + internal.reason = err; + }); + } + + Object.keys(internal).forEach(function (name) { + Object.defineProperty(_this, "__".concat(name, "__"), { + enumerable: true, + get: function get() { + return internal[name]; + } + }); + }); this.__promise__ = promise; } // ---------------------------------------------------------------------- QuotedPromise.prototype.then = function (fn) { - return new QuotedPromise(this.__promise__.then(fn)); + return new QuotedPromise(this.valueOf().then(fn)); }; // ---------------------------------------------------------------------- QuotedPromise.prototype["catch"] = function (fn) { - return new QuotedPromise(this.__promise__["catch"](fn)); + return new QuotedPromise(this.valueOf()["catch"](fn)); }; // ---------------------------------------------------------------------- QuotedPromise.prototype.valueOf = function () { - return this.__promise__; + if (!this._promise) { + throw new Error('QuotedPromise: invalid promise created'); + } + + return this._promise; }; // ---------------------------------------------------------------------- + + + QuotedPromise.prototype.toString = function () { + if (this.__pending__) { + return QuotedPromise.pending_str; + } + + if (this.__rejected__) { + return QuotedPromise.rejected_str; + } + + return "#"); + }; + + QuotedPromise.pending_str = '#'; + QuotedPromise.rejected_str = '#'; // ---------------------------------------------------------------------- // :: Parser macros transformers // ---------------------------------------------------------------------- - var specials = { LITERAL: Symbol["for"]('literal'), SPLICE: Symbol["for"]('splice'), @@ -2212,13 +2281,13 @@ }, // events are used in Lexer dynamic rules off: function off(name) { - var _this = this; + var _this2 = this; var fn = arguments.length > 1 && arguments[1] !== undefined$1 ? arguments[1] : null; if (Array.isArray(name)) { name.forEach(function (name) { - return _this.off(name, fn); + return _this2.off(name, fn); }); } else if (fn === null) { delete this._events[name]; @@ -2229,11 +2298,11 @@ } }, on: function on(name, fn) { - var _this2 = this; + var _this3 = this; if (Array.isArray(name)) { name.forEach(function (name) { - return _this2.on(name, fn); + return _this3.on(name, fn); }); } else if (!this._events[name]) { this._events[name] = [fn]; @@ -2302,7 +2371,7 @@ var Lexer = /*#__PURE__*/function () { function Lexer(input) { - var _this3 = this; + var _this4 = this; var _ref7 = arguments.length > 1 && arguments[1] !== undefined$1 ? arguments[1] : {}, _ref7$whitespace = _ref7.whitespace, @@ -2316,7 +2385,7 @@ }); var internals = {}; ['_i', '_whitespace', '_col', '_newline', '_line', '_state', '_next', '_token', '_prev_char'].forEach(function (name) { - Object.defineProperty(_this3, name, { + Object.defineProperty(_this4, name, { configurable: false, enumerable: false, get: function get() { @@ -2536,7 +2605,7 @@ this._newline = i + 1; } - if (this._whitespace) { + if (this._whitespace && this._state === null) { this._next = i + 1; this._col = this._i - newline; return true; @@ -2662,12 +2731,12 @@ Lexer.symbol = Symbol["for"]('symbol'); Lexer.comment = Symbol["for"]('comment'); Lexer.regex = Symbol["for"]('regex'); + Lexer.regex_class = Symbol["for"]('regex_class'); Lexer.character = Symbol["for"]('character'); Lexer.bracket = Symbol["for"]('bracket'); Lexer.b_symbol = Symbol["for"]('b_symbol'); Lexer.b_comment = Symbol["for"]('b_comment'); - Lexer.i_comment = Symbol["for"]('i_comment'); - Lexer.character = Symbol["for"]('character'); // ---------------------------------------------------------------------- + Lexer.i_comment = Symbol["for"]('i_comment'); // ---------------------------------------------------------------------- Lexer.boundary = /^$|[\s()[\]]/; // ---------------------------------------------------------------------- @@ -2683,7 +2752,7 @@ [/#/, null, /[bdxoeitf]/i, null, Lexer.symbol], // characters [/#/, null, /\\/, null, Lexer.character], [/\\/, /#/, /\s/, Lexer.character, Lexer.character], [/\\/, /#/, /[()[\]]/, Lexer.character, Lexer.character], [/\s/, /\\/, null, Lexer.character, null], [/\S/, null, Lexer.boundary, Lexer.character, null], // brackets [/[()[\]]/, null, null, null, null], // regex - [/#/, Lexer.boundary, /\//, null, Lexer.regex], [/[ \t]/, null, null, Lexer.regex, Lexer.regex], [/[()[\]]/, null, null, Lexer.regex, Lexer.regex], [/\//, /[^#]/, Lexer.boundary, Lexer.regex, null], [/[gimyus]/, /\//, Lexer.boundary, Lexer.regex, null], [/[gimyus]/, /\//, /[gimyus]/, Lexer.regex, Lexer.regex], [/[gimyus]/, /[gimyus]/, Lexer.boundary, Lexer.regex, null]]; // ---------------------------------------------------------------------- + [/#/, Lexer.boundary, /\//, null, Lexer.regex], [/[ \t]/, null, null, Lexer.regex, Lexer.regex], [/\[/, null, null, Lexer.regex, Lexer.regex_class], [/\]/, /[^\\]/, null, Lexer.regex_class, Lexer.regex], [/[()[\]]/, null, null, Lexer.regex, Lexer.regex], [/\//, /\\/, null, Lexer.regex, Lexer.regex], [/\//, /[^#]/, Lexer.boundary, Lexer.regex, null], [/[gimyus]/, /\//, Lexer.boundary, Lexer.regex, null], [/[gimyus]/, /\//, /[gimyus]/, Lexer.regex, Lexer.regex], [/[gimyus]/, /[gimyus]/, Lexer.boundary, Lexer.regex, null]]; // ---------------------------------------------------------------------- // :: symbols should be matched last // ---------------------------------------------------------------------- @@ -2765,10 +2834,14 @@ arg = arg.toString(); } - this._formatter = formatter; - this._meta = meta; - this.__lexer__ = new Lexer(arg); - this.__env__ = env; + read_only(this, '_formatter', formatter, { + hidden: true + }); + read_only(this, '_meta', meta, { + hidden: true + }); + read_only(this, '__lexer__', new Lexer(arg)); + read_only(this, '__env__', env); } createClass(Parser, [{ @@ -2864,13 +2937,13 @@ this.__lexer__.skip(); } }, { - key: "special", - value: function special(token) { + key: "is_special", + value: function is_special(token) { return specials.names().includes(token); } }, { - key: "builtin", - value: function builtin(token) { + key: "is_builtin", + value: function is_builtin(token) { return specials.builtin.includes(token); } }, { @@ -3048,9 +3121,9 @@ return token.match(/^;/) || token.match(/^#\|/) && token.match(/\|#$/); } }, { - key: "_eval", - value: function _eval(code) { - return evaluate(code, { + key: "evaluate", + value: function evaluate(code) { + return _evaluate(code, { env: this.__env__, error: function error(e) { throw e; @@ -3080,7 +3153,7 @@ return _context5.abrupt("return", token); case 5: - if (!this.special(token)) { + if (!this.is_special(token)) { _context5.next = 35; break; } @@ -3093,7 +3166,7 @@ // MACRO: if macros are used they are evaluated in place and // result is returned by parser but they are quoted special = specials.get(token); - bultin = this.builtin(token); + bultin = this.is_builtin(token); this.skip(); _context5.next = 11; return this.read_object(); @@ -3126,7 +3199,7 @@ break; } - return _context5.abrupt("return", extension.apply(this.__env__, object.toArray(false))); + return _context5.abrupt("return", extension.apply(this.__env__, object.to_array(false))); case 21: throw new Error('Parser: Invalid parser extension ' + "invocation ".concat(special.symbol)); @@ -3153,7 +3226,7 @@ } _context5.next = 28; - return this._eval(expr); + return this.evaluate(expr); case 28: result = _context5.sent; @@ -3335,6 +3408,19 @@ return fn(value); } // ---------------------------------------------------------------------- + + + function read_only(object, property, value) { + var _ref10 = arguments.length > 3 && arguments[3] !== undefined$1 ? arguments[3] : {}, + _ref10$hidden = _ref10.hidden, + hidden = _ref10$hidden === void 0 ? false : _ref10$hidden; + + Object.defineProperty(object, property, { + value: value, + configurable: true, + enumerable: !hidden + }); + } // ---------------------------------------------------------------------- // :: Function similar to Array.from that work on async iterators // ---------------------------------------------------------------------- @@ -3550,34 +3636,57 @@ // :: token based pattern matching (used by formatter) // ---------------------------------------------------------------------- - + /* function nested_pattern(pattern) { - return pattern instanceof Array || pattern instanceof Pattern; - } // ---------------------------------------------------------------------- + return pattern instanceof Array || + pattern instanceof Pattern; + } + */ + // ---------------------------------------------------------------------- function match(pattern, input) { return inner_match(pattern, input) === input.length; function inner_match(pattern, input) { + /* function empty_match() { - if (p <= 0 && i <= 0) { - return false; - } - - var prev_pattern = pattern[p - 1]; + if (p <= 0 && i <= 0) { + return false; + } + var prev_pattern = pattern[p - 1]; + if (!nested_pattern(prev_pattern)) { + prev_pattern = [prev_pattern]; + } + var next_pattern = pattern[p + 1]; + if (next_pattern && !nested_pattern(next_pattern)) { + next_pattern = [next_pattern]; + } + return match(prev_pattern, [input[i - 1]]) && + (!next_pattern || match(next_pattern, [input[i]])); + } + */ + function get_first_match(patterns, input) { + var _iterator5 = _createForOfIteratorHelper(patterns), + _step5; - if (!nested_pattern(prev_pattern)) { - prev_pattern = [prev_pattern]; - } + try { + for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) { + var _p = _step5.value; - var next_pattern = pattern[p + 1]; + var _m = inner_match(_p, input); - if (next_pattern && !nested_pattern(next_pattern)) { - next_pattern = [next_pattern]; + if (_m !== -1) { + return _m; + } + } + } catch (err) { + _iterator5.e(err); + } finally { + _iterator5.f(); } - return match(prev_pattern, [input[i - 1]]) && (!next_pattern || match(next_pattern, [input[i]])); + return -1; } function not_symbol_match() { @@ -3606,7 +3715,7 @@ if (['+', '*'].includes(pattern[p].flag)) { while (i < input.length) { - m = inner_match(pattern[p].pattern, input.slice(i)); + m = get_first_match(pattern[p].patterns, input.slice(i)); if (m === -1) { break; @@ -3619,7 +3728,7 @@ p++; continue; } else if (pattern[p].flag === '?') { - m = inner_match(pattern[p].pattern, input.slice(i)); + m = get_first_match(pattern[p].patterns, input.slice(i)); if (m === -1) { i -= 2; // if not found use same test on same input again @@ -3640,18 +3749,15 @@ } else if (_typeof_1(pattern[p]) === 'symbol') { if (pattern[p] === Symbol["for"]('*')) { // ignore S-expressions inside for case when next pattern is ) - glob[p] = glob[p] || 0; - var zero_match = empty_match(); + glob[p] = glob[p] || 0; //var zero_match = empty_match(); if (['(', '['].includes(input[i])) { glob[p]++; - } else if ([')', ']'].includes(input[i]) && !zero_match) { + } else if ([')', ']'].includes(input[i])) { glob[p]--; } - if (zero_match) { - i -= 1; - } else if (typeof pattern[p + 1] !== 'undefined' && glob[p] === 0 && match_next() === -1 || glob[p] > 0) { + if (typeof pattern[p + 1] !== 'undefined' && glob[p] === 0 && match_next() === -1 || glob[p] > 0) { continue; } } else if (not_symbol_match()) { @@ -3701,7 +3807,7 @@ exceptions: { specials: [ /* eslint-disable max-len */ - /^(?:#:)?(?:define(?:-values|-syntax|-macro)?|lambda|let*|let-env|try|catch|when|unless|while|syntax-rules|(let|letrec)(-syntax))$/ + /^(?:#:)?(?:define(?:-values|-syntax|-macro|-class|-record-type)?|(?:call-with-(?:input-file|output-file|port))|lambda|let-env|try|catch|when|unless|while|syntax-rules|(let|letrec)(-syntax|\*)?)$/ /* eslint-enable */ ], shift: { @@ -3759,21 +3865,21 @@ return false; } - var _iterator5 = _createForOfIteratorHelper(regexes), - _step5; + var _iterator6 = _createForOfIteratorHelper(regexes), + _step6; try { - for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) { - var re = _step5.value; + for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) { + var re = _step6.value; if (token.match(re)) { return true; } } } catch (err) { - _iterator5.e(err); + _iterator6.e(err); } finally { - _iterator5.f(); + _iterator6.f(); } } @@ -3883,27 +3989,38 @@ Ahead.prototype.match = function (string) { return string.match(this.pattern); }; // ---------------------------------------------------------------------- + // Pattern have any number of patterns that is match using OR operator + // pattern is in form of array with regular expressions + // ---------------------------------------------------------------------- - function Pattern(pattern, flag) { - this.pattern = pattern; - this.flag = flag; - } // TODO: make it print + function Pattern() { + for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { + args[_key3] = arguments[_key3]; + } + var flag = args.pop(); + this.patterns = args; + this.flag = flag; + } Pattern.prototype.toString = function () { - return "#"); + var patterns = this.patterns.map(function (x) { + return toString(x); + }).join('|'); + return "#"); }; // ---------------------------------------------------------------------- Formatter.Pattern = Pattern; Formatter.Ahead = Ahead; - var p_o = /[[(]/; - var p_e = /[\])]/; + var p_o = /^[[(]$/; + var p_e = /^[\])]$/; var not_p = /[^()[\]]/; - var not_close = new Ahead(/[^)\]]/); - var open = new Ahead(/[([]/); + var not_close = new Ahead(/[^)\]]/); //const open = new Ahead(/[([]/); + var glob = Symbol["for"]('*'); + var sexp_or_atom = new Pattern([p_o, glob, p_e], [not_p], '+'); var sexp = new Pattern([p_o, glob, p_e], '+'); var symbol = new Pattern([Symbol["for"]('symbol')], '?'); var symbols = new Pattern([Symbol["for"]('symbol')], '*'); @@ -3916,29 +4033,33 @@ var non_def = /^(?!.*\b(?:[()[\]]|define|let(?:\*|rec|-env|-syntax)?|lambda|syntax-rules)\b).*$/; /* eslint-enable */ - var let_re = /^(?:#:)?(let(?:\*|rec|-env|-syntax)?)$/; + var let_re = /^(?:#:)?(let(?:\*|rec|-env|-syntax)?)$/; // match keyword if it's normal token or gensym (prefixed with #:) function keywords_re() { - for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { - args[_key3] = arguments[_key3]; + for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { + args[_key4] = arguments[_key4]; } return new RegExp("^(?:#:)?(?:".concat(args.join('|'), ")$")); } // line breaking rules - Formatter.rules = [[[p_o, keywords_re('begin')], 1], [[p_o, let_re, symbol, p_o, let_value, p_e], 1], [[p_o, let_re, p_o, let_value, p_e, sexp], 1, not_close], [[p_o, keywords_re('define-syntax'), /.+/], 1], [[p_o, non_def, new Pattern([/[^()[\]]/], '+'), sexp], 1, not_close], [[p_o, sexp], 1, open], [[p_o, keywords_re('lambda', 'if'), not_p], 1, not_close], [[p_o, keywords_re('while'), not_p, sexp], 1, not_close], [[p_o, keywords_re('if'), not_p, glob], 1], [[p_o, def_lambda_re, identifiers], 1, not_close], [[p_o, def_lambda_re, identifiers, string_re], 1, not_close], [[p_o, def_lambda_re, identifiers, string_re, sexp], 1, not_close], [[p_o, def_lambda_re, identifiers, sexp], 1, not_close]]; // ---------------------------------------------------------------------- + Formatter.rules = [[[p_o, keywords_re('begin')], 1], [[p_o, let_re, symbol, p_o, let_value, p_e], 1], [[p_o, let_re, symbol, sexp, sexp_or_atom], 0, not_close], //[[p_o, let_re, p_o, let_value], 1, not_close], + [[p_o, keywords_re('define-syntax'), /.+/], 1], [[p_o, non_def, new Pattern([/[^()[\]]/], '+'), sexp], 1, not_close], [[p_o, sexp], 1, not_close], [[p_o, let_re, sexp], 1, not_close], [[p_o, keywords_re('lambda', 'if'), not_p], 1, not_close], [[p_o, keywords_re('while'), not_p, sexp], 1, not_close], [[p_o, keywords_re('if'), not_p, glob], 1], [[p_o, def_lambda_re, identifiers], 1, not_close], [[p_o, def_lambda_re, identifiers, string_re], 1, not_close], [[p_o, def_lambda_re, identifiers, string_re, sexp], 1, not_close], [[p_o, def_lambda_re, identifiers, sexp], 1, not_close]]; // ---------------------------------------------------------------------- Formatter.prototype["break"] = function () { - var code = this.__code__.replace(/\n[ \t]*/g, '\n '); + var code = this.__code__.replace(/\n[ \t]*/g, '\n '); // function that work when calling tokenize with meta data or not + var token = function token(t) { - if (t.token.match(string_re)) { + if (t.token.match(string_re) || t.token.match(re_re)) { return t.token; } else { return t.token.replace(/\s+/, ' '); } - }; + }; // tokenize is part of the parser/lexer that split code into tokens and inclue + // meta data like number of column or line + var tokens = tokenize(code, true).map(token).filter(function (t) { return t !== '\n'; @@ -3955,25 +4076,28 @@ rules.map(function (b) { return b[1]; }).forEach(function (count) { - count = count.valueOf(); + count = count.valueOf(); // some patterns require to check what was before like + // if inside let binding - if (!sexp[count]) { + if (count > 0 && !sexp[count]) { sexp[count] = previousSexp(sub, count); } }); - var _iterator6 = _createForOfIteratorHelper(rules), - _step6; + var _iterator7 = _createForOfIteratorHelper(rules), + _step7; try { - for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) { - var _step6$value = slicedToArray(_step6.value, 3), - pattern = _step6$value[0], - count = _step6$value[1], - ext = _step6$value[2]; - - count = count.valueOf(); - var m = match(pattern, sexp[count].filter(function (t) { + for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) { + var _step7$value = slicedToArray(_step7.value, 3), + pattern = _step7$value[0], + count = _step7$value[1], + ext = _step7$value[2]; + + count = count.valueOf(); // 0 count mean ignore the previous S-Expression + + var test_sexp = count > 0 ? sexp[count] : sub; + var m = match(pattern, test_sexp.filter(function (t) { return t.trim(); })); var next = tokens.slice(i).find(function (t) { @@ -3981,15 +4105,20 @@ }); if (m && (ext instanceof Ahead && ext.match(next) || !ext)) { - tokens.splice(i, 0, '\n'); - i++; + if (!tokens[i - 1].trim()) { + tokens[i - 1] = '\n'; + } else { + tokens.splice(i, 0, '\n'); + i++; + } + continue; } } } catch (err) { - _iterator6.e(err); + _iterator7.e(err); } finally { - _iterator6.f(); + _iterator7.f(); } } @@ -4103,7 +4232,7 @@ return undefined$1; }; - Nil.prototype.toObject = function () { + Nil.prototype.to_object = function () { return {}; }; @@ -4111,7 +4240,7 @@ return new Pair(x, nil); }; - Nil.prototype.toArray = function () { + Nil.prototype.to_array = function () { return []; }; @@ -4129,7 +4258,7 @@ } // ---------------------------------------------------------------------- - function toArray$1(name, deep) { + function to_array(name, deep) { return function recur(list) { typecheck(name, list, ['pair', 'nil']); @@ -4167,7 +4296,7 @@ Pair.prototype.flatten = function () { - return Pair.fromArray(flatten(this.toArray())); + return Pair.fromArray(flatten(this.to_array())); }; // ---------------------------------------------------------------------- @@ -4213,6 +4342,7 @@ Pair.prototype.clone = function () { + var deep = arguments.length > 0 && arguments[0] !== undefined$1 ? arguments[0] : true; var visited = new Map(); function clone(node) { @@ -4223,7 +4353,13 @@ var pair = new Pair(); visited.set(node, pair); - pair.car = clone(node.car); + + if (deep) { + pair.car = clone(node.car); + } else { + pair.car = node.car; + } + pair.cdr = clone(node.cdr); pair[__cycles__] = node[__cycles__]; return pair; @@ -4236,7 +4372,7 @@ }; // ---------------------------------------------------------------------- - Pair.prototype.lastPair = function () { + Pair.prototype.last_pair = function () { var node = this; while (true) { @@ -4249,13 +4385,13 @@ }; // ---------------------------------------------------------------------- - Pair.prototype.toArray = function () { + Pair.prototype.to_array = function () { var deep = arguments.length > 0 && arguments[0] !== undefined$1 ? arguments[0] : true; var result = []; if (this.car instanceof Pair) { if (deep) { - result.push(this.car.toArray()); + result.push(this.car.to_array()); } else { result.push(this.car); } @@ -4264,7 +4400,7 @@ } if (this.cdr instanceof Pair) { - result = result.concat(this.cdr.toArray()); + result = result.concat(this.cdr.to_array()); } return result; @@ -4312,13 +4448,13 @@ return result; }; // ---------------------------------------------------------------------- - // by default toObject was created to create JavaScript objects, + // by default to_object was created to create JavaScript objects, // so it use valueOf to get native values // literal parameter was a hack to allow create LComplex from LIPS code // ---------------------------------------------------------------------- - Pair.prototype.toObject = function () { + Pair.prototype.to_object = function () { var literal = arguments.length > 0 && arguments[0] !== undefined$1 ? arguments[0] : false; var node = this; var result = {}; @@ -4339,7 +4475,7 @@ var cdr = pair.cdr; if (cdr instanceof Pair) { - cdr = cdr.toObject(literal); + cdr = cdr.to_object(literal); } if (is_native(cdr)) { @@ -4498,10 +4634,10 @@ var str_mapping = new Map(); - [[Number.NEGATIVE_INFINITY, '-inf.0'], [Number.POSITIVE_INFINITY, '+inf.0'], [true, '#t'], [false, '#f'], [null, 'null'], [undefined$1, '#']].forEach(function (_ref10) { - var _ref11 = slicedToArray(_ref10, 2), - key = _ref11[0], - value = _ref11[1]; + [[true, '#t'], [false, '#f'], [null, 'null'], [undefined$1, '#']].forEach(function (_ref11) { + var _ref12 = slicedToArray(_ref11, 2), + key = _ref12[0], + value = _ref12[1]; str_mapping.set(key, value); }); // ---------------------------------------------------------------------- @@ -4586,86 +4722,110 @@ if (has_own_function(fn, 'toString')) { return fn.toString(); } else if (fn.name && !fn[__lambda__]) { - return "#"); + return "#"); } else { return '#'; } } // ---------------------------------------------------------------------- + // instances extracted to make cyclomatic complexity of toString smaller - function toString(obj, quote, skip_cycles) { - if (typeof jQuery !== 'undefined' && obj instanceof jQuery.fn.init) { - return '#'; - } + var instances = new Map(); // ---------------------------------------------------------------------- - if (str_mapping.has(obj)) { - return str_mapping.get(obj); + [[Error, function (e) { + return e.message; + }], [Pair, function (pair, _ref13) { + var quote = _ref13.quote, + skip_cycles = _ref13.skip_cycles, + pair_args = _ref13.pair_args; + + // make sure that repr directly after update set the cycle ref + if (!skip_cycles) { + pair.markCycles(); } - if (obj instanceof Error) { - return obj.message; + return pair.toString.apply(pair, [quote].concat(toConsumableArray(pair_args))); + }], [LCharacter, function (chr, _ref14) { + var quote = _ref14.quote; + + if (quote) { + return chr.toString(); } - if (obj instanceof Pair) { - var _obj; + return chr.valueOf(); + }], [LString, function (str, _ref15) { + var quote = _ref15.quote; + str = str.toString(); - // make sure that repr directly after update set the cycle ref - if (!skip_cycles) { - obj.markCycles(); - } + if (quote) { + return JSON.stringify(str).replace(/\\n/g, '\n'); + } - for (var _len4 = arguments.length, pair_args = new Array(_len4 > 3 ? _len4 - 3 : 0), _key4 = 3; _key4 < _len4; _key4++) { - pair_args[_key4 - 3] = arguments[_key4]; - } + return str; + }], [RegExp, function (re) { + return '#' + re.toString(); + }]].forEach(function (_ref16) { + var _ref17 = slicedToArray(_ref16, 2), + cls = _ref17[0], + fn = _ref17[1]; + + instances.set(cls, fn); + }); // ---------------------------------------------------------------------- + + var native_types = [LSymbol, LNumber, Macro, Values, InputPort, OutputPort, Environment, QuotedPromise]; // ---------------------------------------------------------------------- - return (_obj = obj).toString.apply(_obj, [quote].concat(pair_args)); + function toString(obj, quote, skip_cycles) { + if (typeof jQuery !== 'undefined' && obj instanceof jQuery.fn.init) { + return '#'; } - if (Number.isNaN(obj)) { - return '+nan.0'; + if (str_mapping.has(obj)) { + return str_mapping.get(obj); } - if (obj instanceof LCharacter) { - if (quote) { - return obj.toString(); - } + if (obj) { + var cls = obj.constructor; - return obj.valueOf(); - } // constants + if (instances.has(cls)) { + for (var _len5 = arguments.length, pair_args = new Array(_len5 > 3 ? _len5 - 3 : 0), _key5 = 3; _key5 < _len5; _key5++) { + pair_args[_key5 - 3] = arguments[_key5]; + } + return instances.get(cls)(obj, { + quote: quote, + skip_cycles: skip_cycles, + pair_args: pair_args + }); + } + } // standard objects that have toString - if ([nil, eof].includes(obj)) { - return obj.toString(); - } - var types = [LSymbol, LNumber, Macro, Values, InputPort, Environment]; + var _iterator8 = _createForOfIteratorHelper(native_types), + _step8; + + try { + for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) { + var _type2 = _step8.value; - for (var _i4 = 0, _types = types; _i4 < _types.length; _i4++) { - var _type2 = _types[_i4]; + if (obj instanceof _type2) { + return obj.toString(quote); + } + } // constants - if (obj instanceof _type2) { - return obj.toString(quote); - } + } catch (err) { + _iterator8.e(err); + } finally { + _iterator8.f(); } - if (obj instanceof RegExp) { - return '#' + obj.toString(); + if ([nil, eof].includes(obj)) { + return obj.toString(); } if (is_function(obj)) { return function_to_string(obj); } - if (obj instanceof LString) { - obj = obj.toString(); - - if (quote) { - return JSON.stringify(obj).replace(/\\n/g, '\n'); - } - - return obj; - } - if (obj === root) { return '#'; } @@ -4923,9 +5083,9 @@ Pair.prototype.toString = function (quote) { - var _ref12 = arguments.length > 1 && arguments[1] !== undefined$1 ? arguments[1] : {}, - _ref12$nested = _ref12.nested, - nested = _ref12$nested === void 0 ? false : _ref12$nested; + var _ref18 = arguments.length > 1 && arguments[1] !== undefined$1 ? arguments[1] : {}, + _ref18$nested = _ref18.nested, + nested = _ref18$nested === void 0 ? false : _ref18$nested; if (is_debug()) { var result = []; @@ -5072,7 +5232,13 @@ _type3 = true; } - return _type3 && x.cmp(y) === 0; + if (_type3 && x.cmp(y) === 0) { + if (x.valueOf() === 0) { + return Object.is(x.valueOf(), y.valueOf()); + } + + return true; + } } return false; @@ -5081,9 +5247,19 @@ return false; } - x = LNumber(x); - y = LNumber(y); - return x.__type__ === y.__type__ && x.cmp(y) === 0; + if (Number.isNaN(x)) { + return Number.isNaN(y); + } + + if (x === Number.NEGATIVE_INFINITY) { + return y === Number.NEGATIVE_INFINITY; + } + + if (x === Number.POSITIVE_INFINITY) { + return y === Number.POSITIVE_INFINITY; + } + + return equal(LNumber(x), LNumber(y)); } else if (x instanceof LCharacter) { if (!(y instanceof LCharacter)) { return false; @@ -5127,7 +5303,9 @@ return Math.trunc; } else { return function (x) { - if (x < 0) { + if (x === 0) { + return 0; + } else if (x < 0) { return Math.ceil(x); } else { return Math.floor(x); @@ -5167,10 +5345,10 @@ }; // ---------------------------------------------------------------------- - Macro.prototype.invoke = function (code, _ref13, macro_expand) { - var env = _ref13.env, - dynamic_scope = _ref13.dynamic_scope, - error = _ref13.error; + Macro.prototype.invoke = function (code, _ref19, macro_expand) { + var env = _ref19.env, + dynamic_scope = _ref19.dynamic_scope, + error = _ref19.error; var args = { dynamic_scope: dynamic_scope, error: error, @@ -5194,7 +5372,7 @@ function macro_expand(single) { return /*#__PURE__*/function () { - var _ref14 = asyncToGenerator( /*#__PURE__*/regenerator.mark(function _callee8(code, args) { + var _ref20 = asyncToGenerator( /*#__PURE__*/regenerator.mark(function _callee8(code, args) { var env, traverse, _traverse; return regenerator.wrap(function _callee8$(_context8) { @@ -5399,7 +5577,7 @@ })); return function (_x4, _x5) { - return _ref14.apply(this, arguments); + return _ref20.apply(this, arguments); }; }(); } // ---------------------------------------------------------------------- @@ -5418,9 +5596,9 @@ Syntax.prototype = Object.create(Macro.prototype); - Syntax.prototype.invoke = function (code, _ref15, macro_expand) { - var error = _ref15.error, - env = _ref15.env; + Syntax.prototype.invoke = function (code, _ref21, macro_expand) { + var error = _ref21.error, + env = _ref21.env; var args = { error: error, env: env, @@ -5511,7 +5689,7 @@ if (pattern.car.cdr instanceof Pair && LSymbol.is(pattern.car.cdr.car, ellipsis_symbol)) { var _name2 = pattern.car.car.valueOf(); - var last = pattern.lastPair(); + var last = pattern.last_pair(); if (LSymbol.is(last.car, ellipsis_symbol)) { bindings['...'].symbols[_name2] = null; @@ -6037,8 +6215,8 @@ function traverse(expr) { - var _ref16 = arguments.length > 1 && arguments[1] !== undefined$1 ? arguments[1] : {}, - disabled = _ref16.disabled; + var _ref22 = arguments.length > 1 && arguments[1] !== undefined$1 ? arguments[1] : {}, + disabled = _ref22.disabled; log('traverse>> ' + expr.toString()); @@ -6642,7 +6820,7 @@ function exec() { var output = new Pair(new LSymbol('begin'), code.cdr); - return evaluate(output, { + return _evaluate(output, { env: env, dynamic_scope: dynamic_scope, error: error @@ -6671,9 +6849,9 @@ } }).then(exec); } else { - values.forEach(function (_ref17) { - var name = _ref17.name, - value = _ref17.value; + values.forEach(function (_ref23) { + var name = _ref23.name, + value = _ref23.value; env.set(name, value); }); } @@ -6687,7 +6865,7 @@ var_body_env = env; } - var value = evaluate(pair.cdr.car, { + var value = _evaluate(pair.cdr.car, { env: var_body_env, dynamic_scope: dynamic_scope, error: error @@ -6717,9 +6895,9 @@ function pararel(name, fn) { return new Macro(name, function (code) { - var _ref18 = arguments.length > 1 && arguments[1] !== undefined$1 ? arguments[1] : {}, - dynamic_scope = _ref18.dynamic_scope, - error = _ref18.error; + var _ref24 = arguments.length > 1 && arguments[1] !== undefined$1 ? arguments[1] : {}, + dynamic_scope = _ref24.dynamic_scope, + error = _ref24.error; var env = this; @@ -6731,7 +6909,7 @@ var results = []; while (node instanceof Pair) { - results.push(evaluate(node.car, { + results.push(_evaluate(node.car, { env: env, dynamic_scope: dynamic_scope, error: error @@ -6751,8 +6929,8 @@ function guardMathCall(fn) { - for (var _len5 = arguments.length, args = new Array(_len5 > 1 ? _len5 - 1 : 0), _key5 = 1; _key5 < _len5; _key5++) { - args[_key5 - 1] = arguments[_key5]; + for (var _len6 = arguments.length, args = new Array(_len6 > 1 ? _len6 - 1 : 0), _key6 = 1; _key6 < _len6; _key6++) { + args[_key6 - 1] = arguments[_key6]; } args.forEach(function (arg) { @@ -6763,30 +6941,30 @@ function pipe() { - var _this4 = this; + var _this5 = this; - for (var _len6 = arguments.length, fns = new Array(_len6), _key6 = 0; _key6 < _len6; _key6++) { - fns[_key6] = arguments[_key6]; + for (var _len7 = arguments.length, fns = new Array(_len7), _key7 = 0; _key7 < _len7; _key7++) { + fns[_key7] = arguments[_key7]; } fns.forEach(function (fn, i) { typecheck('pipe', fn, 'function', i + 1); }); return function () { - for (var _len7 = arguments.length, args = new Array(_len7), _key7 = 0; _key7 < _len7; _key7++) { - args[_key7] = arguments[_key7]; + for (var _len8 = arguments.length, args = new Array(_len8), _key8 = 0; _key8 < _len8; _key8++) { + args[_key8] = arguments[_key8]; } return fns.reduce(function (args, f) { - return [f.apply(_this4, args)]; + return [f.apply(_this5, args)]; }, args)[0]; }; } // ------------------------------------------------------------------------- function compose() { - for (var _len8 = arguments.length, fns = new Array(_len8), _key8 = 0; _key8 < _len8; _key8++) { - fns[_key8] = arguments[_key8]; + for (var _len9 = arguments.length, fns = new Array(_len9), _key9 = 0; _key9 < _len9; _key9++) { + fns[_key9] = arguments[_key9]; } fns.forEach(function (fn, i) { @@ -6803,8 +6981,8 @@ return function recur(fn, init) { typecheck(name, fn, 'function'); - for (var _len9 = arguments.length, lists = new Array(_len9 > 2 ? _len9 - 2 : 0), _key9 = 2; _key9 < _len9; _key9++) { - lists[_key9 - 2] = arguments[_key9]; + for (var _len10 = arguments.length, lists = new Array(_len10 > 2 ? _len10 - 2 : 0), _key10 = 2; _key10 < _len10; _key10++) { + lists[_key10 - 2] = arguments[_key10]; } if (lists.some(is_null)) { @@ -6833,8 +7011,8 @@ function reduceMathOp(fn) { var init = arguments.length > 1 && arguments[1] !== undefined$1 ? arguments[1] : null; return function () { - for (var _len10 = arguments.length, args = new Array(_len10), _key10 = 0; _key10 < _len10; _key10++) { - args[_key10] = arguments[_key10]; + for (var _len11 = arguments.length, args = new Array(_len11), _key11 = 0; _key11 < _len11; _key11++) { + args[_key11] = arguments[_key11]; } if (init !== null) { @@ -6847,8 +7025,8 @@ function curry(fn) { - for (var _len11 = arguments.length, init_args = new Array(_len11 > 1 ? _len11 - 1 : 0), _key11 = 1; _key11 < _len11; _key11++) { - init_args[_key11 - 1] = arguments[_key11]; + for (var _len12 = arguments.length, init_args = new Array(_len12 > 1 ? _len12 - 1 : 0), _key12 = 1; _key12 < _len12; _key12++) { + init_args[_key12 - 1] = arguments[_key12]; } typecheck('curry', fn, 'function'); @@ -6857,8 +7035,8 @@ var args = init_args.slice(); function call() { - for (var _len12 = arguments.length, more_args = new Array(_len12), _key12 = 0; _key12 < _len12; _key12++) { - more_args[_key12] = arguments[_key12]; + for (var _len13 = arguments.length, more_args = new Array(_len13), _key13 = 0; _key13 < _len13; _key13++) { + more_args[_key13] = arguments[_key13]; } args = args.concat(more_args); @@ -6879,8 +7057,8 @@ function limit(n, fn) { typecheck('limit', fn, 'function', 2); return function () { - for (var _len13 = arguments.length, args = new Array(_len13), _key13 = 0; _key13 < _len13; _key13++) { - args[_key13] = arguments[_key13]; + for (var _len14 = arguments.length, args = new Array(_len14), _key14 = 0; _key14 < _len14; _key14++) { + args[_key14] = arguments[_key14]; } return fn.apply(void 0, toConsumableArray(args.slice(0, n))); @@ -6890,34 +7068,43 @@ // ------------------------------------------------------------------------- - function LCharacter(chr) { + function LCharacter(_char7) { if (typeof this !== 'undefined' && !(this instanceof LCharacter) || typeof this === 'undefined') { - return new LCharacter(chr); + return new LCharacter(_char7); } - if (chr instanceof LString) { - chr = chr.valueOf(); + if (_char7 instanceof LString) { + _char7 = _char7.valueOf(); } - if (Array.from(chr).length > 1) { + var name; + + if (Array.from(_char7).length > 1) { // this is name - chr = chr.toLowerCase(); + _char7 = _char7.toLowerCase(); - if (LCharacter.__names__[chr]) { - this.__name__ = chr; - this.__char__ = LCharacter.__names__[chr]; + if (LCharacter.__names__[_char7]) { + name = _char7; + _char7 = LCharacter.__names__[_char7]; } else { // this should never happen // parser don't alow not defined named characters throw new Error('Internal: Unknown named character'); } } else { - this.__char__ = chr; - var name = LCharacter.__rev_names__[chr]; + name = LCharacter.__rev_names__[_char7]; + } - if (name) { - this.__name__ = name; - } + Object.defineProperty(this, '__char__', { + value: _char7, + enumerable: true + }); + + if (name) { + Object.defineProperty(this, '__name__', { + value: name, + enumerable: true + }); } } @@ -6971,26 +7158,26 @@ var wrap = function wrap(fn) { return function () { - for (var _len14 = arguments.length, args = new Array(_len14), _key14 = 0; _key14 < _len14; _key14++) { - args[_key14] = arguments[_key14]; + for (var _len15 = arguments.length, args = new Array(_len15), _key15 = 0; _key15 < _len15; _key15++) { + args[_key15] = arguments[_key15]; } return fn.apply(this.__string__, args); }; }; - var _iterator7 = _createForOfIteratorHelper(_keys), - _step7; + var _iterator9 = _createForOfIteratorHelper(_keys), + _step9; try { - for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) { - var key = _step7.value; + for (_iterator9.s(); !(_step9 = _iterator9.n()).done;) { + var key = _step9.value; LString.prototype[key] = wrap(String.prototype[key]); } } catch (err) { - _iterator7.e(err); + _iterator9.e(err); } finally { - _iterator7.f(); + _iterator9.f(); } } @@ -7024,9 +7211,9 @@ return LString(this.__string__.toUpperCase()); }; - LString.prototype.set = function (n, _char7) { - if (_char7 instanceof LCharacter) { - _char7 = _char7.__char__; + LString.prototype.set = function (n, _char8) { + if (_char8 instanceof LCharacter) { + _char8 = _char8.__char__; } var string = []; @@ -7035,7 +7222,7 @@ string.push(this.__string__.substring(0, n)); } - string.push(_char7); + string.push(_char8); if (n < this.__string__.length - 1) { string.push(this.__string__.substring(n + 1)); @@ -7130,7 +7317,9 @@ } } - if (typeof BigInt !== 'undefined') { + if (Number.isNaN(n)) { + return LFloat(n); + } else if (typeof BigInt !== 'undefined') { if (typeof n !== 'bigint') { if (parsable) { var prefix; // default number base (radix) supported by BigInt constructor @@ -7183,13 +7372,25 @@ return LBigInteger(new BN(n)); } else if (parsable) { - this.value = parseInt(str, radix); + this.constant(parseInt(str, radix), 'integer'); } else { - this.value = n; + this.constant(n, 'integer'); } } // ------------------------------------------------------------------------- + LNumber.prototype.constant = function (value, type) { + Object.defineProperty(this, '__value__', { + value: value, + enumerable: true + }); + Object.defineProperty(this, '__type__', { + value: type, + enumerable: true + }); + }; // ------------------------------------------------------------------------- + + LNumber.types = { "float": function float(n) { var force = arguments.length > 1 && arguments[1] !== undefined$1 ? arguments[1] : false; @@ -7221,6 +7422,11 @@ } }; // ------------------------------------------------------------------------- + LNumber.prototype.isNaN = function () { + return Number.isNaN(this.__value__); + }; // ------------------------------------------------------------------------- + + LNumber.prototype.gcd = function (b) { // ref: https://rosettacode.org/wiki/Greatest_common_divisor#JavaScript var a = this.abs(); @@ -7254,17 +7460,25 @@ LNumber.isNumber = function (n) { - return n instanceof LNumber || !Number.isNaN(n) && LNumber.isNative(n) || LNumber.isBN(n); + return n instanceof LNumber || LNumber.isNative(n) || LNumber.isBN(n); }; // ------------------------------------------------------------------------- LNumber.isComplex = function (n) { - var ret = n instanceof LComplex || LNumber.isNumber(n.im) && LNumber.isNumber(n.re); + if (!n) { + return false; + } + + var ret = n instanceof LComplex || (LNumber.isNumber(n.im) || Number.isNaN(n.im)) && (LNumber.isNumber(n.re) || Number.isNaN(n.re)); return ret; }; // ------------------------------------------------------------------------- LNumber.isRational = function (n) { + if (!n) { + return false; + } + return n instanceof LRational || LNumber.isNumber(n.num) && LNumber.isNumber(n.denom); }; // ------------------------------------------------------------------------- @@ -7319,11 +7533,15 @@ LNumber.prototype.toString = LNumber.prototype.toJSON = function (radix) { + if (Number.isNaN(this.__value__)) { + return '+nan.0'; + } + if (radix > 2 && radix < 36) { - return this.value.toString(radix); + return this.__value__.toString(radix); } - return this.value.toString(); + return this.__value__.toString(); }; // ------------------------------------------------------------------------- @@ -7335,14 +7553,14 @@ LNumber.prototype.isBigNumber = function () { - return typeof this.value === 'bigint' || typeof BN !== 'undefined' && !(this.value instanceof BN); + return typeof this.__value__ === 'bigint' || typeof BN !== 'undefined' && !(this.value instanceof BN); }; // ------------------------------------------------------------------------- ['floor', 'ceil', 'round'].forEach(function (fn) { LNumber.prototype[fn] = function () { - if (this["float"] || LNumber.isFloat(this.value)) { - return LNumber(Math[fn](this.value)); + if (this["float"] || LNumber.isFloat(this.__value__)) { + return LNumber(Math[fn](this.__value__)); } else { return LNumber(Math[fn](this.valueOf())); } @@ -7350,12 +7568,14 @@ }); // ------------------------------------------------------------------------- LNumber.prototype.valueOf = function () { - if (LNumber.isNative(this.value)) { - return Number(this.value); - } else if (LNumber.isBN(this.value)) { - return this.value.toNumber(); + if (LNumber.isNative(this.__value__)) { + return Number(this.__value__); + } else if (LNumber.isBN(this.__value__)) { + return this.__value__.toNumber(); } }; // ------------------------------------------------------------------------- + // type coercion matrix + // ------------------------------------------------------------------------- var matrix = function () { @@ -7365,17 +7585,35 @@ return { bigint: { - 'bigint': i, - 'float': function float(a, b) { + bigint: i, + "float": function float(a, b) { return [LFloat(a.valueOf()), b]; }, - 'rational': function rational(a, b) { + rational: function rational(a, b) { return [{ num: a, denom: 1 }, b]; }, - 'complex': function complex(a, b) { + complex: function complex(a, b) { + return [{ + im: 0, + re: a + }, b]; + } + }, + integer: { + integer: i, + "float": function float(a, b) { + return [LFloat(a.valueOf()), b]; + }, + rational: function rational(a, b) { + return [{ + num: a, + denom: 1 + }, b]; + }, + complex: function complex(a, b) { return [{ im: 0, re: a @@ -7383,14 +7621,17 @@ } }, "float": { - 'bigint': function bigint(a, b) { + bigint: function bigint(a, b) { + return [a, b && LFloat(b.valueOf())]; + }, + integer: function integer(a, b) { return [a, b && LFloat(b.valueOf())]; }, - 'float': i, - 'rational': function rational(a, b) { + "float": i, + rational: function rational(a, b) { return [a, b && LFloat(b.valueOf())]; }, - 'complex': function complex(a, b) { + complex: function complex(a, b) { return [{ re: a, im: LFloat(0) @@ -7399,6 +7640,7 @@ }, complex: { bigint: complex('bigint'), + integer: complex('integer'), "float": complex('float'), rational: complex('rational'), complex: function complex(a, b) { @@ -7428,17 +7670,23 @@ denom: 1 }]; }, + integer: function integer(a, b) { + return [a, b && { + num: b, + denom: 1 + }]; + }, "float": function float(a, b) { return [LFloat(a.valueOf()), b]; }, rational: i, complex: function complex(a, b) { return [{ - im: coerce(a.__type__, b.__im__.__type__, 0), - re: coerce(a.__type__, b.__re__.__type__, a) + im: coerce(a.__type__, b.__im__.__type__, 0)[0], + re: coerce(a.__type__, b.__re__.__type__, a)[0] }, { - im: coerce(a.__type__, b.__im__.__type__, b.__im__), - re: coerce(a.__type__, b.__re__.__type__, b.__re__) + im: coerce(a.__type__, b.__im__.__type__, b.__im__)[0], + re: coerce(a.__type__, b.__re__.__type__, b.__re__)[0] }]; } } @@ -7447,33 +7695,25 @@ function complex(type) { return function (a, b) { return [{ - im: coerce(type, a.__im__.__type__, a.__im__), - re: coerce(type, a.__re__.__type__, a.__re__) + im: coerce(type, a.__im__.__type__, 0, a.__im__)[1], + re: coerce(type, a.__re__.__type__, 0, a.__re__)[1] }, { - im: coerce(type, a.__im__.__type__, 0), - re: coerce(type, b.__type__, b) + im: coerce(type, a.__im__.__type__, 0, 0)[1], + re: coerce(type, b.__type__, 0, b)[1] }]; }; } }(); // ------------------------------------------------------------------------- - function coerce(type_a, type_b, a) { - return matrix[type_a][type_b](a)[0]; + function coerce(type_a, type_b, a, b) { + return matrix[type_a][type_b](a, b); } // ------------------------------------------------------------------------- LNumber.coerce = function (a, b) { - function clean(type) { - if (type === 'integer') { - return 'bigint'; - } - - return type; - } - - var a_type = clean(LNumber.getType(a)); - var b_type = clean(LNumber.getType(b)); + var a_type = LNumber.getType(a); + var b_type = LNumber.getType(b); if (!matrix[a_type]) { throw new Error("LNumber::coerce unknown lhs type ".concat(a_type)); @@ -7481,7 +7721,8 @@ throw new Error("LNumber::coerce unknown rhs type ".concat(b_type)); } - return matrix[a_type][b_type](a, b).map(function (n) { + var tmp = matrix[a_type][b_type](a, b); + return tmp.map(function (n) { return LNumber(n, true); }); }; // ------------------------------------------------------------------------- @@ -7528,7 +7769,7 @@ LNumber.prototype.isFloat = function () { - return !!(LNumber.isFloat(this.value) || this["float"]); + return !!(LNumber.isFloat(this.__value__) || this["float"]); }; // ------------------------------------------------------------------------- @@ -7595,6 +7836,14 @@ return LNumber(LNumber._ops[op](this.valueOf())); } + if (typeof n === 'number') { + n = LNumber(n); + } + + if (Number.isNaN(this.__value__) && !LNumber.isComplex(n) || !LNumber.isComplex(this) && Number.isNaN(n.__value__)) { + return LNumber(NaN); + } + var _this$coerce = this.coerce(n), _this$coerce2 = slicedToArray(_this$coerce, 2), a = _this$coerce2[0], @@ -7633,10 +7882,10 @@ LNumber.prototype.pow = function (n) { var value; - if (LNumber.isBN(this.value)) { - value = this.value.pow(n.value); + if (LNumber.isBN(this.__value__)) { + value = this.__value__.pow(n.__value__); } else { - value = pow(this.value, n.value); + value = pow(this.__value__, n.__value__); } return LNumber(value); @@ -7644,9 +7893,9 @@ LNumber.prototype.abs = function () { - var value = this.value; + var value = this.__value__; - if (LNumber.isNative(this.value)) { + if (LNumber.isNative(this.__value__)) { if (value < 0) { value = -value; } @@ -7659,14 +7908,14 @@ LNumber.prototype.isOdd = function () { - if (LNumber.isNative(this.value)) { + if (LNumber.isNative(this.__value__)) { if (this.isBigNumber()) { - return this.value % BigInt(2) === BigInt(1); + return this.__value__ % BigInt(2) === BigInt(1); } - return this.value % 2 === 1; - } else if (LNumber.isBN(this.value)) { - return this.value.isOdd(); + return this.__value__ % 2 === 1; + } else if (LNumber.isBN(this.__value__)) { + return this.__value__.isOdd(); } }; // ------------------------------------------------------------------------- @@ -7683,9 +7932,9 @@ b = _this$coerce4[1]; function cmp(a, b) { - if (a.value < b.value) { + if (a.__value__ < b.__value__) { return -1; - } else if (a.value === b.value) { + } else if (a.__value__ === b.__value__) { return 0; } else { return 1; @@ -7693,10 +7942,10 @@ } if (a.__type__ === 'bigint') { - if (LNumber.isNative(a.value)) { + if (LNumber.isNative(a.__value__)) { return cmp(a, b); - } else if (LNumber.isBN(a.value)) { - return this.value.cmp(b.value); + } else if (LNumber.isBN(a.__value__)) { + return this.__value__.cmp(b.__value__); } } else if (a instanceof LFloat) { return cmp(a, b); @@ -7730,15 +7979,29 @@ var im = n.im instanceof LNumber ? n.im : LNumber(n.im); var re = n.re instanceof LNumber ? n.re : LNumber(n.re); - this.__im__ = im; - this.__re__ = re; - this.__type__ = 'complex'; + this.constant(im, re); } // ------------------------------------------------------------------------- LComplex.prototype = Object.create(LNumber.prototype); LComplex.prototype.constructor = LComplex; // ------------------------------------------------------------------------- + LComplex.prototype.constant = function (im, re) { + Object.defineProperty(this, '__im__', { + value: im, + enumerable: true + }); + Object.defineProperty(this, '__re__', { + value: re, + enumerable: true + }); + Object.defineProperty(this, '__type__', { + value: 'complex', + enumerable: true + }); + }; // ------------------------------------------------------------------------- + + LComplex.prototype.toRational = function (n) { if (LNumber.isFloat(this.__im__) && LNumber.isFloat(this.__re__)) { var im = LFloat(this.__im__).toRational(n); @@ -7754,7 +8017,7 @@ LComplex.prototype.add = function (n) { - return this.complex_op(n, function (a_re, b_re, a_im, b_im) { + return this.complex_op('add', n, function (a_re, b_re, a_im, b_im) { return { re: a_re.add(b_re), im: a_im.add(b_im) @@ -7796,6 +8059,14 @@ }; // ------------------------------------------------------------------------- + LComplex.prototype.conjugate = function () { + return LComplex({ + re: this.__re__, + im: this.__im__.sub() + }); + }; // ------------------------------------------------------------------------- + + LComplex.prototype.sqrt = function () { var r = this.modulus(); // code based ok Kawa Scheme source code (file DComplex.java) // Copyright (c) 1997 Per M.A. Bothner. @@ -7827,12 +8098,20 @@ LComplex.prototype.div = function (n) { if (LNumber.isNumber(n) && !LNumber.isComplex(n)) { - n = LComplex({ - im: 0, - re: n + if (!(n instanceof LNumber)) { + n = LNumber(n); + } + + var _re = this.__re__.div(n); + + var _im = this.__im__.div(n); + + return LComplex({ + re: _re, + im: _im }); } else if (!LNumber.isComplex(n)) { - throw new Error('[LComplex::add] Invalid value'); + throw new Error('[LComplex::div] Invalid value'); } var _this$coerce5 = this.coerce(n), @@ -7840,12 +8119,8 @@ a = _this$coerce6[0], b = _this$coerce6[1]; - var conj = LComplex({ - re: b.__re__, - im: b.__im__.sub() - }); - var denom = b.factor().valueOf(); - var num = a.mul(conj); + var denom = b.factor(); + var num = a.mul(b.conjugate()); var re = num.__re__.op('/', denom); @@ -7859,17 +8134,17 @@ LComplex.prototype.sub = function (n) { - return this.complex_op(n, function (a_re, b_re, a_im, b_im) { + return this.complex_op('sub', n, function (a_re, b_re, a_im, b_im) { return { re: a_re.sub(b_re), - im: a_im.add(b_im) + im: a_im.sub(b_im) }; }); }; // ------------------------------------------------------------------------- LComplex.prototype.mul = function (n) { - return this.complex_op(n, function (a_re, b_re, a_im, b_im) { + return this.complex_op('mul', n, function (a_re, b_re, a_im, b_im) { var ret = { re: a_re.mul(b_re).sub(a_im.mul(b_im)), im: a_re.mul(b_im).add(b_re.mul(a_im)) @@ -7879,32 +8154,45 @@ }; // ------------------------------------------------------------------------- - LComplex.prototype.complex_op = function (n, fn) { - if (LNumber.isNumber(n) && !LNumber.isComplex(n)) { - if (!(n instanceof LNumber)) { - n = LNumber(n); - } + LComplex.prototype.complex_op = function (name, n, fn) { + var _this6 = this; - var _im = n.asType(0); + var calc = function calc(re, im) { + var result = fn(_this6.__re__, re, _this6.__im__, im); - n = { - __im__: _im, - __re__: n - }; - } else if (!LNumber.isComplex(n)) { - throw new Error('[LComplex::add] Invalid value'); + if ('im' in result && 're' in result) { + if (result.im.cmp(0) === 0 && !LNumber.isFloat(result.im)) { + return result.re; + } + + return LComplex(result, true); + } + + return result; + }; + + if (typeof n === 'undefined') { + return calc(); } - var re = n.__re__ instanceof LNumber ? n.__re__ : this.__re__.asType(n.__re__); - var im = n.__im__ instanceof LNumber ? n.__im__ : this.__im__.asType(n.__im__); - var ret = fn(this.__re__, re, this.__im__, im); + if (LNumber.isNumber(n) && !LNumber.isComplex(n)) { + if (!(n instanceof LNumber)) { + n = LNumber(n); + } - if ('im' in ret && 're' in ret) { - var x = LComplex(ret, true); - return x; + var _im2 = n.asType(0); + + n = { + __im__: _im2, + __re__: n + }; + } else if (!LNumber.isComplex(n)) { + throw new Error("[LComplex::".concat(name, "] Invalid value")); } - return ret; + var re = n.__re__ instanceof LNumber ? n.__re__ : this.__re__.asType(n.__re__); + var im = n.__im__ instanceof LNumber ? n.__im__ : this.__im__.asType(n.__im__); + return calc(re, im); }; // ------------------------------------------------------------------------- @@ -7958,13 +8246,30 @@ var result; if (this.__re__.cmp(0) !== 0) { - result = [this.__re__.toString()]; + result = [toString(this.__re__)]; } else { result = []; + } // NaN and inf already have sign + + + var im = this.__im__.valueOf(); + + var inf = [Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY].includes(im); + var im_str = toString(this.__im__); + + if (!inf && !Number.isNaN(im)) { + var zero_check = this.__im__.cmp(0); + + if (zero_check < 0 || zero_check === 0 && this.__im__._minus) { + result.push('-'); + } else { + result.push('+'); + } + + im_str = im_str.replace(/^-/, ''); } - result.push(this.__im__.cmp(0) < 0 ? '-' : '+'); - result.push(this.__im__.toString().replace(/^-/, '')); + result.push(im_str); result.push('i'); return result.join(''); }; // ------------------------------------------------------------------------- @@ -7986,8 +8291,13 @@ } if (typeof n === 'number') { - this.value = n; - this.__type__ = 'float'; + if (Object.is(n, -0)) { + Object.defineProperty(this, '_minus', { + value: true + }); + } + + this.constant(n, 'float'); } } // ------------------------------------------------------------------------- @@ -7996,10 +8306,23 @@ LFloat.prototype.constructor = LFloat; // ------------------------------------------------------------------------- LFloat.prototype.toString = function () { - var str = this.value.toString(); + if (this.__value__ === Number.NEGATIVE_INFINITY) { + return '-inf.0'; + } - if (!LNumber.isFloat(this.value) && !str.match(/e/i)) { - return str + '.0'; + if (this.__value__ === Number.POSITIVE_INFINITY) { + return '+inf.0'; + } + + if (Number.isNaN(this.__value__)) { + return '+nan.0'; + } + + var str = this.__value__.toString(); + + if (!LNumber.isFloat(this.__value__) && !str.match(/e/i)) { + var result = str + '.0'; + return this._minus ? '-' + result : result; } return str.replace(/^([0-9]+)e/, '$1.0e'); @@ -8008,16 +8331,16 @@ LFloat.prototype._op = function (op, n) { if (n instanceof LNumber) { - n = n.value; + n = n.__value__; } var fn = LNumber._ops[op]; - if (op === '/' && this.value === 0 && n === 0) { + if (op === '/' && this.__value__ === 0 && n === 0) { return NaN; } - return LFloat(fn(this.value, n)); + return LFloat(fn(this.__value__, n)); }; // ------------------------------------------------------------------------- // same aproximation as in guile scheme @@ -8026,10 +8349,10 @@ var n = arguments.length > 0 && arguments[0] !== undefined$1 ? arguments[0] : null; if (n === null) { - return toRational(this.value.valueOf()); + return toRational(this.__value__.valueOf()); } - return approxRatio(n.valueOf())(this.value.valueOf()); + return approxRatio(n.valueOf())(this.__value__.valueOf()); }; // ------------------------------------------------------------------------- // ref: https://rosettacode.org/wiki/Convert_decimal_number_to_rational // ------------------------------------------------------------------------- @@ -8113,8 +8436,15 @@ throw new Error('Invalid constructor call for LRational'); } - var num = LNumber(n.num); - var denom = LNumber(n.denom); + var num, denom; + + if (n instanceof LRational) { + num = LNumber(n.__num__); + denom = LNumber(n.__denom__); + } else { + num = LNumber(n.num); + denom = LNumber(n.denom); + } if (!force && denom.cmp(0) !== 0) { var is_integer = num.op('%', denom).cmp(0) === 0; @@ -8124,15 +8454,29 @@ } } - this.num = num; - this.denom = denom; - this.__type__ = 'rational'; + this.constant(num, denom); } // ------------------------------------------------------------------------- LRational.prototype = Object.create(LNumber.prototype); LRational.prototype.constructor = LRational; // ------------------------------------------------------------------------- + LRational.prototype.constant = function (num, denom) { + Object.defineProperty(this, '__num__', { + value: num, + enumerable: true + }); + Object.defineProperty(this, '__denom__', { + value: denom, + enumerable: true + }); + Object.defineProperty(this, '__type__', { + value: 'rational', + enumerable: true + }); + }; // ------------------------------------------------------------------------- + + LRational.prototype.pow = function (n) { var cmp = n.cmp(0); @@ -8142,8 +8486,11 @@ if (cmp === -1) { n = n.sub(); - var num = this.denom.pow(n); - var denom = this.num.pow(n); + + var num = this.__denom__.pow(n); + + var denom = this.__num__.pow(n); + return LRational({ num: num, denom: denom @@ -8163,8 +8510,9 @@ LRational.prototype.sqrt = function () { - var num = this.num.sqrt(); - var denom = this.denom.sqrt(); + var num = this.__num__.sqrt(); + + var denom = this.__denom__.sqrt(); if (num instanceof LFloat) { num = (readOnlyError("num"), num.toRational()); @@ -8182,8 +8530,8 @@ LRational.prototype.abs = function () { - var num = this.num; - var denom = this.denom; + var num = this.__num__; + var denom = this.__denom__; if (num.cmp(0) === -1) { num = num.sub(); @@ -8206,24 +8554,25 @@ LRational.prototype.toString = function () { - var gcd = this.num.gcd(this.denom); + var gcd = this.__num__.gcd(this.__denom__); + var num, denom; if (gcd.cmp(1) !== 0) { - num = this.num.div(gcd); + num = this.__num__.div(gcd); if (num instanceof LRational) { num = LNumber(num.valueOf(true)); } - denom = this.denom.div(gcd); + denom = this.__denom__.div(gcd); if (denom instanceof LRational) { denom = LNumber(denom.valueOf(true)); } } else { - num = this.num; - denom = this.denom; + num = this.__num__; + denom = this.__denom__; } var minus = this.cmp(0) < 0; @@ -8241,8 +8590,8 @@ LRational.prototype.valueOf = function (exact) { - if (this.denom.cmp(0) === 0) { - if (this.num.cmp(0) < 0) { + if (this.__denom__.cmp(0) === 0) { + if (this.__num__.cmp(0) < 0) { return Number.NEGATIVE_INFINITY; } @@ -8250,10 +8599,10 @@ } if (exact) { - return LNumber._ops['/'](this.num.value, this.denom.value); + return LNumber._ops['/'](this.__num__.value, this.__denom__.value); } - return LFloat(this.num.valueOf()).div(this.denom.valueOf()); + return LFloat(this.__num__.valueOf()).div(this.__denom__.valueOf()); }; // ------------------------------------------------------------------------- @@ -8263,8 +8612,10 @@ } if (LNumber.isRational(n)) { - var num = this.num.mul(n.num); - var denom = this.denom.mul(n.denom); + var num = this.__num__.mul(n.__num__); + + var denom = this.__denom__.mul(n.__denom__); + return LRational({ num: num, denom: denom @@ -8286,8 +8637,10 @@ } if (LNumber.isRational(n)) { - var num = this.num.mul(n.denom); - var denom = this.denom.mul(n.num); + var num = this.__num__.mul(n.__denom__); + + var denom = this.__denom__.mul(n.__num__); + return LRational({ num: num, denom: denom @@ -8319,8 +8672,9 @@ } if (LNumber.isRational(n)) { - var num = n.num.sub(); - var denom = n.denom; + var num = n.__num__.sub(); + + var denom = n.__denom__; return this.add(LRational({ num: num, denom: denom @@ -8348,10 +8702,10 @@ } if (LNumber.isRational(n)) { - var a_denom = this.denom; - var b_denom = n.denom; - var a_num = this.num; - var b_num = n.num; + var a_denom = this.__denom__; + var b_denom = n.__denom__; + var a_num = this.__num__; + var b_num = n.__num__; var denom, num; if (a_denom !== b_denom) { @@ -8387,16 +8741,17 @@ } if (n instanceof LBigInteger) { - return LBigInteger(n.value, n._native); + return LBigInteger(n.__value__, n._native); } if (!LNumber.isBigInteger(n)) { throw new Error('Invalid constructor call for LBigInteger'); } - this.value = n; - this._native = _native2; - this.__type__ = 'bigint'; + this.constant(n, 'bigint'); + Object.defineProperty(this, '_native', { + value: _native2 + }); } // ------------------------------------------------------------------------- @@ -8418,20 +8773,20 @@ LBigInteger.prototype._op = function (op, n) { if (typeof n === 'undefined') { - if (LNumber.isBN(this.value)) { + if (LNumber.isBN(this.__value__)) { op = LBigInteger.bn_op[op]; - return LBigInteger(this.value.clone()[op](), false); + return LBigInteger(this.__value__.clone()[op](), false); } - return LBigInteger(LNumber._ops[op](this.value), true); + return LBigInteger(LNumber._ops[op](this.__value__), true); } - if (LNumber.isBN(this.value) && LNumber.isBN(n.value)) { + if (LNumber.isBN(this.__value__) && LNumber.isBN(n.__value__)) { op = LBigInteger.bn_op[op]; - return LBigInteger(this.value.clone()[op](n), false); + return LBigInteger(this.__value__.clone()[op](n), false); } - var ret = LNumber._ops[op](this.value, n.value); + var ret = LNumber._ops[op](this.__value__, n.__value__); if (op === '/') { var is_integer = this.op('%', n).cmp(0) === 0; @@ -8455,10 +8810,10 @@ var value; var minus = this.cmp(0) < 0; - if (LNumber.isNative(this.value)) { + if (LNumber.isNative(this.__value__)) { value = LNumber(Math.sqrt(minus ? -this.valueOf() : this.valueOf())); - } else if (LNumber.isBN(this.value)) { - value = minus ? this.value.neg().sqrt() : this.value.sqrt(); + } else if (LNumber.isBN(this.__value__)) { + value = minus ? this.__value__.neg().sqrt() : this.__value__.sqrt(); } if (minus) { @@ -8475,13 +8830,25 @@ function InputPort(read) { - var _this5 = this; + var _this7 = this; if (typeof this !== 'undefined' && !(this instanceof InputPort) || typeof this === 'undefined') { return new InputPort(read); } typecheck('InputPort', read, 'function'); + read_only(this, '__type__', text_port); + var parser; + Object.defineProperty(this, '__parser__', { + enumerable: true, + get: function get() { + return parser; + }, + set: function set(value) { + typecheck('InputPort::__parser__', value, 'parser'); + parser = value; + } + }); this._read = read; this._with_parser = this._with_init_parser.bind(this, /*#__PURE__*/asyncToGenerator( /*#__PURE__*/regenerator.mark(function _callee9() { var line; @@ -8489,22 +8856,22 @@ while (1) { switch (_context9.prev = _context9.next) { case 0: - if (_this5.char_ready()) { + if (_this7.char_ready()) { _context9.next = 5; break; } _context9.next = 3; - return _this5._read(); + return _this7._read(); case 3: line = _context9.sent; - _this5.__parser__ = new Parser(line, { - env: _this5 + parser = new Parser(line, { + env: _this7 }); case 5: - return _context9.abrupt("return", _this5.__parser__); + return _context9.abrupt("return", _this7.__parser__); case 6: case "end": @@ -8515,7 +8882,7 @@ }))); this.char_ready = function () { - return this.__parser__ && this.__parser__.__lexer__.peek() !== eof; + return !!this.__parser__ && this.__parser__.__lexer__.peek() !== eof; }; this._make_defaults(); @@ -8548,11 +8915,11 @@ InputPort.prototype._with_init_parser = function (make_parser, fn) { var self = this; return /*#__PURE__*/function () { - var _ref20 = asyncToGenerator( /*#__PURE__*/regenerator.mark(function _callee10() { + var _ref26 = asyncToGenerator( /*#__PURE__*/regenerator.mark(function _callee10() { var parser, - _len15, + _len16, args, - _key15, + _key16, _args12 = arguments; return regenerator.wrap(function _callee10$(_context10) { @@ -8565,8 +8932,8 @@ case 2: parser = _context10.sent; - for (_len15 = _args12.length, args = new Array(_len15), _key15 = 0; _key15 < _len15; _key15++) { - args[_key15] = _args12[_key15]; + for (_len16 = _args12.length, args = new Array(_len16), _key16 = 0; _key16 < _len16; _key16++) { + args[_key16] = _args12[_key16]; } return _context10.abrupt("return", fn.apply(void 0, [parser].concat(args))); @@ -8580,7 +8947,7 @@ })); return function () { - return _ref20.apply(this, arguments); + return _ref26.apply(this, arguments); }; }(); }; @@ -8590,14 +8957,14 @@ }; InputPort.prototype.close = function () { - var _this6 = this; + var _this8 = this; - delete this.__parser__; // make content garbage collected, we assign null, + this.__parser__ = null; // make content garbage collected, we assign null, // because the value is in prototype this._with_parser = null; ['read', 'close', 'read_char', 'peek-char', 'read_line'].forEach(function (name) { - _this6[name] = function () { + _this8[name] = function () { throw new Error('input-port: port is closed'); }; }); @@ -8618,6 +8985,7 @@ } typecheck('OutputPort', write, 'function'); + read_only(this, '__type__', text_port); this.write = write; } @@ -8646,14 +9014,15 @@ function OutputStringPort(toString) { - var _this7 = this; + var _this9 = this; if (typeof this !== 'undefined' && !(this instanceof OutputStringPort) || typeof this === 'undefined') { return new OutputStringPort(toString); } typecheck('OutputStringPort', toString, 'function'); - this._buffer = []; + read_only(this, '__type__', text_port); + read_only(this, '__buffer__', []); this.write = function (x) { if (!LString.isString(x)) { @@ -8662,34 +9031,37 @@ x = x.valueOf(); } - _this7._buffer.push(x); + _this9.__buffer__.push(x); }; } OutputStringPort.prototype = Object.create(OutputPort.prototype); + OutputStringPort.prototype.constructor = OutputStringPort; OutputStringPort.prototype.toString = function () { - return '#>'; + return '#'; }; - OutputStringPort.prototype.getString = function () { - return this._buffer.map(function (x) { + OutputStringPort.prototype.valueOf = function () { + return this.__buffer__.map(function (x) { return x.valueOf(); }).join(''); - }; + }; // ------------------------------------------------------------------------- - OutputStringPort.prototype.constructor = OutputStringPort; // ------------------------------------------------------------------------- function OutputFilePort(filename, fd) { - var _this8 = this; + var _this10 = this; if (typeof this !== 'undefined' && !(this instanceof OutputFilePort) || typeof this === 'undefined') { return new OutputFilePort(filename, fd); } typecheck('OutputFilePort', filename, 'string'); - this._filename = filename; - this._fd = fd.valueOf(); + read_only(this, '__filename__', filename); + read_only(this, '_fd', fd.valueOf(), { + hidden: true + }); + read_only(this, '__type__', text_port); this.write = function (x) { if (!LString.isString(x)) { @@ -8698,23 +9070,41 @@ x = x.valueOf(); } - root.fs.write(_this8._fd, x, function () {}); + _this10.fs().write(_this10._fd, x, function (err) { + if (err) { + throw err; + } + }); }; } OutputFilePort.prototype = Object.create(OutputPort.prototype); OutputFilePort.prototype.constructor = OutputFilePort; + OutputFilePort.prototype.fs = function () { + if (!this._fs) { + this._fs = this.internal('fs'); + } + + return this._fs; + }; + + OutputFilePort.prototype.internal = function (name) { + return user_env.get('**internal-env**').get(name); + }; + OutputFilePort.prototype.close = function () { - var _this9 = this; + var _this11 = this; return new Promise(function (resolve, reject) { - root.fs.close(_this9._fd, function (err) { + _this11.fs().close(_this11._fd, function (err) { if (err) { reject(err); } else { - _this9._fd = null; - OutputPort.prototype.close.call(_this9); + read_only(_this11, '_fd', null, { + hidden: true + }); + OutputPort.prototype.close.call(_this11); resolve(); } }); @@ -8722,12 +9112,12 @@ }; OutputFilePort.prototype.toString = function () { - return "#"); + return "#"); }; // ------------------------------------------------------------------------- function InputStringPort(string, env) { - var _this10 = this; + var _this12 = this; if (typeof this !== 'undefined' && !(this instanceof InputStringPort) || typeof this === 'undefined') { return new InputStringPort(string); @@ -8737,14 +9127,15 @@ env = env || global_env; string = string.valueOf(); this._with_parser = this._with_init_parser.bind(this, function () { - if (!_this10.__parser__) { - _this10.__parser__ = new Parser(string, { + if (!_this12.__parser__) { + _this12.__parser__ = new Parser(string, { env: env }); } - return _this10.__parser__; + return _this12.__parser__; }); + read_only(this, '__type__', text_port); this._make_defaults(); } @@ -8757,7 +9148,168 @@ InputStringPort.prototype.constructor = InputStringPort; InputStringPort.prototype.toString = function () { - return "#>"; + return "#"; + }; // ------------------------------------------------------------------------- + + + function InputByteVectorPort(bytevectors) { + if (typeof this !== 'undefined' && !(this instanceof InputByteVectorPort) || typeof this === 'undefined') { + return new InputByteVectorPort(bytevectors); + } + + typecheck('InputByteVectorPort', bytevectors, 'uint8array'); + read_only(this, '__vector__', bytevectors); + read_only(this, '__type__', binary_port); + var index = 0; + Object.defineProperty(this, '__index__', { + enumerable: true, + get: function get() { + return index; + }, + set: function set(value) { + typecheck('InputByteVectorPort::__index__', value, 'number'); + + if (value instanceof LNumber) { + value = value.valueOf(); + } + + if (typeof value === 'bigint') { + value = Number(value); + } + + if (Math.floor(value) !== value) { + throw new Error('InputByteVectorPort::__index__ value is ' + 'not integer'); + } + + index = value; + } + }); + } + + InputByteVectorPort.prototype = Object.create(InputPort.prototype); + InputByteVectorPort.prototype.constructor = InputByteVectorPort; + + InputByteVectorPort.prototype.toString = function () { + return "#"; + }; + + InputByteVectorPort.prototype.close = function () { + var _this13 = this; + + read_only(this, '__vector__', nil); + ['read_u8', 'close', 'peek_u8', 'read_u8_vector'].forEach(function (name) { + _this13[name] = function () { + throw new Error('Input-binary-port: port is closed'); + }; + }); + + this.char_ready = function () { + return false; + }; + }; + + InputByteVectorPort.prototype.u8_ready = function () { + return true; + }; + + InputByteVectorPort.prototype.peek_u8 = function () { + if (this.__index__ >= this.__vector__.length) { + return eof; + } + + return this.__vector__[this.__index__]; + }; + + InputByteVectorPort.prototype.skip = function () { + if (this.__index__ <= this.__vector__.length) { + ++this.__index__; + } + }; + + InputByteVectorPort.prototype.read_u8 = function () { + var _byte = this.peek_u8(); + + this.skip(); + return _byte; + }; + + InputByteVectorPort.prototype.read_u8_vector = function (len) { + if (typeof len === 'undefined') { + len = this.__vector__.length; + } else if (len > this.__index__ + this.__vector__.length) { + len = this.__index__ + this.__vector__.length; + } + + if (this.peek_u8() === eof) { + return eof; + } + + return this.__vector__.slice(this.__index__, len); + }; // ------------------------------------------------------------------------- + + + function OutputByteVectorPort() { + if (typeof this !== 'undefined' && !(this instanceof OutputByteVectorPort) || typeof this === 'undefined') { + return new OutputByteVectorPort(); + } + + read_only(this, '__type__', binary_port); + read_only(this, '_buffer', [], { + hidden: true + }); + + this.write = function (x) { + typecheck('write', x, ['number', 'uint8array']); + + if (LNumber.isNumber(x)) { + this._buffer.push(x.valueOf()); + } else { + var _this$_buffer; + + (_this$_buffer = this._buffer).push.apply(_this$_buffer, toConsumableArray(Array.from(x))); + } + }; + + Object.defineProperty(this, '__buffer__', { + enumerable: true, + get: function get() { + return Uint8Array.from(this._buffer); + } + }); + } + + OutputByteVectorPort.prototype = Object.create(OutputPort.prototype); + OutputByteVectorPort.prototype.constructor = OutputByteVectorPort; + + OutputByteVectorPort.prototype.close = function () { + OutputPort.prototype.close.call(this); + read_only(this, '_buffer', null, { + hidden: true + }); + }; + + OutputByteVectorPort.prototype._close_guard = function () { + if (this._closed) { + throw new Error('output-port: binary port is closed'); + } + }; + + OutputByteVectorPort.prototype.write_u8 = function (_byte2) { + typecheck('OutputByteVectorPort::write_u8', _byte2, 'number'); + this.write(_byte2); + }; + + OutputByteVectorPort.prototype.write_u8_vector = function (vector) { + typecheck('OutputByteVectorPort::write_u8_vector', vector, 'uint8array'); + this.write(vector); + }; + + OutputByteVectorPort.prototype.toString = function () { + return '#'; + }; + + OutputByteVectorPort.prototype.valueOf = function () { + return this.__buffer__; }; // ------------------------------------------------------------------------- @@ -8768,17 +9320,96 @@ InputStringPort.call(this, content); typecheck('InputFilePort', filename, 'string'); - this.__filename__ = filename; + read_only(this, '__filename__', filename); } InputFilePort.prototype = Object.create(InputStringPort.prototype); InputFilePort.prototype.constructor = InputFilePort; InputFilePort.prototype.toString = function () { - return "#"); + return "#"); + }; // ------------------------------------------------------------------------- + + + function InputBinaryFilePort(content, filename) { + if (typeof this !== 'undefined' && !(this instanceof InputBinaryFilePort) || typeof this === 'undefined') { + return new InputBinaryFilePort(content, filename); + } + + InputByteVectorPort.call(this, content); + typecheck('InputBinaryFilePort', filename, 'string'); + read_only(this, '__filename__', filename); + } + + InputBinaryFilePort.prototype = Object.create(InputByteVectorPort.prototype); + InputBinaryFilePort.prototype.constructor = InputBinaryFilePort; + + InputBinaryFilePort.prototype.toString = function () { + return "#"); }; // ------------------------------------------------------------------------- + function OutputBinaryFilePort(filename, fd) { + if (typeof this !== 'undefined' && !(this instanceof OutputBinaryFilePort) || typeof this === 'undefined') { + return new OutputBinaryFilePort(filename, fd); + } + + typecheck('OutputBinaryFilePort', filename, 'string'); + read_only(this, '__filename__', filename); + read_only(this, '_fd', fd.valueOf(), { + hidden: true + }); + read_only(this, '__type__', binary_port); + var fs, Buffer; + + this.write = function (x) { + var _this14 = this; + + typecheck('write', x, ['number', 'uint8array']); + var buffer; + + if (!fs) { + fs = this.internal('fs'); + } + + if (!Buffer) { + Buffer = this.internal('Buffer'); + } + + if (LNumber.isNumber(x)) { + buffer = Buffer.from([x.valueOf()]); + } else { + buffer = Buffer.from(Array.from(x)); + } + + return new Promise(function (resolve, reject) { + fs.write(_this14._fd, buffer, function (err) { + if (err) { + reject(err); + } else { + resolve(); + } + }); + }); + }; + } + + OutputBinaryFilePort.prototype = Object.create(OutputFilePort.prototype); + OutputBinaryFilePort.prototype.constructor = OutputBinaryFilePort; + + OutputBinaryFilePort.prototype.write_u8 = function (_byte3) { + typecheck('OutputByteVectorPort::write_u8', _byte3, 'number'); + this.write(_byte3); + }; + + OutputBinaryFilePort.prototype.write_u8_vector = function (vector) { + typecheck('OutputByteVectorPort::write_u8_vector', vector, 'uint8array'); + this.write(vector); + }; // ------------------------------------------------------------------------- + + + var binary_port = Symbol["for"]('binary'); + var text_port = Symbol["for"]('text'); var eof = new EOF(); function EOF() {} @@ -8791,11 +9422,11 @@ function Interpreter(name) { - var _ref21 = arguments.length > 1 && arguments[1] !== undefined$1 ? arguments[1] : {}, - stderr = _ref21.stderr, - stdin = _ref21.stdin, - stdout = _ref21.stdout, - obj = objectWithoutProperties(_ref21, ["stderr", "stdin", "stdout"]); + var _ref27 = arguments.length > 1 && arguments[1] !== undefined$1 ? arguments[1] : {}, + stderr = _ref27.stderr, + stdin = _ref27.stdin, + stdout = _ref27.stdout, + obj = objectWithoutProperties(_ref27, ["stderr", "stdin", "stdout"]); if (typeof this !== 'undefined' && !(this instanceof Interpreter) || typeof this === 'undefined') { return new Interpreter(name, _objectSpread({ @@ -8826,8 +9457,7 @@ inter.set('stdout', stdout); } - this.constant('**internal-env**', inter); - global_env.set('**interaction-environment**', this.__env__); + set_interaction_env(this.__env__, inter); } // ------------------------------------------------------------------------- @@ -8878,7 +9508,7 @@ parent = null; } else if (typeof arguments[0] === 'string') { obj = {}; - parent = {}; + parent = null; name = arguments[0]; } } @@ -8895,6 +9525,11 @@ }; // ------------------------------------------------------------------------- + Environment.prototype.fs = function () { + return this.get('**fs**'); + }; // ------------------------------------------------------------------------- + + Environment.prototype.unset = function (name) { if (name instanceof LSymbol) { name = name.valueOf(); @@ -8927,6 +9562,7 @@ Environment.prototype.doc = function (name) { var value = arguments.length > 1 && arguments[1] !== undefined$1 ? arguments[1] : null; + var dump = arguments.length > 2 && arguments[2] !== undefined$1 ? arguments[2] : false; if (name instanceof LSymbol) { name = name.__name__; @@ -8937,6 +9573,10 @@ } if (value) { + if (!dump) { + value = trim_lines(value); + } + this.__docs__.set(name, value); return this; @@ -9005,13 +9645,13 @@ Environment.prototype.clone = function () { - var _this11 = this; + var _this15 = this; // duplicate refs var env = {}; // TODO: duplicated Symbols Object.keys(this.__env__).forEach(function (key) { - env[key] = _this11.__env__[key]; + env[key] = _this15.__env__[key]; }); return new Environment(env, this.__parent__, this.__name__); }; // ------------------------------------------------------------------------- @@ -9168,7 +9808,7 @@ Environment.prototype.constant = function (name, value) { - var _this12 = this; + var _this16 = this; if (this.__env__.hasOwnProperty(name)) { throw new Error("Environment::constant: ".concat(name, " already exists")); @@ -9177,7 +9817,7 @@ if (arguments.length === 1 && is_plain_object(arguments[0])) { var obj = arguments[0]; Object.keys(obj).forEach(function (key) { - _this12.constant(name, obj[key]); + _this16.constant(name, obj[key]); }); } else { Object.defineProperty(this.__env__, name, { @@ -9243,8 +9883,8 @@ var native_lambda = parse(tokenize("(lambda ()\n \"[native code]\"\n (throw \"Invalid Invocation\"))"))[0]; // ------------------------------------------------------------------------------- var get = doc(function get(object) { - for (var _len16 = arguments.length, args = new Array(_len16 > 1 ? _len16 - 1 : 0), _key16 = 1; _key16 < _len16; _key16++) { - args[_key16 - 1] = arguments[_key16]; + for (var _len17 = arguments.length, args = new Array(_len17 > 1 ? _len17 - 1 : 0), _key17 = 1; _key17 < _len17; _key17++) { + args[_key17 - 1] = arguments[_key17]; } // if arg is symbol someone probably want to get __fn__ from binded function @@ -9323,7 +9963,7 @@ 'letter-unicode-regex': /(?:[A-Za-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0560-\u0588\u05D0-\u05EA\u05EF-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u0860-\u086A\u08A0-\u08B4\u08B6-\u08C7\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D04-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E86-\u0E8A\u0E8C-\u0EA3\u0EA5\u0EA7-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16F1-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1878\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1C80-\u1C88\u1C90-\u1CBA\u1CBD-\u1CBF\u1CE9-\u1CEC\u1CEE-\u1CF3\u1CF5\u1CF6\u1CFA\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312F\u3131-\u318E\u31A0-\u31BF\u31F0-\u31FF\u3400-\u4DBF\u4E00-\u9FFC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA7BF\uA7C2-\uA7CA\uA7F5-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA8FE\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB69\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF2D-\uDF40\uDF42-\uDF49\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF]|\uD801[\uDC00-\uDC9D\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE35\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2\uDD00-\uDD23\uDE80-\uDEA9\uDEB0\uDEB1\uDF00-\uDF1C\uDF27\uDF30-\uDF45\uDFB0-\uDFC4\uDFE0-\uDFF6]|\uD804[\uDC03-\uDC37\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD44\uDD47\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC5F-\uDC61\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDEB8\uDF00-\uDF1A]|\uD806[\uDC00-\uDC2B\uDCA0-\uDCDF\uDCFF-\uDD06\uDD09\uDD0C-\uDD13\uDD15\uDD16\uDD18-\uDD2F\uDD3F\uDD41\uDDA0-\uDDA7\uDDAA-\uDDD0\uDDE1\uDDE3\uDE00\uDE0B-\uDE32\uDE3A\uDE50\uDE5C-\uDE89\uDE9D\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC72-\uDC8F\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD30\uDD46\uDD60-\uDD65\uDD67\uDD68\uDD6A-\uDD89\uDD98\uDEE0-\uDEF2\uDFB0]|\uD808[\uDC00-\uDF99]|\uD809[\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD822\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879\uD880-\uD883][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDE40-\uDE7F\uDF00-\uDF4A\uDF50\uDF93-\uDF9F\uDFE0\uDFE1\uDFE3]|\uD821[\uDC00-\uDFF7]|\uD823[\uDC00-\uDCD5\uDD00-\uDD08]|\uD82C[\uDC00-\uDD1E\uDD50-\uDD52\uDD64-\uDD67\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD838[\uDD00-\uDD2C\uDD37-\uDD3D\uDD4E\uDEC0-\uDEEB]|\uD83A[\uDC00-\uDCC4\uDD00-\uDD43\uDD4B]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDEDD\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D]|\uD884[\uDC00-\uDF4A])/, 'numeral-unicode-regex': /(?:[0-9\xB2\xB3\xB9\xBC-\xBE\u0660-\u0669\u06F0-\u06F9\u07C0-\u07C9\u0966-\u096F\u09E6-\u09EF\u09F4-\u09F9\u0A66-\u0A6F\u0AE6-\u0AEF\u0B66-\u0B6F\u0B72-\u0B77\u0BE6-\u0BF2\u0C66-\u0C6F\u0C78-\u0C7E\u0CE6-\u0CEF\u0D58-\u0D5E\u0D66-\u0D78\u0DE6-\u0DEF\u0E50-\u0E59\u0ED0-\u0ED9\u0F20-\u0F33\u1040-\u1049\u1090-\u1099\u1369-\u137C\u16EE-\u16F0\u17E0-\u17E9\u17F0-\u17F9\u1810-\u1819\u1946-\u194F\u19D0-\u19DA\u1A80-\u1A89\u1A90-\u1A99\u1B50-\u1B59\u1BB0-\u1BB9\u1C40-\u1C49\u1C50-\u1C59\u2070\u2074-\u2079\u2080-\u2089\u2150-\u2182\u2185-\u2189\u2460-\u249B\u24EA-\u24FF\u2776-\u2793\u2CFD\u3007\u3021-\u3029\u3038-\u303A\u3192-\u3195\u3220-\u3229\u3248-\u324F\u3251-\u325F\u3280-\u3289\u32B1-\u32BF\uA620-\uA629\uA6E6-\uA6EF\uA830-\uA835\uA8D0-\uA8D9\uA900-\uA909\uA9D0-\uA9D9\uA9F0-\uA9F9\uAA50-\uAA59\uABF0-\uABF9\uFF10-\uFF19]|\uD800[\uDD07-\uDD33\uDD40-\uDD78\uDD8A\uDD8B\uDEE1-\uDEFB\uDF20-\uDF23\uDF41\uDF4A\uDFD1-\uDFD5]|\uD801[\uDCA0-\uDCA9]|\uD802[\uDC58-\uDC5F\uDC79-\uDC7F\uDCA7-\uDCAF\uDCFB-\uDCFF\uDD16-\uDD1B\uDDBC\uDDBD\uDDC0-\uDDCF\uDDD2-\uDDFF\uDE40-\uDE48\uDE7D\uDE7E\uDE9D-\uDE9F\uDEEB-\uDEEF\uDF58-\uDF5F\uDF78-\uDF7F\uDFA9-\uDFAF]|\uD803[\uDCFA-\uDCFF\uDD30-\uDD39\uDE60-\uDE7E\uDF1D-\uDF26\uDF51-\uDF54\uDFC5-\uDFCB]|\uD804[\uDC52-\uDC6F\uDCF0-\uDCF9\uDD36-\uDD3F\uDDD0-\uDDD9\uDDE1-\uDDF4\uDEF0-\uDEF9]|\uD805[\uDC50-\uDC59\uDCD0-\uDCD9\uDE50-\uDE59\uDEC0-\uDEC9\uDF30-\uDF3B]|\uD806[\uDCE0-\uDCF2\uDD50-\uDD59]|\uD807[\uDC50-\uDC6C\uDD50-\uDD59\uDDA0-\uDDA9\uDFC0-\uDFD4]|\uD809[\uDC00-\uDC6E]|\uD81A[\uDE60-\uDE69\uDF50-\uDF59\uDF5B-\uDF61]|\uD81B[\uDE80-\uDE96]|\uD834[\uDEE0-\uDEF3\uDF60-\uDF78]|\uD835[\uDFCE-\uDFFF]|\uD838[\uDD40-\uDD49\uDEF0-\uDEF9]|\uD83A[\uDCC7-\uDCCF\uDD50-\uDD59]|\uD83B[\uDC71-\uDCAB\uDCAD-\uDCAF\uDCB1-\uDCB4\uDD01-\uDD2D\uDD2F-\uDD3D]|\uD83C[\uDD00-\uDD0C]|\uD83E[\uDFF0-\uDFF9])/, 'space-unicode-regex': /[\t-\r \xA0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000\uFEFF]/ - }); // ------------------------------------------------------------------------- + }, undefined$1, 'internal'); // ------------------------------------------------------------------------- var global_env = new Environment({ nil: nil, @@ -9332,137 +9972,153 @@ 'true': true, 'false': false, 'null': null, - 'NaN': NaN, + 'NaN': LNumber(NaN), // ------------------------------------------------------------------ - 'peek-char': doc('peek-char', function (port) { - if (port) { - typecheck('peek-char', port, ['input-port']); - } else { + 'peek-char': doc('peek-char', function () { + var port = arguments.length > 0 && arguments[0] !== undefined$1 ? arguments[0] : null; + + if (port === null) { port = internal(this, 'stdin'); } + typecheck_text_port('peek-char', port, 'input-port'); return port.peek_char(); }, "(peek-char port)\n\n Function get character from string port or EOF object if no more\n data in string port."), // ------------------------------------------------------------------ - 'read-line': doc('read-line', function (port) { - if (typeof port === 'undefined') { + 'read-line': doc('read-line', function () { + var port = arguments.length > 0 && arguments[0] !== undefined$1 ? arguments[0] : null; + + if (port === null) { port = internal(this, 'stdin'); } - typecheck('read-line', port, ['input-port']); + typecheck_text_port('read-line', port, 'input-port'); return port.read_line(); }, "(read-char port)\n\n Function read next character from input port."), // ------------------------------------------------------------------ - 'read-char': doc('read-char', function (port) { - if (typeof port === 'undefined') { + 'read-char': doc('read-char', function () { + var port = arguments.length > 0 && arguments[0] !== undefined$1 ? arguments[0] : null; + + if (port === null) { port = internal(this, 'stdin'); } - typecheck('read-char', port, ['input-port', 'input-string-port']); + typecheck_text_port('read-char', port, 'input-port'); return port.read_char(); }, "(read-char port)\n\n Function read next character from input port."), // ------------------------------------------------------------------ read: doc( /*#__PURE__*/function () { - var _read2 = asyncToGenerator( /*#__PURE__*/regenerator.mark(function _callee11(arg) { - var _iteratorNormalCompletion2, _didIteratorError2, _iteratorError2, _iterator2, _step2, _value2, value, port; + var _read2 = asyncToGenerator( /*#__PURE__*/regenerator.mark(function _callee11() { + var arg, + _iteratorNormalCompletion2, + _didIteratorError2, + _iteratorError2, + _iterator2, + _step2, + _value2, + value, + port, + _args13 = arguments; return regenerator.wrap(function _callee11$(_context11) { while (1) { switch (_context11.prev = _context11.next) { case 0: + arg = _args13.length > 0 && _args13[0] !== undefined$1 ? _args13[0] : null; + if (!LString.isString(arg)) { - _context11.next = 34; + _context11.next = 35; break; } _iteratorNormalCompletion2 = true; _didIteratorError2 = false; - _context11.prev = 3; + _context11.prev = 4; _iterator2 = asyncIterator(parse(arg, this)); - case 5: - _context11.next = 7; + case 6: + _context11.next = 8; return _iterator2.next(); - case 7: + case 8: _step2 = _context11.sent; _iteratorNormalCompletion2 = _step2.done; - _context11.next = 11; + _context11.next = 12; return _step2.value; - case 11: + case 12: _value2 = _context11.sent; if (_iteratorNormalCompletion2) { - _context11.next = 18; + _context11.next = 19; break; } value = _value2; return _context11.abrupt("return", value); - case 15: + case 16: _iteratorNormalCompletion2 = true; - _context11.next = 5; + _context11.next = 6; break; - case 18: - _context11.next = 24; + case 19: + _context11.next = 25; break; - case 20: - _context11.prev = 20; - _context11.t0 = _context11["catch"](3); + case 21: + _context11.prev = 21; + _context11.t0 = _context11["catch"](4); _didIteratorError2 = true; _iteratorError2 = _context11.t0; - case 24: - _context11.prev = 24; + case 25: _context11.prev = 25; + _context11.prev = 26; if (!(!_iteratorNormalCompletion2 && _iterator2["return"] != null)) { - _context11.next = 29; + _context11.next = 30; break; } - _context11.next = 29; + _context11.next = 30; return _iterator2["return"](); - case 29: - _context11.prev = 29; + case 30: + _context11.prev = 30; if (!_didIteratorError2) { - _context11.next = 32; + _context11.next = 33; break; } throw _iteratorError2; - case 32: - return _context11.finish(29); - case 33: - return _context11.finish(24); + return _context11.finish(30); case 34: - if (arg) { - typecheck('read', arg, 'input-port'); - port = arg; - } else { + return _context11.finish(25); + + case 35: + if (arg === null) { port = internal(this, 'stdin'); + } else { + port = arg; } + typecheck_text_port('read', port, 'input-port'); return _context11.abrupt("return", port.read.call(this)); - case 36: + case 38: case "end": return _context11.stop(); } } - }, _callee11, this, [[3, 20, 24, 34], [25,, 29, 33]]); + }, _callee11, this, [[4, 21, 25, 35], [26,, 30, 34]]); })); - function read(_x9) { + function read() { return _read2.apply(this, arguments); } @@ -9484,8 +10140,8 @@ var display = global_env.get('display'); var newline = global_env.get('newline'); - for (var _len17 = arguments.length, args = new Array(_len17), _key17 = 0; _key17 < _len17; _key17++) { - args[_key17] = arguments[_key17]; + for (var _len18 = arguments.length, args = new Array(_len18), _key18 = 0; _key18 < _len18; _key18++) { + args[_key18] = arguments[_key18]; } args.forEach(function (arg) { @@ -9495,8 +10151,8 @@ }, "(print . args)\n\n Function convert each argument to string and print the result to\n standard output (by default it's console but it can be defined\n it user code), the function call newline after printing each arg."), // ------------------------------------------------------------------ 'format': doc(function format(str) { - for (var _len18 = arguments.length, args = new Array(_len18 > 1 ? _len18 - 1 : 0), _key18 = 1; _key18 < _len18; _key18++) { - args[_key18 - 1] = arguments[_key18]; + for (var _len19 = arguments.length, args = new Array(_len19 > 1 ? _len19 - 1 : 0), _key19 = 1; _key19 < _len19; _key19++) { + args[_key19 - 1] = arguments[_key19]; } typecheck('format', str, 'string'); @@ -9540,6 +10196,8 @@ if (port === null) { port = internal(this, 'stdout'); + } else { + typecheck('display', port, 'output-port'); } var value = global_env.get('repr')(arg); @@ -9550,8 +10208,8 @@ var port = internal(this, 'stderr'); var repr = global_env.get('repr'); - for (var _len19 = arguments.length, args = new Array(_len19), _key19 = 0; _key19 < _len19; _key19++) { - args[_key19] = arguments[_key19]; + for (var _len20 = arguments.length, args = new Array(_len20), _key20 = 0; _key20 < _len20; _key20++) { + args[_key20] = arguments[_key20]; } var value = args.map(repr).join(' '); @@ -9571,9 +10229,9 @@ return unbind(a) === unbind(b); }, "(%same-functions a b)\n\n Helper function that check if two bound functions are the same"), // ------------------------------------------------------------------ - help: doc(new Macro('help', function (code, _ref22) { - var dynamic_scope = _ref22.dynamic_scope, - error = _ref22.error; + help: doc(new Macro('help', function (code, _ref28) { + var dynamic_scope = _ref28.dynamic_scope, + error = _ref28.error; var symbol; if (code.car instanceof LSymbol) { @@ -9587,7 +10245,7 @@ dynamic_scope = this; } - var ret = evaluate(code.car, { + var ret = _evaluate(code.car, { env: env, error: error, dynamic_scope: dynamic_scope @@ -9635,11 +10293,11 @@ }, "(cdr pair)\n\n Function returns cdr (tail) of the list/pair."), // ------------------------------------------------------------------ 'set!': doc(new Macro('set!', function (code) { - var _this13 = this; + var _this17 = this; - var _ref23 = arguments.length > 1 && arguments[1] !== undefined$1 ? arguments[1] : {}, - dynamic_scope = _ref23.dynamic_scope, - error = _ref23.error; + var _ref29 = arguments.length > 1 && arguments[1] !== undefined$1 ? arguments[1] : {}, + dynamic_scope = _ref29.dynamic_scope, + error = _ref29.error; if (dynamic_scope) { dynamic_scope = this; @@ -9647,11 +10305,13 @@ var env = this; var ref; - var value = evaluate(code.cdr.car, { + + var value = _evaluate(code.cdr.car, { env: this, dynamic_scope: dynamic_scope, error: error }); + value = resolve_promises(value); function set(object, key, value) { @@ -9680,16 +10340,19 @@ if (code.car instanceof Pair && LSymbol.is(code.car.car, '.')) { var second = code.car.cdr.car; var thrid = code.car.cdr.cdr.car; - var object = evaluate(second, { + + var object = _evaluate(second, { env: this, dynamic_scope: dynamic_scope, error: error }); - var key = evaluate(thrid, { + + var key = _evaluate(thrid, { env: this, dynamic_scope: dynamic_scope, error: error }); + return set(object, key, value); } @@ -9710,7 +10373,7 @@ var key = parts.pop(); var name = parts.join('.'); - var obj = _this13.get(name, { + var obj = _this17.get(name, { throwError: false }); @@ -9838,14 +10501,14 @@ }, "(load filename)\n (load filename environment)\n\n Function fetch the file and evaluate its content as LIPS code,\n If second argument is provided and it's environment the evaluation\n will happen in that environment."), // ------------------------------------------------------------------ 'do': doc(new Macro('do', /*#__PURE__*/function () { - var _ref24 = asyncToGenerator( /*#__PURE__*/regenerator.mark(function _callee13(code, _ref25) { + var _ref30 = asyncToGenerator( /*#__PURE__*/regenerator.mark(function _callee13(code, _ref31) { var dynamic_scope, error, self, scope, vars, test, body, eval_args, node, item, _loop3; return regenerator.wrap(function _callee13$(_context13) { while (1) { switch (_context13.prev = _context13.next) { case 0: - dynamic_scope = _ref25.dynamic_scope, error = _ref25.error; + dynamic_scope = _ref31.dynamic_scope, error = _ref31.error; self = this; if (dynamic_scope) { @@ -9878,7 +10541,7 @@ _context13.t0 = scope; _context13.t1 = item.car; _context13.next = 16; - return evaluate(item.cdr.car, eval_args); + return _evaluate(item.cdr.car, eval_args); case 16: _context13.t2 = _context13.sent; @@ -9928,7 +10591,7 @@ } _context12.next = 10; - return evaluate(_item.cdr.cdr.car, eval_args); + return _evaluate(_item.cdr.cdr.car, eval_args); case 10: value = _context12.sent; @@ -9955,7 +10618,7 @@ case 23: _context13.next = 25; - return evaluate(test.car, eval_args); + return _evaluate(test.car, eval_args); case 25: _context13.t3 = _context13.sent; @@ -9978,7 +10641,7 @@ } _context13.next = 33; - return evaluate(test.cdr.car, eval_args); + return _evaluate(test.cdr.car, eval_args); case 33: return _context13.abrupt("return", _context13.sent); @@ -9991,14 +10654,14 @@ }, _callee13, this); })); - return function (_x10, _x11) { - return _ref24.apply(this, arguments); + return function (_x9, _x10) { + return _ref30.apply(this, arguments); }; }()), "(do (( )) (test expression) . body)\n\n Iteration macro that evaluate the expression body in scope of the variables.\n On Eeach loop it increase the variables according to next expression and run\n test to check if the loop should continue. If test is signle call the macro\n will not return anything. If the test is pair of expression and value the\n macro will return that value after finish."), // ------------------------------------------------------------------ - 'if': doc(new Macro('if', function (code, _ref26) { - var dynamic_scope = _ref26.dynamic_scope, - error = _ref26.error; + 'if': doc(new Macro('if', function (code, _ref32) { + var dynamic_scope = _ref32.dynamic_scope, + error = _ref32.error; if (dynamic_scope) { dynamic_scope = this; @@ -10008,13 +10671,13 @@ var resolve = function resolve(cond) { if (cond === false) { - return evaluate(code.cdr.cdr.car, { + return _evaluate(code.cdr.cdr.car, { env: env, dynamic_scope: dynamic_scope, error: error }); } else { - return evaluate(code.cdr.car, { + return _evaluate(code.cdr.car, { env: env, dynamic_scope: dynamic_scope, error: error @@ -10026,11 +10689,12 @@ throw new Error('too few expressions for `if`'); } - var cond = evaluate(code.car, { + var cond = _evaluate(code.car, { env: env, dynamic_scope: dynamic_scope, error: error }); + return unpromise(cond, resolve); }), "(if cond true-expr false-expr)\n\n Macro evaluate condition expression and if the value is true, it\n evaluate and return true expression if not it evaluate and return\n false expression"), // ------------------------------------------------------------------ @@ -10039,14 +10703,16 @@ var dynamic_scope = options.dynamic_scope, error = options.error; typecheck('let-env', code, 'pair'); - var ret = evaluate(code.car, { + + var ret = _evaluate(code.car, { env: this, dynamic_scope: dynamic_scope, error: error }); + return unpromise(ret, function (value) { typecheck('let-env', value, 'environment'); - return evaluate(Pair(LSymbol('begin'), code.cdr), { + return _evaluate(Pair(LSymbol('begin'), code.cdr), { env: value, dynamic_scope: dynamic_scope, error: error @@ -10056,6 +10722,8 @@ // ------------------------------------------------------------------ 'letrec': doc(let_macro(Symbol["for"]('letrec')), "(letrec ((a value-a) (b value-b)) body)\n\n Macro that creates new environment, then evaluate and assign values to\n names and then evaluate the body in context of that environment.\n Values are evaluated sequentialy and next value can access to\n previous values/names."), // --------------------------------------------------------------------- + 'letrec*': doc(let_macro(Symbol["for"]('letrec')), "(letrec* ((a value-a) (b value-b)) body)\n\n Same as letrec but the order of execution of the binding is guaranteed,\n so use can use recursive code as well as reference previous binding.\n In LIPS both letrec and letrec* behave the same."), + // --------------------------------------------------------------------- 'let*': doc(let_macro(Symbol["for"]('let*')), "(let* ((a value-a) (b value-b)) body)\n\n Macro similar to `let` but next argument get environment\n from previous let variable, so they you can define one variable,\n and use in next argument."), // --------------------------------------------------------------------- 'let': doc(let_macro(Symbol["for"]('let')), "(let ((a value-a) (b value-b)) body)\n\n Macro that creates new environment, then evaluate and assign values to\n names and then evaluate the body in context of that environment.\n Values are evaluated sequentialy but you can't access\n previous values/names when next are evaluated. You can only get them\n from body of let expression."), @@ -10077,7 +10745,9 @@ return function loop() { if (arr.length) { var code = arr.shift(); - var ret = evaluate(code, args); + + var ret = _evaluate(code, args); + return unpromise(ret, function (value) { result = value; return loop(); @@ -10088,9 +10758,9 @@ }(); }), "(begin . args)\n\n Macro runs list of expression and return valuate of the list one.\n It can be used in place where you can only have single exression,\n like if expression."), // ------------------------------------------------------------------ - 'ignore': new Macro('ignore', function (code, _ref27) { - var dynamic_scope = _ref27.dynamic_scope, - error = _ref27.error; + 'ignore': new Macro('ignore', function (code, _ref33) { + var dynamic_scope = _ref33.dynamic_scope, + error = _ref33.error; var args = { env: this, error: error @@ -10100,7 +10770,7 @@ args.dynamic_scope = this; } - evaluate(new Pair(new LSymbol('begin'), code), args); + _evaluate(new Pair(new LSymbol('begin'), code), args); }, "(ignore expression)\n\n Macro that will evaluate expression and swallow any promises that may\n be created. It wil run and ignore any value that may be returned by\n expression. The code should have side effects and/or when it's promise\n it should resolve to undefined."), // ------------------------------------------------------------------ define: doc(Macro.defmacro('define', function (code, eval_args) { @@ -10123,7 +10793,7 @@ var new_expr; if (value instanceof Pair) { - value = evaluate(value, eval_args); + value = _evaluate(value, eval_args); new_expr = true; } else if (value instanceof LSymbol) { value = env.get(value); @@ -10149,7 +10819,7 @@ __doc__ = code.cdr.cdr.car.valueOf(); } - env.set(code.car, value, __doc__); + env.set(code.car, value, __doc__, true); }); }), "(define name expression)\n (define (function-name . args) body)\n\n Macro for defining values. It can be used to define variables,\n or function. If first argument is list it will create function\n with name beeing first element of the list. The macro evalute\n code `(define function (lambda args body))`"), // ------------------------------------------------------------------ @@ -10181,8 +10851,8 @@ }, "(null-environment)\n\n Function return new base environment with std lib."), // ------------------------------------------------------------------ 'values': doc(function values() { - for (var _len20 = arguments.length, args = new Array(_len20), _key20 = 0; _key20 < _len20; _key20++) { - args[_key20] = arguments[_key20]; + for (var _len21 = arguments.length, args = new Array(_len21), _key21 = 0; _key21 < _len21; _key21++) { + args[_key21] = arguments[_key21]; } return Values(args); @@ -10213,30 +10883,30 @@ }, "(parent.frame)\n\n Return parent environment if called from inside function.\n If no parent frame found it return nil."), // ------------------------------------------------------------------ 'eval': doc('eval', function (code, env) { - var _this14 = this; + var _this18 = this; env = env || this; - return evaluate(code, { + return _evaluate(code, { env: env, //dynamic_scope: this, error: function error(e) { var error = global_env.get('error'); - error.call(_this14, e.message); + error.call(_this18, e.message); if (e.code) { var stack = e.code.map(function (line, i) { return "[".concat(i + 1, "]: ").concat(line); }).join('\n'); - error.call(_this14, stack); + error.call(_this18, stack); } } }); }, "(eval expr)\n (eval expr environment)\n\n Function evalute LIPS Scheme code."), // ------------------------------------------------------------------ lambda: new Macro('lambda', function (code) { - var _ref28 = arguments.length > 1 && arguments[1] !== undefined$1 ? arguments[1] : {}, - dynamic_scope = _ref28.dynamic_scope, - error = _ref28.error; + var _ref34 = arguments.length > 1 && arguments[1] !== undefined$1 ? arguments[1] : {}, + dynamic_scope = _ref34.dynamic_scope, + error = _ref34.error; var self = this; @@ -10281,8 +10951,8 @@ } // arguments and arguments.callee inside lambda function - for (var _len21 = arguments.length, args = new Array(_len21), _key21 = 0; _key21 < _len21; _key21++) { - args[_key21] = arguments[_key21]; + for (var _len22 = arguments.length, args = new Array(_len22), _key22 = 0; _key22 < _len22; _key22++) { + args[_key22] = arguments[_key22]; } if (this instanceof Environment) { @@ -10329,7 +10999,7 @@ var rest = __doc__ ? code.cdr.cdr : code.cdr; var output = new Pair(new LSymbol('begin'), rest); - return evaluate(output, { + return _evaluate(output, { env: env, dynamic_scope: dynamic_scope, error: error @@ -10350,9 +11020,9 @@ 'macroexpand': new Macro('macroexpand', macro_expand()), 'macroexpand-1': new Macro('macroexpand-1', macro_expand(true)), // ------------------------------------------------------------------ - 'define-macro': doc(new Macro(macro, function (macro, _ref29) { - var dynamic_scope = _ref29.dynamic_scope, - error = _ref29.error; + 'define-macro': doc(new Macro(macro, function (macro, _ref35) { + var dynamic_scope = _ref35.dynamic_scope, + error = _ref35.error; if (macro.car instanceof Pair && macro.car.car instanceof LSymbol) { var name = macro.car.car.__name__; @@ -10413,7 +11083,7 @@ // this eval will return lips code var rest = __doc__ ? macro.cdr.cdr : macro.cdr; var result = rest.reduce(function (result, node) { - return evaluate(node, eval_args); + return _evaluate(node, eval_args); }); return unpromise(result, function (result) { if (_typeof_1(result) === 'object') { @@ -10464,8 +11134,8 @@ validate_identifiers(macro.car); } - var syntax = new Syntax(function (code, _ref30) { - var macro_expand = _ref30.macro_expand; + var syntax = new Syntax(function (code, _ref36) { + var macro_expand = _ref36.macro_expand; var scope = env.inherit('syntax'); if (dynamic_scope) { @@ -10544,13 +11214,14 @@ }; } - var result = evaluate(expr, _objectSpread(_objectSpread({}, eval_args), {}, { + var result = _evaluate(expr, _objectSpread(_objectSpread({}, eval_args), {}, { env: new_env })); // Hack: update the result if there are generated // gensyms that should be literal symbols // TODO: maybe not the part move when literal elisps may // be generated, maybe they will need to be mark somehow + return clear_gensyms(result, names); } @@ -10604,10 +11275,10 @@ } if (is_promise(car) || is_promise(cdr)) { - return Promise.all([car, cdr]).then(function (_ref31) { - var _ref32 = slicedToArray(_ref31, 2), - car = _ref32[0], - cdr = _ref32[1]; + return Promise.all([car, cdr]).then(function (_ref37) { + var _ref38 = slicedToArray(_ref37, 2), + car = _ref38[0], + cdr = _ref38[1]; return new Pair(car, cdr); }); @@ -10636,7 +11307,7 @@ function unquoted_arr(arr) { return !!arr.filter(function (value) { - return value instanceof Pair && LSymbol.is(value.car, 'unquote'); + return value instanceof Pair && LSymbol.is(value.car, /^(unquote|unquote-splicing)$/); }).length; } // ----------------------------------------------------------------- @@ -10654,7 +11325,7 @@ if (unquote_cnt + 1 < max_unq) { result = recur(x.cdr, unquote_cnt + 1, max_unq); } else { - result = evaluate(x.cdr.car, { + result = _evaluate(x.cdr.car, { env: self, dynamic_scope: dynamic_scope, error: error @@ -10665,7 +11336,7 @@ throw new Error("Expecting list ".concat(type(x), " found")); } - return acc.concat(result.toArray()); + return acc.concat(result.to_array()); } acc.push(recur(x, unquote_cnt, max_unq)); @@ -10690,7 +11361,7 @@ if (unquote_cnt < max_unq) { output = recur(value.cdr.car, unquote_cnt, max_unq); } else { - output = evaluate(value.cdr.car, { + output = _evaluate(value.cdr.car, { env: self, dynamic_scope: dynamic_scope, error: error @@ -10718,11 +11389,12 @@ var lists = []; return function next(node) { - var value = evaluate(node.car, { + var value = _evaluate(node.car, { env: self, dynamic_scope: dynamic_scope, error: error }); + lists.push(value); if (node.cdr instanceof Pair) { @@ -10813,7 +11485,7 @@ return Pair.fromArray(result); } - return unpromise(evaluate(node.car, { + return unpromise(_evaluate(node.car, { env: self, dynamic_scope: dynamic_scope, error: error @@ -10860,7 +11532,7 @@ return Pair.fromArray(_result3); } - return unpromise(evaluate(node.car, { + return unpromise(_evaluate(node.car, { env: self, dynamic_scope: dynamic_scope, error: error @@ -10874,7 +11546,7 @@ return pair.cdr; } } else { - return evaluate(pair.cdr.car, { + return _evaluate(pair.cdr.car, { env: self, dynamic_scope: dynamic_scope, error: error @@ -10941,8 +11613,8 @@ append: doc(function append() { var _global_env$get; - for (var _len22 = arguments.length, items = new Array(_len22), _key22 = 0; _key22 < _len22; _key22++) { - items[_key22] = arguments[_key22]; + for (var _len23 = arguments.length, items = new Array(_len23), _key23 = 0; _key23 < _len23; _key23++) { + items[_key23] = arguments[_key23]; } items = items.map(function (item) { @@ -10958,8 +11630,8 @@ 'append!': doc('append!', function () { var is_list = global_env.get('list?'); - for (var _len23 = arguments.length, items = new Array(_len23), _key23 = 0; _key23 < _len23; _key23++) { - items[_key23] = arguments[_key23]; + for (var _len24 = arguments.length, items = new Array(_len24), _key24 = 0; _key24 < _len24; _key24++) { + items[_key24] = arguments[_key24]; } return items.reduce(function (acc, item) { @@ -11028,8 +11700,8 @@ }, "(nth index obj)\n\n Function return nth element of the list or array. If used with different\n value it will throw exception"), // ------------------------------------------------------------------ list: doc(function list() { - for (var _len24 = arguments.length, args = new Array(_len24), _key24 = 0; _key24 < _len24; _key24++) { - args[_key24] = arguments[_key24]; + for (var _len25 = arguments.length, args = new Array(_len25), _key25 = 0; _key25 < _len25; _key25++) { + args[_key25] = arguments[_key25]; } return args.reverse().reduce(function (list, item) { @@ -11045,8 +11717,8 @@ }, "(substring string start end)\n\n Function return part of the string starting at start ending with end."), // ------------------------------------------------------------------ concat: doc(function concat() { - for (var _len25 = arguments.length, args = new Array(_len25), _key25 = 0; _key25 < _len25; _key25++) { - args[_key25] = arguments[_key25]; + for (var _len26 = arguments.length, args = new Array(_len26), _key26 = 0; _key26 < _len26; _key26++) { + args[_key26] = arguments[_key26]; } args.forEach(function (arg, i) { @@ -11091,9 +11763,14 @@ return toString(obj, quote); }, "(repr obj)\n\n Function return string LIPS representation of an object as string."), // ------------------------------------------------------------------ + 'escape-regex': doc('escape-regex', function (string) { + typecheck('escape-regex', string, 'string'); + return escape_regex(string.valueOf()); + }, "(escape-regex string)\n\n Function return new string where all special operators used in regex,\n are escaped with slash so they can be used in RegExp constructor\n to match literal string"), + // ------------------------------------------------------------------ env: doc(function env(env) { env = env || this; - var names = Object.keys(env.__env__); // TODO: get symbols + var names = Object.keys(env.__env__).map(LSymbol); // TODO: get symbols var result; @@ -11103,16 +11780,16 @@ result = nil; } - if (env.__parent__ !== undefined$1) { + if (env.__parent__ instanceof Environment) { return global_env.get('env')(env.__parent__).append(result); } return result; - }, "(env obj)\n\n Function return list values (functions and variables) inside environment."), + }, "(env)\n (env obj)\n\n Function return list of values (functions, macros and variables)\n inside environment and it's parents."), // ------------------------------------------------------------------ 'new': doc('new', function (obj) { - for (var _len26 = arguments.length, args = new Array(_len26 > 1 ? _len26 - 1 : 0), _key26 = 1; _key26 < _len26; _key26++) { - args[_key26 - 1] = arguments[_key26]; + for (var _len27 = arguments.length, args = new Array(_len27 > 1 ? _len27 - 1 : 0), _key27 = 1; _key27 < _len27; _key27++) { + args[_key27 - 1] = arguments[_key27]; } var instance = construct(unbind(obj), toConsumableArray(args.map(function (x) { @@ -11150,11 +11827,11 @@ }, "(debugger)\n\n Function stop JavaScript code in debugger."), // ------------------------------------------------------------------ 'in': doc('in', function (a, b) { - if (a instanceof LSymbol || a instanceof LString) { + if (a instanceof LSymbol || a instanceof LString || a instanceof LNumber) { a = a.valueOf(); } - return a in b; + return a in unbox(b); }, "(in key value)\n\n Function use is in operator to check if value is in object."), // ------------------------------------------------------------------ 'instanceof': doc('instanceof', function (type, obj) { @@ -11181,7 +11858,9 @@ return LNumber.isFloat(value); }, "(real? number)\n\n Function check if value is real number."), // ------------------------------------------------------------------ - 'number?': doc('number?', LNumber.isNumber, "(number? expression)\n\n Function check if value is a number"), + 'number?': doc('number?', function (x) { + return Number.isNaN(x) || LNumber.isNumber(x); + }, "(number? expression)\n\n Function check if value is a number or NaN value."), // ------------------------------------------------------------------ 'string?': doc('string?', function (obj) { return LString.isString(obj); @@ -11225,13 +11904,13 @@ return Pair.fromArray(array); }, "(array->list array)\n\n Function convert JavaScript array to LIPS list."), // ------------------------------------------------------------------ - 'tree->array': doc('tree->array', toArray$1('tree->array', true), "(tree->array list)\n\n Function convert LIPS list structure into JavaScript array."), + 'tree->array': doc('tree->array', to_array('tree->array', true), "(tree->array list)\n\n Function convert LIPS list structure into JavaScript array."), // ------------------------------------------------------------------ - 'list->array': doc('list->array', toArray$1('list->array'), "(list->array list)\n\n Function convert LIPS list into JavaScript array."), + 'list->array': doc('list->array', to_array('list->array'), "(list->array list)\n\n Function convert LIPS list into JavaScript array."), // ------------------------------------------------------------------ apply: doc(function apply(fn) { - for (var _len27 = arguments.length, args = new Array(_len27 > 1 ? _len27 - 1 : 0), _key27 = 1; _key27 < _len27; _key27++) { - args[_key27 - 1] = arguments[_key27]; + for (var _len28 = arguments.length, args = new Array(_len28 > 1 ? _len28 - 1 : 0), _key28 = 1; _key28 < _len28; _key28++) { + args[_key28 - 1] = arguments[_key28]; } typecheck('apply', fn, 'function', 1); @@ -11281,11 +11960,11 @@ return false; }, "(string->number number [radix])\n\n Function convert string to number."), // ------------------------------------------------------------------ - 'try': doc(new Macro('try', function (code, _ref33) { - var _this15 = this; + 'try': doc(new Macro('try', function (code, _ref39) { + var _this19 = this; - var dynamic_scope = _ref33.dynamic_scope, - _error = _ref33.error; + var dynamic_scope = _ref39.dynamic_scope, + _error = _ref39.error; return new Promise(function (resolve, reject) { var catch_clause, finally_clause; @@ -11309,16 +11988,16 @@ _next = function next(result, cont) { // prevent infinite loop when finally throw exception _next = reject; - unpromise(evaluate(new Pair(new LSymbol('begin'), finally_clause.cdr), args), function () { + unpromise(_evaluate(new Pair(new LSymbol('begin'), finally_clause.cdr), args), function () { cont(result); }); }; } var args = { - env: _this15, + env: _this19, error: function error(e) { - var env = _this15.inherit('try'); + var env = _this19.inherit('try'); if (catch_clause) { env.set(catch_clause.cdr.car.car, e); @@ -11328,10 +12007,10 @@ }; if (dynamic_scope) { - args.dynamic_scope = _this15; + args.dynamic_scope = _this19; } - unpromise(evaluate(new Pair(new LSymbol('begin'), catch_clause.cdr.cdr), args), function (result) { + unpromise(_evaluate(new Pair(new LSymbol('begin'), catch_clause.cdr.cdr), args), function (result) { _next(result, resolve); }); } else { @@ -11341,10 +12020,10 @@ }; if (dynamic_scope) { - args.dynamic_scope = _this15; + args.dynamic_scope = _this19; } - var result = evaluate(code.car, args); + var result = _evaluate(code.car, args); if (is_promise(result)) { result.then(function (result) { @@ -11383,8 +12062,8 @@ typecheck('for-each', fn, 'function'); - for (var _len28 = arguments.length, lists = new Array(_len28 > 1 ? _len28 - 1 : 0), _key28 = 1; _key28 < _len28; _key28++) { - lists[_key28 - 1] = arguments[_key28]; + for (var _len29 = arguments.length, lists = new Array(_len29 > 1 ? _len29 - 1 : 0), _key29 = 1; _key29 < _len29; _key29++) { + lists[_key29 - 1] = arguments[_key29]; } lists.forEach(function (arg, i) { @@ -11401,10 +12080,10 @@ }, "(for-each fn . lists)\n\n Higher order function that call function `fn` by for each\n value of the argument. If you provide more then one list as argument\n it will take each value from each list and call `fn` function\n with that many argument as number of list arguments."), // ------------------------------------------------------------------ map: doc(function map(fn) { - var _this16 = this; + var _this20 = this; - for (var _len29 = arguments.length, lists = new Array(_len29 > 1 ? _len29 - 1 : 0), _key29 = 1; _key29 < _len29; _key29++) { - lists[_key29 - 1] = arguments[_key29]; + for (var _len30 = arguments.length, lists = new Array(_len30 > 1 ? _len30 - 1 : 0), _key30 = 1; _key30 < _len30; _key30++) { + lists[_key30 - 1] = arguments[_key30]; } typecheck('map', fn, 'function'); @@ -11412,7 +12091,7 @@ lists.forEach(function (arg, i) { typecheck('map', arg, ['pair', 'nil'], i + 1); // detect cycles - if (arg instanceof Pair && !is_list.call(_this16, arg)) { + if (arg instanceof Pair && !is_list.call(_this20, arg)) { throw new Error("map: argument ".concat(i + 1, " is not a list")); } }); @@ -11434,7 +12113,7 @@ var env = this.newFrame(fn, args); env.set('parent.frame', parent_frame); return unpromise(fn.call.apply(fn, [env].concat(toConsumableArray(args))), function (head) { - return unpromise(map.call.apply(map, [_this16, fn].concat(toConsumableArray(lists.map(function (l) { + return unpromise(map.call.apply(map, [_this20, fn].concat(toConsumableArray(lists.map(function (l) { return l.cdr; })))), function (rest) { return new Pair(head, rest); @@ -11476,8 +12155,8 @@ }, "(some fn list)\n\n Higher order function that call argument on each element of the list.\n It stops when function fn return true for a value if so it will\n return true. If none of the values give true, the function return false"), // ------------------------------------------------------------------ fold: doc('fold', fold('fold', function (fold, fn, init) { - for (var _len30 = arguments.length, lists = new Array(_len30 > 3 ? _len30 - 3 : 0), _key30 = 3; _key30 < _len30; _key30++) { - lists[_key30 - 3] = arguments[_key30]; + for (var _len31 = arguments.length, lists = new Array(_len31 > 3 ? _len31 - 3 : 0), _key31 = 3; _key31 < _len31; _key31++) { + lists[_key31 - 3] = arguments[_key31]; } typecheck('fold', fn, 'function'); @@ -11502,8 +12181,8 @@ }), "(fold fn init . lists)\n\n Function fold is reverse of the reduce. it call function `fn`\n on each elements of the list and return single value.\n e.g. it call (fn a1 b1 (fn a2 b2 (fn a3 b3 '())))\n for: (fold fn '() alist blist)"), // ------------------------------------------------------------------ pluck: doc(function pluck() { - for (var _len31 = arguments.length, keys = new Array(_len31), _key31 = 0; _key31 < _len31; _key31++) { - keys[_key31] = arguments[_key31]; + for (var _len32 = arguments.length, keys = new Array(_len32), _key32 = 0; _key32 < _len32; _key32++) { + keys[_key32] = arguments[_key32]; } return function (obj) { @@ -11516,9 +12195,9 @@ } else if (keys.length === 1) { var _keys3 = keys, _keys4 = slicedToArray(_keys3, 1), - _key32 = _keys4[0]; + _key33 = _keys4[0]; - return obj[_key32]; + return obj[_key33]; } var result = {}; @@ -11530,10 +12209,10 @@ }, "(pluck . string)\n\n If called with single string it will return function that will return\n key from object. If called with more then one argument function will\n return new object by taking all properties from given object."), // ------------------------------------------------------------------ reduce: doc('reduce', fold('reduce', function (reduce, fn, init) { - var _this17 = this; + var _this21 = this; - for (var _len32 = arguments.length, lists = new Array(_len32 > 3 ? _len32 - 3 : 0), _key33 = 3; _key33 < _len32; _key33++) { - lists[_key33 - 3] = arguments[_key33]; + for (var _len33 = arguments.length, lists = new Array(_len33 > 3 ? _len33 - 3 : 0), _key34 = 3; _key34 < _len33; _key34++) { + lists[_key34 - 3] = arguments[_key34]; } typecheck('reduce', fn, 'function'); @@ -11550,7 +12229,7 @@ return unpromise(fn.apply(void 0, toConsumableArray(lists.map(function (l) { return l.car; })).concat([init])), function (value) { - return reduce.call.apply(reduce, [_this17, fn, value].concat(toConsumableArray(lists.map(function (l) { + return reduce.call.apply(reduce, [_this21, fn, value].concat(toConsumableArray(lists.map(function (l) { return l.cdr; })))); }); @@ -11583,30 +12262,39 @@ compose: doc(compose, "(compose . fns)\n\n Higher order function and create new function that apply all functions\n From right to left and return it's value. Reverse of compose.\n e.g.:\n ((compose (curry + 2) (curry * 3)) 3)\n 11\n "), pipe: doc(pipe, "(pipe . fns)\n\n Higher order function and create new function that apply all functions\n From left to right and return it's value. Reverse of compose.\n e.g.:\n ((pipe (curry + 2) (curry * 3)) 3)\n 15"), curry: doc(curry, "(curry fn . args)\n\n Higher order function that create curried version of the function.\n The result function will have parially applied arguments and it\n will keep returning functions until all arguments are added\n\n e.g.:\n (define (add a b c d) (+ a b c d))\n (define add1 (curry add 1))\n (define add12 (add 2))\n (display (add12 3 4))"), + // ------------------------------------------------------------------ + // Numbers + // ------------------------------------------------------------------ 'gcd': doc(function gcd() { - for (var _len33 = arguments.length, args = new Array(_len33), _key34 = 0; _key34 < _len33; _key34++) { - args[_key34] = arguments[_key34]; + for (var _len34 = arguments.length, args = new Array(_len34), _key35 = 0; _key35 < _len34; _key35++) { + args[_key35] = arguments[_key35]; } + typecheck_args('lcm', args, 'number'); return args.reduce(function (result, item) { return result.gcd(item); }); }, "(gcd n1 n2 ...)\n\n Function return the greatest common divisor of their arguments."), // ------------------------------------------------------------------ 'lcm': doc(function lcm() { - // ref: https://rosettacode.org/wiki/Least_common_multiple#JavaScript - var n = arguments.length, - a = abs(arguments.length <= 0 ? undefined$1 : arguments[0]); + for (var _len35 = arguments.length, args = new Array(_len35), _key36 = 0; _key36 < _len35; _key36++) { + args[_key36] = arguments[_key36]; + } + + typecheck_args('lcm', args, 'number'); // ref: https://rosettacode.org/wiki/Least_common_multiple#JavaScript + + var n = args.length, + a = abs(args[0]); for (var i = 1; i < n; i++) { - var b = abs(i < 0 || arguments.length <= i ? undefined$1 : arguments[i]), + var b = abs(args[i]), c = a; while (a && b) { a > b ? a %= b : b %= a; } - a = abs(c * (i < 0 || arguments.length <= i ? undefined$1 : arguments[i])) / (a + b); + a = abs(c * args[i]) / (a + b); } return LNumber(a); @@ -11630,14 +12318,16 @@ }, LNumber(0)), "(+ . numbers)\n\n Sum all numbers passed as arguments. If single value is passed it will\n return that value."), // ------------------------------------------------------------------ '-': doc('-', function () { - for (var _len34 = arguments.length, args = new Array(_len34), _key35 = 0; _key35 < _len34; _key35++) { - args[_key35] = arguments[_key35]; + for (var _len36 = arguments.length, args = new Array(_len36), _key37 = 0; _key37 < _len36; _key37++) { + args[_key37] = arguments[_key37]; } if (args.length === 0) { throw new Error('-: procedure require at least one argument'); } + typecheck_args('-', args, 'number'); + if (args.length === 1) { return LNumber(args[0]).sub(); } @@ -11647,17 +12337,35 @@ return LNumber(a).sub(b); })); } - }, "(- n1 n2 ...)\n (- n1)\n\n Substract number passed as argument. If only one argument is passed\n it will negate the value."), + }, "(- n1 n2 ...)\n (- n)\n\n Substract number passed as argument. If only one argument is passed\n it will negate the value."), // ------------------------------------------------------------------ - '/': doc('/', reduceMathOp(function (a, b) { - return LNumber(a).div(b); - }), "(/ . numbers)\n\n Divide number passed as arguments one by one. If single argument\n is passed it will return that value."), + '/': doc('/', function () { + for (var _len37 = arguments.length, args = new Array(_len37), _key38 = 0; _key38 < _len37; _key38++) { + args[_key38] = arguments[_key38]; + } + + if (args.length === 0) { + throw new Error('/: procedure require at least one argument'); + } + + typecheck_args('/', args, 'number'); + + if (args.length === 1) { + return LNumber(1).div(args[0]); + } + + return args.reduce(binaryMathOp(function (a, b) { + return LNumber(a).div(b); + })); + }, "(/ n1 n2 ...)\n (/ n)\n\n Divide number passed as arguments one by one. If single argument\n is passed it will calculate (/ 1 n1)."), // ------------------------------------------------------------------ abs: doc('abs', singleMathOp(function (n) { return LNumber(n).abs(); }), "(abs number)\n\n Function create absolute value from number."), // ------------------------------------------------------------------ truncate: doc('truncate', function (n) { + typecheck('truncate', n, 'number'); + if (LNumber.isFloat(n)) { if (n instanceof LNumber) { n = n.valueOf(); @@ -11693,65 +12401,71 @@ }), "(1- number)\n\n Function substract 1 from the number and return result."), // ------------------------------------------------------------------ '%': doc('%', function (a, b) { + typecheck_args('%', [a, b], 'number'); return LNumber(a).rem(b); }, "(% n1 n2)\n\n Function get reminder of it's arguments."), // ------------------------------------------------------------------ // Booleans '==': doc('==', function () { - for (var _len35 = arguments.length, args = new Array(_len35), _key36 = 0; _key36 < _len35; _key36++) { - args[_key36] = arguments[_key36]; + for (var _len38 = arguments.length, args = new Array(_len38), _key39 = 0; _key39 < _len38; _key39++) { + args[_key39] = arguments[_key39]; } + typecheck_args('==', args, 'number'); return seq_compare(function (a, b) { return LNumber(a).cmp(b) === 0; }, args); - }, "(== x1 x2 x3 ...)\n\n Function compare its numerical arguments and check if they are equal"), + }, "(== x1 x2 ...)\n\n Function compare its numerical arguments and check if they are equal"), // ------------------------------------------------------------------ '>': doc('>', function () { - for (var _len36 = arguments.length, args = new Array(_len36), _key37 = 0; _key37 < _len36; _key37++) { - args[_key37] = arguments[_key37]; + for (var _len39 = arguments.length, args = new Array(_len39), _key40 = 0; _key40 < _len39; _key40++) { + args[_key40] = arguments[_key40]; } + typecheck_args('>', args, 'number'); return seq_compare(function (a, b) { return LNumber(a).cmp(b) === 1; }, args); - }, "(> x1 x2 x3 ...)\n\n Function compare its numerical arguments and check if they are\n monotonically increasing"), + }, "(> x1 x2 ...)\n\n Function compare its numerical arguments and check if they are\n monotonically increasing"), // ------------------------------------------------------------------ '<': doc('<', function () { - for (var _len37 = arguments.length, args = new Array(_len37), _key38 = 0; _key38 < _len37; _key38++) { - args[_key38] = arguments[_key38]; + for (var _len40 = arguments.length, args = new Array(_len40), _key41 = 0; _key41 < _len40; _key41++) { + args[_key41] = arguments[_key41]; } + typecheck_args('<', args, 'number'); return seq_compare(function (a, b) { return LNumber(a).cmp(b) === -1; }, args); - }, "(< x1 x2 x3 ...)\n\n Function compare its numerical arguments and check if they are\n monotonically decreasing"), + }, "(< x1 x2 ...)\n\n Function compare its numerical arguments and check if they are\n monotonically decreasing"), // ------------------------------------------------------------------ '<=': doc(function () { - for (var _len38 = arguments.length, args = new Array(_len38), _key39 = 0; _key39 < _len38; _key39++) { - args[_key39] = arguments[_key39]; + for (var _len41 = arguments.length, args = new Array(_len41), _key42 = 0; _key42 < _len41; _key42++) { + args[_key42] = arguments[_key42]; } + typecheck_args('<=', args, 'number'); return seq_compare(function (a, b) { return [0, -1].includes(LNumber(a).cmp(b)); }, args); - }, "(<= x1 x2 x3 ...)\n\n Function compare its numerical arguments and check if they are\n monotonically nonincreasing"), + }, "(<= x1 x2 ...)\n\n Function compare its numerical arguments and check if they are\n monotonically nonincreasing"), // ------------------------------------------------------------------ '>=': doc('>=', function () { - for (var _len39 = arguments.length, args = new Array(_len39), _key40 = 0; _key40 < _len39; _key40++) { - args[_key40] = arguments[_key40]; + for (var _len42 = arguments.length, args = new Array(_len42), _key43 = 0; _key43 < _len42; _key43++) { + args[_key43] = arguments[_key43]; } + typecheck_args('>=', args, 'number'); return seq_compare(function (a, b) { return [0, 1].includes(LNumber(a).cmp(b)); }, args); - }, "(>= x1 x2 x3 ...)\n\n Function compare its numerical arguments and check if they are\n monotonically nondecreasing"), + }, "(>= x1 x2 ...)\n\n Function compare its numerical arguments and check if they are\n monotonically nondecreasing"), // ------------------------------------------------------------------ 'eq?': doc('eq?', equal, "(eq? a b)\n\n Function compare two values if they are identical."), // ------------------------------------------------------------------ - or: doc(new Macro('or', function (code, _ref34) { - var dynamic_scope = _ref34.dynamic_scope, - error = _ref34.error; + or: doc(new Macro('or', function (code, _ref40) { + var dynamic_scope = _ref40.dynamic_scope, + error = _ref40.error; var args = global_env.get('list->array')(code); var self = this; @@ -11783,20 +12497,22 @@ } } else { var arg = args.shift(); - var value = evaluate(arg, { + + var value = _evaluate(arg, { env: self, dynamic_scope: dynamic_scope, error: error }); + return unpromise(value, next); } }(); }), "(or . expressions)\n\n Macro execute the values one by one and return the one that is truthy value.\n If there are no expression that evaluate to true it return false."), // ------------------------------------------------------------------ and: doc(new Macro('and', function (code) { - var _ref35 = arguments.length > 1 && arguments[1] !== undefined$1 ? arguments[1] : {}, - dynamic_scope = _ref35.dynamic_scope, - error = _ref35.error; + var _ref41 = arguments.length > 1 && arguments[1] !== undefined$1 ? arguments[1] : {}, + dynamic_scope = _ref41.dynamic_scope, + error = _ref41.error; var args = global_env.get('list->array')(code); var self = this; @@ -11830,11 +12546,12 @@ return false; } } else { - var value = evaluate(arg, { + var value = _evaluate(arg, { env: self, dynamic_scope: dynamic_scope, error: error }); + return unpromise(value, next); } }(); @@ -11863,9 +12580,17 @@ return !value; }, "(not object)\n\n Function return negation of the argument.") }, undefined$1, 'global'); - var user_env = global_env.inherit('user-env'); - global_env.set('**interaction-environment**', user_env); - global_env.constant('**internal-env**', internal_env); // ------------------------------------------------------------------------- + var user_env = global_env.inherit('user-env'); // ------------------------------------------------------------------------- + + function set_interaction_env(interaction, internal) { + interaction.constant('**internal-env**', internal); + interaction.doc('**internal-env**', "**internal-env**\n\n Constant used to hide stdin, stdout and stderr so they don't interfere\n with variables with the same name. Constants are internal type\n of variables that can't be redefined, defining variable with same name\n will throw an error."); + global_env.set('**interaction-environment**', interaction); + } // ------------------------------------------------------------------------- + + + set_interaction_env(user_env, internal_env); + global_env.doc('**interaction-environment**', "**interaction-environment**\n\n Internal dynamic, global variable used to find interpreter environment.\n It's used so the read and write functions can locate **internal-env**\n that contain references to stdin, stdout and stderr."); // ------------------------------------------------------------------------- (function () { var map = { @@ -12042,6 +12767,22 @@ } // ------------------------------------------------------------------------- + function typecheck_args(fn, args, expected) { + args.forEach(function (arg, i) { + typecheck(fn, arg, expected, i + 1); + }); + } // ------------------------------------------------------------------------- + + + function typecheck_text_port(fn, arg, type) { + typecheck(fn, arg, type); + + if (arg.__type__ === binary_port) { + throw new Error(typeErrorMessage(fn, 'binary-port', 'textual-port')); + } + } // ------------------------------------------------------------------------- + + function typecheck(fn, arg, expected) { var position = arguments.length > 3 && arguments[3] !== undefined$1 ? arguments[3] : null; fn = fn.valueOf(); @@ -12049,7 +12790,7 @@ var match = false; if (expected instanceof Pair) { - expected = expected.toArray(); + expected = expected.to_array(); } if (expected instanceof Array) { @@ -12122,7 +12863,7 @@ }; if (Number.isNaN(obj)) { - return 'NaN '; + return 'NaN'; } if (obj === nil) { @@ -12133,13 +12874,13 @@ return 'null'; } - for (var _i5 = 0, _Object$entries2 = Object.entries(mapping); _i5 < _Object$entries2.length; _i5++) { - var _Object$entries2$_i = slicedToArray(_Object$entries2[_i5], 2), - _key41 = _Object$entries2$_i[0], + for (var _i4 = 0, _Object$entries2 = Object.entries(mapping); _i4 < _Object$entries2.length; _i4++) { + var _Object$entries2$_i = slicedToArray(_Object$entries2[_i4], 2), + _key44 = _Object$entries2$_i[0], value = _Object$entries2$_i[1]; if (obj instanceof value) { - return _key41; + return _key44; } } @@ -12148,6 +12889,10 @@ obj.__instance__ = false; if (obj.__instance__) { + if (is_function(obj.toType)) { + return obj.toType(); + } + return 'instance'; } } @@ -12171,10 +12916,6 @@ } } - if (is_function(obj) && obj[Symbol["for"]('promise')]) { - return 'promise'; - } - return _typeof_1(obj); } // ------------------------------------------------------------------------- // :; wrap tree of Promises with single Promise or return argument as is @@ -12208,7 +12949,7 @@ } } - function promise(_x12) { + function promise(_x11) { return _promise.apply(this, arguments); } @@ -12290,10 +13031,10 @@ } // ------------------------------------------------------------------------- - function evaluate_args(rest, _ref36) { - var env = _ref36.env, - dynamic_scope = _ref36.dynamic_scope, - error = _ref36.error; + function evaluate_args(rest, _ref42) { + var env = _ref42.env, + dynamic_scope = _ref42.dynamic_scope, + error = _ref42.error; var args = []; var node = rest; markCycles(node); @@ -12304,7 +13045,7 @@ return function loop() { if (node instanceof Pair) { - var arg = evaluate(node.car, { + var arg = _evaluate(node.car, { env: env, dynamic_scope: dynamic_scope, error: error @@ -12366,7 +13107,7 @@ if (value && value[__data__] || !value || self_evaluated(value)) { return value; } else { - return unpromise(evaluate(value, eval_args), finalize); + return unpromise(_evaluate(value, eval_args), finalize); } }); } // ------------------------------------------------------------------------- @@ -12388,8 +13129,8 @@ args = args.map(function (arg) { if (is_lips_function(arg)) { var wrapper = function wrapper() { - for (var _len40 = arguments.length, args = new Array(_len40), _key42 = 0; _key42 < _len40; _key42++) { - args[_key42] = arguments[_key42]; + for (var _len43 = arguments.length, args = new Array(_len43), _key45 = 0; _key45 < _len43; _key45++) { + args[_key45] = arguments[_key45]; } return unpromise(arg.apply(this, args), unbox); @@ -12412,11 +13153,11 @@ function apply(fn, args) { - var _ref37 = arguments.length > 2 && arguments[2] !== undefined$1 ? arguments[2] : {}, - env = _ref37.env, - dynamic_scope = _ref37.dynamic_scope, - _ref37$error = _ref37.error, - error = _ref37$error === void 0 ? function () {} : _ref37$error; + var _ref43 = arguments.length > 2 && arguments[2] !== undefined$1 ? arguments[2] : {}, + env = _ref43.env, + dynamic_scope = _ref43.dynamic_scope, + _ref43$error = _ref43.error, + error = _ref43$error === void 0 ? function () {} : _ref43$error; args = evaluate_args(args, { env: env, @@ -12460,12 +13201,12 @@ } // ------------------------------------------------------------------------- - function evaluate(code) { - var _ref38 = arguments.length > 1 && arguments[1] !== undefined$1 ? arguments[1] : {}, - env = _ref38.env, - dynamic_scope = _ref38.dynamic_scope, - _ref38$error = _ref38.error, - error = _ref38$error === void 0 ? function () {} : _ref38$error; + function _evaluate(code) { + var _ref44 = arguments.length > 1 && arguments[1] !== undefined$1 ? arguments[1] : {}, + env = _ref44.env, + dynamic_scope = _ref44.dynamic_scope, + _ref44$error = _ref44.error, + error = _ref44$error === void 0 ? function () {} : _ref44$error; try { if (dynamic_scope === true) { @@ -12499,11 +13240,11 @@ var rest = code.cdr; if (first instanceof Pair) { - value = resolve_promises(evaluate(first, eval_args)); + value = resolve_promises(_evaluate(first, eval_args)); if (is_promise(value)) { return value.then(function (value) { - return evaluate(new Pair(value, code.cdr), eval_args); + return _evaluate(new Pair(value, code.cdr), eval_args); }); // else is later in code } else if (!is_function(value)) { throw new Error(type(value) + ' ' + env.get('repr')(value) + ' is not a function while evaluating ' + code.toString()); @@ -12544,6 +13285,16 @@ }); if (__promise__ === true && is_promise(result)) { + // fix #139 evaluate the code inside the promise that is not data. + // When promise is not quoted it happen automatically, when returing + // promise from evaluate. + result = result.then(function (result) { + if (result instanceof Pair && !value[__data__]) { + return _evaluate(result, eval_args); + } + + return result; + }); return new QuotedPromise(result); } @@ -12554,7 +13305,7 @@ } // ------------------------------------------------------------------------- - function exec(_x13, _x14, _x15) { + function exec(_x12, _x13, _x14) { return _exec.apply(this, arguments); } // ------------------------------------------------------------------------- @@ -12600,13 +13351,18 @@ } code = _value3; - value = evaluate(code, { + value = _evaluate(code, { env: env, dynamic_scope: dynamic_scope, error: function error(e, code) { if (e && e.message) { - // clean duplicated Error: added by JS - e.message = e.message.replace(/.*:\s*([^:]+:\s*)/, '$1'); + if (e.message.match(/^Error:/)) { + // clean duplicated Error: added by JS + e.message = e.message.replace(/.*:\s*([^:]+:\s*)/, '$1'); + } else { + // add missing Error + e.message = "Error: ".concat(e.message); + } if (code) { // LIPS stack trace @@ -12719,12 +13475,12 @@ }); var stack = new Stack(); - var _iterator8 = _createForOfIteratorHelper(tokens), - _step8; + var _iterator10 = _createForOfIteratorHelper(tokens), + _step10; try { - for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) { - var token = _step8.value; + for (_iterator10.s(); !(_step10 = _iterator10.n()).done;) { + var token = _step10.value; if (open_tokens.includes(token)) { stack.push(token); @@ -12745,9 +13501,9 @@ } } } catch (err) { - _iterator8.e(err); + _iterator10.e(err); } finally { - _iterator8.f(); + _iterator10.f(); } return stack.is_empty(); @@ -13034,10 +13790,10 @@ var banner = function () { // Rollup tree-shaking is removing the variable if it's normal string because - // obviously 'Sun, 31 Jan 2021 11:47:57 +0000' == '{{' + 'DATE}}'; can be removed + // obviously 'Tue, 16 Mar 2021 12:52:41 +0000' == '{{' + 'DATE}}'; can be removed // but disablig Tree-shaking is adding lot of not used code so we use this // hack instead - var date = LString('Sun, 31 Jan 2021 11:47:57 +0000').valueOf(); + var date = LString('Tue, 16 Mar 2021 12:52:41 +0000').valueOf(); var _date = date === '{{' + 'DATE}}' ? new Date() : new Date(date); @@ -13049,7 +13805,7 @@ var _build = [_year, _format(_date.getMonth() + 1), _format(_date.getDate())].join('-'); - var banner = "\n __ __ __\n / / \\ \\ _ _ ___ ___ \\ \\\n| | \\ \\ | | | || . \\/ __> | |\n| | > \\ | |_ | || _/\\__ \\ | |\n| | / ^ \\ |___||_||_| <___/ | |\n \\_\\ /_/ \\_\\ /_/\n\nLIPS Interpreter 1.0.0-beta.11 (".concat(_build, ") \nCopyright (c) 2018-").concat(_year, " Jakub T. Jankiewicz\n\nType (env) to see environment with functions macros and variables.\nYou can also use (help name) to display help for specic function or macro and\n(apropos name) to display list of matched names in environment.\n").replace(/^.*\n/, ''); + var banner = "\n __ __ __\n / / \\ \\ _ _ ___ ___ \\ \\\n| | \\ \\ | | | || . \\/ __> | |\n| | > \\ | |_ | || _/\\__ \\ | |\n| | / ^ \\ |___||_||_| <___/ | |\n \\_\\ /_/ \\_\\ /_/\n\nLIPS Interpreter DEV (".concat(_build, ") \nCopyright (c) 2018-").concat(_year, " Jakub T. Jankiewicz\n\nType (env) to see environment with functions macros and variables.\nYou can also use (help name) to display help for specic function or macro and\n(apropos name) to display list of matched names in environment.\n").replace(/^.*\n/, ''); return banner; }(); // ------------------------------------------------------------------------- // to be used with string function when code is minified @@ -13065,21 +13821,24 @@ InputPort.__class__ = 'input-port'; OutputPort.__class__ = 'output-port'; OutputStringPort.__class__ = 'output-string-port'; - InputStringPort.__class__ = 'input-string-port'; // types used for detect lips objects + InputStringPort.__class__ = 'input-string-port'; + InputFilePort.__class__ = 'input-file-port'; + OutputFilePort.__class__ = 'output-file-port'; // types used for detect lips objects LNumber.__class__ = 'number'; LCharacter.__class__ = 'character'; - LString.__class__ = 'string'; // ------------------------------------------------------------------------- + LString.__class__ = 'string'; + QuotedPromise.__class__ = 'promise'; // ------------------------------------------------------------------------- var lips = { - version: '1.0.0-beta.11', + version: 'DEV', banner: banner, - date: 'Sun, 31 Jan 2021 11:47:57 +0000', + date: 'Tue, 16 Mar 2021 12:52:41 +0000', exec: exec, // unwrap async generator into Promise parse: compose(uniterate_async, parse), tokenize: tokenize, - evaluate: evaluate, + evaluate: _evaluate, bootstrap: bootstrap, Environment: Environment, env: user_env, @@ -13100,6 +13859,10 @@ OutputFilePort: OutputFilePort, InputStringPort: InputStringPort, OutputStringPort: OutputStringPort, + InputByteVectorPort: InputByteVectorPort, + OutputByteVectorPort: OutputByteVectorPort, + InputBinaryFilePort: InputBinaryFilePort, + OutputBinaryFilePort: OutputBinaryFilePort, Formatter: Formatter, Parser: Parser, Lexer: Lexer, diff --git a/dist/lips.min.js b/dist/lips.min.js index c776a015..8c545cf7 100644 --- a/dist/lips.min.js +++ b/dist/lips.min.js @@ -4,7 +4,7 @@ * | | \ \ | | | || . \/ __> | | * | | > \ | |_ | || _/\__ \ | | * | | / ^ \ |___||_||_| <___/ | | - * \_\ /_/ \_\ /_/ v. 1.0.0-beta.11 + * \_\ /_/ \_\ /_/ v. DEV * * LIPS is Pretty Simple - Scheme based Powerful LISP in JavaScript * @@ -31,6 +31,6 @@ * Copyright (c) 2014-present, Facebook, Inc. * released under MIT license * - * build: Sun, 31 Jan 2021 11:47:57 +0000 + * build: Tue, 16 Mar 2021 12:52:41 +0000 */ -(function(){"use strict";function _readOnlyError(e){throw new Error('"'+e+'" is read-only')}var readOnlyError=_readOnlyError;function createCommonjsModule(e,r){return r={exports:{}},e(r,r.exports),r.exports}var setPrototypeOf=createCommonjsModule(function(n){function t(e,r){n.exports=t=Object.setPrototypeOf||function e(r,n){r.__proto__=n;return r};return t(e,r)}n.exports=t});function _isNativeReflectConstruct(){if(typeof Reflect==="undefined"||!Reflect.construct)return false;if(Reflect.construct.sham)return false;if(typeof Proxy==="function")return true;try{Date.prototype.toString.call(Reflect.construct(Date,[],function(){}));return true}catch(e){return false}}var isNativeReflectConstruct=_isNativeReflectConstruct;var construct=createCommonjsModule(function(t){function i(e,r,n){if(isNativeReflectConstruct()){t.exports=i=Reflect.construct}else{t.exports=i=function e(r,n,t){var i=[null];i.push.apply(i,n);var a=Function.bind.apply(r,i);var u=new a;if(t)setPrototypeOf(u,t.prototype);return u}}return i.apply(null,arguments)}t.exports=i});function _arrayWithHoles(e){if(Array.isArray(e))return e}var arrayWithHoles=_arrayWithHoles;function _iterableToArray(e){if(typeof Symbol!=="undefined"&&Symbol.iterator in Object(e))return Array.from(e)}var iterableToArray=_iterableToArray;function _arrayLikeToArray(e,r){if(r==null||r>e.length)r=e.length;for(var n=0,t=new Array(r);n=0;--r){var i=this.tryEntries[r];var a=i.completion;if(i.tryLoc==="root"){return e("end")}if(i.tryLoc<=this.prev){var u=l.call(i,"catchLoc");var o=l.call(i,"finallyLoc");if(u&&o){if(this.prev=0;--n){var t=this.tryEntries[n];if(t.tryLoc<=this.prev&&l.call(t,"finallyLoc")&&this.prev=0;--r){var n=this.tryEntries[r];if(n.finallyLoc===e){this.complete(n.completion,n.afterLoc);S(n);return m}}},catch:function(e){for(var r=this.tryEntries.length-1;r>=0;--r){var n=this.tryEntries[r];if(n.tryLoc===e){var t=n.completion;if(t.type==="throw"){var i=t.arg;S(n)}return i}}throw new Error("illegal catch attempt")},delegateYield:function(e,r,n){this.delegate={iterator:k(e),resultName:r,nextLoc:n};if(this.method==="next"){this.arg=c}return m}};return u}(e.exports);try{regeneratorRuntime=r}catch(e){Function("r","regeneratorRuntime = r")(r)}});var regenerator=runtime_1;function asyncGeneratorStep(e,r,n,t,i,a,u){try{var o=e[a](u);var c=o.value}catch(e){n(e);return}if(o.done){r(c)}else{Promise.resolve(c).then(t,i)}}function _asyncToGenerator(o){return function(){var e=this,u=arguments;return new Promise(function(r,n){var t=o.apply(e,u);function i(e){asyncGeneratorStep(t,r,n,i,a,"next",e)}function a(e){asyncGeneratorStep(t,r,n,i,a,"throw",e)}i(undefined)})}}var asyncToGenerator=_asyncToGenerator;function _classCallCheck(e,r){if(!(e instanceof r)){throw new TypeError("Cannot call a class as a function")}}var classCallCheck=_classCallCheck;function _defineProperties(e,r){for(var n=0;n=0)continue;n[i]=e[i]}return n}var objectWithoutPropertiesLoose=_objectWithoutPropertiesLoose;function _objectWithoutProperties(e,r){if(e==null)return{};var n=objectWithoutPropertiesLoose(e,r);var t,i;if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(i=0;i=0)continue;if(!Object.prototype.propertyIsEnumerable.call(e,t))continue;n[t]=e[t]}}return n}var objectWithoutProperties=_objectWithoutProperties;function _iterableToArrayLimit(e,r){if(typeof Symbol==="undefined"||!(Symbol.iterator in Object(e)))return;var n=[];var t=true;var i=false;var a=undefined;try{for(var u=e[Symbol.iterator](),o;!(t=(o=u.next()).done);t=true){n.push(o.value);if(r&&n.length===r)break}}catch(e){i=true;a=e}finally{try{if(!t&&u["return"]!=null)u["return"]()}finally{if(i)throw a}}return n}var iterableToArrayLimit=_iterableToArrayLimit;function _slicedToArray(e,r){return arrayWithHoles(e)||iterableToArrayLimit(e,r)||unsupportedIterableToArray(e,r)||nonIterableRest()}var slicedToArray=_slicedToArray;var _typeof_1=createCommonjsModule(function(r){function n(e){"@babel/helpers - typeof";if(typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"){r.exports=n=function e(r){return typeof r}}else{r.exports=n=function e(r){return r&&typeof Symbol==="function"&&r.constructor===Symbol&&r!==Symbol.prototype?"symbol":typeof r}}return n(e)}r.exports=n});function _asyncIterator(e){var r;if(typeof Symbol!=="undefined"){if(Symbol.asyncIterator){r=e[Symbol.asyncIterator];if(r!=null)return r.call(e)}if(Symbol.iterator){r=e[Symbol.iterator];if(r!=null)return r.call(e)}}throw new TypeError("Object is not async iterable")}var asyncIterator=_asyncIterator;function _AwaitValue(e){this.wrapped=e}var AwaitValue=_AwaitValue;function _awaitAsyncGenerator(e){return new AwaitValue(e)}var awaitAsyncGenerator=_awaitAsyncGenerator;function AsyncGenerator(a){var u,o;function e(t,i){return new Promise(function(e,r){var n={key:t,arg:i,resolve:e,reject:r,next:null};if(o){o=o.next=n}else{u=o=n;c(t,i)}})}function c(r,e){try{var n=a[r](e);var t=n.value;var i=t instanceof AwaitValue;Promise.resolve(i?t.wrapped:t).then(function(e){if(i){c(r==="return"?"return":"next",e);return}s(n.done?"return":"normal",e)},function(e){c("throw",e)})}catch(e){s("throw",e)}}function s(e,r){switch(e){case"return":u.resolve({value:r,done:true});break;case"throw":u.reject(r);break;default:u.resolve({value:r,done:false});break}u=u.next;if(u){c(u.key,u.arg)}else{o=null}}this._invoke=e;if(typeof a["return"]!=="function"){this["return"]=undefined}}if(typeof Symbol==="function"&&Symbol.asyncIterator){AsyncGenerator.prototype[Symbol.asyncIterator]=function(){return this}}AsyncGenerator.prototype.next=function(e){return this._invoke("next",e)};AsyncGenerator.prototype["throw"]=function(e){return this._invoke("throw",e)};AsyncGenerator.prototype["return"]=function(e){return this._invoke("return",e)};var AsyncGenerator_1=AsyncGenerator;function _wrapAsyncGenerator(e){return function(){return new AsyncGenerator_1(e.apply(this,arguments))}}var wrapAsyncGenerator=_wrapAsyncGenerator;function _createForOfIteratorHelper(r,e){var n;if(typeof Symbol==="undefined"||r[Symbol.iterator]==null){if(Array.isArray(r)||(n=_unsupportedIterableToArray$1(r))||e&&r&&typeof r.length==="number"){if(n)r=n;var t=0;var i=function e(){};return{s:i,n:function e(){if(t>=r.length)return{done:true};return{done:false,value:r[t++]}},e:function e(r){throw r},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var a=true,u=false,o;return{s:function e(){n=r[Symbol.iterator]()},n:function e(){var r=n.next();a=r.done;return r},e:function e(r){u=true;o=r},f:function e(){try{if(!a&&n["return"]!=null)n["return"]()}finally{if(u)throw o}}}}function _unsupportedIterableToArray$1(e,r){if(!e)return;if(typeof e==="string")return _arrayLikeToArray$1(e,r);var n=Object.prototype.toString.call(e).slice(8,-1);if(n==="Object"&&e.constructor)n=e.constructor.name;if(n==="Map"||n==="Set")return Array.from(e);if(n==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return _arrayLikeToArray$1(e,r)}function _arrayLikeToArray$1(e,r){if(r==null||r>e.length)r=e.length;for(var n=0,t=new Array(r);n1&&arguments[1]!==undefined$1?arguments[1]:null;var t=arguments[1]===true;function r(e){if(!is_debug()){return}var r=global_env.get("repr")(e);if(n===null||n instanceof RegExp&&n.test(r)){console.log(global_env.get("type")(e)+": "+r)}if(t){console.log(e)}}if(is_promise(e)){e.then(r)}else{r(e)}return e}function is_debug(){return user_env.get("DEBUG",{throwError:false})}if(!root.fetch){root.fetch=function(i,a){a=a||{};return new Promise(function(e,r){var n=new XMLHttpRequest;n.open(a.method||"get",i,true);for(var t in a.headers){n.setRequestHeader(t,a.headers[t])}n.withCredentials=a.credentials=="include";n.onload=function(){e(o())};n.onerror=r;n.send(a.body||null);function o(){var t=[],i=[],a={},u;n.getAllResponseHeaders().replace(/^(.*?):[^\S\n]*([\s\S]*?)$/gm,function(e,r,n){t.push(r=r.toLowerCase());i.push([r,n]);u=a[r];a[r]=u?"".concat(u,",").concat(n):n});return{ok:(n.status/100|0)==2,status:n.status,statusText:n.statusText,url:n.responseURL,clone:o,text:function e(){return Promise.resolve(n.responseText)},json:function e(){return Promise.resolve(n.responseText).then(JSON.parse)},blob:function e(){return Promise.resolve(new Blob([n.response]))},headers:{keys:function e(){return t},entries:function e(){return i},get:function e(r){return a[r.toLowerCase()]},has:function e(r){return r.toLowerCase()in a}}}}})}}function num_mnemicic_re(e){return e?"(?:#".concat(e,"(?:#[ie])?|#[ie]#").concat(e,")"):"(?:#[ie])?"}function gen_rational_re(e,r){return"".concat(num_mnemicic_re(e),"[+-]?").concat(r,"+/").concat(r,"+")}function gen_complex_re(e,r){return"".concat(num_mnemicic_re(e),"(?:[+-]?(?:").concat(r,"+/").concat(r,"+|").concat(r,"+))?(?:[+-]i|[+-]?(?:").concat(r,"+/").concat(r,"+|").concat(r,"+)i)(?=[()[\\]\\s]|$)")}function gen_integer_re(e,r){return"".concat(num_mnemicic_re(e),"[+-]?").concat(r,"+")}var re_re=/^#\/((?:\\\/|[^/]|\[[^\]]*\/[^\]]*\])+)\/([gimyus]*)$/;var float_stre="(?:[-+]?(?:[0-9]+(?:[eE][-+]?[0-9]+)|(?:\\.[0-9]+|[0-9]+\\.[0-9]+)(?:[eE][-+]?[0-9]+)?)|[0-9]+\\.)";var complex_float_stre="(?:#[ie])?(?:[+-]?(?:[0-9]+/[0-9]+|".concat(float_stre,"|[+-]?[0-9]+))?(?:").concat(float_stre,"|[+-](?:[0-9]+/[0-9]+|[0-9]+))i");var float_re=new RegExp("^(#[ie])?".concat(float_stre,"$"),"i");function make_complex_match_re(e,r){var n=e==="x"?"(?!\\+|".concat(r,")"):"(?!\\.|".concat(r,")");var t="";if(e===""){t="(?:[-+]?(?:[0-9]+(?:[eE][-+]?[0-9]+)|(?:\\.[0-9]+|[0-9]+\\.[0-9]+(?![0-9]))(?:[eE][-+]?[0-9]+)?))"}return new RegExp("^((?:(?:".concat(t,"|[+-]?").concat(r,"+/").concat(r,"+(?!").concat(r,")|[+-]?").concat(r,"+)").concat(n,")?)(").concat(t,"|[+-]?").concat(r,"+/").concat(r,"+|[+-]?").concat(r,"+|[+-])i$"),"i")}var complex_list_re=function(){var a={};[[10,"","[0-9]"],[16,"x","[0-9a-fA-F]"],[8,"o","[0-7]"],[2,"b","[01]"]].forEach(function(e){var r=slicedToArray(e,3),n=r[0],t=r[1],i=r[2];a[n]=make_complex_match_re(t,i)});return a}();var characters={alarm:"",backspace:"\b",delete:"",escape:"",newline:"\n",null:"\0",return:"\r",space:" ",tab:"\t",dle:"",soh:"",dc1:"",stx:"",dc2:"",etx:"",dc3:"",eot:"",dc4:"",enq:"",nak:"",ack:"",syn:"",bel:"",etb:"",bs:"\b",can:"",ht:"\t",em:"",lf:"\n",sub:"",vt:"\v",esc:"",ff:"\f",fs:"",cr:"\r",gs:"",so:"",rs:"",si:"",us:"",del:""};function ucs2decode(e){var r=[];var n=0;var t=e.length;while(n=55296&&i<=56319&&n1&&arguments[1]!==undefined$1?arguments[1]:10;var n=num_pre_parse(e);var t=n.number.split("/");var i=LRational({num:LNumber([t[0],n.radix||r]),denom:LNumber([t[1],n.radix||r])});if(n.inexact){return i.valueOf()}else{return i}}function parse_integer(e){var r=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:10;var n=num_pre_parse(e);if(n.inexact){return LFloat(parseInt(n.number,n.radix||r))}return LNumber([n.number,n.radix||r])}function parse_character(e){var r=e.match(/#\\x([0-9a-f]+)$/i);var n;if(r){var t=parseInt(r[1],16);n=String.fromCodePoint(t)}else{r=e.match(/#\\(.+)$/);if(r){n=r[1]}}if(n){return LCharacter(n)}throw new Error("Parse: invalid character")}function parse_complex(e){var i=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:10;function r(e){var r;if(e==="+"){r=LNumber(1)}else if(e==="-"){r=LNumber(-1)}else if(e.match(int_bare_re)){r=LNumber([e,i])}else if(e.match(rational_bare_re)){var n=e.split("/");r=LRational({num:LNumber([n[0],i]),denom:LNumber([n[1],i])})}else if(e.match(float_re)){var t=parse_float(e);if(a.exact){return t.toRational()}return t}else{throw new Error("Internal Parser Error")}if(a.inexact){return LFloat(r.valueOf())}return r}var a=num_pre_parse(e);i=a.radix||i;var n;var t=a.number.match(complex_bare_match_re);if(i!==10&&t){n=t}else{n=a.number.match(complex_list_re[i])}var u,o;o=r(n[2]);if(n[1]){u=r(n[1])}else if(o instanceof LFloat){u=LFloat(0)}else{u=LNumber(0)}return LComplex({im:o,re:u})}function is_int(e){return parseInt(e.toString(),10)===e}function parse_big_int(e){var r=e.match(/^(([-+]?[0-9]*)(?:\.([0-9]+))?)e([-+]?[0-9]+)/i);if(r){var n=parseInt(r[4],10);var t;var i=r[1].replace(/[-+]?([0-9]*)\..+$/,"$1").length;var a=r[3]&&r[3].length;if(i0){return LNumber(a).mul(o)}}}n=LFloat(n);if(r.exact){return n.toRational()}return n}function parse_string(e){e=e.replace(/\\x([0-9a-f]+);/gi,function(e,r){return"\\u"+r.padStart(4,"0")}).replace(/\n/g,"\\n");var r=e.match(/(\\*)(\\x[0-9A-F])/i);if(r&&r[1].length%2===0){throw new Error("Invalid string literal, unclosed ".concat(r[2]))}try{return LString(JSON.parse(e))}catch(e){throw new Error("Invalid string literal")}}function parse_symbol(e){if(e.match(/^\|.*\|$/)){e=e.replace(/(^\|)|(\|$)/g,"");var n={t:"\t",r:"\r",n:"\n"};e=e.replace(/\\(x[^;]+);/g,function(e,r){return String.fromCharCode(parseInt("0"+r,16))}).replace(/\\(.)/g,function(e,r){return n[r]||r})}return new LSymbol(e)}function parse_argument(e){var r=e.match(re_re);if(r){return new RegExp(r[1],r[2])}else if(e.match(/^"[\s\S]*"$/)){return parse_string(e)}else if(e.match(char_re)){return parse_character(e)}else if(e.match(rational_re)){return parse_rational(e)}else if(e.match(complex_re)){return parse_complex(e)}else if(e.match(int_re)){return parse_integer(e)}else if(e.match(float_re)){return parse_float(e)}else if(e==="nil"){return nil}else if(["true","#t","#true"].includes(e)){return true}else if(["false","#f","#false"].includes(e)){return false}else if(e.match(/^#[iexobd]/)){throw new Error("Invalid numeric constant")}else{var n=e.match(/#\\(.+)/);if(n&&ucs2decode(n[1]).length===1){return parse_character(e)}return parse_symbol(e)}}function is_symbol_string(e){return!(["(",")"].includes(e)||e.match(re_re)||e.match(/^"[\s\S]*"$/)||e.match(int_re)||e.match(float_re)||e.match(complex_re)||e.match(rational_re)||e.match(char_re)||["#t","#f","nil","true","false"].includes(e))}var string_re=/"(?:\\[\S\s]|[^"])*"?/g;function Stack(){this.data=[]}Stack.prototype.push=function(e){this.data.push(e)};Stack.prototype.top=function(){return this.data[this.data.length-1]};Stack.prototype.pop=function(){return this.data.pop()};Stack.prototype.is_empty=function(){return!this.data.length};function tokens(e){if(e instanceof LString){e=e.valueOf()}var r=new Lexer(e,{whitespace:true});var n=[];while(true){var t=r.peek(true);if(t===eof){break}n.push(t);r.skip()}return n}function multiline_formatter(e){var r=e.token,n=objectWithoutProperties(e,["token"]);if(r.match(/^"[\s\S]*"$/)&&r.match(/\n/)){var t=new RegExp("^ {1,"+(e.col+1)+"}","mg");r=r.replace(t,"")}return _objectSpread({token:r},n)}function Thunk(e){var r=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:function(){};this.fn=e;this.cont=r}Thunk.prototype.toString=function(){return"#"};function trampoline(t){return function(){for(var e=arguments.length,r=new Array(e),n=0;n1&&arguments[1]!==undefined$1?arguments[1]:false;if(e instanceof LString){e=e.toString()}if(r){return tokens(e)}else{var n=tokens(e).map(function(e){if(e.token==="#\\ "){return e.token}return e.token.trim()}).filter(function(e){return e&&!e.match(/^;/)&&!e.match(/^#\|[\s\S]*\|#$/)});return strip_s_comments(n)}}function strip_s_comments(e){var r=0;var n=null;var t=[];for(var i=0;i0&&arguments[0]!==undefined$1?arguments[0]:null;if(e instanceof LSymbol){e=e.valueOf()}if(is_gensym(e)){return LSymbol(e)}if(e!==null){return new LSymbol(Symbol("#:".concat(e)))}r++;return new LSymbol(Symbol("#:g".concat(r)))}}();function QuotedPromise(e){e["catch"](function(){});this.__promise__=e}QuotedPromise.prototype.then=function(e){return new QuotedPromise(this.__promise__.then(e))};QuotedPromise.prototype["catch"]=function(e){return new QuotedPromise(this.__promise__["catch"](e))};QuotedPromise.prototype.valueOf=function(){return this.__promise__};var specials={LITERAL:Symbol["for"]("literal"),SPLICE:Symbol["for"]("splice"),SYMBOL:Symbol["for"]("symbol"),names:function e(){return Object.keys(this._specials)},type:function e(r){return this.get(r).type},get:function e(r){return this._specials[r]},off:function e(r){var n=this;var t=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:null;if(Array.isArray(r)){r.forEach(function(e){return n.off(e,t)})}else if(t===null){delete this._events[r]}else{this._events=this._events.filter(function(e){return e!==t})}},on:function e(r,n){var t=this;if(Array.isArray(r)){r.forEach(function(e){return t.on(e,n)})}else if(!this._events[r]){this._events[r]=[n]}else{this._events[r].push(n)}},trigger:function e(r){for(var n=arguments.length,t=new Array(n>1?n-1:0),i=1;i",new LSymbol("quote-promise"),specials.LITERAL]];Object.defineProperty(specials,"builtin",{writable:false,value:defined_specials.map(function(e){return e[0]})});defined_specials.forEach(function(e){var r=slicedToArray(e,3),n=r[0],t=r[1],i=r[2];specials.append(n,t,i)});var Lexer=function(){function _(e){var r=this;var n=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:{},t=n.whitespace,i=t===void 0?false:t;classCallCheck(this,_);Object.defineProperty(this,"__input__",{value:e.replace(/\r/g,""),enumerable:true});var a={};["_i","_whitespace","_col","_newline","_line","_state","_next","_token","_prev_char"].forEach(function(n){Object.defineProperty(r,n,{configurable:false,enumerable:false,get:function e(){return a[n]},set:function e(r){a[n]=r}})});this._whitespace=i;this._i=this._line=this._col=this._newline=0;this._state=this._next=this._token=null;this._prev_char=""}createClass(_,[{key:"get",value:function e(r){return this.__internal[r]}},{key:"set",value:function e(r,n){this.__internal[r]=n}},{key:"token",value:function e(){var r=arguments.length>0&&arguments[0]!==undefined$1?arguments[0]:false;if(r){var n=this._line;if(this._whitespace&&this._token==="\n"){--n}return{token:this._token,col:this._col,offset:this._i,line:n}}return this._token}},{key:"peek",value:function e(){var r=arguments.length>0&&arguments[0]!==undefined$1?arguments[0]:false;if(this._i>=this.__input__.length){return eof}if(this._token){return this.token(r)}var n=this.next_token();if(n){this._token=this.__input__.substring(this._i,this._next);return this.token(r)}return eof}},{key:"skip",value:function e(){if(this._next!==null){this._token=null;this._i=this._next}}},{key:"read_line",value:function e(){var r=this.__input__.length;if(this._i>=r){return eof}for(var n=this._i;n=n){return eof}if(r+this._i>=n){return this.read_rest()}var t=this._i+r;var i=this.__input__.substring(this._i,t);var a=i.match(/\n/g);if(a){this._line+=a.length}this._i=t;return i}},{key:"peek_char",value:function e(){if(this._i>=this.__input__.length){return eof}return LCharacter(this.__input__[this._i])}},{key:"read_char",value:function e(){var r=this.peek_char();this.skip_char();return r}},{key:"skip_char",value:function e(){if(this._i1&&arguments[1]!==undefined$1?arguments[1]:{},t=n.prev_char,i=n["char"],a=n.next_char;var u=slicedToArray(r,4),o=u[0],c=u[1],s=u[2],l=u[3];if(r.length!==5){throw new Error("Lexer: Invald rule of length ".concat(r.length))}if(!i.match(o)){return false}if(!match_or_null(c,t)){return false}if(!match_or_null(s,a)){return false}if(l!==this._state){return false}return true}},{key:"next_token",value:function e(){if(this._i>=this.__input__.length){return false}var r=true;e:for(var n=this._i,t=this.__input__.length;n2&&arguments[2]!==undefined$1?arguments[2]:null;var i=arguments.length>3&&arguments[3]!==undefined$1?arguments[3]:null;if(r.length===0){throw new Error("Lexer: invalid literal rule")}if(r.length===1){return[[r,t,i,null,null]]}var a=[];for(var u=0,o=r.length;u1&&arguments[1]!==undefined$1?arguments[1]:{},n=r.env,t=r.meta,i=t===void 0?false:t,a=r.formatter,u=a===void 0?multiline_formatter:a;classCallCheck(this,o);if(e instanceof LString){e=e.toString()}this._formatter=u;this._meta=i;this.__lexer__=new Lexer(e);this.__env__=n}createClass(o,[{key:"resolve",value:function e(r){return this.__env__&&this.__env__.get(r,{throwError:false})}},{key:"peek",value:function(){var e=asyncToGenerator(regenerator.mark(function e(){var n;return regenerator.wrap(function e(r){while(1){switch(r.prev=r.next){case 0:n=this.__lexer__.peek(true);if(!(n===eof)){r.next=4;break}return r.abrupt("return",eof);case 4:if(!this.is_comment(n.token)){r.next=7;break}this.skip();return r.abrupt("continue",0);case 7:if(!(n.token==="#;")){r.next=14;break}this.skip();if(!(this.__lexer__.peek()===eof)){r.next=11;break}throw new Error("Lexer: syntax error eof found after comment");case 11:r.next=13;return this.read_object();case 13:return r.abrupt("continue",0);case 14:return r.abrupt("break",17);case 17:n=this._formatter(n);if(!this._meta){r.next=20;break}return r.abrupt("return",n);case 20:return r.abrupt("return",n.token);case 21:case"end":return r.stop()}}},e,this)}));function r(){return e.apply(this,arguments)}return r}()},{key:"skip",value:function e(){this.__lexer__.skip()}},{key:"special",value:function e(r){return specials.names().includes(r)}},{key:"builtin",value:function e(r){return specials.builtin.includes(r)}},{key:"read",value:function(){var e=asyncToGenerator(regenerator.mark(function e(){var n;return regenerator.wrap(function e(r){while(1){switch(r.prev=r.next){case 0:r.next=2;return this.peek();case 2:n=r.sent;this.skip();return r.abrupt("return",n);case 5:case"end":return r.stop()}}},e,this)}));function r(){return e.apply(this,arguments)}return r}()},{key:"is_open",value:function e(r){return["(","["].includes(r)}},{key:"is_close",value:function e(r){return[")","]"].includes(r)}},{key:"read_list",value:function(){var e=asyncToGenerator(regenerator.mark(function e(){var n,t,i,a;return regenerator.wrap(function e(r){while(1){switch(r.prev=r.next){case 0:n=nil,t=n;case 1:r.next=4;return this.peek();case 4:i=r.sent;if(!(i===eof)){r.next=7;break}return r.abrupt("break",27);case 7:if(!this.is_close(i)){r.next=10;break}this.skip();return r.abrupt("break",27);case 10:if(!(i==="."&&n!==nil)){r.next=17;break}this.skip();r.next=14;return this.read_object();case 14:t.cdr=r.sent;r.next=25;break;case 17:r.t0=Pair;r.next=20;return this.read_object();case 20:r.t1=r.sent;r.t2=nil;a=new r.t0(r.t1,r.t2);if(n===nil){n=a}else{t.cdr=a}t=a;case 25:r.next=1;break;case 27:return r.abrupt("return",n);case 28:case"end":return r.stop()}}},e,this)}));function r(){return e.apply(this,arguments)}return r}()},{key:"read_value",value:function(){var e=asyncToGenerator(regenerator.mark(function e(){var n;return regenerator.wrap(function e(r){while(1){switch(r.prev=r.next){case 0:r.next=2;return this.read();case 2:n=r.sent;if(!(n===eof)){r.next=5;break}throw new Error("Parser: Expected token eof found");case 5:return r.abrupt("return",parse_argument(n));case 6:case"end":return r.stop()}}},e,this)}));function r(){return e.apply(this,arguments)}return r}()},{key:"is_comment",value:function e(r){return r.match(/^;/)||r.match(/^#\|/)&&r.match(/\|#$/)}},{key:"_eval",value:function e(r){return evaluate(r,{env:this.__env__,error:function e(r){throw r}})}},{key:"read_object",value:function(){var e=asyncToGenerator(regenerator.mark(function e(){var n,t,i,a,u,o,c;return regenerator.wrap(function e(r){while(1){switch(r.prev=r.next){case 0:r.next=2;return this.peek();case 2:n=r.sent;if(!(n===eof)){r.next=5;break}return r.abrupt("return",n);case 5:if(!this.special(n)){r.next=35;break}t=specials.get(n);i=this.builtin(n);this.skip();r.next=11;return this.read_object();case 11:u=r.sent;if(i){r.next=22;break}o=this.__env__.get(t.symbol);if(!(typeof o==="function")){r.next=22;break}if(!is_literal(n)){r.next=19;break}return r.abrupt("return",o.call(this.__env__,u));case 19:if(!(u instanceof Pair)){r.next=21;break}return r.abrupt("return",o.apply(this.__env__,u.toArray(false)));case 21:throw new Error("Parser: Invalid parser extension "+"invocation ".concat(t.symbol));case 22:if(is_literal(n)){a=new Pair(t.symbol,new Pair(u,nil))}else{a=new Pair(t.symbol,u)}if(!i){r.next=25;break}return r.abrupt("return",a);case 25:if(!(o instanceof Macro)){r.next=34;break}r.next=28;return this._eval(a);case 28:c=r.sent;if(!(c instanceof Pair||c instanceof LSymbol)){r.next=31;break}return r.abrupt("return",Pair.fromArray([LSymbol("quote"),c]));case 31:return r.abrupt("return",c);case 34:throw new Error("Parser: invlid parser extension: ".concat(t.symbol));case 35:if(!this.is_open(n)){r.next=42;break}this.skip();r.next=39;return this.read_list();case 39:return r.abrupt("return",r.sent);case 42:r.next=44;return this.read_value();case 44:return r.abrupt("return",r.sent);case 45:case"end":return r.stop()}}},e,this)}));function r(){return e.apply(this,arguments)}return r}()}]);return o}();function parse(e,r){return _parse.apply(this,arguments)}function _parse(){_parse=wrapAsyncGenerator(regenerator.mark(function e(n,t){var i,a;return regenerator.wrap(function e(r){while(1){switch(r.prev=r.next){case 0:if(!t){if(global_env){t=global_env.get("**interaction-environment**",{throwError:false})}else{t=user_env}}i=new Parser(n,{env:t});case 2:r.next=5;return awaitAsyncGenerator(i.read_object());case 5:a=r.sent;if(!(a===eof)){r.next=8;break}return r.abrupt("break",12);case 8:r.next=10;return a;case 10:r.next=2;break;case 12:case"end":return r.stop()}}},e)}));return _parse.apply(this,arguments)}function unpromise(r){var e=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:function(e){return e};var n=arguments.length>2&&arguments[2]!==undefined$1?arguments[2]:null;if(r instanceof Array){var t=r.filter(is_promise);if(t.length){return unpromise(Promise.all(r),function(e){if(Object.isFrozen(r)){Object.freeze(e)}return e},n)}return e(r)}if(is_plain_object(r)){var i=Object.keys(r);var a=i.map(function(e){return r[e]});var u=a.filter(is_promise);if(u.length){return unpromise(Promise.all(a),function(e){var t={};e.forEach(function(e,r){var n=i[r];t[n]=e});if(Object.isFrozen(r)){Object.freeze(t)}return t},n)}}if(is_promise(r)){var o=r.then(e);if(n===null){return o}else{return o["catch"](n)}}return e(r)}function uniterate_async(e){return _uniterate_async.apply(this,arguments)}function _uniterate_async(){_uniterate_async=asyncToGenerator(regenerator.mark(function e(n){var t,i,a,u,o,c,s,l;return regenerator.wrap(function e(r){while(1){switch(r.prev=r.next){case 0:t=[];i=true;a=false;r.prev=3;o=asyncIterator(n);case 5:r.next=7;return o.next();case 7:c=r.sent;i=c.done;r.next=11;return c.value;case 11:s=r.sent;if(i){r.next=18;break}l=s;t.push(l);case 15:i=true;r.next=5;break;case 18:r.next=24;break;case 20:r.prev=20;r.t0=r["catch"](3);a=true;u=r.t0;case 24:r.prev=24;r.prev=25;if(!(!i&&o["return"]!=null)){r.next=29;break}r.next=29;return o["return"]();case 29:r.prev=29;if(!a){r.next=32;break}throw u;case 32:return r.finish(29);case 33:return r.finish(24);case 34:return r.abrupt("return",t);case 35:case"end":return r.stop()}}},e,null,[[3,20,24,34],[25,,29,33]])}));return _uniterate_async.apply(this,arguments)}function matcher(e,r){if(r instanceof RegExp){return function(e){return String(e).match(r)}}else if(is_function(r)){return r}}function doc(e,r,n,t){if(typeof e!=="string"){r=arguments[0];n=arguments[1];t=arguments[2];e=null}if(n){if(t){r.__doc__=n}else{r.__doc__=trim_lines(n)}}if(e){r.__name__=e}else if(r.name&&!r[__lambda__]){r.__name__=r.name}return r}function trim_lines(e){return e.split("\n").map(function(e){return e.trim()}).join("\n")}function previousSexp(e){var r=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:1;var n=e.length;if(r<=0){throw Error("previousSexp: Invalid argument sexp = ".concat(r))}e:while(r--&&n>=0){var t=1;while(t>0){var i=e[--n];if(!i){break e}if(i==="("||i.token==="("){t--}else if(i===")"||i.token===")"){t++}}n--}return e.slice(n+1)}function lineIndent(e){if(!e||!e.length){return 0}var r=e.length;if(e[r-1].token==="\n"){return 0}while(--r){if(e[r].token==="\n"){var n=(e[r+1]||{}).token;if(n){return n.length}}}return 0}function nested_pattern(e){return e instanceof Array||e instanceof Pattern}function match(e,r){return f(e,r)===r.length;function f(n,t){function e(){if(a<=0&&o<=0){return false}var e=n[a-1];if(!nested_pattern(e)){e=[e]}var r=n[a+1];if(r&&!nested_pattern(r)){r=[r]}return match(e,[t[o-1]])&&(!r||match(r,[t[o]]))}function r(){return n[a]===Symbol["for"]("symbol")&&!is_symbol_string(t[o])}function i(){var e=n[a+1];var r=t[o+1];if(e!==undefined$1&&r!==undefined$1){return f([e],[r])}}var a=0;var u={};for(var o=0;o0){continue}}else if(r()){return-1}}else if(n[a]instanceof Array){var l=f(n[a],t.slice(o));if(l===-1||l+o>t.length){return-1}o+=l-1;a++;continue}else{return-1}a++}if(n.length!==a){return-1}return t.length}}function Formatter(e){this.__code__=e.replace(/\r/g,"")}Formatter.defaults={offset:0,indent:2,exceptions:{specials:[/^(?:#:)?(?:define(?:-values|-syntax|-macro)?|lambda|let*|let-env|try|catch|when|unless|while|syntax-rules|(let|letrec)(-syntax))$/],shift:{1:["&","#"]}}};Formatter.match=match;Formatter.prototype._options=function e(r){var n=Formatter.defaults;if(typeof r==="undefined"){return Object.assign({},n)}var t=r&&r.exceptions||{};var i=t.specials||[];var a=t.shift||{1:[]};return _objectSpread(_objectSpread(_objectSpread({},n),r),{},{exceptions:{specials:[].concat(toConsumableArray(n.exceptions.specials),toConsumableArray(i)),shift:_objectSpread(_objectSpread({},a),{},{1:[].concat(toConsumableArray(n.exceptions.shift[1]),toConsumableArray(a[1]))})}})};Formatter.prototype.indent=function e(r){var n=tokenize(this.__code__,true);return this._indent(n,r)};Formatter.exception_shift=function(a,e){function r(e){if(!e.length){return false}if(e.indexOf(a)!==-1){return true}else{var r=e.filter(function(e){return e instanceof RegExp});if(!r.length){return false}var n=_createForOfIteratorHelper(r),t;try{for(n.s();!(t=n.n()).done;){var i=t.value;if(a.match(i)){return true}}}catch(e){n.e(e)}finally{n.f()}}return false}if(r(e.exceptions.specials)){return e.indent}var n=e.exceptions.shift;for(var t=0,i=Object.entries(n);t0){t.offset=0}if(a.toString()===r.toString()&&balanced(a)){return t.offset+a[0].col}else if(a.length===1){return t.offset+a[0].col+1}else{var c=-1;if(u){var s=Formatter.exception_shift(u.token,t);if(s!==-1){c=s}}if(c===-1){c=Formatter.exception_shift(a[1].token,t)}if(c!==-1){return t.offset+a[0].col+c}else if(a[0].line3&&a[1].line===a[3].line){if(a[1].token==="("||a[1].token==="["){return t.offset+a[1].col}return t.offset+a[3].col}else if(a[0].line===a[1].line){return t.offset+t.indent+a[0].col}else{var l=a.slice(2);for(var f=0;f")};Ahead.prototype.match=function(e){return e.match(this.pattern)};function Pattern(e,r){this.pattern=e;this.flag=r}Pattern.prototype.toString=function(){return"#")};Formatter.Pattern=Pattern;Formatter.Ahead=Ahead;var p_o=/[[(]/;var p_e=/[\])]/;var not_p=/[^()[\]]/;var not_close=new Ahead(/[^)\]]/);var open=new Ahead(/[([]/);var glob=Symbol["for"]("*");var sexp=new Pattern([p_o,glob,p_e],"+");var symbol=new Pattern([Symbol["for"]("symbol")],"?");var symbols=new Pattern([Symbol["for"]("symbol")],"*");var identifiers=[p_o,symbols,p_e];var let_value=new Pattern([p_o,Symbol["for"]("symbol"),glob,p_e],"+");var def_lambda_re=keywords_re("define","lambda","syntax-rules");var non_def=/^(?!.*\b(?:[()[\]]|define|let(?:\*|rec|-env|-syntax)?|lambda|syntax-rules)\b).*$/;var let_re=/^(?:#:)?(let(?:\*|rec|-env|-syntax)?)$/;function keywords_re(){for(var e=arguments.length,r=new Array(e),n=0;n0&&arguments[0]!==undefined$1?arguments[0]:true;var r=[];if(this.car instanceof Pair){if(e){r.push(this.car.toArray())}else{r.push(this.car)}}else{r.push(this.car.valueOf())}if(this.cdr instanceof Pair){r=r.concat(this.cdr.toArray())}return r};Pair.fromArray=function(e){var r=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:true;var n=arguments.length>2&&arguments[2]!==undefined$1?arguments[2]:false;if(e instanceof Pair||n&&e instanceof Array&&e[__data__]){return e}if(r===false){var t=nil;for(var i=e.length;i--;){t=new Pair(e[i],t)}return t}if(e.length&&!(e instanceof Array)){e=toConsumableArray(e)}var a=nil;var u=e.length;while(u--){var o=e[u];if(o instanceof Array){o=Pair.fromArray(o,r,n)}else if(typeof o==="string"){o=LString(o)}else if(typeof o==="number"&&!Number.isNaN(o)){o=LNumber(o)}a=new Pair(o,a)}return a};Pair.prototype.toObject=function(){var e=arguments.length>0&&arguments[0]!==undefined$1?arguments[0]:false;var r=this;var n={};while(true){if(r instanceof Pair&&r.car instanceof Pair){var t=r.car;var i=t.car;if(i instanceof LSymbol){i=i.__name__}if(i instanceof LString){i=i.valueOf()}var a=t.cdr;if(a instanceof Pair){a=a.toObject(e)}if(is_native(a)){if(!e){a=a.valueOf()}}n[i]=a;r=r.cdr}else{break}}return n};Pair.fromPairs=function(e){return e.reduce(function(e,r){return new Pair(new Pair(new LSymbol(r[0]),r[1]),e)},nil)};Pair.fromObject=function(r){var e=Object.keys(r).map(function(e){return[e,r[e]]});return Pair.fromPairs(e)};Pair.prototype.reduce=function(e){var r=this;var n=nil;while(true){if(r!==nil){n=e(n,r.car);r=r.cdr}else{break}}return n};Pair.prototype.reverse=function(){if(this.haveCycles()){throw new Error("You can't reverse list that have cycles")}var e=this;var r=nil;while(e!==nil){var n=e.cdr;e.cdr=r;r=e;e=n}return r};Pair.prototype.transform=function(t){function i(e){if(e instanceof Pair){if(e.replace){delete e.replace;return e}var r=t(e.car);if(r instanceof Pair){r=i(r)}var n=t(e.cdr);if(n instanceof Pair){n=i(n)}return new Pair(r,n)}return e}return i(this)};Pair.prototype.map=function(e){if(typeof this.car!=="undefined"){return new Pair(e(this.car),this.cdr===nil?nil:this.cdr.map(e))}else{return nil}};var repr=new Map;function is_plain_object(e){return e&&_typeof_1(e)==="object"&&e.constructor===Object}var props=Object.getOwnPropertyNames(Array.prototype);var array_methods=[];props.forEach(function(e){array_methods.push(Array[e],Array.prototype[e])});function is_array_method(e){e=unbind(e);return array_methods.includes(e)}function is_lips_function(e){return is_function(e)&&(e[__lambda__]||e.__doc__)}function user_repr(n){var e=n.constructor||Object;var t=is_plain_object(n);var i=is_function(n[Symbol.asyncIterator])||is_function(n[Symbol.iterator]);var a;if(repr.has(e)){a=repr.get(e)}else{repr.forEach(function(e,r){r=unbind(r);if(n.constructor===r&&(r===Object&&t&&!i||r!==Object)){a=e}})}return a}var str_mapping=new Map;[[Number.NEGATIVE_INFINITY,"-inf.0"],[Number.POSITIVE_INFINITY,"+inf.0"],[true,"#t"],[false,"#f"],[null,"null"],[undefined$1,"#"]].forEach(function(e){var r=slicedToArray(e,2),n=r[0],t=r[1];str_mapping.set(n,t)});function symbolize(n){if(n&&_typeof_1(n)==="object"){var t={};var e=Object.getOwnPropertySymbols(n);e.forEach(function(e){var r=e.toString().replace(/Symbol\(([^)]+)\)/,"$1");t[r]=toString(n[e])});var r=Object.getOwnPropertyNames(n);r.forEach(function(e){var r=n[e];if(r&&_typeof_1(r)==="object"&&r.constructor===Object){t[e]=symbolize(r)}else{t[e]=toString(r)}});return t}return n}function get_props(e){return Object.keys(e).concat(Object.getOwnPropertySymbols(e))}function has_own_function(e,r){return e.hasOwnProperty(r)&&is_function(e.toString)}function function_to_string(e){if(is_native_function(e)){return"#"}var r=e.prototype&&e.prototype.constructor;if(is_function(r)&&r[__lambda__]){if(e[__class__]&&r.hasOwnProperty("__name__")){var n=r.__name__;if(LString.isString(n)){n=n.toString();return"#")}return"#"}}if(e.hasOwnProperty("__name__")){var t=e.__name__;if(_typeof_1(t)==="symbol"){t=symbol_to_string(t)}if(typeof t==="string"){return"#")}}if(has_own_function(e,"toString")){return e.toString()}else if(e.name&&!e[__lambda__]){return"#")}else{return"#"}}function toString(e,r,n){if(typeof jQuery!=="undefined"&&e instanceof jQuery.fn.init){return"#"}if(str_mapping.has(e)){return str_mapping.get(e)}if(e instanceof Error){return e.message}if(e instanceof Pair){var t;if(!n){e.markCycles()}for(var i=arguments.length,a=new Array(i>3?i-3:0),u=3;u"}if(e===null){return"null"}if(_typeof_1(e)==="object"){if(is_function(e.toString)&&e.toString[__lambda__]){return e.toString().valueOf()}var f=e.constructor;if(!f){f=Object}var p;if(typeof f.__class__==="string"){p=f.__class__}else{if(is_prototype(e)){return"#"}var _=user_repr(e);if(_){if(is_function(_)){return _(e,r)}else{throw new Error("toString: Invalid repr value")}}p=f.name}if(type(e)==="instance"&&!is_native_function(f)){p="instance"}if(is_iterator(e,Symbol.iterator)){if(p){return"#")}return"#"}if(is_iterator(e,Symbol.asyncIterator)){if(p){return"#")}return"#"}if(p!==""){return"#<"+p+">"}return"#"}if(typeof e!=="string"){return e.toString()}return e}function is_prototype(e){return e&&_typeof_1(e)==="object"&&e.hasOwnProperty&&e.hasOwnProperty("constructor")&&typeof e.constructor==="function"&&e.constructor.prototype===e}Pair.prototype.markCycles=function(){markCycles(this);return this};Pair.prototype.haveCycles=function(){var e=arguments.length>0&&arguments[0]!==undefined$1?arguments[0]:null;if(!e){return this.haveCycles("car")||this.haveCycles("cdr")}return!!(this[__cycles__]&&this[__cycles__][e])};function markCycles(e){var r=[];var i=[];var a=[];function u(e){if(!r.includes(e)){r.push(e)}}function o(e,r,n,t){if(n instanceof Pair){if(t.includes(n)){if(!a.includes(n)){a.push(n)}if(!e[__cycles__]){e[__cycles__]={}}e[__cycles__][r]=n;if(!i.includes(e)){i.push(e)}return true}}}var c=trampoline(function e(r,n){if(r instanceof Pair){delete r.ref;delete r[__cycles__];u(r);n.push(r);var t=o(r,"car",r.car,n);var i=o(r,"cdr",r.cdr,n);if(!t){c(r.car,n.slice())}if(!i){return new Thunk(function(){return e(r.cdr,n.slice())})}}});function n(e,r){if(e[__cycles__][r]instanceof Pair){var n=t.indexOf(e[__cycles__][r]);e[__cycles__][r]="#".concat(n,"#")}}c(e,[]);var t=r.filter(function(e){return a.includes(e)});t.forEach(function(e,r){e[__ref__]="#".concat(r,"=")});i.forEach(function(e){n(e,"car");n(e,"cdr")})}var pair_to_string=function(){var f=function e(r,n){var t=[];if(r[__ref__]){t.push(r[__ref__]+"(")}else if(!n){t.push("(")}return t};var p=function e(r,n){if(is_debug());if(!n||r[__ref__]){return[")"]}return[]};return trampoline(function e(r,n){var t=arguments.length>2&&arguments[2]!==undefined$1?arguments[2]:{};var i=t.nested,a=i===void 0?false:i,u=t.result,o=u===void 0?[]:u,c=t.cont,s=c===void 0?function(){o.push.apply(o,toConsumableArray(p(r,a)))}:c;o.push.apply(o,toConsumableArray(f(r,a)));var l;if(r[__cycles__]&&r[__cycles__].car){l=r[__cycles__].car}else{l=toString(r.car,n,true,{result:o,cont:s})}if(l!==undefined$1){o.push(l)}return new Thunk(function(){if(r.cdr instanceof Pair){if(r[__cycles__]&&r[__cycles__].cdr){o.push(" . ");o.push(r[__cycles__].cdr)}else{if(r.cdr[__ref__]){o.push(" . ")}else{o.push(" ")}return e(r.cdr,n,{nested:true,result:o,cont:s})}}else if(r.cdr!==nil){o.push(" . ");o.push(toString(r.cdr,n))}},s)})}();Pair.prototype.toString=function(e){var r=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:{},n=r.nested,t=n===void 0?false:n;if(is_debug()){var i=[];pair_to_string(this,e,{result:i});return i.join("")}var a=[];if(this[__ref__]){a.push(this[__ref__]+"(")}else if(!t){a.push("(")}var u;if(this[__cycles__]&&this[__cycles__].car){u=this[__cycles__].car}else{u=toString(this.car,e,true)}if(u!==undefined$1){a.push(u)}if(this.cdr instanceof Pair){if(this[__cycles__]&&this[__cycles__].cdr){a.push(" . ");a.push(this[__cycles__].cdr)}else{if(this.cdr[__ref__]){a.push(" . ")}else{a.push(" ")}var o=this.cdr.toString(e,{nested:true});a.push(o)}}else if(this.cdr!==nil){a=a.concat([" . ",toString(this.cdr,e,true)])}if(!t||this[__ref__]){a.push(")")}return a.join("")};Pair.prototype.set=function(e,r){this[e]=r;if(r instanceof Pair){this.markCycles()}};Pair.prototype.append=function(e){if(e instanceof Array){return this.append(Pair.fromArray(e))}var r=this;if(r.car===undefined$1){if(e instanceof Pair){this.car=e.car;this.cdr=e.cdr}else{this.car=e}}else if(e!==nil){while(true){if(r instanceof Pair&&r.cdr!==nil){r=r.cdr}else{break}}r.cdr=e}return this};function abs(e){return e<0?-e:e}function seq_compare(e,r){var n=toArray(r),t=n[0],i=n.slice(1);while(i.length>0){var a=i,u=slicedToArray(a,1),o=u[0];if(!e(t,o)){return false}var c=i;var s=toArray(c);t=s[0];i=s.slice(1)}return true}function equal(e,r){if(is_function(e)){return is_function(r)&&unbind(e)===unbind(r)}else if(e instanceof LNumber){if(!(r instanceof LNumber)){return false}var n;if(e.__type__===r.__type__){if(e.__type__==="complex"){n=e.__im__.__type__===r.__im__.__type__&&e.__re__.__type__===r.__re__.__type__}else{n=true}return n&&e.cmp(r)===0}return false}else if(typeof e==="number"){if(typeof r!=="number"){return false}e=LNumber(e);r=LNumber(r);return e.__type__===r.__type__&&e.cmp(r)===0}else if(e instanceof LCharacter){if(!(r instanceof LCharacter)){return false}return e.__char__===r.__char__}else{return e===r}}function same_atom(e,r){if(type(e)!==type(r)){return false}if(!is_atom(e)){return false}if(e instanceof RegExp){return e.source===r.source}if(e instanceof LString){return e.valueOf()===r.valueOf()}return equal(e,r)}function is_atom(e){return e instanceof LSymbol||LString.isString(e)||e===nil||e===null||e instanceof LCharacter||e instanceof LNumber||e===true||e===false}var truncate=function(){if(Math.trunc){return Math.trunc}else{return function(e){if(e<0){return Math.ceil(e)}else{return Math.floor(e)}}}}();function Macro(e,r,n,t){if(typeof this!=="undefined"&&this.constructor!==Macro||typeof this==="undefined"){return new Macro(e,r)}typecheck("Macro",e,"string",1);typecheck("Macro",r,"function",2);if(n){if(t){this.__doc__=n}else{this.__doc__=trim_lines(n)}}this.__name__=e;this.__fn__=r}Macro.defmacro=function(e,r,n,t){var i=new Macro(e,r,n,t);i.__defmacro__=true;return i};Macro.prototype.invoke=function(e,r,n){var t=r.env,i=r.dynamic_scope,a=r.error;var u={dynamic_scope:i,error:a,macro_expand:n};var o=this.__fn__.call(t,e,u,this.__name__);return o};Macro.prototype.toString=function(){return"#")};var macro="define-macro";var recur_guard=-1e4;function macro_expand(a){return function(){var n=asyncToGenerator(regenerator.mark(function e(n,h){var t,d,i;return regenerator.wrap(function e(r){while(1){switch(r.prev=r.next){case 0:i=function e(){i=asyncToGenerator(regenerator.mark(function e(n,t,i){var a,u,o,c,s,l,f,p,_;return regenerator.wrap(function e(r){while(1){switch(r.prev=r.next){case 0:if(!(n instanceof Pair&&n.car instanceof LSymbol)){r.next=26;break}if(!n[__data__]){r.next=3;break}return r.abrupt("return",n);case 3:a=i.get(n.car,{throwError:false});if(!(a instanceof Macro&&a.__defmacro__)){r.next=26;break}u=a instanceof Syntax?n:n.cdr;r.next=8;return a.invoke(u,_objectSpread(_objectSpread({},h),{},{env:i}),true);case 8:o=r.sent;if(!(a instanceof Syntax)){r.next=17;break}c=o,s=c.expr,l=c.scope;if(!(s instanceof Pair)){r.next=16;break}if(!(t!==-1&&t<=1||t")}return"#"};Syntax.className="syntax";function extract_patterns(e,r,D,w){var n=arguments.length>4&&arguments[4]!==undefined$1?arguments[4]:{};var L={"...":{symbols:{},lists:[]},symbols:{}};var x=n.expansion,F=n.define;function A(e){if(is_debug()){console.log(e)}}A(D);function E(e,r){var n=arguments.length>2&&arguments[2]!==undefined$1?arguments[2]:[];var t=arguments.length>3&&arguments[3]!==undefined$1?arguments[3]:false;A({code:r&&toString(r,true),pattern:e&&toString(e,true)});if(is_atom(e)&&!(e instanceof LSymbol)){return same_atom(e,r)}if(e instanceof LSymbol&&D.includes(e.valueOf())){var i=x.ref(r);if(LSymbol.is(r,e)){if(typeof i==="undefined"){return true}return i===F||i===global_env}return false}if(e instanceof Pair&&e.car instanceof Pair&&e.car.cdr instanceof Pair&&LSymbol.is(e.car.cdr.car,w)){A(">> 0");if(r===nil){A({pattern:e.toString()});if(e.car.car instanceof LSymbol){if(e.car.cdr instanceof Pair&&LSymbol.is(e.car.cdr.car,w)){var a=e.car.car.valueOf();var u=e.lastPair();if(LSymbol.is(u.car,w)){L["..."].symbols[a]=null;return true}else{return false}}var o=e.car.car.valueOf();if(L["..."].symbols[o]){throw new Error("syntax: named ellipsis can only "+"appear onces")}L["..."].symbols[o]=r}}}if(e instanceof Pair&&e.cdr instanceof Pair&&LSymbol.is(e.cdr.car,w)){if(e.cdr.cdr!==nil){if(e.cdr.cdr instanceof Pair){var c=e.cdr.cdr.length();var s=r.length();var l=r;while(s-1>c){l=l.cdr;s--}var f=l.cdr;l.cdr=nil;if(!E(e.cdr.cdr,f,n,t)){return false}}}if(e.car instanceof LSymbol){var p=e.car.__name__;if(L["..."].symbols[p]&&!n.includes(p)&&!t){throw new Error("syntax: named ellipsis can only appear onces")}A(">> 1");if(r===nil){A(">> 2");if(t){A("NIL");L["..."].symbols[p]=nil}else{A("NULL");L["..."].symbols[p]=null}}else if(r instanceof Pair&&(r.car instanceof Pair||r.car===nil)){A(">> 3 "+t);if(t){if(L["..."].symbols[p]){var _=L["..."].symbols[p];if(_===nil){_=new Pair(nil,new Pair(r,nil))}else{_=_.append(new Pair(r,nil))}L["..."].symbols[p]=_}else{L["..."].symbols[p]=new Pair(r,nil)}}else{A(">> 4");L["..."].symbols[p]=new Pair(r,nil)}}else{A(">> 6");if(r instanceof Pair){A(">> 7 "+t);n.push(p);if(!L["..."].symbols[p]){L["..."].symbols[p]=new Pair(r,nil)}else{var h=L["..."].symbols[p];L["..."].symbols[p]=h.append(new Pair(r,nil))}A({IIIIII:L["..."].symbols[p].toString()})}else{A(">> 8");return false}}return true}else if(e.car instanceof Pair){var d=toConsumableArray(n);if(r===nil){A(">> 9");L["..."].lists.push(nil);return true}A(">> 10");var m=r;while(m instanceof Pair){if(!E(e.car,m.car,d,true)){return false}m=m.cdr}return true}return false}if(e instanceof LSymbol){if(LSymbol.is(e,w)){throw new Error("syntax: invalid usage of ellipsis")}A(">> 11");var v=e.__name__;if(D.includes(v)){return true}A({name:v,ellipsis:t});if(t){L["..."].symbols[v]=L["..."].symbols[v]||[];L["..."].symbols[v].push(r)}L.symbols[v]=r;if(!L.symbols[v]);return true}if(e instanceof Pair&&r instanceof Pair){A(">> 12");A({a:12,code:r&&r.toString(),pattern:e.toString()});if(r.cdr===nil){var y=e.car instanceof LSymbol&&e.cdr instanceof LSymbol;if(y){if(!E(e.car,r.car,n,t)){return false}A(">> 12 | 1");var b=e.cdr.valueOf();if(!(b in L.symbols)){L.symbols[b]=nil}b=e.car.valueOf();if(!(b in L.symbols)){L.symbols[b]=r.car}return true}}A({pattern:e.toString(),code:r.toString()});if(e.cdr instanceof Pair&&e.car instanceof LSymbol&&e.cdr.cdr instanceof Pair&&e.cdr.car instanceof LSymbol&&LSymbol.is(e.cdr.cdr.car,w)&&e.cdr.cdr.cdr instanceof Pair&&!LSymbol.is(e.cdr.cdr.cdr.car,w)&&E(e.car,r.car,n,t)&&E(e.cdr.cdr.cdr,r.cdr,n,t)){var g=e.cdr.car.__name__;A({pattern:e.car.toString(),code:r.car.toString(),name:g});if(D.includes(g)){return true}L["..."].symbols[g]=null;return true}A("recur");if(E(e.car,r.car,n,t)&&E(e.cdr,r.cdr,n,t)){return true}}else if(e===nil&&(r===nil||r===undefined$1)){return true}else if(e.car instanceof Pair&&LSymbol.is(e.car.car,w)){throw new Error("syntax: invalid usage of ellipsis")}else{return false}}if(E(e,r)){return L}}function clear_gensyms(e,i){function a(r){if(r instanceof Pair){if(!i.length){return r}var e=a(r.car);var n=a(r.cdr);return new Pair(e,n)}else if(r instanceof LSymbol){var t=i.find(function(e){return e.gensym===r});if(t){return LSymbol(t.name)}return r}else{return r}}return a(e)}function transform_syntax(){var e=arguments.length>0&&arguments[0]!==undefined$1?arguments[0]:{};var A=e.bindings,r=e.expr,E=e.scope,u=e.symbols,a=e.names,S=e.ellipsis;var o={};function c(e){if(e instanceof LSymbol){return true}return["string","symbol"].includes(_typeof_1(e))}function C(e){if(!c(e)){var r=type(e);throw new Error("syntax: internal error, need symbol got ".concat(r))}var n=e.valueOf();if(n===S){throw new Error("syntax: internal error, ellipis not transformed")}var t=_typeof_1(n);if(["string","symbol"].includes(t)){if(n in A.symbols){return A.symbols[n]}else if(t==="string"&&n.match(/\./)){var i=n.split(".");var a=i[0];if(a in A.symbols){return Pair.fromArray([LSymbol("."),A.symbols[a]].concat(i.slice(1).map(function(e){return LString(e)})))}}}if(u.includes(n)){return LSymbol(n)}return s(n)}function k(e){if(is_debug()){console.log(e)}}function s(e){if(!o[e]){var r=E.ref(e);var n=gensym(e);if(r){var t=E.get(e);E.set(n,t)}else{var i=E.get(e,{throwError:false});if(typeof i!=="undefined"){E.set(n,i)}}a.push({name:e,gensym:n});o[e]=n}return o[e]}function P(e,r,n){var t=arguments.length>3&&arguments[3]!==undefined$1?arguments[3]:function(){};var i=n.nested;k(" ==> "+e.toString(true));k(r);if(e instanceof LSymbol){var a=e.valueOf();k("[t 1");if(r[a]){if(r[a]instanceof Pair){var u=r[a],o=u.car,c=u.cdr;if(i){var s=o.car,l=o.cdr;if(l!==nil){t(a,new Pair(l,nil))}return s}if(c!==nil){t(a,c)}return o}else if(r[a]instanceof Array){t(a,r[a].slice(1));return r[a][0]}}return C(a)}if(e instanceof Pair){if(e.car instanceof LSymbol&&e.cdr instanceof Pair&&LSymbol.is(e.cdr.car,S)){k("[t 2");var f=e.car.valueOf();var p=r[f];k({expr:e.toString(true),name:f,bindings:r,item:p});if(p===null){return}else if(p){k({b:r[f].toString()});if(p instanceof Pair){k("[t 2 Pair "+i);k({______:p.toString()});var _=p.car,h=p.cdr;if(i){if(h!==nil){k("|| next 1");t(f,h)}k({car:_.toString()});return _}else{if(_.cdr!==nil){k("|| next 2");t(f,new Pair(_.cdr,h))}k({car:_.car.toString()});return _.car}}else if(p instanceof Array){k("[t 2 Array "+i);if(i){t(f,p.slice(1));return Pair.fromArray(p)}else{var d=p.slice(1);if(d.length){t(f,d)}return p[0]}}else{return p}}}k("[t 3 recur "+e.toString());var m=P(e.car,r,n,t);var v=P(e.cdr,r,n,t);return new Pair(m,v)}return e}function N(r,n){var e=Object.values(r);var t=Object.getOwnPropertySymbols(r);if(t.length){e.push.apply(e,toConsumableArray(t.map(function(e){return r[e]})))}return e.length&&e.every(function(e){if(e===null){return!n}return e instanceof Pair||e===nil||e instanceof Array&&e.length})}function O(e){return Object.keys(e).concat(Object.getOwnPropertySymbols(e))}function B(i){var e=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:{},r=e.disabled;k("traverse>> "+i.toString());if(i instanceof Pair){if(!r&&i.car instanceof Pair&&LSymbol.is(i.car.car,S)){return B(i.car.cdr,{disabled:true})}if(i.cdr instanceof Pair&&LSymbol.is(i.cdr.car,S)&&!r){k(">> 1");var n=A["..."].symbols;var t=Object.values(n);if(t.length&&t.every(function(e){return e===null})){return B(i.cdr.cdr,{disabled:r})}var a=O(n);var u=i.car instanceof LSymbol&&LSymbol.is(i.cdr.cdr.car,S);if(i.car instanceof Pair||u){if(A["..."].lists[0]===nil){return nil}var o=i.car;if(u){o=new Pair(i.car,new Pair(i.cdr.car,nil))}k(">> 2");var c;if(a.length){k(">> 2 (a)");var s=_objectSpread({},n);c=nil;var l=function e(){if(!N(s)){return"break"}var t={};var r=function e(r,n){t[r]=n};var n=P(o,s,{nested:true},r);if(n!==undefined$1){if(u){if(c===nil){c=n}else{c=c.append(n)}}else{c=new Pair(n,c)}}s=t};while(true){var f=l();if(f==="break")break}if(c!==nil&&!u){c=c.reverse()}if(i.cdr.cdr!==nil&&!LSymbol.is(i.cdr.cdr.car,S)){var p=B(i.cdr.cdr,{disabled:r});return c.append(p)}return c}else{k(">> 3");var _=P(i.car,n,{nested:true});if(_){return new Pair(_,nil)}return nil}}else if(i.car instanceof LSymbol){k(">> 4");if(LSymbol.is(i.cdr.cdr.car,S)){k(">> 4 (a)")}else{k(">> 4 (b)")}var h=i.car.__name__;var d=defineProperty({},h,n[h]);var m=n[h]===null;var v=nil;var y=function e(){if(!N(d,true)){k({bind:d});return"break"}var t={};var r=function e(r,n){t[r]=n;if(is_debug()){console.log({NEWBIND:t[r].toString()})}};var n=P(i,d,{nested:false},r);k({value:n.toString()});if(typeof n!=="undefined"){v=new Pair(n,v)}d=t};while(true){var b=y();if(b==="break")break}if(v!==nil){v=v.reverse()}if(i.cdr instanceof Pair){if(i.cdr.cdr instanceof Pair||i.cdr.cdr instanceof LSymbol){var g=B(i.cdr.cdr,{disabled:r});if(m){return g}k("<<<< 1");v.append(g)}}k("<<<< 2");return v}}var D=B(i.car,{disabled:r});var w;var L;if(i.car instanceof LSymbol){var x=E.get(i.car,{throwError:false});L=x instanceof Macro&&x.__name__==="syntax-rules"}if(L){if(i.cdr.car instanceof LSymbol){w=new Pair(B(i.cdr.car,{disabled:r}),new Pair(i.cdr.cdr.car,B(i.cdr.cdr.cdr,{disabled:r})))}else{w=new Pair(i.cdr.car,B(i.cdr.cdr,{disabled:r}))}}else{w=B(i.cdr,{disabled:r})}k({a:true,car:toString(i.car),cdr:toString(i.cdr),head:toString(D),rest:toString(w)});return new Pair(D,w)}if(i instanceof LSymbol){if(r&&LSymbol.is(i,S)){return i}var F=C(i);if(typeof F!=="undefined"){return F}}return i}return B(r,{})}function is_null(e){return typeof e==="undefined"||e===nil||e===null}function is_function(e){return typeof e==="function"&&typeof e.bind==="function"}function is_promise(e){if(e instanceof QuotedPromise){return false}if(e instanceof Promise){return true}return e&&typeof e!=="undefined"&&is_function(e.then)}function box(e){switch(_typeof_1(e)){case"string":return LString(e);case"number":if(!Number.isNaN(e)){return LNumber(e)}}return e}function map_object(t,i){var e=Object.getOwnPropertyNames(t);var r=Object.getOwnPropertySymbols(t);e.concat(r).forEach(function(e){var r=i(t[e]);var n=Object.getOwnPropertyDescriptor(t,e);if(!n||n.writable&&t[e]!==r){t[e]=r}});return t}function unbox(r){var e=[LString,LCharacter,LNumber].some(function(e){return r instanceof e});if(e){return r.valueOf()}if(r instanceof Array){return r.map(unbox)}if(is_plain_object(r)){return map_object(r,unbox)}return r}function patch_value(e,r){if(e instanceof Pair){e.markCycles();return quote(e)}if(is_function(e)){if(r){return bind(e,r)}}return box(e)}function unbind(e){if(is_bound(e)){return e[__fn__]}return e}function bind(r,e){if(r[Symbol["for"]("__bound__")]){return r}var n=r.bind(e);var t=Object.getOwnPropertyNames(r).filter(filter_fn_names);t.forEach(function(e){try{n[e]=r[e]}catch(e){}});hidden_prop(n,"__fn__",r);hidden_prop(n,"__context__",e);hidden_prop(n,"__bound__",true);if(is_native_function(r)){hidden_prop(n,"__native__",true)}if(is_plain_object(e)&&r[__lambda__]){hidden_prop(n,"__method__",true)}n.valueOf=function(){return r};return n}function is_object_bound(e){return is_bound(e)&&e[Symbol["for"]("__context__")]===Object}function is_bound(e){return!!(is_function(e)&&e[__fn__])}function lips_context(e){if(is_function(e)){var r=e[__context__];if(r&&(r===lips||r.constructor&&r.constructor.__class__)){return true}}return false}function is_port(e){return e instanceof InputPort||e instanceof OutputPort}function is_port_method(e){if(is_function(e)){if(is_port(e[__context__])){return true}}return false}var __context__=Symbol["for"]("__context__");var __fn__=Symbol["for"]("__fn__");var __data__=Symbol["for"]("__data__");var __ref__=Symbol["for"]("__ref__");var __cycles__=Symbol["for"]("__cycles__");var __class__=Symbol["for"]("__class__");var __method__=Symbol["for"]("__method__");var __prototype__=Symbol["for"]("__prototype__");var __lambda__=Symbol["for"]("__lambda__");var exluded_names=["name","length","caller","callee","arguments","prototype"];function filter_fn_names(e){return!exluded_names.includes(e)}function hidden_prop(e,r,n){Object.defineProperty(e,Symbol["for"](r),{get:function e(){return n},set:function e(){},configurable:false,enumerable:false})}function setFnLength(r,n){try{Object.defineProperty(r,"length",{get:function e(){return n}});return r}catch(e){var t=new Array(n).fill(0).map(function(e,r){return"a"+r}).join(",");var i=new Function("f","return function(".concat(t,") {\n return f.apply(this, arguments);\n };"));return i(r)}}function is_native_function(e){var r=Symbol["for"]("__native__");return is_function(e)&&e.toString().match(/\{\s*\[native code\]\s*\}/)&&(e.name.match(/^bound /)&&e[r]===true||!e.name.match(/^bound /)&&!e[r])}function let_macro(e){var h;switch(e){case Symbol["for"]("letrec"):h="letrec";break;case Symbol["for"]("let"):h="let";break;case Symbol["for"]("let*"):h="let*";break;default:throw new Error("Invalid let_macro value")}return Macro.defmacro(h,function(r,e){var a=e.dynamic_scope,u=e.error,n=e.macro_expand;var o;if(r.car instanceof LSymbol){if(!(r.cdr.car instanceof Pair||r.cdr.car===nil)){throw new Error("let require list of pairs")}var t;if(r.cdr.car===nil){o=nil;t=nil}else{t=r.cdr.car.map(function(e){return e.car});o=r.cdr.car.map(function(e){return e.cdr.car})}return Pair.fromArray([LSymbol("letrec"),[[r.car,Pair(LSymbol("lambda"),Pair(t,r.cdr.cdr))]],Pair(r.car,o)])}else if(n){return}var c=this;o=global_env.get("list->array")(r.car);var s=c.inherit(h);var l,f;if(h==="let*"){f=s}else if(h==="let"){l=[]}var p=0;function _(){var e=new Pair(new LSymbol("begin"),r.cdr);return evaluate(e,{env:s,dynamic_scope:a,error:u})}return function r(){var n=o[p++];if(a){a=h==="let*"?s:c}if(!n){if(l&&l.length){var e=l.map(function(e){return e.value});var t=e.filter(is_promise);if(t.length){return Promise.all(e).then(function(e){for(var r=0,n=e.length;r1&&arguments[1]!==undefined$1?arguments[1]:{},n=r.dynamic_scope,t=r.error;var i=this;if(n){n=this}var a=e;var u=[];while(a instanceof Pair){u.push(evaluate(a.car,{env:i,dynamic_scope:n,error:t}));a=a.cdr}var o=u.filter(is_promise).length;if(o){return Promise.all(u).then(c.bind(this))}else{return c.call(this,u)}})}function guardMathCall(e){for(var r=arguments.length,n=new Array(r>1?r-1:0),t=1;t2?t-2:0),a=2;a1&&arguments[1]!==undefined$1?arguments[1]:null;return function(){for(var e=arguments.length,r=new Array(e),n=0;n1?e-1:0),n=1;n=u){return a.apply(this,t)}else{return i}}return i.apply(this,arguments)}}function limit(t,i){typecheck("limit",i,"function",2);return function(){for(var e=arguments.length,r=new Array(e),n=0;n1){e=e.toLowerCase();if(LCharacter.__names__[e]){this.__name__=e;this.__char__=LCharacter.__names__[e]}else{throw new Error("Internal: Unknown named character")}}else{this.__char__=e;var r=LCharacter.__rev_names__[e];if(r){this.__name__=r}}}LCharacter.__names__=characters;LCharacter.__rev_names__={};Object.keys(LCharacter.__names__).forEach(function(e){var r=LCharacter.__names__[e];LCharacter.__rev_names__[r]=e});LCharacter.prototype.toUpperCase=function(){return LCharacter(this.__char__.toUpperCase())};LCharacter.prototype.toLowerCase=function(){return LCharacter(this.__char__.toLowerCase())};LCharacter.prototype.toString=function(){return"#\\"+(this.__name__||this.__char__)};LCharacter.prototype.valueOf=function(){return this.__char__};function LString(e){if(typeof this!=="undefined"&&!(this instanceof LString)||typeof this==="undefined"){return new LString(e)}if(e instanceof Array){this.__string__=e.map(function(e,r){typecheck("LString",e,"character",r+1);return e.toString()}).join("")}else{this.__string__=e.valueOf()}}{var ignore=["length","constructor"];var _keys=Object.getOwnPropertyNames(String.prototype).filter(function(e){return!ignore.includes(e)});var wrap=function e(t){return function(){for(var e=arguments.length,r=new Array(e),n=0;n0){n.push(this.__string__.substring(0,e))}n.push(r);if(e1&&arguments[1]!==undefined$1?arguments[1]:false;if(e instanceof LNumber){return e}if(typeof this!=="undefined"&&!(this instanceof LNumber)||typeof this==="undefined"){return new LNumber(e,r)}if(typeof e==="undefined"){throw new Error("Invalid LNumber constructor call")}var n=LNumber.getType(e);if(LNumber.types[n]){return LNumber.types[n](e,r)}var t=e instanceof Array&&LString.isString(e[0])&&LNumber.isNumber(e[1]);if(e instanceof LNumber){return LNumber(e.value)}if(!LNumber.isNumber(e)&&!t){throw new Error("You can't create LNumber from ".concat(type(e)))}if(e===null){e=0}var i;if(t){var a=e,u=slicedToArray(a,2),o=u[0],c=u[1];if(o instanceof LString){o=o.valueOf()}if(c instanceof LNumber){c=c.valueOf()}var s=o.match(/^([+-])/);var l=false;if(s){o=o.replace(/^[+-]/,"");if(s[1]==="-"){l=true}}}if(typeof BigInt!=="undefined"){if(typeof e!=="bigint"){if(t){var f;switch(c){case 8:f="0o";break;case 16:f="0x";break;case 2:f="0b";break;case 10:f="";break}if(typeof f==="undefined"){var p=BigInt(c);i=toConsumableArray(o).map(function(e,r){return BigInt(parseInt(e,c))*Math.pow(p,BigInt(r))}).reduce(function(e,r){return e+r})}else{i=BigInt(f+o)}}else{i=BigInt(e)}if(l){i*=BigInt(-1)}}else{i=e}return LBigInteger(i,true)}else if(typeof BN!=="undefined"&&!(e instanceof BN)){if(e instanceof Array){return LBigInteger(construct(BN,toConsumableArray(e)))}return LBigInteger(new BN(e))}else if(t){this.value=parseInt(o,c)}else{this.value=e}}LNumber.types={float:function e(r){var n=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:false;return new LFloat(r,n)},complex:function e(r){var n=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:false;if(!LNumber.isComplex(r)){r={im:0,re:r}}return new LComplex(r,n)},rational:function e(r){var n=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:false;if(!LNumber.isRational(r)){r={num:r,denom:1}}return new LRational(r,n)}};LNumber.prototype.gcd=function(e){var r=this.abs();e=e.abs();if(e.cmp(r)===1){var n=r;r=e;e=n}while(true){r=r.rem(e);if(r.cmp(0)===0){return e}e=e.rem(r);if(e.cmp(0)===0){return r}}};LNumber.isFloat=function e(r){return r instanceof LFloat||Number(r)===r&&r%1!==0};LNumber.isNumber=function(e){return e instanceof LNumber||!Number.isNaN(e)&&LNumber.isNative(e)||LNumber.isBN(e)};LNumber.isComplex=function(e){var r=e instanceof LComplex||LNumber.isNumber(e.im)&&LNumber.isNumber(e.re);return r};LNumber.isRational=function(e){return e instanceof LRational||LNumber.isNumber(e.num)&&LNumber.isNumber(e.denom)};LNumber.isInteger=function(e){if(!(LNumber.isNative(e)||e instanceof LNumber)){return false}if(LNumber.isFloat(e)){return false}if(LNumber.isRational(e)){return false}if(LNumber.isComplex(e)){return false}return true};LNumber.isNative=function(e){return typeof e==="bigint"||typeof e==="number"};LNumber.isBigInteger=function(e){return e instanceof LBigInteger||typeof e==="bigint"||LNumber.isBN(e)};LNumber.isBN=function(e){return typeof BN!=="undefined"&&e instanceof BN};LNumber.getArgsType=function(e,r){if(e instanceof LFloat||r instanceof LFloat){return LFloat}if(e instanceof LBigInteger||r instanceof LBigInteger){return LBigInteger}return LNumber};LNumber.prototype.toString=LNumber.prototype.toJSON=function(e){if(e>2&&e<36){return this.value.toString(e)}return this.value.toString()};LNumber.prototype.asType=function(e){var r=LNumber.getType(this);return LNumber.types[r]?LNumber.types[r](e):LNumber(e)};LNumber.prototype.isBigNumber=function(){return typeof this.value==="bigint"||typeof BN!=="undefined"&&!(this.value instanceof BN)};["floor","ceil","round"].forEach(function(e){LNumber.prototype[e]=function(){if(this["float"]||LNumber.isFloat(this.value)){return LNumber(Math[e](this.value))}else{return LNumber(Math[e](this.valueOf()))}}});LNumber.prototype.valueOf=function(){if(LNumber.isNative(this.value)){return Number(this.value)}else if(LNumber.isBN(this.value)){return this.value.toNumber()}};var matrix=function(){var e=function e(r,n){return[r,n]};return{bigint:{bigint:e,float:function e(r,n){return[LFloat(r.valueOf()),n]},rational:function e(r,n){return[{num:r,denom:1},n]},complex:function e(r,n){return[{im:0,re:r},n]}},float:{bigint:function e(r,n){return[r,n&&LFloat(n.valueOf())]},float:e,rational:function e(r,n){return[r,n&&LFloat(n.valueOf())]},complex:function e(r,n){return[{re:r,im:LFloat(0)},n]}},complex:{bigint:r("bigint"),float:r("float"),rational:r("rational"),complex:function e(r,n){var t=LNumber.coerce(r.__re__,n.__re__),i=slicedToArray(t,2),a=i[0],u=i[1];var o=LNumber.coerce(r.__im__,n.__im__),c=slicedToArray(o,2),s=c[0],l=c[1];return[{im:s,re:a},{im:l,re:u}]}},rational:{bigint:function e(r,n){return[r,n&&{num:n,denom:1}]},float:function e(r,n){return[LFloat(r.valueOf()),n]},rational:e,complex:function e(r,n){return[{im:coerce(r.__type__,n.__im__.__type__,0),re:coerce(r.__type__,n.__re__.__type__,r)},{im:coerce(r.__type__,n.__im__.__type__,n.__im__),re:coerce(r.__type__,n.__re__.__type__,n.__re__)}]}}};function r(n){return function(e,r){return[{im:coerce(n,e.__im__.__type__,e.__im__),re:coerce(n,e.__re__.__type__,e.__re__)},{im:coerce(n,e.__im__.__type__,0),re:coerce(n,r.__type__,r)}]}}}();function coerce(e,r,n){return matrix[e][r](n)[0]}LNumber.coerce=function(e,r){function n(e){if(e==="integer"){return"bigint"}return e}var t=n(LNumber.getType(e));var i=n(LNumber.getType(r));if(!matrix[t]){throw new Error("LNumber::coerce unknown lhs type ".concat(t))}else if(!matrix[t][i]){throw new Error("LNumber::coerce unknown rhs type ".concat(i))}return matrix[t][i](e,r).map(function(e){return LNumber(e,true)})};LNumber.prototype.coerce=function(e){if(!(typeof e==="number"||e instanceof LNumber)){throw new Error("LNumber: you can't coerce ".concat(type(e)))}if(typeof e==="number"){e=LNumber(e)}return LNumber.coerce(this,e)};LNumber.getType=function(e){if(e instanceof LNumber){return e.__type__}if(LNumber.isFloat(e)){return"float"}if(LNumber.isComplex(e)){return"complex"}if(LNumber.isRational(e)){return"rational"}if(typeof e==="number"){return"integer"}if(typeof BigInt!=="undefined"&&typeof e!=="bigint"||typeof BN!=="undefined"&&!(e instanceof BN)){return"bigint"}};LNumber.prototype.isFloat=function(){return!!(LNumber.isFloat(this.value)||this["float"])};var mapping={add:"+",sub:"-",mul:"*",div:"/",rem:"%",or:"|",and:"&",neg:"~",shl:">>",shr:"<<"};var rev_mapping={};Object.keys(mapping).forEach(function(r){rev_mapping[mapping[r]]=r;LNumber.prototype[r]=function(e){return this.op(mapping[r],e)}});LNumber._ops={"*":function e(r,n){return r*n},"+":function e(r,n){return r+n},"-":function e(r,n){if(typeof n==="undefined"){return-r}return r-n},"/":function e(r,n){return r/n},"%":function e(r,n){return r%n},"|":function e(r,n){return r|n},"&":function e(r,n){return r&n},"~":function e(r){return~r},">>":function e(r,n){return r>>n},"<<":function e(r,n){return r<1&&arguments[1]!==undefined$1?arguments[1]:false;if(typeof this!=="undefined"&&!(this instanceof LComplex)||typeof this==="undefined"){return new LComplex(e,r)}if(e instanceof LComplex){return LComplex({im:e.__im__,re:e.__re__})}if(LNumber.isNumber(e)&&r){if(!r){return Number(e)}}else if(!LNumber.isComplex(e)){throw new Error("Invalid constructor call for LComplex")}var n=e.im instanceof LNumber?e.im:LNumber(e.im);var t=e.re instanceof LNumber?e.re:LNumber(e.re);this.__im__=n;this.__re__=t;this.__type__="complex"}LComplex.prototype=Object.create(LNumber.prototype);LComplex.prototype.constructor=LComplex;LComplex.prototype.toRational=function(e){if(LNumber.isFloat(this.__im__)&&LNumber.isFloat(this.__re__)){var r=LFloat(this.__im__).toRational(e);var n=LFloat(this.__re__).toRational(e);return LComplex({im:r,re:n})}return this};LComplex.prototype.add=function(e){return this.complex_op(e,function(e,r,n,t){return{re:e.add(r),im:n.add(t)}})};LComplex.prototype.factor=function(){if(this.__im__ instanceof LFloat||this.__im__ instanceof LFloat){var e=this.__re__,r=this.__im__;var n,t;if(e instanceof LFloat){n=e.toRational().mul(e.toRational())}else{n=e.mul(e)}if(r instanceof LFloat){t=r.toRational().mul(r.toRational())}else{t=r.mul(r)}return n.add(t)}else{return this.__re__.mul(this.__re__).add(this.__im__.mul(this.__im__))}};LComplex.prototype.modulus=function(){return this.factor().sqrt()};LComplex.prototype.sqrt=function(){var e=this.modulus();var r,n;if(e.cmp(0)===0){r=n=e}else if(this.__re__.cmp(0)===1){r=LFloat(.5).mul(e.add(this.__re__)).sqrt();n=this.__im__.div(r).div(2)}else{n=LFloat(.5).mul(e.sub(this.__re__)).sqrt();if(this.__im__.cmp(0)===-1){n=n.sub()}r=this.__im__.div(n).div(2)}return LComplex({im:n,re:r})};LComplex.prototype.div=function(e){if(LNumber.isNumber(e)&&!LNumber.isComplex(e)){e=LComplex({im:0,re:e})}else if(!LNumber.isComplex(e)){throw new Error("[LComplex::add] Invalid value")}var r=this.coerce(e),n=slicedToArray(r,2),t=n[0],i=n[1];var a=LComplex({re:i.__re__,im:i.__im__.sub()});var u=i.factor().valueOf();var o=t.mul(a);var c=o.__re__.op("/",u);var s=o.__im__.op("/",u);return LComplex({re:c,im:s})};LComplex.prototype.sub=function(e){return this.complex_op(e,function(e,r,n,t){return{re:e.sub(r),im:n.add(t)}})};LComplex.prototype.mul=function(e){return this.complex_op(e,function(e,r,n,t){var i={re:e.mul(r).sub(n.mul(t)),im:e.mul(t).add(r.mul(n))};return i})};LComplex.prototype.complex_op=function(e,r){if(LNumber.isNumber(e)&&!LNumber.isComplex(e)){if(!(e instanceof LNumber)){e=LNumber(e)}var n=e.asType(0);e={__im__:n,__re__:e}}else if(!LNumber.isComplex(e)){throw new Error("[LComplex::add] Invalid value")}var t=e.__re__ instanceof LNumber?e.__re__:this.__re__.asType(e.__re__);var i=e.__im__ instanceof LNumber?e.__im__:this.__im__.asType(e.__im__);var a=r(this.__re__,t,this.__im__,i);if("im"in a&&"re"in a){var u=LComplex(a,true);return u}return a};LComplex._op={"+":"add","-":"sub","*":"mul","/":"div"};LComplex.prototype._op=function(e,r){var n=LComplex._op[e];return this[n](r)};LComplex.prototype.cmp=function(e){var r=this.coerce(e),n=slicedToArray(r,2),t=n[0],i=n[1];var a=t.__re__.coerce(i.__re__),u=slicedToArray(a,2),o=u[0],c=u[1];var s=o.cmp(c);if(s!==0){return s}else{var l=t.__im__.coerce(i.__im__),f=slicedToArray(l,2),p=f[0],_=f[1];return p.cmp(_)}};LComplex.prototype.valueOf=function(){return[this.__re__,this.__im__].map(function(e){return e.valueOf()})};LComplex.prototype.toString=function(){var e;if(this.__re__.cmp(0)!==0){e=[this.__re__.toString()]}else{e=[]}e.push(this.__im__.cmp(0)<0?"-":"+");e.push(this.__im__.toString().replace(/^-/,""));e.push("i");return e.join("")};function LFloat(e){if(typeof this!=="undefined"&&!(this instanceof LFloat)||typeof this==="undefined"){return new LFloat(e)}if(!LNumber.isNumber(e)){throw new Error("Invalid constructor call for LFloat")}if(e instanceof LNumber){return LFloat(e.valueOf())}if(typeof e==="number"){this.value=e;this.__type__="float"}}LFloat.prototype=Object.create(LNumber.prototype);LFloat.prototype.constructor=LFloat;LFloat.prototype.toString=function(){var e=this.value.toString();if(!LNumber.isFloat(this.value)&&!e.match(/e/i)){return e+".0"}return e.replace(/^([0-9]+)e/,"$1.0e")};LFloat.prototype._op=function(e,r){if(r instanceof LNumber){r=r.value}var n=LNumber._ops[e];if(e==="/"&&this.value===0&&r===0){return NaN}return LFloat(n(this.value,r))};LFloat.prototype.toRational=function(){var e=arguments.length>0&&arguments[0]!==undefined$1?arguments[0]:null;if(e===null){return toRational(this.value.valueOf())}return approxRatio(e.valueOf())(this.value.valueOf())};var toRational=approxRatio(1e-10);function approxRatio(t){return function(e){var r=function e(t,r,n){var i=function e(r,n){return n0){i=simplest_rational2(t,n)}else if(t.cmp(n)<=0){i=n}else if(n.cmp(0)>0){i=simplest_rational2(n,t)}else if(r.cmp(0)<0){i=LNumber(simplest_rational2(t.sub(),n.sub())).sub()}else{i=LNumber(0)}if(LNumber.isFloat(r)||LNumber.isFloat(e)){return LFloat(i)}return i}function simplest_rational2(e,r){var n=LNumber(e).floor();var t=LNumber(r).floor();if(e.cmp(n)<1){return n}else if(n.cmp(t)===0){var i=LNumber(1).div(r.sub(t));var a=LNumber(1).div(e.sub(n));return n.add(LNumber(1).div(simplest_rational2(i,a)))}else{return n.add(LNumber(1))}}function LRational(e){var r=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:false;if(typeof this!=="undefined"&&!(this instanceof LRational)||typeof this==="undefined"){return new LRational(e,r)}if(!LNumber.isRational(e)){throw new Error("Invalid constructor call for LRational")}var n=LNumber(e.num);var t=LNumber(e.denom);if(!r&&t.cmp(0)!==0){var i=n.op("%",t).cmp(0)===0;if(i){return LNumber(n.div(t))}}this.num=n;this.denom=t;this.__type__="rational"}LRational.prototype=Object.create(LNumber.prototype);LRational.prototype.constructor=LRational;LRational.prototype.pow=function(e){var r=e.cmp(0);if(r===0){return LNumber(1)}if(r===-1){e=e.sub();var n=this.denom.pow(e);var t=this.num.pow(e);return LRational({num:n,denom:t})}var i=this;e=e.valueOf();while(e>1){i=i.mul(this);e--}return i};LRational.prototype.sqrt=function(){var e=this.num.sqrt();var r=this.denom.sqrt();if(e instanceof LFloat){e=(readOnlyError("num"),e.toRational())}if(r instanceof LFloat){r=(readOnlyError("denom"),r.toRational())}return LRational({num:e,denom:r})};LRational.prototype.abs=function(){var e=this.num;var r=this.denom;if(e.cmp(0)===-1){e=e.sub()}if(r.cmp(0)!==1){r=r.sub()}return LRational({num:e,denom:r})};LRational.prototype.cmp=function(e){return LNumber(this.valueOf(),true).cmp(e)};LRational.prototype.toString=function(){var e=this.num.gcd(this.denom);var r,n;if(e.cmp(1)!==0){r=this.num.div(e);if(r instanceof LRational){r=LNumber(r.valueOf(true))}n=this.denom.div(e);if(n instanceof LRational){n=LNumber(n.valueOf(true))}}else{r=this.num;n=this.denom}var t=this.cmp(0)<0;if(t){if(r.abs().cmp(n.abs())===0){return r.toString()}}else if(r.cmp(n)===0){return r.toString()}return r.toString()+"/"+n.toString()};LRational.prototype.valueOf=function(e){if(this.denom.cmp(0)===0){if(this.num.cmp(0)<0){return Number.NEGATIVE_INFINITY}return Number.POSITIVE_INFINITY}if(e){return LNumber._ops["/"](this.num.value,this.denom.value)}return LFloat(this.num.valueOf()).div(this.denom.valueOf())};LRational.prototype.mul=function(e){if(!(e instanceof LNumber)){e=LNumber(e)}if(LNumber.isRational(e)){var r=this.num.mul(e.num);var n=this.denom.mul(e.denom);return LRational({num:r,denom:n})}var t=LNumber.coerce(this,e),i=slicedToArray(t,2),a=i[0],u=i[1];return a.mul(u)};LRational.prototype.div=function(e){if(!(e instanceof LNumber)){e=LNumber(e)}if(LNumber.isRational(e)){var r=this.num.mul(e.denom);var n=this.denom.mul(e.num);return LRational({num:r,denom:n})}var t=LNumber.coerce(this,e),i=slicedToArray(t,2),a=i[0],u=i[1];var o=a.div(u);return o};LRational.prototype._op=function(e,r){return this[rev_mapping[e]](r)};LRational.prototype.sub=function(e){if(typeof e==="undefined"){return this.mul(-1)}if(!(e instanceof LNumber)){e=LNumber(e)}if(LNumber.isRational(e)){var r=e.num.sub();var n=e.denom;return this.add(LRational({num:r,denom:n}))}if(!(e instanceof LNumber)){e=LNumber(e).sub()}else{e=e.sub()}var t=LNumber.coerce(this,e),i=slicedToArray(t,2),a=i[0],u=i[1];return a.add(u)};LRational.prototype.add=function(e){if(!(e instanceof LNumber)){e=LNumber(e)}if(LNumber.isRational(e)){var r=this.denom;var n=e.denom;var t=this.num;var i=e.num;var a,u;if(r!==n){u=n.mul(t).add(i.mul(r));a=r.mul(n)}else{u=t.add(i);a=r}return LRational({num:u,denom:a})}if(LNumber.isFloat(e)){return LFloat(this.valueOf()).add(e)}var o=LNumber.coerce(this,e),c=slicedToArray(o,2),s=c[0],l=c[1];return s.add(l)};function LBigInteger(e,r){if(typeof this!=="undefined"&&!(this instanceof LBigInteger)||typeof this==="undefined"){return new LBigInteger(e,r)}if(e instanceof LBigInteger){return LBigInteger(e.value,e._native)}if(!LNumber.isBigInteger(e)){throw new Error("Invalid constructor call for LBigInteger")}this.value=e;this._native=r;this.__type__="bigint"}LBigInteger.prototype=Object.create(LNumber.prototype);LBigInteger.prototype.constructor=LBigInteger;LBigInteger.bn_op={"+":"iadd","-":"isub","*":"imul","/":"idiv","%":"imod","|":"ior","&":"iand","~":"inot","<<":"ishrn",">>":"ishln"};LBigInteger.prototype._op=function(e,r){if(typeof r==="undefined"){if(LNumber.isBN(this.value)){e=LBigInteger.bn_op[e];return LBigInteger(this.value.clone()[e](),false)}return LBigInteger(LNumber._ops[e](this.value),true)}if(LNumber.isBN(this.value)&&LNumber.isBN(r.value)){e=LBigInteger.bn_op[e];return LBigInteger(this.value.clone()[e](r),false)}var n=LNumber._ops[e](this.value,r.value);if(e==="/"){var t=this.op("%",r).cmp(0)===0;if(t){return LNumber(n)}return LRational({num:this,denom:r})}return LBigInteger(n,true)};LBigInteger.prototype.sqrt=function(){var e;var r=this.cmp(0)<0;if(LNumber.isNative(this.value)){e=LNumber(Math.sqrt(r?-this.valueOf():this.valueOf()))}else if(LNumber.isBN(this.value)){e=r?this.value.neg().sqrt():this.value.sqrt()}if(r){return LComplex({re:0,im:e})}return e};function InputPort(e){var t=this;if(typeof this!=="undefined"&&!(this instanceof InputPort)||typeof this==="undefined"){return new InputPort(e)}typecheck("InputPort",e,"function");this._read=e;this._with_parser=this._with_init_parser.bind(this,asyncToGenerator(regenerator.mark(function e(){var n;return regenerator.wrap(function e(r){while(1){switch(r.prev=r.next){case 0:if(t.char_ready()){r.next=5;break}r.next=3;return t._read();case 3:n=r.sent;t.__parser__=new Parser(n,{env:t});case 5:return r.abrupt("return",t.__parser__);case 6:case"end":return r.stop()}}},e)})));this.char_ready=function(){return this.__parser__&&this.__parser__.__lexer__.peek()!==eof};this._make_defaults()}InputPort.prototype._make_defaults=function(){this.read=this._with_parser(function(e){return e.read_object()});this.read_line=this._with_parser(function(e){return e.__lexer__.read_line()});this.read_char=this._with_parser(function(e){return e.__lexer__.read_char()});this.read_string=this._with_parser(function(e,r){if(!LNumber.isInteger(r)){var n=LNumber.getType(r);typeErrorMessage("read-string",n,"integer")}return e.__lexer__.read_string(r.valueOf())});this.peek_char=this._with_parser(function(e){return e.__lexer__.peek_char()})};InputPort.prototype._with_init_parser=function(o,c){var s=this;return function(){var e=asyncToGenerator(regenerator.mark(function e(){var n,t,i,a,u=arguments;return regenerator.wrap(function e(r){while(1){switch(r.prev=r.next){case 0:r.next=2;return o.call(s);case 2:n=r.sent;for(t=u.length,i=new Array(t),a=0;a"};function OutputPort(e){if(typeof this!=="undefined"&&!(this instanceof OutputPort)||typeof this==="undefined"){return new OutputPort(e)}typecheck("OutputPort",e,"function");this.write=e}OutputPort.prototype.is_open=function(){return this._closed!==true};OutputPort.prototype.close=function(){Object.defineProperty(this,"_closed",{get:function e(){return true},set:function e(){},configurable:false,enumerable:false});this.write=function(){throw new Error("output-port: port is closed")}};OutputPort.prototype.toString=function(){return"#"};function OutputStringPort(r){var n=this;if(typeof this!=="undefined"&&!(this instanceof OutputStringPort)||typeof this==="undefined"){return new OutputStringPort(r)}typecheck("OutputStringPort",r,"function");this._buffer=[];this.write=function(e){if(!LString.isString(e)){e=r(e)}else{e=e.valueOf()}n._buffer.push(e)}}OutputStringPort.prototype=Object.create(OutputPort.prototype);OutputStringPort.prototype.toString=function(){return"#>"};OutputStringPort.prototype.getString=function(){return this._buffer.map(function(e){return e.valueOf()}).join("")};OutputStringPort.prototype.constructor=OutputStringPort;function OutputFilePort(e,r){var n=this;if(typeof this!=="undefined"&&!(this instanceof OutputFilePort)||typeof this==="undefined"){return new OutputFilePort(e,r)}typecheck("OutputFilePort",e,"string");this._filename=e;this._fd=r.valueOf();this.write=function(e){if(!LString.isString(e)){e=toString(e)}else{e=e.valueOf()}root.fs.write(n._fd,e,function(){})}}OutputFilePort.prototype=Object.create(OutputPort.prototype);OutputFilePort.prototype.constructor=OutputFilePort;OutputFilePort.prototype.close=function(){var t=this;return new Promise(function(r,n){root.fs.close(t._fd,function(e){if(e){n(e)}else{t._fd=null;OutputPort.prototype.close.call(t);r()}})})};OutputFilePort.prototype.toString=function(){return"#")};function InputStringPort(e,r){var n=this;if(typeof this!=="undefined"&&!(this instanceof InputStringPort)||typeof this==="undefined"){return new InputStringPort(e)}typecheck("InputStringPort",e,"string");r=r||global_env;e=e.valueOf();this._with_parser=this._with_init_parser.bind(this,function(){if(!n.__parser__){n.__parser__=new Parser(e,{env:r})}return n.__parser__});this._make_defaults()}InputStringPort.prototype.char_ready=function(){return true};InputStringPort.prototype=Object.create(InputPort.prototype);InputStringPort.prototype.constructor=InputStringPort;InputStringPort.prototype.toString=function(){return"#>"};function InputFilePort(e,r){if(typeof this!=="undefined"&&!(this instanceof InputFilePort)||typeof this==="undefined"){return new InputFilePort(e,r)}InputStringPort.call(this,e);typecheck("InputFilePort",r,"string");this.__filename__=r}InputFilePort.prototype=Object.create(InputStringPort.prototype);InputFilePort.prototype.constructor=InputFilePort;InputFilePort.prototype.toString=function(){return"#")};var eof=new EOF;function EOF(){}EOF.prototype.toString=function(){return"#"};function Interpreter(e){var r=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:{},n=r.stderr,t=r.stdin,i=r.stdout,a=objectWithoutProperties(r,["stderr","stdin","stdout"]);if(typeof this!=="undefined"&&!(this instanceof Interpreter)||typeof this==="undefined"){return new Interpreter(e,_objectSpread({stdin:t,stdout:i,stderr:n},a))}if(typeof e==="undefined"){e="anonymous"}this.__env__=user_env.inherit(e,a);var u="**interaction-environment-defaults**";this.set(u,get_props(a).concat(u));var o=internal_env.inherit("internal-".concat(e));if(is_port(t)){o.set("stdin",t)}if(is_port(n)){o.set("stderr",n)}if(is_port(i)){o.set("stdout",i)}this.constant("**internal-env**",o);global_env.set("**interaction-environment**",this.__env__)}Interpreter.prototype.exec=function(e){var r=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:false;var n=arguments.length>2&&arguments[2]!==undefined$1?arguments[2]:null;typecheck("Interpreter::exec",e,"string",1);typecheck("Interpreter::exec",r,"boolean",2);global_env.set("**interaction-environment**",this.__env__);if(n===null){n=this.__env__}return exec(e,n,r?n:false)};Interpreter.prototype.get=function(e){var r=this.__env__.get(e);if(is_function(r)){return r.bind(this.__env__)}return r};Interpreter.prototype.set=function(e,r){return this.__env__.set(e,r)};Interpreter.prototype.constant=function(e,r){return this.__env__.constant(e,r)};function Environment(e,r,n){if(arguments.length===1){if(_typeof_1(arguments[0])==="object"){e=arguments[0];r=null}else if(typeof arguments[0]==="string"){e={};r={};n=arguments[0]}}this.__docs__=new Map;this.__env__=e;this.__parent__=r;this.__name__=n||"anonymous"}Environment.prototype.list=function(){return get_props(this.__env__)};Environment.prototype.unset=function(e){if(e instanceof LSymbol){e=e.valueOf()}if(e instanceof LString){e=e.valueOf()}delete this.__env__[e]};Environment.prototype.inherit=function(e){var r=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:{};if(_typeof_1(e)==="object"){r=e}if(!e||_typeof_1(e)==="object"){e="child of "+(this.__name__||"unknown")}return new Environment(r||{},this,e)};Environment.prototype.doc=function(e){var r=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:null;if(e instanceof LSymbol){e=e.__name__}if(e instanceof LString){e=e.valueOf()}if(r){this.__docs__.set(e,r);return this}if(this.__docs__.has(e)){return this.__docs__.get(e)}if(this.__parent__){return this.__parent__.doc(e)}};Environment.prototype.newFrame=function(e,r){var t=this.inherit("__frame__");t.set("parent.frame",doc("parent.frame",function(){var e=arguments.length>0&&arguments[0]!==undefined$1?arguments[0]:1;e=e.valueOf();var r=t.__parent__;if(!(r instanceof Environment)){return nil}if(e<=0){return r}var n=r.get("parent.frame");return n(e-1)},global_env.__env__["parent.frame"].__doc__));r.callee=e;t.set("arguments",r);return t};Environment.prototype._lookup=function(e){if(e instanceof LSymbol){e=e.__name__}if(e instanceof LString){e=e.valueOf()}if(this.__env__.hasOwnProperty(e)){return Value(this.__env__[e])}if(this.__parent__){return this.__parent__._lookup(e)}};Environment.prototype.toString=function(){return"#"};Environment.prototype.clone=function(){var r=this;var n={};Object.keys(this.__env__).forEach(function(e){n[e]=r.__env__[e]});return new Environment(n,this.__parent__,this.__name__)};Environment.prototype.merge=function(e){var r=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:"merge";typecheck("Environment::merge",e,"environment");return this.inherit(r,e.__env__)};function Value(e){if(typeof this!=="undefined"&&!(this instanceof Value)||typeof this==="undefined"){return new Value(e)}this.value=e}Value.isUndefined=function(e){return e instanceof Value&&typeof e.value==="undefined"};Value.prototype.valueOf=function(){return this.value};function Values(e){if(e.length){if(e.length===1){return e[0]}}if(typeof this!=="undefined"&&!(this instanceof Values)||typeof this==="undefined"){return new Values(e)}this.__values__=e}Values.prototype.toString=function(){return this.__values__.map(function(e){return toString(e)}).join("\n")};Values.prototype.valueOf=function(){return this.__values__};Environment.prototype.get=function(e){var r=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:{};typecheck("Environment::get",e,["symbol","string"]);var n=r.throwError,t=n===void 0?true:n;var i=e;if(i instanceof LSymbol||i instanceof LString){i=i.valueOf()}var a=this._lookup(i);if(a instanceof Value){if(Value.isUndefined(a)){return undefined$1}return patch_value(a.valueOf())}if(typeof i==="string"){var u=i.split(".").filter(Boolean);if(u.length>0){var o=toArray(u),c=o[0],s=o.slice(1);a=this._lookup(c);if(s.length){try{if(a instanceof Value){a=a.valueOf()}else{a=get(root,c);if(is_function(a)){a=unbind(a)}}return get.apply(void 0,[a].concat(toConsumableArray(s)))}catch(e){}}else if(a instanceof Value){return patch_value(a.valueOf())}}a=get(root,i)}if(typeof a!=="undefined"){return a}if(t){throw new Error("Unbound variable `"+i.toString()+"'")}};Environment.prototype.set=function(e,r){var n=arguments.length>2&&arguments[2]!==undefined$1?arguments[2]:null;typecheck("Environment::set",e,["string","symbol"]);if(LNumber.isNumber(r)){r=LNumber(r)}if(e instanceof LSymbol){e=e.__name__}if(e instanceof LString){e=e.valueOf()}this.__env__[e]=r;if(n){this.doc(e,n)}return this};Environment.prototype.constant=function(r,e){var n=this;if(this.__env__.hasOwnProperty(r)){throw new Error("Environment::constant: ".concat(r," already exists"))}if(arguments.length===1&&is_plain_object(arguments[0])){var t=arguments[0];Object.keys(t).forEach(function(e){n.constant(r,t[e])})}else{Object.defineProperty(this.__env__,r,{value:e,enumerable:true})}return this};Environment.prototype.has=function(e){return this.__env__.hasOwnProperty(e)};Environment.prototype.ref=function(e){var r=this;while(true){if(!r){break}if(r.has(e)){return r}r=r.__parent__}};Environment.prototype.parents=function(){var e=this;var r=[];while(e){r.unshift(e);e=e.__parent__}return r};function quote(e){if(is_promise(e)){return e.then(quote)}if(e instanceof Pair||e instanceof LSymbol){e[__data__]=true}return e}var native_lambda=parse(tokenize('(lambda ()\n "[native code]"\n (throw "Invalid Invocation"))'))[0];var get=doc(function e(r){for(var n=arguments.length,t=new Array(n>1?n-1:0),i=1;i1?n-1:0),i=1;it.length){throw new Error("Not enough arguments")}var o=0;var c=global_env.get("repr");r=r.replace(a,function(e){var r=e[1];if(r==="~"){return"~"}else if(r==="%"){return"\n"}else{var n=t[o++];if(r==="a"){return c(n)}else{return c(n,true)}}});u=r.match(/~([\S])/);if(u){throw new Error("format: Unrecognized escape seqence ".concat(u[1]))}return r},"(format string n1 n2 ...)\n\n Function accepts string template and replacing any escape sequences\n by arguments:\n\n * ~a value as if printed with display\n * ~s value as if printed with write\n * ~% newline character\n * ~~ literal tilde '~' is inserted\n\n if there missing arguments or other escape character it throw exception."),display:doc(function e(r){var n=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:null;if(n===null){n=internal(this,"stdout")}var t=global_env.get("repr")(r);n.write.call(global_env,t)},"(display arg [port])\n\n Function send string to standard output or provied port."),error:doc(function e(){var r=internal(this,"stderr");var n=global_env.get("repr");for(var t=arguments.length,i=new Array(t),a=0;a1&&arguments[1]!==undefined$1?arguments[1]:{},n=r.dynamic_scope,t=r.error;if(n){n=this}var i=this;var u;var o=evaluate(e.cdr.car,{env:this,dynamic_scope:n,error:t});o=resolve_promises(o);function c(r,n,t){if(is_promise(r)){return r.then(function(e){return c(r,e,t)})}if(is_promise(n)){return n.then(function(e){return c(r,e,t)})}if(is_promise(t)){return t.then(function(e){return c(r,n,e)})}i.get("set-obj!").call(i,r,n,t);return t}if(e.car instanceof Pair&&LSymbol.is(e.car.car,".")){var s=e.car.cdr.car;var l=e.car.cdr.cdr.car;var f=evaluate(s,{env:this,dynamic_scope:n,error:t});var p=evaluate(l,{env:this,dynamic_scope:n,error:t});return c(f,p,o)}if(!(e.car instanceof LSymbol)){throw new Error("set! first argument need to be a symbol or "+"dot accessor that evaluate to object.")}var _=e.car.valueOf();u=this.ref(e.car.__name__);return unpromise(o,function(e){if(!u){var r=_.split(".");if(r.length>1){var n=r.pop();var t=r.join(".");var i=a.get(t,{throwError:false});if(i){c(i,n,e);return}}throw new Error("Unbound variable `"+_+"'")}u.set(_,e)})}),"(set! name value)\n\n Macro that can be used to set the value of the variable (mutate)\n it search the scope chain until it finds first non emtpy slot and set it."),"unset!":doc(new Macro("set!",function(e){if(!(e.car instanceof LSymbol)){throw new Error("unset! first argument need to be a symbol or "+"dot accessor that evaluate to object.")}var r=e.car;var n=this.ref(r);if(n){delete n.__env__[r.__name__]}}),"(unset! name)\n\n Function delete specified name from environment."),"set-car!":doc("set-car!",function(e,r){typecheck("set-car!",e,"pair");e.car=r},"(set-car! obj value)\n\n Function that set car (head) of the list/pair to specified value.\n It can destroy the list. Old value is lost."),"set-cdr!":doc("set-cdr!",function(e,r){typecheck("set-cdr!",e,"pair");e.cdr=r},"(set-cdr! obj value)\n\n Function that set cdr (tail) of the list/pair to specified value.\n It can destroy the list. Old value is lost."),"empty?":doc("empty?",function(e){return typeof e==="undefined"||e===nil},"(empty? object)\n\n Function return true if value is undfined empty list."),gensym:doc("gensym",gensym,"(gensym)\n\n Function generate unique symbol, to use with macros as meta name."),load:doc(function e(r,n){typecheck("load",r,"string");var t=this;if(t.__name__==="__frame__"){t=t.__parent__}if(!(n instanceof Environment)){if(t===global_env){n=t}else{n=this.get("**interaction-environment**")}}var i="**module-path**";var a=global_env.get(i,{throwError:false});r=r.valueOf();if(!r.match(/.[^.]+$/)){r+=".scm"}function u(e){if(type(e)==="buffer"){e=e.toString()}return exec(e.replace(/^#!.*/,""),n)}if(is_node()){return new Promise(function(n,t){var e=nodeRequire("path");if(a){a=a.valueOf();r=e.join(a,r)}global_env.set(i,e.dirname(r));nodeRequire("fs").readFile(r,function(e,r){if(e){t(e);global_env.set(i,a)}else{try{u(r).then(function(){n();global_env.set(i,a)})["catch"](t)}catch(e){t(e)}}})})}if(a){a=a.valueOf();r=a+"/"+r.replace(/^\.?\/?/,"")}return root.fetch(r).then(function(e){return e.text()}).then(function(e){global_env.set(i,r.replace(/\/[^/]*$/,""));return u(e)}).then(function(){})["finally"](function(){global_env.set(i,a)})},"(load filename)\n (load filename environment)\n\n Function fetch the file and evaluate its content as LIPS code,\n If second argument is provided and it's environment the evaluation\n will happen in that environment."),do:doc(new Macro("do",function(){var n=asyncToGenerator(regenerator.mark(function e(n,t){var i,a,u,o,c,s,l,f,p,_,h;return regenerator.wrap(function e(r){while(1){switch(r.prev=r.next){case 0:i=t.dynamic_scope,a=t.error;u=this;if(i){i=u}o=u.inherit("do");c=n.car;s=n.cdr.car;l=n.cdr.cdr;if(l!==nil){l=new Pair(LSymbol("begin"),l)}f={env:u,dynamic_scope:i,error:a};p=c;case 10:if(!(p!==nil)){r.next=21;break}_=p.car;r.t0=o;r.t1=_.car;r.next=16;return evaluate(_.cdr.car,f);case 16:r.t2=r.sent;r.t0.set.call(r.t0,r.t1,r.t2);p=p.cdr;r.next=10;break;case 21:f={env:o,dynamic_scope:i,error:a};h=regenerator.mark(function e(){var n,t,i,a,u;return regenerator.wrap(function e(r){while(1){switch(r.prev=r.next){case 0:if(!(l!==nil)){r.next=3;break}r.next=3;return lips.evaluate(l,f);case 3:n=c;t={};case 5:if(!(n!==nil)){r.next=15;break}i=n.car;if(!(i.cdr.cdr!==nil)){r.next=12;break}r.next=10;return evaluate(i.cdr.cdr.car,f);case 10:a=r.sent;t[i.car.valueOf()]=a;case 12:n=n.cdr;r.next=5;break;case 15:u=Object.getOwnPropertySymbols(t);Object.keys(t).concat(u).forEach(function(e){o.set(e,t[e])});case 17:case"end":return r.stop()}}},e)});case 23:r.next=25;return evaluate(s.car,f);case 25:r.t3=r.sent;if(!(r.t3===false)){r.next=30;break}return r.delegateYield(h(),"t4",28);case 28:r.next=23;break;case 30:if(!(s.cdr!==nil)){r.next=34;break}r.next=33;return evaluate(s.cdr.car,f);case 33:return r.abrupt("return",r.sent);case 34:case"end":return r.stop()}}},e,this)}));return function(e,r){return n.apply(this,arguments)}}()),"(do (( )) (test expression) . body)\n\n Iteration macro that evaluate the expression body in scope of the variables.\n On Eeach loop it increase the variables according to next expression and run\n test to check if the loop should continue. If test is signle call the macro\n will not return anything. If the test is pair of expression and value the\n macro will return that value after finish."),if:doc(new Macro("if",function(n,e){var t=e.dynamic_scope,i=e.error;if(t){t=this}var a=this;var r=function e(r){if(r===false){return evaluate(n.cdr.cdr.car,{env:a,dynamic_scope:t,error:i})}else{return evaluate(n.cdr.car,{env:a,dynamic_scope:t,error:i})}};if(n===nil){throw new Error("too few expressions for `if`")}var u=evaluate(n.car,{env:a,dynamic_scope:t,error:i});return unpromise(u,r)}),"(if cond true-expr false-expr)\n\n Macro evaluate condition expression and if the value is true, it\n evaluate and return true expression if not it evaluate and return\n false expression"),"let-env":new Macro("let-env",function(r){var e=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:{};var n=e.dynamic_scope,t=e.error;typecheck("let-env",r,"pair");var i=evaluate(r.car,{env:this,dynamic_scope:n,error:t});return unpromise(i,function(e){typecheck("let-env",e,"environment");return evaluate(Pair(LSymbol("begin"),r.cdr),{env:e,dynamic_scope:n,error:t})})},"(let-env env . body)\n\n Special macro that evaluate body in context of given environment\n object."),letrec:doc(let_macro(Symbol["for"]("letrec")),"(letrec ((a value-a) (b value-b)) body)\n\n Macro that creates new environment, then evaluate and assign values to\n names and then evaluate the body in context of that environment.\n Values are evaluated sequentialy and next value can access to\n previous values/names."),"let*":doc(let_macro(Symbol["for"]("let*")),"(let* ((a value-a) (b value-b)) body)\n\n Macro similar to `let` but next argument get environment\n from previous let variable, so they you can define one variable,\n and use in next argument."),let:doc(let_macro(Symbol["for"]("let")),"(let ((a value-a) (b value-b)) body)\n\n Macro that creates new environment, then evaluate and assign values to\n names and then evaluate the body in context of that environment.\n Values are evaluated sequentialy but you can't access\n previous values/names when next are evaluated. You can only get them\n from body of let expression."),"begin*":doc(pararel("begin*",function(e){return e.pop()}),"(begin* . expr)\n\n This macro is parallel version of begin. It evaluate each expression and\n if it's a promise it will evaluate it in parallel and return value\n of last expression."),begin:doc(new Macro("begin",function(e,r){var t=Object.assign({},r);var i=global_env.get("list->array")(e);if(t.dynamic_scope){t.dynamic_scope=this}t.env=this;var a;return function r(){if(i.length){var e=i.shift();var n=evaluate(e,t);return unpromise(n,function(e){a=e;return r()})}else{return a}}()}),"(begin . args)\n\n Macro runs list of expression and return valuate of the list one.\n It can be used in place where you can only have single exression,\n like if expression."),ignore:new Macro("ignore",function(e,r){var n=r.dynamic_scope,t=r.error;var i={env:this,error:t};if(n){i.dynamic_scope=this}evaluate(new Pair(new LSymbol("begin"),e),i)},"(ignore expression)\n\n Macro that will evaluate expression and swallow any promises that may\n be created. It wil run and ignore any value that may be returned by\n expression. The code should have side effects and/or when it's promise\n it should resolve to undefined."),define:doc(Macro.defmacro("define",function(n,e){var t=this;if(n.car instanceof Pair&&n.car.car instanceof LSymbol){var r=new Pair(new LSymbol("define"),new Pair(n.car.car,new Pair(new Pair(new LSymbol("lambda"),new Pair(n.car.cdr,n.cdr)))));return r}else if(e.macro_expand){return}if(e.dynamic_scope){e.dynamic_scope=this}e.env=t;var i=n.cdr.car;var a;if(i instanceof Pair){i=evaluate(i,e);a=true}else if(i instanceof LSymbol){i=t.get(i)}typecheck("define",n.car,"symbol");return unpromise(i,function(e){if(t.__name__===Syntax.__merge_env__){t=t.__parent__}if(a&&(is_function(e)&&e[__lambda__]||e instanceof Syntax)){e.__name__=n.car.valueOf();if(e.__name__ instanceof LString){e.__name__=e.__name__.valueOf()}}var r;if(n.cdr.cdr instanceof Pair&&LString.isString(n.cdr.cdr.car)){r=n.cdr.cdr.car.valueOf()}t.set(n.car,e,r)})}),"(define name expression)\n (define (function-name . args) body)\n\n Macro for defining values. It can be used to define variables,\n or function. If first argument is list it will create function\n with name beeing first element of the list. The macro evalute\n code `(define function (lambda args body))`"),"set-obj!":doc("set-obj!",function(e,r,n){var t=_typeof_1(e);if(is_null(e)||t!=="object"&&t!=="function"){var i=typeErrorMessage("set-obj!",type(e),["object","function"]);throw new Error(i)}e=unbind(e);r=r.valueOf();if(arguments.length===2){delete e[r]}else if(is_prototype(e)&&is_function(n)){e[r]=unbind(n);e[r][__prototype__]=true}else if(is_function(n)||is_native(n)||n===nil){e[r]=n}else{e[r]=n?n.valueOf():n}},"(set-obj! obj key value)\n\n Function set property of JavaScript object"),"null-environment":doc("null-environment",function(){return global_env.inherit("null")},"(null-environment)\n\n Function return new base environment with std lib."),values:doc(function e(){for(var r=arguments.length,n=new Array(r),t=0;t1&&arguments[1]!==undefined$1?arguments[1]:{},p=e.dynamic_scope,_=e.error;var h=this;var d;if(f.cdr instanceof Pair&&LString.isString(f.cdr.car)&&f.cdr.cdr!==nil){d=f.cdr.car.valueOf()}function m(){var e;if(p){if(!(this instanceof Environment)){e=h}else{e=this}}else{e=h}e=e.inherit("lambda");var r=f.car;var n=0;var t;if(typeof this!=="undefined"&&!(this instanceof Environment)){if(this&&!this.__instance__){Object.defineProperty(this,"__instance__",{enumerable:false,get:function e(){return true},set:function e(){},configurable:false})}e.set("this",this)}for(var i=arguments.length,a=new Array(i),u=0;u2&&arguments[2]!==undefined$1?arguments[2]:a;if(e instanceof Pair){var t=e.car;var i=e.cdr;if(n(t)){t=r(t)}if(n(i)){i=r(i)}if(is_promise(t)||is_promise(i)){return Promise.all([t,i]).then(function(e){var r=slicedToArray(e,2),n=r[0],t=r[1];return new Pair(n,t)})}else{return new Pair(t,i)}}return e}function u(e,r){if(e instanceof Pair){if(r!==nil){e.append(r)}}else{e=new Pair(e,r)}return e}function n(e){return!!e.filter(function(e){return e instanceof Pair&&LSymbol.is(e.car,"unquote")}).length}function f(e,t,i){return e.reduce(function(e,r){if(!(r instanceof Pair)){e.push(r);return e}if(LSymbol.is(r.car,"unquote-splicing")){var n;if(t+11){var r="You can't splice multiple atoms inside list";throw new Error(r)}if(!(i.cdr instanceof Pair&&n[0]===nil)){return n[0]}}n=n.map(function(e){if(h.has(e)){return e.clone()}else{h.add(e);return e}});var t=d(i.cdr,0,1);if(t===nil&&n[0]===nil){return undefined$1}return unpromise(t,function(e){if(n[0]===nil){return e}if(n.length===1){return u(n[0],e)}var r=n.reduce(function(e,r){return u(e,r)});return u(r,e)})})}(i.car.cdr)}var h=new Set;function d(e,r,n){if(e instanceof Pair){if(LSymbol.is(e.car.car,"unquote-splicing")){return _(e,r+1,n)}if(LSymbol.is(e.car,"quasiquote")){var t=d(e.cdr,r,n+1);return new Pair(e.car,t)}if(LSymbol.is(e.car.car,"unquote")){if(r+2===n&&e.car.cdr instanceof Pair&&e.car.cdr.car instanceof Pair&&LSymbol.is(e.car.cdr.car.car,"unquote-splicing")){var i=e.car.cdr;return new Pair(new Pair(new LSymbol("unquote"),_(i,r+2,n)),nil)}else if(e.car.cdr instanceof Pair&&e.car.cdr.cdr!==nil){if(e.car.cdr.car instanceof Pair){var a=[];return function r(n){if(n===nil){return Pair.fromArray(a)}return unpromise(evaluate(n.car,{env:s,dynamic_scope:o,error:c}),function(e){a.push(e);return r(n.cdr)})}(e.car.cdr)}else{return e.car.cdr}}}if(LSymbol.is(e.car,"quote")){return new Pair(e.car,d(e.cdr,r,n))}if(LSymbol.is(e.car,"unquote")){r++;if(rn){throw new Error("You can't call `unquote` outside "+"of quasiquote")}if(e.cdr instanceof Pair){if(e.cdr.cdr!==nil){if(e.cdr.car instanceof Pair){var u=[];return function r(n){if(n===nil){return Pair.fromArray(u)}return unpromise(evaluate(n.car,{env:s,dynamic_scope:o,error:c}),function(e){u.push(e);return r(n.cdr)})}(e.cdr)}else{return e.cdr}}else{return evaluate(e.cdr.car,{env:s,dynamic_scope:o,error:c})}}else{return e.cdr}}return l(e,function(e){return d(e,r,n)})}else if(is_plain_object(e)){return p(e,r,n)}else if(e instanceof Array){return f(e,r,n)}return e}function t(e){if(e instanceof Pair){delete e[__data__];if(!e.haveCycles("car")){t(e.car)}if(!e.haveCycles("cdr")){t(e.cdr)}}}if(is_plain_object(e.car)&&!n(Object.values(e.car))){return quote(e.car)}if(Array.isArray(e.car)&&!n(e.car)){return quote(e.car)}if(e.car instanceof Pair&&!e.car.find("unquote")&&!e.car.find("unquote-splicing")&&!e.car.find("quasiquote")){return quote(e.car)}var i=d(e.car,0,1);return unpromise(i,function(e){t(e);return quote(e)})},"(quasiquote list ,value ,@value)\n\n Similar macro to `quote` but inside it you can use special\n expressions unquote abbreviated to , that will evaluate expresion inside\n and return its value or unquote-splicing abbreviated to ,@ that will\n evaluate expression but return value without parenthesis (it will join)\n the list with its value. Best used with macros but it can be used outside"),clone:doc(function e(r){typecheck("clone",r,"pair");return r.clone()},"(clone list)\n\n Function return clone of the list."),append:doc(function e(){var r;for(var n=arguments.length,t=new Array(n),i=0;iarray")(r).reverse();return global_env.get("array->list")(n)}else if(!(r instanceof Array)){throw new Error(typeErrorMessage("reverse",type(r),"array or pair"))}else{return r.reverse()}},"(reverse list)\n\n Function will reverse the list or array. If value is not a list\n or array it will throw exception."),nth:doc(function e(r,n){typecheck("nth",r,"number");typecheck("nth",n,["array","pair"]);if(n instanceof Pair){var t=n;var i=0;while(iarray")(n).join(r)},"(join separator list)\n\n Function return string by joining elements of the list"),split:doc(function e(r,n){typecheck("split",r,["regex","string"]);typecheck("split",n,"string");return global_env.get("array->list")(n.split(r))},"(split separator string)\n\n Function create list by splitting string by separatar that can\n be a string or regular expression."),replace:doc(function e(r,n,t){typecheck("replace",r,["regex","string"]);typecheck("replace",n,["string","function"]);typecheck("replace",t,"string");return t.replace(r,n)},"(replace pattern replacement string)\n\n Function change pattern to replacement inside string. Pattern can be string\n or regex and replacement can be function or string."),match:doc(function e(r,n){typecheck("match",r,["regex","string"]);typecheck("match",n,"string");var t=n.match(r);return t?global_env.get("array->list")(t):nil},"(match pattern string)\n\n function return match object from JavaScript as list."),search:doc(function e(r,n){typecheck("search",r,["regex","string"]);typecheck("search",n,"string");return n.search(r)},"(search pattern string)\n\n Function return first found index of the pattern inside a string"),repr:doc(function e(r,n){return toString(r,n)},"(repr obj)\n\n Function return string LIPS representation of an object as string."),env:doc(function e(e){e=e||this;var r=Object.keys(e.__env__);var n;if(r.length){n=Pair.fromArray(r)}else{n=nil}if(e.__parent__!==undefined$1){return global_env.get("env")(e.__parent__).append(n)}return n},"(env obj)\n\n Function return list values (functions and variables) inside environment."),new:doc("new",function(e){for(var r=arguments.length,n=new Array(r>1?r-1:0),t=1;t2&&arguments[2]!==undefined$1?arguments[2]:specials.LITERAL;typecheck("set-special!",e,"string",1);typecheck("set-special!",r,"symbol",2);specials.append(e.valueOf(),r,n)},'(set-special! symbol name [type])\n\n Add special symbol to the list of transforming operators by the parser.\n e.g.: `(add-special! "#" \'x)` will allow to use `#(1 2 3)` and it will be\n transformed into (x (1 2 3)) so you can write x macro that will process\n the list. 3rd argument is optional and it can be constant value\n lips.specials.SPLICE if this constant is used it will transform\n `#(1 2 3)` into (x 1 2 3) that is required by # that define vectors.'),get:get,".":get,unbind:doc(unbind,"(unbind fn)\n\n Function remove bidning from function so you can get props from it."),type:doc(type,"(type object)\n\n Function return type of an object as string."),debugger:doc("debugger",function(){debugger},"(debugger)\n\n Function stop JavaScript code in debugger."),in:doc("in",function(e,r){if(e instanceof LSymbol||e instanceof LString){e=e.valueOf()}return e in r},"(in key value)\n\n Function use is in operator to check if value is in object."),instanceof:doc("instanceof",function(e,r){return r instanceof unbind(e)},"(instanceof type obj)\n\n Function check of object is instance of object."),"prototype?":doc("prototype?",is_prototype,"(prototype? obj)\n\n Function check if value is JavaScript Object prototype."),"macro?":doc("macro?",function(e){return e instanceof Macro},"(macro? expression)\n\n Function check if value is a macro."),"function?":doc("function?",is_function,"(function? expression)\n\n Function check if value is a function."),"real?":doc("real?",function(e){if(type(e)!=="number"){return false}if(e instanceof LNumber){return e.isFloat()}return LNumber.isFloat(e)},"(real? number)\n\n Function check if value is real number."),"number?":doc("number?",LNumber.isNumber,"(number? expression)\n\n Function check if value is a number"),"string?":doc("string?",function(e){return LString.isString(e)},"(string? expression)\n\n Function check if value is a string."),"pair?":doc("pair?",function(e){return e instanceof Pair},"(pair? expression)\n\n Function check if value is a pair or list structure."),"regex?":doc(function(e){return e instanceof RegExp},"(regex? expression)\n\n Function check if value is regular expression."),"null?":doc("null?",function(e){return is_null(e)},"(null? expression)\n\n Function check if value is nulish."),"boolean?":doc("boolean?",function(e){return typeof e==="boolean"},"(boolean? expression)\n\n Function check if value is boolean."),"symbol?":doc("symbol?",function(e){return e instanceof LSymbol},"(symbol? expression)\n\n Function check if value is LIPS symbol"),"array?":doc("array?",function(e){return e instanceof Array},"(array? expression)\n\n Function check if value is an arrray."),"object?":doc("object?",function(e){return e!==nil&&e!==null&&!(e instanceof LCharacter)&&!(e instanceof RegExp)&&!(e instanceof LString)&&!(e instanceof Pair)&&!(e instanceof LNumber)&&_typeof_1(e)==="object"&&!(e instanceof Array)},"(object? expression)\n\n Function check if value is an plain object."),flatten:doc(function e(r){typecheck("flatten",r,"pair");return r.flatten()},"(flatten list)\n\n Return shallow list from tree structure (pairs)."),"array->list":doc("array->list",function(e){typecheck("array->list",e,"array");return Pair.fromArray(e)},"(array->list array)\n\n Function convert JavaScript array to LIPS list."),"tree->array":doc("tree->array",toArray$1("tree->array",true),"(tree->array list)\n\n Function convert LIPS list structure into JavaScript array."),"list->array":doc("list->array",toArray$1("list->array"),"(list->array list)\n\n Function convert LIPS list into JavaScript array."),apply:doc(function e(r){for(var n=arguments.length,t=new Array(n>1?n-1:0),i=1;iarray").call(this,a));return r.apply(this,prepare_fn_args(r,t))},"(apply fn list)\n\n Function that call function with list of arguments."),length:doc(function e(r){if(!r){return LNumber(0)}if(r instanceof Pair){return LNumber(r.length())}if("length"in r){return LNumber(r.length)}},"(length expression)\n\n Function return length of the object, the object can be list\n or any object that have length property."),"string->number":doc("string->number",function(e){var r=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:10;typecheck("string->number",e,"string",1);typecheck("string->number",r,"number",2);e=e.valueOf();r=r.valueOf();if(e.match(rational_bare_re)||e.match(rational_re)){return parse_rational(e,r)}else if(e.match(complex_bare_re)||e.match(complex_re)){return parse_complex(e,r)}else{var n=r===10&&!e.match(/e/i)||r===16;if(e.match(int_bare_re)&&n||e.match(int_re)){return parse_integer(e,r)}if(e.match(float_re)){return parse_float(e)}}return false},"(string->number number [radix])\n\n Function convert string to number."),try:doc(new Macro("try",function(r,e){var s=this;var l=e.dynamic_scope,f=e.error;return new Promise(function(i,t){var a,u;if(LSymbol.is(r.cdr.car.car,"catch")){a=r.cdr.car;if(r.cdr.cdr instanceof Pair&&LSymbol.is(r.cdr.cdr.car.car,"finally")){u=r.cdr.cdr.car}}else if(LSymbol.is(r.cdr.car.car,"finally")){u=r.cdr.car}if(!(u||a)){throw new Error("try: invalid syntax")}var o=i;if(u){o=function e(r,n){o=t;unpromise(evaluate(new Pair(new LSymbol("begin"),u.cdr),c),function(){n(r)})}}var c={env:s,error:function e(r){var n=s.inherit("try");if(a){n.set(a.cdr.car.car,r);var t={env:n,error:f};if(l){t.dynamic_scope=s}unpromise(evaluate(new Pair(new LSymbol("begin"),a.cdr.cdr),t),function(e){o(e,i)})}else{o(r,f)}}};if(l){c.dynamic_scope=s}var e=evaluate(r.car,c);if(is_promise(e)){e.then(function(e){o(e,i)})["catch"](c.error)}else{o(e,i)}})}),"(try expr (catch (e) code))\n (try expr (catch (e) code) (finally code))\n (try expr (finally code))\n\n Macro execute user code and catch exception. If catch is provided\n it's executed when expression expr throw error. If finally is provide\n it's always executed at the end."),throw:doc("throw",function(e){throw new Error(e)},"(throw string)\n\n Throw new expection."),find:doc(function r(n,t){typecheck("find",n,["regex","function"]);typecheck("find",t,["pair","nil"]);if(is_null(t)){return nil}var e=matcher("find",n);return unpromise(e(t.car),function(e){if(e&&e!==nil){return t.car}return r(n,t.cdr)})},"(find fn list)\n (find regex list)\n\n Higher order Function find first value for which function return true.\n If called with regex it will create matcher function."),"for-each":doc("for-each",function(e){var r;typecheck("for-each",e,"function");for(var n=arguments.length,t=new Array(n>1?n-1:0),i=1;i1?r-1:0),a=1;a3?t-3:0),a=3;a3?i-3:0),u=3;uarray")(n);var a=[];var u=matcher("filter",r);return function r(n){function e(e){if(e&&e!==nil){a.push(t)}return r(++n)}if(n===i.length){return Pair.fromArray(a)}var t=i[n];return unpromise(u(t),e)}(0)},"(filter fn list)\n (filter regex list)\n\n Higher order function that call `fn` for each element of the list\n and return list for only those elements for which funtion return\n true value. If called with regex it will create matcher function."),compose:doc(compose,"(compose . fns)\n\n Higher order function and create new function that apply all functions\n From right to left and return it's value. Reverse of compose.\n e.g.:\n ((compose (curry + 2) (curry * 3)) 3)\n 11\n "),pipe:doc(pipe,"(pipe . fns)\n\n Higher order function and create new function that apply all functions\n From left to right and return it's value. Reverse of compose.\n e.g.:\n ((pipe (curry + 2) (curry * 3)) 3)\n 15"),curry:doc(curry,"(curry fn . args)\n\n Higher order function that create curried version of the function.\n The result function will have parially applied arguments and it\n will keep returning functions until all arguments are added\n\n e.g.:\n (define (add a b c d) (+ a b c d))\n (define add1 (curry add 1))\n (define add12 (add 2))\n (display (add12 3 4))"),gcd:doc(function e(){for(var r=arguments.length,n=new Array(r),t=0;ti?n%=i:i%=n}n=abs(a*(t<0||arguments.length<=t?undefined$1:arguments[t]))/(n+i)}return LNumber(n)},"(lcm n1 n2 ...)\n\n Function return the least common multiple of their arguments."),"odd?":doc("odd?",singleMathOp(function(e){return LNumber(e).isOdd()}),"(odd? number)\n\n Function check if number os odd."),"even?":doc("even?",singleMathOp(function(e){return LNumber(e).isEven()}),"(even? number)\n\n Function check if number is even."),"*":doc("*",reduceMathOp(function(e,r){return LNumber(e).mul(r)},LNumber(1)),"(* . numbers)\n\n Multiplicate all numbers passed as arguments. If single value is passed\n it will return that value."),"+":doc("+",reduceMathOp(function(e,r){return LNumber(e).add(r)},LNumber(0)),"(+ . numbers)\n\n Sum all numbers passed as arguments. If single value is passed it will\n return that value."),"-":doc("-",function(){for(var e=arguments.length,r=new Array(e),n=0;n":doc(">",function(){for(var e=arguments.length,r=new Array(e),n=0;n x1 x2 x3 ...)\n\n Function compare its numerical arguments and check if they are\n monotonically increasing"),"<":doc("<",function(){for(var e=arguments.length,r=new Array(e),n=0;n=":doc(">=",function(){for(var e=arguments.length,r=new Array(e),n=0;n= x1 x2 x3 ...)\n\n Function compare its numerical arguments and check if they are\n monotonically nondecreasing"),"eq?":doc("eq?",equal,"(eq? a b)\n\n Function compare two values if they are identical."),or:doc(new Macro("or",function(e,r){var i=r.dynamic_scope,a=r.error;var u=global_env.get("list->array")(e);var o=this;if(i){i=o}if(!u.length){return false}var c;return function r(){function e(e){c=e;if(c!==false){return c}else{return r()}}if(!u.length){if(c!==false){return c}else{return false}}else{var n=u.shift();var t=evaluate(n,{env:o,dynamic_scope:i,error:a});return unpromise(t,e)}}()}),"(or . expressions)\n\n Macro execute the values one by one and return the one that is truthy value.\n If there are no expression that evaluate to true it return false."),and:doc(new Macro("and",function(e){var r=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:{},i=r.dynamic_scope,a=r.error;var u=global_env.get("list->array")(e);var o=this;if(i){i=o}if(!u.length){return true}var c;return function r(){function e(e){c=e;if(c===false){return false}else{return r()}}var n=u.shift();if(typeof n==="undefined"){if(c!==false){return c}else{return false}}else{var t=evaluate(n,{env:o,dynamic_scope:i,error:a});return unpromise(t,e)}}()}),"(and . expressions)\n\n Macro evalute each expression in sequence if any value return false it will\n return false. If each value return true it will return the last value.\n If it's called without arguments it will return true."),"|":doc("|",function(e,r){return LNumber(e).or(r)},"(& a b)\n\n Function calculate or bit operation."),"&":doc("&",function(e,r){return LNumber(e).and(r)},"(& a b)\n\n Function calculate and bit operation."),"~":doc("~",function(e){return LNumber(e).neg()},"(~ number)\n\n Function negate the value."),">>":doc(">>",function(e,r){return LNumber(e).shr(r)},"(>> a b)\n\n Function right shit the value a by value b."),"<<":doc(function(e,r){return LNumber(e).shl(r)},"(<< a b)\n\n Function left shit the value a by value b."),not:doc(function e(r){if(is_null(r)){return true}return!r},"(not object)\n\n Function return negation of the argument.")},undefined$1,"global");var user_env=global_env.inherit("user-env");global_env.set("**interaction-environment**",user_env);global_env.constant("**internal-env**",internal_env);(function(){var e={ceil:"ceiling"};["floor","round","ceil"].forEach(function(r){var n=e[r]?e[r]:r;global_env.set(n,doc(n,function(e){typecheck(n,e,"number");if(e instanceof LNumber){return e[r]()}},"(".concat(n," number)\n\n Function calculate ").concat(n," of a number.")))})})();function allPossibleCases(e){if(e.length===1){return e[0]}else{var r=[];var n=allPossibleCases(e.slice(1));for(var t=0;t3&&arguments[3]!==undefined$1?arguments[3]:null;var i=e?" in expression `".concat(e,"`"):"";if(t!==null){i+=" (argument ".concat(t,")")}if(n instanceof Array){if(n.length===1){n=n[0]}else{var a=n[n.length-1];n=n.slice(0,-1).join(", ")+" or "+a}}return"Expecting ".concat(n,", got ").concat(r).concat(i)}function typecheck(e,r,n){var t=arguments.length>3&&arguments[3]!==undefined$1?arguments[3]:null;e=e.valueOf();var i=type(r).toLowerCase();var a=false;if(n instanceof Pair){n=n.toArray()}if(n instanceof Array){n=n.map(function(e){return e.valueOf()})}if(n instanceof Array){n=n.map(function(e){return e.valueOf().toLowerCase()});if(n.includes(i)){a=true}}else{n=n.valueOf().toLowerCase()}if(!a&&i!==n){throw new Error(typeErrorMessage(e,i,n,t))}}function self_evaluated(e){var r=_typeof_1(e);return["string","function"].includes(r)||_typeof_1(e)==="symbol"||e instanceof LSymbol||e instanceof LNumber||e instanceof LString||e instanceof RegExp}function is_native(e){return e instanceof LNumber||e instanceof LString||e instanceof LCharacter}function has_own_symbol(e,r){if(e===null){return false}return _typeof_1(e)==="object"&&r in Object.getOwnPropertySymbols(e)}function is_iterator(e,r){if(has_own_symbol(e,r)||has_own_symbol(e.__proto__,r)){return is_function(e[r])}}function type(e){var r={pair:Pair,symbol:LSymbol,character:LCharacter,values:Values,"input-port":InputPort,"output-port":OutputPort,number:LNumber,regex:RegExp,syntax:Syntax,macro:Macro,string:LString,array:Array,"native-symbol":Symbol};if(Number.isNaN(e)){return"NaN "}if(e===nil){return"nil"}if(e===null){return"null"}for(var n=0,t=Object.entries(r);n2&&arguments[2]!==undefined$1?arguments[2]:{},a=r.env,u=r.dynamic_scope,n=r.error,o=n===void 0?function(){}:n;e=evaluate_args(e,{env:a,dynamic_scope:u,error:o});return unpromise(e,function(e){if(is_raw_lambda(i)){i=unbind(i)}e=prepare_fn_args(i,e);var r=e.slice();var n=(u||a).newFrame(i,r);var t=resolve_promises(i.apply(n,e));return unpromise(t,function(e){if(e instanceof Pair){e.markCycles();return quote(e)}if(Number.isNaN(e)){return e}if(typeof e==="number"){return LNumber(e)}if(typeof e==="string"){return LString(e)}return e},o)})}function evaluate(r){var e=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:{},n=e.env,t=e.dynamic_scope,i=e.error,a=i===void 0?function(){}:i;try{if(t===true){n=t=n||global_env}else if(n===true){n=t=global_env}else{n=n||global_env}var u={env:n,dynamic_scope:t,error:a};var o;if(is_null(r)){return r}if(r instanceof LSymbol){return n.get(r)}if(!(r instanceof Pair)){return r}var c=r.car;var s=r.cdr;if(c instanceof Pair){o=resolve_promises(evaluate(c,u));if(is_promise(o)){return o.then(function(e){return evaluate(new Pair(e,r.cdr),u)})}else if(!is_function(o)){throw new Error(type(o)+" "+n.get("repr")(o)+" is not a function while evaluating "+r.toString())}}if(c instanceof LSymbol){o=n.get(c)}else if(is_function(c)){o=c}var l;if(o instanceof Syntax){l=evaluate_syntax(o,r,u)}else if(o instanceof Macro){l=evaluate_macro(o,s,u)}else if(is_function(o)){l=apply(o,s,u)}else if(r instanceof Pair){o=c&&c.toString();throw new Error("".concat(type(c)," ").concat(o," is not a function"))}else if(!is_function(o)){if(o){var f="".concat(type(o)," `").concat(o,"' is not a function");throw new Error(f)}throw new Error("Unknown function `".concat(c.toString(),"'"))}else{return r}var p=n.get(Symbol["for"]("__promise__"),{throwError:false});if(p===true&&is_promise(l)){return new QuotedPromise(l)}return l}catch(e){a&&a.call(n,e,r)}}function exec(e,r,n){return _exec.apply(this,arguments)}function _exec(){_exec=asyncToGenerator(regenerator.mark(function e(n,t,i){var a,u,o,c,s,l,f,p,_;return regenerator.wrap(function e(r){while(1){switch(r.prev=r.next){case 0:if(i===true){t=i=t||user_env}else if(t===true){t=i=user_env}else{t=t||user_env}a=[];u=true;o=false;r.prev=4;s=asyncIterator(parse(n));case 6:r.next=8;return s.next();case 8:l=r.sent;u=l.done;r.next=12;return l.value;case 12:f=r.sent;if(u){r.next=28;break}p=f;_=evaluate(p,{env:t,dynamic_scope:i,error:function e(r,n){if(r&&r.message){r.message=r.message.replace(/.*:\s*([^:]+:\s*)/,"$1");if(n){if(!(r.__code__ instanceof Array)){r.__code__=[]}r.__code__.push(n.toString(true))}}throw r}});if(is_promise(_)){r.next=20;break}a.push(_);r.next=25;break;case 20:r.t0=a;r.next=23;return _;case 23:r.t1=r.sent;r.t0.push.call(r.t0,r.t1);case 25:u=true;r.next=6;break;case 28:r.next=34;break;case 30:r.prev=30;r.t2=r["catch"](4);o=true;c=r.t2;case 34:r.prev=34;r.prev=35;if(!(!u&&s["return"]!=null)){r.next=39;break}r.next=39;return s["return"]();case 39:r.prev=39;if(!o){r.next=42;break}throw c;case 42:return r.finish(39);case 43:return r.finish(34);case 44:return r.abrupt("return",a);case 45:case"end":return r.stop()}}},e,null,[[4,30,34,44],[35,,39,43]])}));return _exec.apply(this,arguments)}function balanced(e){var r={"[":"]","(":")"};var n;if(typeof e==="string"){n=tokenize(e)}else{n=e.map(function(e){return e&&e.token?e.token:e})}var t=Object.keys(r);var i=Object.values(r).concat(t);n=n.filter(function(e){return i.includes(e)});var a=new Stack;var u=_createForOfIteratorHelper(n),o;try{for(u.s();!(o=u.n()).done;){var c=o.value;if(t.includes(c)){a.push(c)}else if(!a.is_empty()){var s=a.top();var l=r[s];if(c===l){a.pop()}else{throw new Error("Syntax error: missing closing ".concat(l))}}else{throw new Error("Syntax error: not matched closing ".concat(c))}}}catch(e){u.e(e)}finally{u.f()}return a.is_empty()}function fworker(e){var r="("+e.toString()+")()";var n=window.URL||window.webkitURL;var t;try{t=new Blob([r],{type:"application/javascript"})}catch(e){var i=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder;t=new i;t.append(r);t=t.getBlob()}return new root.Worker(n.createObjectURL(t))}function is_dev(){return lips.version.match(/^(\{\{VER\}\}|DEV)$/)}function bootstrap(){var e=arguments.length>0&&arguments[0]!==undefined$1?arguments[0]:"";if(e===""){if(is_dev()){e="https://cdn.jsdelivr.net/gh/jcubic/lips@devel/"}else{e="https://cdn.jsdelivr.net/npm/@jcubic/lips@".concat(lips.version,"/")}}else if(!e.match(/\/$/)){e+="/"}var r=global_env.get("load");return r.call(lips.env,"".concat(e,"dist/std.scm"),global_env)}function Worker(e){this.url=e;var u=this.worker=fworker(function(){var u;var o;self.addEventListener("message",function(e){var n=e.data;var r=n.id;if(n.type!=="RPC"||r===null){return}function t(e){self.postMessage({id:r,type:"RPC",result:e})}function i(e){self.postMessage({id:r,type:"RPC",error:e})}if(n.method==="eval"){if(!o){i("Worker RPC: LIPS not initilized, call init first");return}o.then(function(){var e=n.params[0];var r=n.params[1];u.exec(e,r).then(function(e){e=e.map(function(e){return e&&e.valueOf()});t(e)})["catch"](function(e){i(e)})})}else if(n.method==="init"){var a=n.params[0];if(typeof a!=="string"){i("Worker RPC: url is not a string")}else{importScripts("".concat(a,"/dist/lips.min.js"));u=new lips.Interpreter("worker");o=bootstrap(a);o.then(function(){t(true)})}}})});this.rpc=function(){var t=0;return function e(r,n){var a=++t;return new Promise(function(t,i){u.addEventListener("message",function e(r){var n=r.data;if(n&&n.type==="RPC"&&n.id===a){if(n.error){i(n.error)}else{t(n.result)}u.removeEventListener("message",e)}});u.postMessage({type:"RPC",method:r,id:a,params:n})})}}();this.rpc("init",[e])["catch"](function(e){console.error(e)});this.exec=function(e){var r=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:false;return this.rpc("eval",[e,r])}}Pair.unDry=function(e){return new Pair(e.car,e.cdr)};Pair.prototype.toDry=function(){return{value:{car:this.car,cdr:this.cdr}}};Nil.prototype.toDry=function(){return{value:null}};Nil.unDry=function(){return nil};LSymbol.prototype.toDry=function(){return{value:{name:this.__name__}}};LSymbol.unDry=function(e){return new LSymbol(e.__name__)};function execError(e){console.error(e.message||e);if(e.code){console.error(e.code.map(function(e,r){return"[".concat(r+1,"]: ").concat(e)}))}}function init(){var u=["text/x-lips","text/x-scheme"];var o;function c(n){return new Promise(function(r){var e=n.getAttribute("src");if(e){return fetch(e).then(function(e){return e.text()}).then(exec).then(r)["catch"](function(e){execError(e);r()})}else{return exec(n.innerHTML).then(r)["catch"](function(e){execError(e);r()})}})}function e(){return new Promise(function(i){var a=Array.from(document.querySelectorAll("script"));return function e(){var r=a.shift();if(!r){i()}else{var n=r.getAttribute("type");if(u.includes(n)){var t=r.getAttribute("bootstrap");if(!o&&typeof t==="string"){bootstrap(t).then(function(){return c(r)}).then(e)}else{c(r).then(e)}}else if(n&&n.match(/lips|lisp/)){console.warn("Expecting "+u.join(" or ")+" found "+n)}return e()}}()})}if(!window.document){return Promise.resolve()}else if(currentScript){var r=currentScript;var n=r.getAttribute("bootstrap");if(typeof n==="string"){return bootstrap(n).then(function(){o=true;return e()})}}return e()}var currentScript=typeof window!=="undefined"&&window.document&&document.currentScript;if(typeof window!=="undefined"){contentLoaded(window,init)}var banner=function(){var e=LString("Sun, 31 Jan 2021 11:47:57 +0000").valueOf();var r=e==="{{"+"DATE}}"?new Date:new Date(e);var n=function e(r){return r.toString().padStart(2,"0")};var t=r.getFullYear();var i=[t,n(r.getMonth()+1),n(r.getDate())].join("-");var a="\n __ __ __\n / / \\ \\ _ _ ___ ___ \\ \\\n| | \\ \\ | | | || . \\/ __> | |\n| | > \\ | |_ | || _/\\__ \\ | |\n| | / ^ \\ |___||_||_| <___/ | |\n \\_\\ /_/ \\_\\ /_/\n\nLIPS Interpreter 1.0.0-beta.11 (".concat(i,") \nCopyright (c) 2018-").concat(t," Jakub T. Jankiewicz\n\nType (env) to see environment with functions macros and variables.\nYou can also use (help name) to display help for specic function or macro and\n(apropos name) to display list of matched names in environment.\n").replace(/^.*\n/,"");return a}();Ahead.__class__="ahead";Pattern.__class__="pattern";Formatter.__class__="formatter";Macro.__class__="macro";Syntax.__class__="syntax";Environment.__class__="environment";InputPort.__class__="input-port";OutputPort.__class__="output-port";OutputStringPort.__class__="output-string-port";InputStringPort.__class__="input-string-port";LNumber.__class__="number";LCharacter.__class__="character";LString.__class__="string";var lips={version:"1.0.0-beta.11",banner:banner,date:"Sun, 31 Jan 2021 11:47:57 +0000",exec:exec,parse:compose(uniterate_async,parse),tokenize:tokenize,evaluate:evaluate,bootstrap:bootstrap,Environment:Environment,env:user_env,Worker:Worker,Interpreter:Interpreter,balanced_parenthesis:balanced,balancedParenthesis:balanced,balanced:balanced,Macro:Macro,Syntax:Syntax,Pair:Pair,Values:Values,QuotedPromise:QuotedPromise,quote:quote,InputPort:InputPort,OutputPort:OutputPort,InputFilePort:InputFilePort,OutputFilePort:OutputFilePort,InputStringPort:InputStringPort,OutputStringPort:OutputStringPort,Formatter:Formatter,Parser:Parser,Lexer:Lexer,specials:specials,repr:repr,nil:nil,eof:eof,LSymbol:LSymbol,LNumber:LNumber,LFloat:LFloat,LComplex:LComplex,LRational:LRational,LBigInteger:LBigInteger,LCharacter:LCharacter,LString:LString,rationalize:rationalize};global_env.set("lips",lips);return lips})})(); \ No newline at end of file +(function(){"use strict";function _readOnlyError(e){throw new Error('"'+e+'" is read-only')}var readOnlyError=_readOnlyError;function createCommonjsModule(e,r){return r={exports:{}},e(r,r.exports),r.exports}var setPrototypeOf=createCommonjsModule(function(t){function n(e,r){t.exports=n=Object.setPrototypeOf||function e(r,t){r.__proto__=t;return r};return n(e,r)}t.exports=n});function _isNativeReflectConstruct(){if(typeof Reflect==="undefined"||!Reflect.construct)return false;if(Reflect.construct.sham)return false;if(typeof Proxy==="function")return true;try{Date.prototype.toString.call(Reflect.construct(Date,[],function(){}));return true}catch(e){return false}}var isNativeReflectConstruct=_isNativeReflectConstruct;var construct=createCommonjsModule(function(n){function i(e,r,t){if(isNativeReflectConstruct()){n.exports=i=Reflect.construct}else{n.exports=i=function e(r,t,n){var i=[null];i.push.apply(i,t);var a=Function.bind.apply(r,i);var u=new a;if(n)setPrototypeOf(u,n.prototype);return u}}return i.apply(null,arguments)}n.exports=i});function _arrayWithHoles(e){if(Array.isArray(e))return e}var arrayWithHoles=_arrayWithHoles;function _iterableToArray(e){if(typeof Symbol!=="undefined"&&Symbol.iterator in Object(e))return Array.from(e)}var iterableToArray=_iterableToArray;function _arrayLikeToArray(e,r){if(r==null||r>e.length)r=e.length;for(var t=0,n=new Array(r);t=0;--r){var i=this.tryEntries[r];var a=i.completion;if(i.tryLoc==="root"){return e("end")}if(i.tryLoc<=this.prev){var u=l.call(i,"catchLoc");var o=l.call(i,"finallyLoc");if(u&&o){if(this.prev=0;--t){var n=this.tryEntries[t];if(n.tryLoc<=this.prev&&l.call(n,"finallyLoc")&&this.prev=0;--r){var t=this.tryEntries[r];if(t.finallyLoc===e){this.complete(t.completion,t.afterLoc);S(t);return m}}},catch:function(e){for(var r=this.tryEntries.length-1;r>=0;--r){var t=this.tryEntries[r];if(t.tryLoc===e){var n=t.completion;if(n.type==="throw"){var i=n.arg;S(t)}return i}}throw new Error("illegal catch attempt")},delegateYield:function(e,r,t){this.delegate={iterator:C(e),resultName:r,nextLoc:t};if(this.method==="next"){this.arg=c}return m}};return u}(e.exports);try{regeneratorRuntime=r}catch(e){Function("r","regeneratorRuntime = r")(r)}});var regenerator=runtime_1;function asyncGeneratorStep(e,r,t,n,i,a,u){try{var o=e[a](u);var c=o.value}catch(e){t(e);return}if(o.done){r(c)}else{Promise.resolve(c).then(n,i)}}function _asyncToGenerator(o){return function(){var e=this,u=arguments;return new Promise(function(r,t){var n=o.apply(e,u);function i(e){asyncGeneratorStep(n,r,t,i,a,"next",e)}function a(e){asyncGeneratorStep(n,r,t,i,a,"throw",e)}i(undefined)})}}var asyncToGenerator=_asyncToGenerator;function _classCallCheck(e,r){if(!(e instanceof r)){throw new TypeError("Cannot call a class as a function")}}var classCallCheck=_classCallCheck;function _defineProperties(e,r){for(var t=0;t=0)continue;t[i]=e[i]}return t}var objectWithoutPropertiesLoose=_objectWithoutPropertiesLoose;function _objectWithoutProperties(e,r){if(e==null)return{};var t=objectWithoutPropertiesLoose(e,r);var n,i;if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(i=0;i=0)continue;if(!Object.prototype.propertyIsEnumerable.call(e,n))continue;t[n]=e[n]}}return t}var objectWithoutProperties=_objectWithoutProperties;function _iterableToArrayLimit(e,r){if(typeof Symbol==="undefined"||!(Symbol.iterator in Object(e)))return;var t=[];var n=true;var i=false;var a=undefined;try{for(var u=e[Symbol.iterator](),o;!(n=(o=u.next()).done);n=true){t.push(o.value);if(r&&t.length===r)break}}catch(e){i=true;a=e}finally{try{if(!n&&u["return"]!=null)u["return"]()}finally{if(i)throw a}}return t}var iterableToArrayLimit=_iterableToArrayLimit;function _slicedToArray(e,r){return arrayWithHoles(e)||iterableToArrayLimit(e,r)||unsupportedIterableToArray(e,r)||nonIterableRest()}var slicedToArray=_slicedToArray;var _typeof_1=createCommonjsModule(function(r){function t(e){"@babel/helpers - typeof";if(typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"){r.exports=t=function e(r){return typeof r}}else{r.exports=t=function e(r){return r&&typeof Symbol==="function"&&r.constructor===Symbol&&r!==Symbol.prototype?"symbol":typeof r}}return t(e)}r.exports=t});function _asyncIterator(e){var r;if(typeof Symbol!=="undefined"){if(Symbol.asyncIterator){r=e[Symbol.asyncIterator];if(r!=null)return r.call(e)}if(Symbol.iterator){r=e[Symbol.iterator];if(r!=null)return r.call(e)}}throw new TypeError("Object is not async iterable")}var asyncIterator=_asyncIterator;function _AwaitValue(e){this.wrapped=e}var AwaitValue=_AwaitValue;function _awaitAsyncGenerator(e){return new AwaitValue(e)}var awaitAsyncGenerator=_awaitAsyncGenerator;function AsyncGenerator(a){var u,o;function e(n,i){return new Promise(function(e,r){var t={key:n,arg:i,resolve:e,reject:r,next:null};if(o){o=o.next=t}else{u=o=t;c(n,i)}})}function c(r,e){try{var t=a[r](e);var n=t.value;var i=n instanceof AwaitValue;Promise.resolve(i?n.wrapped:n).then(function(e){if(i){c(r==="return"?"return":"next",e);return}s(t.done?"return":"normal",e)},function(e){c("throw",e)})}catch(e){s("throw",e)}}function s(e,r){switch(e){case"return":u.resolve({value:r,done:true});break;case"throw":u.reject(r);break;default:u.resolve({value:r,done:false});break}u=u.next;if(u){c(u.key,u.arg)}else{o=null}}this._invoke=e;if(typeof a["return"]!=="function"){this["return"]=undefined}}if(typeof Symbol==="function"&&Symbol.asyncIterator){AsyncGenerator.prototype[Symbol.asyncIterator]=function(){return this}}AsyncGenerator.prototype.next=function(e){return this._invoke("next",e)};AsyncGenerator.prototype["throw"]=function(e){return this._invoke("throw",e)};AsyncGenerator.prototype["return"]=function(e){return this._invoke("return",e)};var AsyncGenerator_1=AsyncGenerator;function _wrapAsyncGenerator(e){return function(){return new AsyncGenerator_1(e.apply(this,arguments))}}var wrapAsyncGenerator=_wrapAsyncGenerator;function _createForOfIteratorHelper(r,e){var t;if(typeof Symbol==="undefined"||r[Symbol.iterator]==null){if(Array.isArray(r)||(t=_unsupportedIterableToArray$1(r))||e&&r&&typeof r.length==="number"){if(t)r=t;var n=0;var i=function e(){};return{s:i,n:function e(){if(n>=r.length)return{done:true};return{done:false,value:r[n++]}},e:function e(r){throw r},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var a=true,u=false,o;return{s:function e(){t=r[Symbol.iterator]()},n:function e(){var r=t.next();a=r.done;return r},e:function e(r){u=true;o=r},f:function e(){try{if(!a&&t["return"]!=null)t["return"]()}finally{if(u)throw o}}}}function _unsupportedIterableToArray$1(e,r){if(!e)return;if(typeof e==="string")return _arrayLikeToArray$1(e,r);var t=Object.prototype.toString.call(e).slice(8,-1);if(t==="Object"&&e.constructor)t=e.constructor.name;if(t==="Map"||t==="Set")return Array.from(e);if(t==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t))return _arrayLikeToArray$1(e,r)}function _arrayLikeToArray$1(e,r){if(r==null||r>e.length)r=e.length;for(var t=0,n=new Array(r);t1&&arguments[1]!==undefined$1?arguments[1]:null;var n=arguments[1]===true;function r(e){if(!is_debug()){return}var r=global_env.get("repr")(e);if(t===null||t instanceof RegExp&&t.test(r)){console.log(global_env.get("type")(e)+": "+r)}if(n){console.log(e)}}if(is_promise(e)){e.then(r)}else{r(e)}return e}function is_debug(){return user_env&&user_env.get("DEBUG",{throwError:false})}if(!root.fetch){root.fetch=function(i,a){a=a||{};return new Promise(function(e,r){var t=new XMLHttpRequest;t.open(a.method||"get",i,true);for(var n in a.headers){t.setRequestHeader(n,a.headers[n])}t.withCredentials=a.credentials=="include";t.onload=function(){e(o())};t.onerror=r;t.send(a.body||null);function o(){var n=[],i=[],a={},u;t.getAllResponseHeaders().replace(/^(.*?):[^\S\n]*([\s\S]*?)$/gm,function(e,r,t){n.push(r=r.toLowerCase());i.push([r,t]);u=a[r];a[r]=u?"".concat(u,",").concat(t):t});return{ok:(t.status/100|0)==2,status:t.status,statusText:t.statusText,url:t.responseURL,clone:o,text:function e(){return Promise.resolve(t.responseText)},json:function e(){return Promise.resolve(t.responseText).then(JSON.parse)},blob:function e(){return Promise.resolve(new Blob([t.response]))},headers:{keys:function e(){return n},entries:function e(){return i},get:function e(r){return a[r.toLowerCase()]},has:function e(r){return r.toLowerCase()in a}}}}})}}function num_mnemicic_re(e){return e?"(?:#".concat(e,"(?:#[ie])?|#[ie]#").concat(e,")"):"(?:#[ie])?"}function gen_rational_re(e,r){return"".concat(num_mnemicic_re(e),"[+-]?").concat(r,"+/").concat(r,"+")}function gen_complex_re(e,r){return"".concat(num_mnemicic_re(e),"(?:[+-]?(?:").concat(r,"+/").concat(r,"+|nan.0|inf.0|").concat(r,"+))?(?:[+-]i|[+-]?(?:").concat(r,"+/").concat(r,"+|").concat(r,"+|nan.0|inf.0)i)(?=[()[\\]\\s]|$)")}function gen_integer_re(e,r){return"".concat(num_mnemicic_re(e),"[+-]?").concat(r,"+")}var re_re=/^#\/((?:\\\/|[^/]|\[[^\]]*\/[^\]]*\])+)\/([gimyus]*)$/;var float_stre="(?:[-+]?(?:[0-9]+(?:[eE][-+]?[0-9]+)|(?:\\.[0-9]+|[0-9]+\\.[0-9]+)(?:[eE][-+]?[0-9]+)?)|[0-9]+\\.)";var complex_float_stre="(?:#[ie])?(?:[+-]?(?:[0-9]+/[0-9]+|nan.0|inf.0|".concat(float_stre,"|[+-]?[0-9]+))?(?:").concat(float_stre,"|[+-](?:[0-9]+/[0-9]+|[0-9]+|nan.0|inf.0))i");var float_re=new RegExp("^(#[ie])?".concat(float_stre,"$"),"i");function make_complex_match_re(e,r){var t=e==="x"?"(?!\\+|".concat(r,")"):"(?!\\.|".concat(r,")");var n="";if(e===""){n="(?:[-+]?(?:[0-9]+(?:[eE][-+]?[0-9]+)|(?:\\.[0-9]+|[0-9]+\\.[0-9]+(?![0-9]))(?:[eE][-+]?[0-9]+)?))"}return new RegExp("^((?:(?:".concat(n,"|[-+]?inf.0|[-+]?nan.0|[+-]?").concat(r,"+/").concat(r,"+(?!").concat(r,")|[+-]?").concat(r,"+)").concat(t,")?)(").concat(n,"|[-+]?inf.0|[-+]?nan.0|[+-]?").concat(r,"+/").concat(r,"+|[+-]?").concat(r,"+|[+-])i$"),"i")}var complex_list_re=function(){var a={};[[10,"","[0-9]"],[16,"x","[0-9a-fA-F]"],[8,"o","[0-7]"],[2,"b","[01]"]].forEach(function(e){var r=slicedToArray(e,3),t=r[0],n=r[1],i=r[2];a[t]=make_complex_match_re(n,i)});return a}();var characters={alarm:"",backspace:"\b",delete:"",escape:"",newline:"\n",null:"\0",return:"\r",space:" ",tab:"\t",dle:"",soh:"",dc1:"",stx:"",dc2:"",etx:"",dc3:"",eot:"",dc4:"",enq:"",nak:"",ack:"",syn:"",bel:"",etb:"",bs:"\b",can:"",ht:"\t",em:"",lf:"\n",sub:"",vt:"\v",esc:"",ff:"\f",fs:"",cr:"\r",gs:"",so:"",rs:"",si:"",us:"",del:""};function ucs2decode(e){var r=[];var t=0;var n=e.length;while(t=55296&&i<=56319&&t1&&arguments[1]!==undefined$1?arguments[1]:10;var t=num_pre_parse(e);var n=t.number.split("/");var i=LRational({num:LNumber([n[0],t.radix||r]),denom:LNumber([n[1],t.radix||r])});if(t.inexact){return i.valueOf()}else{return i}}function parse_integer(e){var r=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:10;var t=num_pre_parse(e);if(t.inexact){return LFloat(parseInt(t.number,t.radix||r))}return LNumber([t.number,t.radix||r])}function parse_character(e){var r=e.match(/#\\x([0-9a-f]+)$/i);var t;if(r){var n=parseInt(r[1],16);t=String.fromCodePoint(n)}else{r=e.match(/#\\(.+)$/);if(r){t=r[1]}}if(t){return LCharacter(t)}throw new Error("Parse: invalid character")}function parse_complex(e){var i=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:10;function r(e){var r;if(e==="+"){r=LNumber(1)}else if(e==="-"){r=LNumber(-1)}else if(e.match(int_bare_re)){r=LNumber([e,i])}else if(e.match(rational_bare_re)){var t=e.split("/");r=LRational({num:LNumber([t[0],i]),denom:LNumber([t[1],i])})}else if(e.match(float_re)){var n=parse_float(e);if(a.exact){return n.toRational()}return n}else if(e.match(/nan.0$/)){return LNumber(NaN)}else if(e.match(/inf.0$/)){if(e[0]==="-"){return LNumber(Number.NEGATIVE_INFINITY)}return LNumber(Number.POSITIVE_INFINITY)}else{throw new Error("Internal Parser Error")}if(a.inexact){return LFloat(r.valueOf())}return r}var a=num_pre_parse(e);i=a.radix||i;var t;var n=a.number.match(complex_bare_match_re);if(i!==10&&n){t=n}else{t=a.number.match(complex_list_re[i])}var u,o;o=r(t[2]);if(t[1]){u=r(t[1])}else{u=LNumber(0)}if(o.cmp(0)===0&&o.__type__==="bigint"){return u}return LComplex({im:o,re:u})}function is_int(e){return parseInt(e.toString(),10)===e}function parse_big_int(e){var r=e.match(/^(([-+]?[0-9]*)(?:\.([0-9]+))?)e([-+]?[0-9]+)/i);if(r){var t=parseInt(r[4],10);var n;var i=r[1].replace(/[-+]?([0-9]*)\..+$/,"$1").length;var a=r[3]&&r[3].length;if(i0){return LNumber(a).mul(o)}}}t=LFloat(t);if(r.exact){return t.toRational()}return t}function parse_string(e){e=e.replace(/\\x([0-9a-f]+);/gi,function(e,r){return"\\u"+r.padStart(4,"0")}).replace(/\n/g,"\\n");var r=e.match(/(\\*)(\\x[0-9A-F])/i);if(r&&r[1].length%2===0){throw new Error("Invalid string literal, unclosed ".concat(r[2]))}try{return LString(JSON.parse(e))}catch(e){throw new Error("Invalid string literal")}}function parse_symbol(e){if(e.match(/^\|.*\|$/)){e=e.replace(/(^\|)|(\|$)/g,"");var t={t:"\t",r:"\r",n:"\n"};e=e.replace(/\\(x[^;]+);/g,function(e,r){return String.fromCharCode(parseInt("0"+r,16))}).replace(/\\(.)/g,function(e,r){return t[r]||r})}return new LSymbol(e)}function parse_argument(e){var r=e.match(re_re);if(r){return new RegExp(r[1],r[2])}else if(e.match(/^"[\s\S]*"$/)){return parse_string(e)}else if(e.match(char_re)){return parse_character(e)}else if(e.match(rational_re)){return parse_rational(e)}else if(e.match(complex_re)){return parse_complex(e)}else if(e.match(int_re)){return parse_integer(e)}else if(e.match(float_re)){return parse_float(e)}else if(e==="nil"){return nil}else if(["+nan.0","-nan.0"].includes(e)){return LNumber(NaN)}else if(["true","#t","#true"].includes(e)){return true}else if(["false","#f","#false"].includes(e)){return false}else if(e.match(/^#[iexobd]/)){throw new Error("Invalid numeric constant")}else{var t=e.match(/#\\(.+)/);if(t&&ucs2decode(t[1]).length===1){return parse_character(e)}return parse_symbol(e)}}function is_symbol_string(e){return!(["(",")","[","]"].includes(e)||e.match(re_re)||e.match(/^"[\s\S]*"$/)||e.match(int_re)||e.match(float_re)||e.match(complex_re)||e.match(rational_re)||e.match(char_re)||["#t","#f","nil","true","false"].includes(e))}var string_re=/"(?:\\[\S\s]|[^"])*"?/g;function escape_regex(e){if(typeof e==="string"){var r=/([-\\^$[\]()+{}?*.|])/g;return e.replace(r,"\\$1")}return e}function Stack(){this.data=[]}Stack.prototype.push=function(e){this.data.push(e)};Stack.prototype.top=function(){return this.data[this.data.length-1]};Stack.prototype.pop=function(){return this.data.pop()};Stack.prototype.is_empty=function(){return!this.data.length};function tokens(e){if(e instanceof LString){e=e.valueOf()}var r=new Lexer(e,{whitespace:true});var t=[];while(true){var n=r.peek(true);if(n===eof){break}t.push(n);r.skip()}return t}function multiline_formatter(e){var r=e.token,t=objectWithoutProperties(e,["token"]);if(r.match(/^"[\s\S]*"$/)&&r.match(/\n/)){var n=new RegExp("^ {1,"+(e.col+1)+"}","mg");r=r.replace(n,"")}return _objectSpread({token:r},t)}function Thunk(e){var r=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:function(){};this.fn=e;this.cont=r}Thunk.prototype.toString=function(){return"#"};function trampoline(n){return function(){for(var e=arguments.length,r=new Array(e),t=0;t1&&arguments[1]!==undefined$1?arguments[1]:false;if(e instanceof LString){e=e.toString()}if(r){return tokens(e)}else{var t=tokens(e).map(function(e){if(e.token==="#\\ "){return e.token}return e.token.trim()}).filter(function(e){return e&&!e.match(/^;/)&&!e.match(/^#\|[\s\S]*\|#$/)});return strip_s_comments(t)}}function strip_s_comments(e){var r=0;var t=null;var n=[];for(var i=0;i0&&arguments[0]!==undefined$1?arguments[0]:null;if(e instanceof LSymbol){e=e.valueOf()}if(is_gensym(e)){return LSymbol(e)}if(e!==null){return new LSymbol(Symbol("#:".concat(e)))}r++;return new LSymbol(Symbol("#:g".concat(r)))}}();function QuotedPromise(e){var t=this;var n={pending:true,rejected:false,fulfilled:false,reason:undefined$1,type:undefined$1};e=e.then(function(e){n.type=type(e);n.fulfilled=true;n.pending=false;return e});read_only(this,"_promise",e,{hidden:true});if(is_function(e["catch"])){e=e["catch"](function(e){n.rejected=true;n.pending=false;n.reason=e})}Object.keys(n).forEach(function(r){Object.defineProperty(t,"__".concat(r,"__"),{enumerable:true,get:function e(){return n[r]}})});this.__promise__=e}QuotedPromise.prototype.then=function(e){return new QuotedPromise(this.valueOf().then(e))};QuotedPromise.prototype["catch"]=function(e){return new QuotedPromise(this.valueOf()["catch"](e))};QuotedPromise.prototype.valueOf=function(){if(!this._promise){throw new Error("QuotedPromise: invalid promise created")}return this._promise};QuotedPromise.prototype.toString=function(){if(this.__pending__){return QuotedPromise.pending_str}if(this.__rejected__){return QuotedPromise.rejected_str}return"#")};QuotedPromise.pending_str="#";QuotedPromise.rejected_str="#";var specials={LITERAL:Symbol["for"]("literal"),SPLICE:Symbol["for"]("splice"),SYMBOL:Symbol["for"]("symbol"),names:function e(){return Object.keys(this._specials)},type:function e(r){return this.get(r).type},get:function e(r){return this._specials[r]},off:function e(r){var t=this;var n=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:null;if(Array.isArray(r)){r.forEach(function(e){return t.off(e,n)})}else if(n===null){delete this._events[r]}else{this._events=this._events.filter(function(e){return e!==n})}},on:function e(r,t){var n=this;if(Array.isArray(r)){r.forEach(function(e){return n.on(e,t)})}else if(!this._events[r]){this._events[r]=[t]}else{this._events[r].push(t)}},trigger:function e(r){for(var t=arguments.length,n=new Array(t>1?t-1:0),i=1;i",new LSymbol("quote-promise"),specials.LITERAL]];Object.defineProperty(specials,"builtin",{writable:false,value:defined_specials.map(function(e){return e[0]})});defined_specials.forEach(function(e){var r=slicedToArray(e,3),t=r[0],n=r[1],i=r[2];specials.append(t,n,i)});var Lexer=function(){function p(e){var r=this;var t=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:{},n=t.whitespace,i=n===void 0?false:n;classCallCheck(this,p);Object.defineProperty(this,"__input__",{value:e.replace(/\r/g,""),enumerable:true});var a={};["_i","_whitespace","_col","_newline","_line","_state","_next","_token","_prev_char"].forEach(function(t){Object.defineProperty(r,t,{configurable:false,enumerable:false,get:function e(){return a[t]},set:function e(r){a[t]=r}})});this._whitespace=i;this._i=this._line=this._col=this._newline=0;this._state=this._next=this._token=null;this._prev_char=""}createClass(p,[{key:"get",value:function e(r){return this.__internal[r]}},{key:"set",value:function e(r,t){this.__internal[r]=t}},{key:"token",value:function e(){var r=arguments.length>0&&arguments[0]!==undefined$1?arguments[0]:false;if(r){var t=this._line;if(this._whitespace&&this._token==="\n"){--t}return{token:this._token,col:this._col,offset:this._i,line:t}}return this._token}},{key:"peek",value:function e(){var r=arguments.length>0&&arguments[0]!==undefined$1?arguments[0]:false;if(this._i>=this.__input__.length){return eof}if(this._token){return this.token(r)}var t=this.next_token();if(t){this._token=this.__input__.substring(this._i,this._next);return this.token(r)}return eof}},{key:"skip",value:function e(){if(this._next!==null){this._token=null;this._i=this._next}}},{key:"read_line",value:function e(){var r=this.__input__.length;if(this._i>=r){return eof}for(var t=this._i;t=t){return eof}if(r+this._i>=t){return this.read_rest()}var n=this._i+r;var i=this.__input__.substring(this._i,n);var a=i.match(/\n/g);if(a){this._line+=a.length}this._i=n;return i}},{key:"peek_char",value:function e(){if(this._i>=this.__input__.length){return eof}return LCharacter(this.__input__[this._i])}},{key:"read_char",value:function e(){var r=this.peek_char();this.skip_char();return r}},{key:"skip_char",value:function e(){if(this._i1&&arguments[1]!==undefined$1?arguments[1]:{},n=t.prev_char,i=t["char"],a=t.next_char;var u=slicedToArray(r,4),o=u[0],c=u[1],s=u[2],l=u[3];if(r.length!==5){throw new Error("Lexer: Invald rule of length ".concat(r.length))}if(!i.match(o)){return false}if(!match_or_null(c,n)){return false}if(!match_or_null(s,a)){return false}if(l!==this._state){return false}return true}},{key:"next_token",value:function e(){if(this._i>=this.__input__.length){return false}var r=true;e:for(var t=this._i,n=this.__input__.length;t2&&arguments[2]!==undefined$1?arguments[2]:null;var i=arguments.length>3&&arguments[3]!==undefined$1?arguments[3]:null;if(r.length===0){throw new Error("Lexer: invalid literal rule")}if(r.length===1){return[[r,n,i,null,null]]}var a=[];for(var u=0,o=r.length;u1&&arguments[1]!==undefined$1?arguments[1]:{},t=r.env,n=r.meta,i=n===void 0?false:n,a=r.formatter,u=a===void 0?multiline_formatter:a;classCallCheck(this,o);if(e instanceof LString){e=e.toString()}read_only(this,"_formatter",u,{hidden:true});read_only(this,"_meta",i,{hidden:true});read_only(this,"__lexer__",new Lexer(e));read_only(this,"__env__",t)}createClass(o,[{key:"resolve",value:function e(r){return this.__env__&&this.__env__.get(r,{throwError:false})}},{key:"peek",value:function(){var e=asyncToGenerator(regenerator.mark(function e(){var t;return regenerator.wrap(function e(r){while(1){switch(r.prev=r.next){case 0:t=this.__lexer__.peek(true);if(!(t===eof)){r.next=4;break}return r.abrupt("return",eof);case 4:if(!this.is_comment(t.token)){r.next=7;break}this.skip();return r.abrupt("continue",0);case 7:if(!(t.token==="#;")){r.next=14;break}this.skip();if(!(this.__lexer__.peek()===eof)){r.next=11;break}throw new Error("Lexer: syntax error eof found after comment");case 11:r.next=13;return this.read_object();case 13:return r.abrupt("continue",0);case 14:return r.abrupt("break",17);case 17:t=this._formatter(t);if(!this._meta){r.next=20;break}return r.abrupt("return",t);case 20:return r.abrupt("return",t.token);case 21:case"end":return r.stop()}}},e,this)}));function r(){return e.apply(this,arguments)}return r}()},{key:"skip",value:function e(){this.__lexer__.skip()}},{key:"is_special",value:function e(r){return specials.names().includes(r)}},{key:"is_builtin",value:function e(r){return specials.builtin.includes(r)}},{key:"read",value:function(){var e=asyncToGenerator(regenerator.mark(function e(){var t;return regenerator.wrap(function e(r){while(1){switch(r.prev=r.next){case 0:r.next=2;return this.peek();case 2:t=r.sent;this.skip();return r.abrupt("return",t);case 5:case"end":return r.stop()}}},e,this)}));function r(){return e.apply(this,arguments)}return r}()},{key:"is_open",value:function e(r){return["(","["].includes(r)}},{key:"is_close",value:function e(r){return[")","]"].includes(r)}},{key:"read_list",value:function(){var e=asyncToGenerator(regenerator.mark(function e(){var t,n,i,a;return regenerator.wrap(function e(r){while(1){switch(r.prev=r.next){case 0:t=nil,n=t;case 1:r.next=4;return this.peek();case 4:i=r.sent;if(!(i===eof)){r.next=7;break}return r.abrupt("break",27);case 7:if(!this.is_close(i)){r.next=10;break}this.skip();return r.abrupt("break",27);case 10:if(!(i==="."&&t!==nil)){r.next=17;break}this.skip();r.next=14;return this.read_object();case 14:n.cdr=r.sent;r.next=25;break;case 17:r.t0=Pair;r.next=20;return this.read_object();case 20:r.t1=r.sent;r.t2=nil;a=new r.t0(r.t1,r.t2);if(t===nil){t=a}else{n.cdr=a}n=a;case 25:r.next=1;break;case 27:return r.abrupt("return",t);case 28:case"end":return r.stop()}}},e,this)}));function r(){return e.apply(this,arguments)}return r}()},{key:"read_value",value:function(){var e=asyncToGenerator(regenerator.mark(function e(){var t;return regenerator.wrap(function e(r){while(1){switch(r.prev=r.next){case 0:r.next=2;return this.read();case 2:t=r.sent;if(!(t===eof)){r.next=5;break}throw new Error("Parser: Expected token eof found");case 5:return r.abrupt("return",parse_argument(t));case 6:case"end":return r.stop()}}},e,this)}));function r(){return e.apply(this,arguments)}return r}()},{key:"is_comment",value:function e(r){return r.match(/^;/)||r.match(/^#\|/)&&r.match(/\|#$/)}},{key:"evaluate",value:function e(r){return _evaluate(r,{env:this.__env__,error:function e(r){throw r}})}},{key:"read_object",value:function(){var e=asyncToGenerator(regenerator.mark(function e(){var t,n,i,a,u,o,c;return regenerator.wrap(function e(r){while(1){switch(r.prev=r.next){case 0:r.next=2;return this.peek();case 2:t=r.sent;if(!(t===eof)){r.next=5;break}return r.abrupt("return",t);case 5:if(!this.is_special(t)){r.next=35;break}n=specials.get(t);i=this.is_builtin(t);this.skip();r.next=11;return this.read_object();case 11:u=r.sent;if(i){r.next=22;break}o=this.__env__.get(n.symbol);if(!(typeof o==="function")){r.next=22;break}if(!is_literal(t)){r.next=19;break}return r.abrupt("return",o.call(this.__env__,u));case 19:if(!(u instanceof Pair)){r.next=21;break}return r.abrupt("return",o.apply(this.__env__,u.to_array(false)));case 21:throw new Error("Parser: Invalid parser extension "+"invocation ".concat(n.symbol));case 22:if(is_literal(t)){a=new Pair(n.symbol,new Pair(u,nil))}else{a=new Pair(n.symbol,u)}if(!i){r.next=25;break}return r.abrupt("return",a);case 25:if(!(o instanceof Macro)){r.next=34;break}r.next=28;return this.evaluate(a);case 28:c=r.sent;if(!(c instanceof Pair||c instanceof LSymbol)){r.next=31;break}return r.abrupt("return",Pair.fromArray([LSymbol("quote"),c]));case 31:return r.abrupt("return",c);case 34:throw new Error("Parser: invlid parser extension: ".concat(n.symbol));case 35:if(!this.is_open(t)){r.next=42;break}this.skip();r.next=39;return this.read_list();case 39:return r.abrupt("return",r.sent);case 42:r.next=44;return this.read_value();case 44:return r.abrupt("return",r.sent);case 45:case"end":return r.stop()}}},e,this)}));function r(){return e.apply(this,arguments)}return r}()}]);return o}();function parse(e,r){return _parse.apply(this,arguments)}function _parse(){_parse=wrapAsyncGenerator(regenerator.mark(function e(t,n){var i,a;return regenerator.wrap(function e(r){while(1){switch(r.prev=r.next){case 0:if(!n){if(global_env){n=global_env.get("**interaction-environment**",{throwError:false})}else{n=user_env}}i=new Parser(t,{env:n});case 2:r.next=5;return awaitAsyncGenerator(i.read_object());case 5:a=r.sent;if(!(a===eof)){r.next=8;break}return r.abrupt("break",12);case 8:r.next=10;return a;case 10:r.next=2;break;case 12:case"end":return r.stop()}}},e)}));return _parse.apply(this,arguments)}function unpromise(r){var e=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:function(e){return e};var t=arguments.length>2&&arguments[2]!==undefined$1?arguments[2]:null;if(r instanceof Array){var n=r.filter(is_promise);if(n.length){return unpromise(Promise.all(r),function(e){if(Object.isFrozen(r)){Object.freeze(e)}return e},t)}return e(r)}if(is_plain_object(r)){var i=Object.keys(r);var a=i.map(function(e){return r[e]});var u=a.filter(is_promise);if(u.length){return unpromise(Promise.all(a),function(e){var n={};e.forEach(function(e,r){var t=i[r];n[t]=e});if(Object.isFrozen(r)){Object.freeze(n)}return n},t)}}if(is_promise(r)){var o=r.then(e);if(t===null){return o}else{return o["catch"](t)}}return e(r)}function read_only(e,r,t){var n=arguments.length>3&&arguments[3]!==undefined$1?arguments[3]:{},i=n.hidden,a=i===void 0?false:i;Object.defineProperty(e,r,{value:t,configurable:true,enumerable:!a})}function uniterate_async(e){return _uniterate_async.apply(this,arguments)}function _uniterate_async(){_uniterate_async=asyncToGenerator(regenerator.mark(function e(t){var n,i,a,u,o,c,s,l;return regenerator.wrap(function e(r){while(1){switch(r.prev=r.next){case 0:n=[];i=true;a=false;r.prev=3;o=asyncIterator(t);case 5:r.next=7;return o.next();case 7:c=r.sent;i=c.done;r.next=11;return c.value;case 11:s=r.sent;if(i){r.next=18;break}l=s;n.push(l);case 15:i=true;r.next=5;break;case 18:r.next=24;break;case 20:r.prev=20;r.t0=r["catch"](3);a=true;u=r.t0;case 24:r.prev=24;r.prev=25;if(!(!i&&o["return"]!=null)){r.next=29;break}r.next=29;return o["return"]();case 29:r.prev=29;if(!a){r.next=32;break}throw u;case 32:return r.finish(29);case 33:return r.finish(24);case 34:return r.abrupt("return",n);case 35:case"end":return r.stop()}}},e,null,[[3,20,24,34],[25,,29,33]])}));return _uniterate_async.apply(this,arguments)}function matcher(e,r){if(r instanceof RegExp){return function(e){return String(e).match(r)}}else if(is_function(r)){return r}}function doc(e,r,t,n){if(typeof e!=="string"){r=arguments[0];t=arguments[1];n=arguments[2];e=null}if(t){if(n){r.__doc__=t}else{r.__doc__=trim_lines(t)}}if(e){r.__name__=e}else if(r.name&&!r[__lambda__]){r.__name__=r.name}return r}function trim_lines(e){return e.split("\n").map(function(e){return e.trim()}).join("\n")}function previousSexp(e){var r=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:1;var t=e.length;if(r<=0){throw Error("previousSexp: Invalid argument sexp = ".concat(r))}e:while(r--&&t>=0){var n=1;while(n>0){var i=e[--t];if(!i){break e}if(i==="("||i.token==="("){n--}else if(i===")"||i.token===")"){n++}}t--}return e.slice(t+1)}function lineIndent(e){if(!e||!e.length){return 0}var r=e.length;if(e[r-1].token==="\n"){return 0}while(--r){if(e[r].token==="\n"){var t=(e[r+1]||{}).token;if(t){return t.length}}}return 0}function match(e,r){return l(e,r)===r.length;function l(t,n){function e(e,r){var t=_createForOfIteratorHelper(e),n;try{for(t.s();!(n=t.n()).done;){var i=n.value;var a=l(i,r);if(a!==-1){return a}}}catch(e){t.e(e)}finally{t.f()}return-1}function r(){return t[a]===Symbol["for"]("symbol")&&!is_symbol_string(n[o])}function i(){var e=t[a+1];var r=n[o+1];if(e!==undefined$1&&r!==undefined$1){return l([e],[r])}}var a=0;var u={};for(var o=0;o0){continue}}else if(r()){return-1}}else if(t[a]instanceof Array){var s=l(t[a],n.slice(o));if(s===-1||s+o>n.length){return-1}o+=s-1;a++;continue}else{return-1}a++}if(t.length!==a){return-1}return n.length}}function Formatter(e){this.__code__=e.replace(/\r/g,"")}Formatter.defaults={offset:0,indent:2,exceptions:{specials:[/^(?:#:)?(?:define(?:-values|-syntax|-macro|-class|-record-type)?|(?:call-with-(?:input-file|output-file|port))|lambda|let-env|try|catch|when|unless|while|syntax-rules|(let|letrec)(-syntax|\*)?)$/],shift:{1:["&","#"]}}};Formatter.match=match;Formatter.prototype._options=function e(r){var t=Formatter.defaults;if(typeof r==="undefined"){return Object.assign({},t)}var n=r&&r.exceptions||{};var i=n.specials||[];var a=n.shift||{1:[]};return _objectSpread(_objectSpread(_objectSpread({},t),r),{},{exceptions:{specials:[].concat(toConsumableArray(t.exceptions.specials),toConsumableArray(i)),shift:_objectSpread(_objectSpread({},a),{},{1:[].concat(toConsumableArray(t.exceptions.shift[1]),toConsumableArray(a[1]))})}})};Formatter.prototype.indent=function e(r){var t=tokenize(this.__code__,true);return this._indent(t,r)};Formatter.exception_shift=function(a,e){function r(e){if(!e.length){return false}if(e.indexOf(a)!==-1){return true}else{var r=e.filter(function(e){return e instanceof RegExp});if(!r.length){return false}var t=_createForOfIteratorHelper(r),n;try{for(t.s();!(n=t.n()).done;){var i=n.value;if(a.match(i)){return true}}}catch(e){t.e(e)}finally{t.f()}}return false}if(r(e.exceptions.specials)){return e.indent}var t=e.exceptions.shift;for(var n=0,i=Object.entries(t);n0){n.offset=0}if(a.toString()===r.toString()&&balanced(a)){return n.offset+a[0].col}else if(a.length===1){return n.offset+a[0].col+1}else{var c=-1;if(u){var s=Formatter.exception_shift(u.token,n);if(s!==-1){c=s}}if(c===-1){c=Formatter.exception_shift(a[1].token,n)}if(c!==-1){return n.offset+a[0].col+c}else if(a[0].line3&&a[1].line===a[3].line){if(a[1].token==="("||a[1].token==="["){return n.offset+a[1].col}return n.offset+a[3].col}else if(a[0].line===a[1].line){return n.offset+n.indent+a[0].col}else{var l=a.slice(2);for(var f=0;f")};Ahead.prototype.match=function(e){return e.match(this.pattern)};function Pattern(){for(var e=arguments.length,r=new Array(e),t=0;t")};Formatter.Pattern=Pattern;Formatter.Ahead=Ahead;var p_o=/^[[(]$/;var p_e=/^[\])]$/;var not_p=/[^()[\]]/;var not_close=new Ahead(/[^)\]]/);var glob=Symbol["for"]("*");var sexp_or_atom=new Pattern([p_o,glob,p_e],[not_p],"+");var sexp=new Pattern([p_o,glob,p_e],"+");var symbol=new Pattern([Symbol["for"]("symbol")],"?");var symbols=new Pattern([Symbol["for"]("symbol")],"*");var identifiers=[p_o,symbols,p_e];var let_value=new Pattern([p_o,Symbol["for"]("symbol"),glob,p_e],"+");var def_lambda_re=keywords_re("define","lambda","syntax-rules");var non_def=/^(?!.*\b(?:[()[\]]|define|let(?:\*|rec|-env|-syntax)?|lambda|syntax-rules)\b).*$/;var let_re=/^(?:#:)?(let(?:\*|rec|-env|-syntax)?)$/;function keywords_re(){for(var e=arguments.length,r=new Array(e),t=0;t0&&!u[e]){u[e]=previousSexp(a,e)}});var o=_createForOfIteratorHelper(n),c;try{for(o.s();!(c=o.n()).done;){var s=slicedToArray(c.value,3),l=s[0],f=s[1],_=s[2];f=f.valueOf();var p=f>0?u[f]:a;var h=match(l,p.filter(function(e){return e.trim()}));var d=t.slice(i).find(function(e){return e.trim()});if(h&&(_ instanceof Ahead&&_.match(d)||!_)){if(!t[i-1].trim()){t[i-1]="\n"}else{t.splice(i,0,"\n");i++}continue}}}catch(e){o.e(e)}finally{o.f()}}this.__code__=t.join("");return this};Formatter.prototype._spaces=function(e){return new Array(e+1).join(" ")};Formatter.prototype.format=function e(r){var t=this.__code__.replace(/[ \t]*\n[ \t]*/g,"\n ");var n=tokenize(t,true);var i=this._options(r);var a=0;var u=0;for(var o=0;o0&&arguments[0]!==undefined$1?arguments[0]:true;var n=new Map;function i(e){if(e instanceof Pair){if(n.has(e)){return n.get(e)}var r=new Pair;n.set(e,r);if(t){r.car=i(e.car)}else{r.car=e.car}r.cdr=i(e.cdr);r[__cycles__]=e[__cycles__];return r}return e}return i(this)};Pair.prototype.last_pair=function(){var e=this;while(true){if(e.cdr===nil){return e}e=e.cdr}};Pair.prototype.to_array=function(){var e=arguments.length>0&&arguments[0]!==undefined$1?arguments[0]:true;var r=[];if(this.car instanceof Pair){if(e){r.push(this.car.to_array())}else{r.push(this.car)}}else{r.push(this.car.valueOf())}if(this.cdr instanceof Pair){r=r.concat(this.cdr.to_array())}return r};Pair.fromArray=function(e){var r=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:true;var t=arguments.length>2&&arguments[2]!==undefined$1?arguments[2]:false;if(e instanceof Pair||t&&e instanceof Array&&e[__data__]){return e}if(r===false){var n=nil;for(var i=e.length;i--;){n=new Pair(e[i],n)}return n}if(e.length&&!(e instanceof Array)){e=toConsumableArray(e)}var a=nil;var u=e.length;while(u--){var o=e[u];if(o instanceof Array){o=Pair.fromArray(o,r,t)}else if(typeof o==="string"){o=LString(o)}else if(typeof o==="number"&&!Number.isNaN(o)){o=LNumber(o)}a=new Pair(o,a)}return a};Pair.prototype.to_object=function(){var e=arguments.length>0&&arguments[0]!==undefined$1?arguments[0]:false;var r=this;var t={};while(true){if(r instanceof Pair&&r.car instanceof Pair){var n=r.car;var i=n.car;if(i instanceof LSymbol){i=i.__name__}if(i instanceof LString){i=i.valueOf()}var a=n.cdr;if(a instanceof Pair){a=a.to_object(e)}if(is_native(a)){if(!e){a=a.valueOf()}}t[i]=a;r=r.cdr}else{break}}return t};Pair.fromPairs=function(e){return e.reduce(function(e,r){return new Pair(new Pair(new LSymbol(r[0]),r[1]),e)},nil)};Pair.fromObject=function(r){var e=Object.keys(r).map(function(e){return[e,r[e]]});return Pair.fromPairs(e)};Pair.prototype.reduce=function(e){var r=this;var t=nil;while(true){if(r!==nil){t=e(t,r.car);r=r.cdr}else{break}}return t};Pair.prototype.reverse=function(){if(this.haveCycles()){throw new Error("You can't reverse list that have cycles")}var e=this;var r=nil;while(e!==nil){var t=e.cdr;e.cdr=r;r=e;e=t}return r};Pair.prototype.transform=function(n){function i(e){if(e instanceof Pair){if(e.replace){delete e.replace;return e}var r=n(e.car);if(r instanceof Pair){r=i(r)}var t=n(e.cdr);if(t instanceof Pair){t=i(t)}return new Pair(r,t)}return e}return i(this)};Pair.prototype.map=function(e){if(typeof this.car!=="undefined"){return new Pair(e(this.car),this.cdr===nil?nil:this.cdr.map(e))}else{return nil}};var repr=new Map;function is_plain_object(e){return e&&_typeof_1(e)==="object"&&e.constructor===Object}var props=Object.getOwnPropertyNames(Array.prototype);var array_methods=[];props.forEach(function(e){array_methods.push(Array[e],Array.prototype[e])});function is_array_method(e){e=unbind(e);return array_methods.includes(e)}function is_lips_function(e){return is_function(e)&&(e[__lambda__]||e.__doc__)}function user_repr(t){var e=t.constructor||Object;var n=is_plain_object(t);var i=is_function(t[Symbol.asyncIterator])||is_function(t[Symbol.iterator]);var a;if(repr.has(e)){a=repr.get(e)}else{repr.forEach(function(e,r){r=unbind(r);if(t.constructor===r&&(r===Object&&n&&!i||r!==Object)){a=e}})}return a}var str_mapping=new Map;[[true,"#t"],[false,"#f"],[null,"null"],[undefined$1,"#"]].forEach(function(e){var r=slicedToArray(e,2),t=r[0],n=r[1];str_mapping.set(t,n)});function symbolize(t){if(t&&_typeof_1(t)==="object"){var n={};var e=Object.getOwnPropertySymbols(t);e.forEach(function(e){var r=e.toString().replace(/Symbol\(([^)]+)\)/,"$1");n[r]=toString(t[e])});var r=Object.getOwnPropertyNames(t);r.forEach(function(e){var r=t[e];if(r&&_typeof_1(r)==="object"&&r.constructor===Object){n[e]=symbolize(r)}else{n[e]=toString(r)}});return n}return t}function get_props(e){return Object.keys(e).concat(Object.getOwnPropertySymbols(e))}function has_own_function(e,r){return e.hasOwnProperty(r)&&is_function(e.toString)}function function_to_string(e){if(is_native_function(e)){return"#"}var r=e.prototype&&e.prototype.constructor;if(is_function(r)&&r[__lambda__]){if(e[__class__]&&r.hasOwnProperty("__name__")){var t=r.__name__;if(LString.isString(t)){t=t.toString();return"#")}return"#"}}if(e.hasOwnProperty("__name__")){var n=e.__name__;if(_typeof_1(n)==="symbol"){n=symbol_to_string(n)}if(typeof n==="string"){return"#")}}if(has_own_function(e,"toString")){return e.toString()}else if(e.name&&!e[__lambda__]){return"#")}else{return"#"}}var instances=new Map;[[Error,function(e){return e.message}],[Pair,function(e,r){var t=r.quote,n=r.skip_cycles,i=r.pair_args;if(!n){e.markCycles()}return e.toString.apply(e,[t].concat(toConsumableArray(i)))}],[LCharacter,function(e,r){var t=r.quote;if(t){return e.toString()}return e.valueOf()}],[LString,function(e,r){var t=r.quote;e=e.toString();if(t){return JSON.stringify(e).replace(/\\n/g,"\n")}return e}],[RegExp,function(e){return"#"+e.toString()}]].forEach(function(e){var r=slicedToArray(e,2),t=r[0],n=r[1];instances.set(t,n)});var native_types=[LSymbol,LNumber,Macro,Values,InputPort,OutputPort,Environment,QuotedPromise];function toString(e,r,t){if(typeof jQuery!=="undefined"&&e instanceof jQuery.fn.init){return"#"}if(str_mapping.has(e)){return str_mapping.get(e)}if(e){var n=e.constructor;if(instances.has(n)){for(var i=arguments.length,a=new Array(i>3?i-3:0),u=3;u"}if(e===null){return"null"}if(_typeof_1(e)==="object"){if(is_function(e.toString)&&e.toString[__lambda__]){return e.toString().valueOf()}var l=e.constructor;if(!l){l=Object}var f;if(typeof l.__class__==="string"){f=l.__class__}else{if(is_prototype(e)){return"#"}var _=user_repr(e);if(_){if(is_function(_)){return _(e,r)}else{throw new Error("toString: Invalid repr value")}}f=l.name}if(type(e)==="instance"&&!is_native_function(l)){f="instance"}if(is_iterator(e,Symbol.iterator)){if(f){return"#")}return"#"}if(is_iterator(e,Symbol.asyncIterator)){if(f){return"#")}return"#"}if(f!==""){return"#<"+f+">"}return"#"}if(typeof e!=="string"){return e.toString()}return e}function is_prototype(e){return e&&_typeof_1(e)==="object"&&e.hasOwnProperty&&e.hasOwnProperty("constructor")&&typeof e.constructor==="function"&&e.constructor.prototype===e}Pair.prototype.markCycles=function(){markCycles(this);return this};Pair.prototype.haveCycles=function(){var e=arguments.length>0&&arguments[0]!==undefined$1?arguments[0]:null;if(!e){return this.haveCycles("car")||this.haveCycles("cdr")}return!!(this[__cycles__]&&this[__cycles__][e])};function markCycles(e){var r=[];var i=[];var a=[];function u(e){if(!r.includes(e)){r.push(e)}}function o(e,r,t,n){if(t instanceof Pair){if(n.includes(t)){if(!a.includes(t)){a.push(t)}if(!e[__cycles__]){e[__cycles__]={}}e[__cycles__][r]=t;if(!i.includes(e)){i.push(e)}return true}}}var c=trampoline(function e(r,t){if(r instanceof Pair){delete r.ref;delete r[__cycles__];u(r);t.push(r);var n=o(r,"car",r.car,t);var i=o(r,"cdr",r.cdr,t);if(!n){c(r.car,t.slice())}if(!i){return new Thunk(function(){return e(r.cdr,t.slice())})}}});function t(e,r){if(e[__cycles__][r]instanceof Pair){var t=n.indexOf(e[__cycles__][r]);e[__cycles__][r]="#".concat(t,"#")}}c(e,[]);var n=r.filter(function(e){return a.includes(e)});n.forEach(function(e,r){e[__ref__]="#".concat(r,"=")});i.forEach(function(e){t(e,"car");t(e,"cdr")})}var pair_to_string=function(){var f=function e(r,t){var n=[];if(r[__ref__]){n.push(r[__ref__]+"(")}else if(!t){n.push("(")}return n};var _=function e(r,t){if(is_debug());if(!t||r[__ref__]){return[")"]}return[]};return trampoline(function e(r,t){var n=arguments.length>2&&arguments[2]!==undefined$1?arguments[2]:{};var i=n.nested,a=i===void 0?false:i,u=n.result,o=u===void 0?[]:u,c=n.cont,s=c===void 0?function(){o.push.apply(o,toConsumableArray(_(r,a)))}:c;o.push.apply(o,toConsumableArray(f(r,a)));var l;if(r[__cycles__]&&r[__cycles__].car){l=r[__cycles__].car}else{l=toString(r.car,t,true,{result:o,cont:s})}if(l!==undefined$1){o.push(l)}return new Thunk(function(){if(r.cdr instanceof Pair){if(r[__cycles__]&&r[__cycles__].cdr){o.push(" . ");o.push(r[__cycles__].cdr)}else{if(r.cdr[__ref__]){o.push(" . ")}else{o.push(" ")}return e(r.cdr,t,{nested:true,result:o,cont:s})}}else if(r.cdr!==nil){o.push(" . ");o.push(toString(r.cdr,t))}},s)})}();Pair.prototype.toString=function(e){var r=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:{},t=r.nested,n=t===void 0?false:t;if(is_debug()){var i=[];pair_to_string(this,e,{result:i});return i.join("")}var a=[];if(this[__ref__]){a.push(this[__ref__]+"(")}else if(!n){a.push("(")}var u;if(this[__cycles__]&&this[__cycles__].car){u=this[__cycles__].car}else{u=toString(this.car,e,true)}if(u!==undefined$1){a.push(u)}if(this.cdr instanceof Pair){if(this[__cycles__]&&this[__cycles__].cdr){a.push(" . ");a.push(this[__cycles__].cdr)}else{if(this.cdr[__ref__]){a.push(" . ")}else{a.push(" ")}var o=this.cdr.toString(e,{nested:true});a.push(o)}}else if(this.cdr!==nil){a=a.concat([" . ",toString(this.cdr,e,true)])}if(!n||this[__ref__]){a.push(")")}return a.join("")};Pair.prototype.set=function(e,r){this[e]=r;if(r instanceof Pair){this.markCycles()}};Pair.prototype.append=function(e){if(e instanceof Array){return this.append(Pair.fromArray(e))}var r=this;if(r.car===undefined$1){if(e instanceof Pair){this.car=e.car;this.cdr=e.cdr}else{this.car=e}}else if(e!==nil){while(true){if(r instanceof Pair&&r.cdr!==nil){r=r.cdr}else{break}}r.cdr=e}return this};function abs(e){return e<0?-e:e}function seq_compare(e,r){var t=toArray(r),n=t[0],i=t.slice(1);while(i.length>0){var a=i,u=slicedToArray(a,1),o=u[0];if(!e(n,o)){return false}var c=i;var s=toArray(c);n=s[0];i=s.slice(1)}return true}function equal(e,r){if(is_function(e)){return is_function(r)&&unbind(e)===unbind(r)}else if(e instanceof LNumber){if(!(r instanceof LNumber)){return false}var t;if(e.__type__===r.__type__){if(e.__type__==="complex"){t=e.__im__.__type__===r.__im__.__type__&&e.__re__.__type__===r.__re__.__type__}else{t=true}if(t&&e.cmp(r)===0){if(e.valueOf()===0){return Object.is(e.valueOf(),r.valueOf())}return true}}return false}else if(typeof e==="number"){if(typeof r!=="number"){return false}if(Number.isNaN(e)){return Number.isNaN(r)}if(e===Number.NEGATIVE_INFINITY){return r===Number.NEGATIVE_INFINITY}if(e===Number.POSITIVE_INFINITY){return r===Number.POSITIVE_INFINITY}return equal(LNumber(e),LNumber(r))}else if(e instanceof LCharacter){if(!(r instanceof LCharacter)){return false}return e.__char__===r.__char__}else{return e===r}}function same_atom(e,r){if(type(e)!==type(r)){return false}if(!is_atom(e)){return false}if(e instanceof RegExp){return e.source===r.source}if(e instanceof LString){return e.valueOf()===r.valueOf()}return equal(e,r)}function is_atom(e){return e instanceof LSymbol||LString.isString(e)||e===nil||e===null||e instanceof LCharacter||e instanceof LNumber||e===true||e===false}var truncate=function(){if(Math.trunc){return Math.trunc}else{return function(e){if(e===0){return 0}else if(e<0){return Math.ceil(e)}else{return Math.floor(e)}}}}();function Macro(e,r,t,n){if(typeof this!=="undefined"&&this.constructor!==Macro||typeof this==="undefined"){return new Macro(e,r)}typecheck("Macro",e,"string",1);typecheck("Macro",r,"function",2);if(t){if(n){this.__doc__=t}else{this.__doc__=trim_lines(t)}}this.__name__=e;this.__fn__=r}Macro.defmacro=function(e,r,t,n){var i=new Macro(e,r,t,n);i.__defmacro__=true;return i};Macro.prototype.invoke=function(e,r,t){var n=r.env,i=r.dynamic_scope,a=r.error;var u={dynamic_scope:i,error:a,macro_expand:t};var o=this.__fn__.call(n,e,u,this.__name__);return o};Macro.prototype.toString=function(){return"#")};var macro="define-macro";var recur_guard=-1e4;function macro_expand(a){return function(){var t=asyncToGenerator(regenerator.mark(function e(t,h){var n,d,i;return regenerator.wrap(function e(r){while(1){switch(r.prev=r.next){case 0:i=function e(){i=asyncToGenerator(regenerator.mark(function e(t,n,i){var a,u,o,c,s,l,f,_,p;return regenerator.wrap(function e(r){while(1){switch(r.prev=r.next){case 0:if(!(t instanceof Pair&&t.car instanceof LSymbol)){r.next=26;break}if(!t[__data__]){r.next=3;break}return r.abrupt("return",t);case 3:a=i.get(t.car,{throwError:false});if(!(a instanceof Macro&&a.__defmacro__)){r.next=26;break}u=a instanceof Syntax?t:t.cdr;r.next=8;return a.invoke(u,_objectSpread(_objectSpread({},h),{},{env:i}),true);case 8:o=r.sent;if(!(a instanceof Syntax)){r.next=17;break}c=o,s=c.expr,l=c.scope;if(!(s instanceof Pair)){r.next=16;break}if(!(n!==-1&&n<=1||n")}return"#"};Syntax.className="syntax";function extract_patterns(e,r,D,w){var t=arguments.length>4&&arguments[4]!==undefined$1?arguments[4]:{};var L={"...":{symbols:{},lists:[]},symbols:{}};var x=t.expansion,F=t.define;function A(e){if(is_debug()){console.log(e)}}A(D);function E(e,r){var t=arguments.length>2&&arguments[2]!==undefined$1?arguments[2]:[];var n=arguments.length>3&&arguments[3]!==undefined$1?arguments[3]:false;A({code:r&&toString(r,true),pattern:e&&toString(e,true)});if(is_atom(e)&&!(e instanceof LSymbol)){return same_atom(e,r)}if(e instanceof LSymbol&&D.includes(e.valueOf())){var i=x.ref(r);if(LSymbol.is(r,e)){if(typeof i==="undefined"){return true}return i===F||i===global_env}return false}if(e instanceof Pair&&e.car instanceof Pair&&e.car.cdr instanceof Pair&&LSymbol.is(e.car.cdr.car,w)){A(">> 0");if(r===nil){A({pattern:e.toString()});if(e.car.car instanceof LSymbol){if(e.car.cdr instanceof Pair&&LSymbol.is(e.car.cdr.car,w)){var a=e.car.car.valueOf();var u=e.last_pair();if(LSymbol.is(u.car,w)){L["..."].symbols[a]=null;return true}else{return false}}var o=e.car.car.valueOf();if(L["..."].symbols[o]){throw new Error("syntax: named ellipsis can only "+"appear onces")}L["..."].symbols[o]=r}}}if(e instanceof Pair&&e.cdr instanceof Pair&&LSymbol.is(e.cdr.car,w)){if(e.cdr.cdr!==nil){if(e.cdr.cdr instanceof Pair){var c=e.cdr.cdr.length();var s=r.length();var l=r;while(s-1>c){l=l.cdr;s--}var f=l.cdr;l.cdr=nil;if(!E(e.cdr.cdr,f,t,n)){return false}}}if(e.car instanceof LSymbol){var _=e.car.__name__;if(L["..."].symbols[_]&&!t.includes(_)&&!n){throw new Error("syntax: named ellipsis can only appear onces")}A(">> 1");if(r===nil){A(">> 2");if(n){A("NIL");L["..."].symbols[_]=nil}else{A("NULL");L["..."].symbols[_]=null}}else if(r instanceof Pair&&(r.car instanceof Pair||r.car===nil)){A(">> 3 "+n);if(n){if(L["..."].symbols[_]){var p=L["..."].symbols[_];if(p===nil){p=new Pair(nil,new Pair(r,nil))}else{p=p.append(new Pair(r,nil))}L["..."].symbols[_]=p}else{L["..."].symbols[_]=new Pair(r,nil)}}else{A(">> 4");L["..."].symbols[_]=new Pair(r,nil)}}else{A(">> 6");if(r instanceof Pair){A(">> 7 "+n);t.push(_);if(!L["..."].symbols[_]){L["..."].symbols[_]=new Pair(r,nil)}else{var h=L["..."].symbols[_];L["..."].symbols[_]=h.append(new Pair(r,nil))}A({IIIIII:L["..."].symbols[_].toString()})}else{A(">> 8");return false}}return true}else if(e.car instanceof Pair){var d=toConsumableArray(t);if(r===nil){A(">> 9");L["..."].lists.push(nil);return true}A(">> 10");var m=r;while(m instanceof Pair){if(!E(e.car,m.car,d,true)){return false}m=m.cdr}return true}return false}if(e instanceof LSymbol){if(LSymbol.is(e,w)){throw new Error("syntax: invalid usage of ellipsis")}A(">> 11");var v=e.__name__;if(D.includes(v)){return true}A({name:v,ellipsis:n});if(n){L["..."].symbols[v]=L["..."].symbols[v]||[];L["..."].symbols[v].push(r)}L.symbols[v]=r;if(!L.symbols[v]);return true}if(e instanceof Pair&&r instanceof Pair){A(">> 12");A({a:12,code:r&&r.toString(),pattern:e.toString()});if(r.cdr===nil){var y=e.car instanceof LSymbol&&e.cdr instanceof LSymbol;if(y){if(!E(e.car,r.car,t,n)){return false}A(">> 12 | 1");var b=e.cdr.valueOf();if(!(b in L.symbols)){L.symbols[b]=nil}b=e.car.valueOf();if(!(b in L.symbols)){L.symbols[b]=r.car}return true}}A({pattern:e.toString(),code:r.toString()});if(e.cdr instanceof Pair&&e.car instanceof LSymbol&&e.cdr.cdr instanceof Pair&&e.cdr.car instanceof LSymbol&&LSymbol.is(e.cdr.cdr.car,w)&&e.cdr.cdr.cdr instanceof Pair&&!LSymbol.is(e.cdr.cdr.cdr.car,w)&&E(e.car,r.car,t,n)&&E(e.cdr.cdr.cdr,r.cdr,t,n)){var g=e.cdr.car.__name__;A({pattern:e.car.toString(),code:r.car.toString(),name:g});if(D.includes(g)){return true}L["..."].symbols[g]=null;return true}A("recur");if(E(e.car,r.car,t,n)&&E(e.cdr,r.cdr,t,n)){return true}}else if(e===nil&&(r===nil||r===undefined$1)){return true}else if(e.car instanceof Pair&&LSymbol.is(e.car.car,w)){throw new Error("syntax: invalid usage of ellipsis")}else{return false}}if(E(e,r)){return L}}function clear_gensyms(e,i){function a(r){if(r instanceof Pair){if(!i.length){return r}var e=a(r.car);var t=a(r.cdr);return new Pair(e,t)}else if(r instanceof LSymbol){var n=i.find(function(e){return e.gensym===r});if(n){return LSymbol(n.name)}return r}else{return r}}return a(e)}function transform_syntax(){var e=arguments.length>0&&arguments[0]!==undefined$1?arguments[0]:{};var A=e.bindings,r=e.expr,E=e.scope,u=e.symbols,a=e.names,S=e.ellipsis;var o={};function c(e){if(e instanceof LSymbol){return true}return["string","symbol"].includes(_typeof_1(e))}function P(e){if(!c(e)){var r=type(e);throw new Error("syntax: internal error, need symbol got ".concat(r))}var t=e.valueOf();if(t===S){throw new Error("syntax: internal error, ellipis not transformed")}var n=_typeof_1(t);if(["string","symbol"].includes(n)){if(t in A.symbols){return A.symbols[t]}else if(n==="string"&&t.match(/\./)){var i=t.split(".");var a=i[0];if(a in A.symbols){return Pair.fromArray([LSymbol("."),A.symbols[a]].concat(i.slice(1).map(function(e){return LString(e)})))}}}if(u.includes(t)){return LSymbol(t)}return s(t)}function C(e){if(is_debug()){console.log(e)}}function s(e){if(!o[e]){var r=E.ref(e);var t=gensym(e);if(r){var n=E.get(e);E.set(t,n)}else{var i=E.get(e,{throwError:false});if(typeof i!=="undefined"){E.set(t,i)}}a.push({name:e,gensym:t});o[e]=t}return o[e]}function k(e,r,t){var n=arguments.length>3&&arguments[3]!==undefined$1?arguments[3]:function(){};var i=t.nested;C(" ==> "+e.toString(true));C(r);if(e instanceof LSymbol){var a=e.valueOf();C("[t 1");if(r[a]){if(r[a]instanceof Pair){var u=r[a],o=u.car,c=u.cdr;if(i){var s=o.car,l=o.cdr;if(l!==nil){n(a,new Pair(l,nil))}return s}if(c!==nil){n(a,c)}return o}else if(r[a]instanceof Array){n(a,r[a].slice(1));return r[a][0]}}return P(a)}if(e instanceof Pair){if(e.car instanceof LSymbol&&e.cdr instanceof Pair&&LSymbol.is(e.cdr.car,S)){C("[t 2");var f=e.car.valueOf();var _=r[f];C({expr:e.toString(true),name:f,bindings:r,item:_});if(_===null){return}else if(_){C({b:r[f].toString()});if(_ instanceof Pair){C("[t 2 Pair "+i);C({______:_.toString()});var p=_.car,h=_.cdr;if(i){if(h!==nil){C("|| next 1");n(f,h)}C({car:p.toString()});return p}else{if(p.cdr!==nil){C("|| next 2");n(f,new Pair(p.cdr,h))}C({car:p.car.toString()});return p.car}}else if(_ instanceof Array){C("[t 2 Array "+i);if(i){n(f,_.slice(1));return Pair.fromArray(_)}else{var d=_.slice(1);if(d.length){n(f,d)}return _[0]}}else{return _}}}C("[t 3 recur "+e.toString());var m=k(e.car,r,t,n);var v=k(e.cdr,r,t,n);return new Pair(m,v)}return e}function N(r,t){var e=Object.values(r);var n=Object.getOwnPropertySymbols(r);if(n.length){e.push.apply(e,toConsumableArray(n.map(function(e){return r[e]})))}return e.length&&e.every(function(e){if(e===null){return!t}return e instanceof Pair||e===nil||e instanceof Array&&e.length})}function O(e){return Object.keys(e).concat(Object.getOwnPropertySymbols(e))}function B(i){var e=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:{},r=e.disabled;C("traverse>> "+i.toString());if(i instanceof Pair){if(!r&&i.car instanceof Pair&&LSymbol.is(i.car.car,S)){return B(i.car.cdr,{disabled:true})}if(i.cdr instanceof Pair&&LSymbol.is(i.cdr.car,S)&&!r){C(">> 1");var t=A["..."].symbols;var n=Object.values(t);if(n.length&&n.every(function(e){return e===null})){return B(i.cdr.cdr,{disabled:r})}var a=O(t);var u=i.car instanceof LSymbol&&LSymbol.is(i.cdr.cdr.car,S);if(i.car instanceof Pair||u){if(A["..."].lists[0]===nil){return nil}var o=i.car;if(u){o=new Pair(i.car,new Pair(i.cdr.car,nil))}C(">> 2");var c;if(a.length){C(">> 2 (a)");var s=_objectSpread({},t);c=nil;var l=function e(){if(!N(s)){return"break"}var n={};var r=function e(r,t){n[r]=t};var t=k(o,s,{nested:true},r);if(t!==undefined$1){if(u){if(c===nil){c=t}else{c=c.append(t)}}else{c=new Pair(t,c)}}s=n};while(true){var f=l();if(f==="break")break}if(c!==nil&&!u){c=c.reverse()}if(i.cdr.cdr!==nil&&!LSymbol.is(i.cdr.cdr.car,S)){var _=B(i.cdr.cdr,{disabled:r});return c.append(_)}return c}else{C(">> 3");var p=k(i.car,t,{nested:true});if(p){return new Pair(p,nil)}return nil}}else if(i.car instanceof LSymbol){C(">> 4");if(LSymbol.is(i.cdr.cdr.car,S)){C(">> 4 (a)")}else{C(">> 4 (b)")}var h=i.car.__name__;var d=defineProperty({},h,t[h]);var m=t[h]===null;var v=nil;var y=function e(){if(!N(d,true)){C({bind:d});return"break"}var n={};var r=function e(r,t){n[r]=t;if(is_debug()){console.log({NEWBIND:n[r].toString()})}};var t=k(i,d,{nested:false},r);C({value:t.toString()});if(typeof t!=="undefined"){v=new Pair(t,v)}d=n};while(true){var b=y();if(b==="break")break}if(v!==nil){v=v.reverse()}if(i.cdr instanceof Pair){if(i.cdr.cdr instanceof Pair||i.cdr.cdr instanceof LSymbol){var g=B(i.cdr.cdr,{disabled:r});if(m){return g}C("<<<< 1");v.append(g)}}C("<<<< 2");return v}}var D=B(i.car,{disabled:r});var w;var L;if(i.car instanceof LSymbol){var x=E.get(i.car,{throwError:false});L=x instanceof Macro&&x.__name__==="syntax-rules"}if(L){if(i.cdr.car instanceof LSymbol){w=new Pair(B(i.cdr.car,{disabled:r}),new Pair(i.cdr.cdr.car,B(i.cdr.cdr.cdr,{disabled:r})))}else{w=new Pair(i.cdr.car,B(i.cdr.cdr,{disabled:r}))}}else{w=B(i.cdr,{disabled:r})}C({a:true,car:toString(i.car),cdr:toString(i.cdr),head:toString(D),rest:toString(w)});return new Pair(D,w)}if(i instanceof LSymbol){if(r&&LSymbol.is(i,S)){return i}var F=P(i);if(typeof F!=="undefined"){return F}}return i}return B(r,{})}function is_null(e){return typeof e==="undefined"||e===nil||e===null}function is_function(e){return typeof e==="function"&&typeof e.bind==="function"}function is_promise(e){if(e instanceof QuotedPromise){return false}if(e instanceof Promise){return true}return e&&typeof e!=="undefined"&&is_function(e.then)}function box(e){switch(_typeof_1(e)){case"string":return LString(e);case"number":if(!Number.isNaN(e)){return LNumber(e)}}return e}function map_object(n,i){var e=Object.getOwnPropertyNames(n);var r=Object.getOwnPropertySymbols(n);e.concat(r).forEach(function(e){var r=i(n[e]);var t=Object.getOwnPropertyDescriptor(n,e);if(!t||t.writable&&n[e]!==r){n[e]=r}});return n}function unbox(r){var e=[LString,LCharacter,LNumber].some(function(e){return r instanceof e});if(e){return r.valueOf()}if(r instanceof Array){return r.map(unbox)}if(is_plain_object(r)){return map_object(r,unbox)}return r}function patch_value(e,r){if(e instanceof Pair){e.markCycles();return quote(e)}if(is_function(e)){if(r){return bind(e,r)}}return box(e)}function unbind(e){if(is_bound(e)){return e[__fn__]}return e}function bind(r,e){if(r[Symbol["for"]("__bound__")]){return r}var t=r.bind(e);var n=Object.getOwnPropertyNames(r).filter(filter_fn_names);n.forEach(function(e){try{t[e]=r[e]}catch(e){}});hidden_prop(t,"__fn__",r);hidden_prop(t,"__context__",e);hidden_prop(t,"__bound__",true);if(is_native_function(r)){hidden_prop(t,"__native__",true)}if(is_plain_object(e)&&r[__lambda__]){hidden_prop(t,"__method__",true)}t.valueOf=function(){return r};return t}function is_object_bound(e){return is_bound(e)&&e[Symbol["for"]("__context__")]===Object}function is_bound(e){return!!(is_function(e)&&e[__fn__])}function lips_context(e){if(is_function(e)){var r=e[__context__];if(r&&(r===lips||r.constructor&&r.constructor.__class__)){return true}}return false}function is_port(e){return e instanceof InputPort||e instanceof OutputPort}function is_port_method(e){if(is_function(e)){if(is_port(e[__context__])){return true}}return false}var __context__=Symbol["for"]("__context__");var __fn__=Symbol["for"]("__fn__");var __data__=Symbol["for"]("__data__");var __ref__=Symbol["for"]("__ref__");var __cycles__=Symbol["for"]("__cycles__");var __class__=Symbol["for"]("__class__");var __method__=Symbol["for"]("__method__");var __prototype__=Symbol["for"]("__prototype__");var __lambda__=Symbol["for"]("__lambda__");var exluded_names=["name","length","caller","callee","arguments","prototype"];function filter_fn_names(e){return!exluded_names.includes(e)}function hidden_prop(e,r,t){Object.defineProperty(e,Symbol["for"](r),{get:function e(){return t},set:function e(){},configurable:false,enumerable:false})}function setFnLength(r,t){try{Object.defineProperty(r,"length",{get:function e(){return t}});return r}catch(e){var n=new Array(t).fill(0).map(function(e,r){return"a"+r}).join(",");var i=new Function("f","return function(".concat(n,") {\n return f.apply(this, arguments);\n };"));return i(r)}}function is_native_function(e){var r=Symbol["for"]("__native__");return is_function(e)&&e.toString().match(/\{\s*\[native code\]\s*\}/)&&(e.name.match(/^bound /)&&e[r]===true||!e.name.match(/^bound /)&&!e[r])}function let_macro(e){var h;switch(e){case Symbol["for"]("letrec"):h="letrec";break;case Symbol["for"]("let"):h="let";break;case Symbol["for"]("let*"):h="let*";break;default:throw new Error("Invalid let_macro value")}return Macro.defmacro(h,function(r,e){var a=e.dynamic_scope,u=e.error,t=e.macro_expand;var o;if(r.car instanceof LSymbol){if(!(r.cdr.car instanceof Pair||r.cdr.car===nil)){throw new Error("let require list of pairs")}var n;if(r.cdr.car===nil){o=nil;n=nil}else{n=r.cdr.car.map(function(e){return e.car});o=r.cdr.car.map(function(e){return e.cdr.car})}return Pair.fromArray([LSymbol("letrec"),[[r.car,Pair(LSymbol("lambda"),Pair(n,r.cdr.cdr))]],Pair(r.car,o)])}else if(t){return}var c=this;o=global_env.get("list->array")(r.car);var s=c.inherit(h);var l,f;if(h==="let*"){f=s}else if(h==="let"){l=[]}var _=0;function p(){var e=new Pair(new LSymbol("begin"),r.cdr);return _evaluate(e,{env:s,dynamic_scope:a,error:u})}return function r(){var t=o[_++];if(a){a=h==="let*"?s:c}if(!t){if(l&&l.length){var e=l.map(function(e){return e.value});var n=e.filter(is_promise);if(n.length){return Promise.all(e).then(function(e){for(var r=0,t=e.length;r1&&arguments[1]!==undefined$1?arguments[1]:{},t=r.dynamic_scope,n=r.error;var i=this;if(t){t=this}var a=e;var u=[];while(a instanceof Pair){u.push(_evaluate(a.car,{env:i,dynamic_scope:t,error:n}));a=a.cdr}var o=u.filter(is_promise).length;if(o){return Promise.all(u).then(c.bind(this))}else{return c.call(this,u)}})}function guardMathCall(e){for(var r=arguments.length,t=new Array(r>1?r-1:0),n=1;n2?n-2:0),a=2;a1&&arguments[1]!==undefined$1?arguments[1]:null;return function(){for(var e=arguments.length,r=new Array(e),t=0;t1?e-1:0),t=1;t=u){return a.apply(this,n)}else{return i}}return i.apply(this,arguments)}}function limit(n,i){typecheck("limit",i,"function",2);return function(){for(var e=arguments.length,r=new Array(e),t=0;t1){e=e.toLowerCase();if(LCharacter.__names__[e]){r=e;e=LCharacter.__names__[e]}else{throw new Error("Internal: Unknown named character")}}else{r=LCharacter.__rev_names__[e]}Object.defineProperty(this,"__char__",{value:e,enumerable:true});if(r){Object.defineProperty(this,"__name__",{value:r,enumerable:true})}}LCharacter.__names__=characters;LCharacter.__rev_names__={};Object.keys(LCharacter.__names__).forEach(function(e){var r=LCharacter.__names__[e];LCharacter.__rev_names__[r]=e});LCharacter.prototype.toUpperCase=function(){return LCharacter(this.__char__.toUpperCase())};LCharacter.prototype.toLowerCase=function(){return LCharacter(this.__char__.toLowerCase())};LCharacter.prototype.toString=function(){return"#\\"+(this.__name__||this.__char__)};LCharacter.prototype.valueOf=function(){return this.__char__};function LString(e){if(typeof this!=="undefined"&&!(this instanceof LString)||typeof this==="undefined"){return new LString(e)}if(e instanceof Array){this.__string__=e.map(function(e,r){typecheck("LString",e,"character",r+1);return e.toString()}).join("")}else{this.__string__=e.valueOf()}}{var ignore=["length","constructor"];var _keys=Object.getOwnPropertyNames(String.prototype).filter(function(e){return!ignore.includes(e)});var wrap=function e(n){return function(){for(var e=arguments.length,r=new Array(e),t=0;t0){t.push(this.__string__.substring(0,e))}t.push(r);if(e1&&arguments[1]!==undefined$1?arguments[1]:false;if(e instanceof LNumber){return e}if(typeof this!=="undefined"&&!(this instanceof LNumber)||typeof this==="undefined"){return new LNumber(e,r)}if(typeof e==="undefined"){throw new Error("Invalid LNumber constructor call")}var t=LNumber.getType(e);if(LNumber.types[t]){return LNumber.types[t](e,r)}var n=e instanceof Array&&LString.isString(e[0])&&LNumber.isNumber(e[1]);if(e instanceof LNumber){return LNumber(e.value)}if(!LNumber.isNumber(e)&&!n){throw new Error("You can't create LNumber from ".concat(type(e)))}if(e===null){e=0}var i;if(n){var a=e,u=slicedToArray(a,2),o=u[0],c=u[1];if(o instanceof LString){o=o.valueOf()}if(c instanceof LNumber){c=c.valueOf()}var s=o.match(/^([+-])/);var l=false;if(s){o=o.replace(/^[+-]/,"");if(s[1]==="-"){l=true}}}if(Number.isNaN(e)){return LFloat(e)}else if(typeof BigInt!=="undefined"){if(typeof e!=="bigint"){if(n){var f;switch(c){case 8:f="0o";break;case 16:f="0x";break;case 2:f="0b";break;case 10:f="";break}if(typeof f==="undefined"){var _=BigInt(c);i=toConsumableArray(o).map(function(e,r){return BigInt(parseInt(e,c))*Math.pow(_,BigInt(r))}).reduce(function(e,r){return e+r})}else{i=BigInt(f+o)}}else{i=BigInt(e)}if(l){i*=BigInt(-1)}}else{i=e}return LBigInteger(i,true)}else if(typeof BN!=="undefined"&&!(e instanceof BN)){if(e instanceof Array){return LBigInteger(construct(BN,toConsumableArray(e)))}return LBigInteger(new BN(e))}else if(n){this.constant(parseInt(o,c),"integer")}else{this.constant(e,"integer")}}LNumber.prototype.constant=function(e,r){Object.defineProperty(this,"__value__",{value:e,enumerable:true});Object.defineProperty(this,"__type__",{value:r,enumerable:true})};LNumber.types={float:function e(r){var t=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:false;return new LFloat(r,t)},complex:function e(r){var t=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:false;if(!LNumber.isComplex(r)){r={im:0,re:r}}return new LComplex(r,t)},rational:function e(r){var t=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:false;if(!LNumber.isRational(r)){r={num:r,denom:1}}return new LRational(r,t)}};LNumber.prototype.isNaN=function(){return Number.isNaN(this.__value__)};LNumber.prototype.gcd=function(e){var r=this.abs();e=e.abs();if(e.cmp(r)===1){var t=r;r=e;e=t}while(true){r=r.rem(e);if(r.cmp(0)===0){return e}e=e.rem(r);if(e.cmp(0)===0){return r}}};LNumber.isFloat=function e(r){return r instanceof LFloat||Number(r)===r&&r%1!==0};LNumber.isNumber=function(e){return e instanceof LNumber||LNumber.isNative(e)||LNumber.isBN(e)};LNumber.isComplex=function(e){if(!e){return false}var r=e instanceof LComplex||(LNumber.isNumber(e.im)||Number.isNaN(e.im))&&(LNumber.isNumber(e.re)||Number.isNaN(e.re));return r};LNumber.isRational=function(e){if(!e){return false}return e instanceof LRational||LNumber.isNumber(e.num)&&LNumber.isNumber(e.denom)};LNumber.isInteger=function(e){if(!(LNumber.isNative(e)||e instanceof LNumber)){return false}if(LNumber.isFloat(e)){return false}if(LNumber.isRational(e)){return false}if(LNumber.isComplex(e)){return false}return true};LNumber.isNative=function(e){return typeof e==="bigint"||typeof e==="number"};LNumber.isBigInteger=function(e){return e instanceof LBigInteger||typeof e==="bigint"||LNumber.isBN(e)};LNumber.isBN=function(e){return typeof BN!=="undefined"&&e instanceof BN};LNumber.getArgsType=function(e,r){if(e instanceof LFloat||r instanceof LFloat){return LFloat}if(e instanceof LBigInteger||r instanceof LBigInteger){return LBigInteger}return LNumber};LNumber.prototype.toString=LNumber.prototype.toJSON=function(e){if(Number.isNaN(this.__value__)){return"+nan.0"}if(e>2&&e<36){return this.__value__.toString(e)}return this.__value__.toString()};LNumber.prototype.asType=function(e){var r=LNumber.getType(this);return LNumber.types[r]?LNumber.types[r](e):LNumber(e)};LNumber.prototype.isBigNumber=function(){return typeof this.__value__==="bigint"||typeof BN!=="undefined"&&!(this.value instanceof BN)};["floor","ceil","round"].forEach(function(e){LNumber.prototype[e]=function(){if(this["float"]||LNumber.isFloat(this.__value__)){return LNumber(Math[e](this.__value__))}else{return LNumber(Math[e](this.valueOf()))}}});LNumber.prototype.valueOf=function(){if(LNumber.isNative(this.__value__)){return Number(this.__value__)}else if(LNumber.isBN(this.__value__)){return this.__value__.toNumber()}};var matrix=function(){var e=function e(r,t){return[r,t]};return{bigint:{bigint:e,float:function e(r,t){return[LFloat(r.valueOf()),t]},rational:function e(r,t){return[{num:r,denom:1},t]},complex:function e(r,t){return[{im:0,re:r},t]}},integer:{integer:e,float:function e(r,t){return[LFloat(r.valueOf()),t]},rational:function e(r,t){return[{num:r,denom:1},t]},complex:function e(r,t){return[{im:0,re:r},t]}},float:{bigint:function e(r,t){return[r,t&&LFloat(t.valueOf())]},integer:function e(r,t){return[r,t&&LFloat(t.valueOf())]},float:e,rational:function e(r,t){return[r,t&&LFloat(t.valueOf())]},complex:function e(r,t){return[{re:r,im:LFloat(0)},t]}},complex:{bigint:r("bigint"),integer:r("integer"),float:r("float"),rational:r("rational"),complex:function e(r,t){var n=LNumber.coerce(r.__re__,t.__re__),i=slicedToArray(n,2),a=i[0],u=i[1];var o=LNumber.coerce(r.__im__,t.__im__),c=slicedToArray(o,2),s=c[0],l=c[1];return[{im:s,re:a},{im:l,re:u}]}},rational:{bigint:function e(r,t){return[r,t&&{num:t,denom:1}]},integer:function e(r,t){return[r,t&&{num:t,denom:1}]},float:function e(r,t){return[LFloat(r.valueOf()),t]},rational:e,complex:function e(r,t){return[{im:coerce(r.__type__,t.__im__.__type__,0)[0],re:coerce(r.__type__,t.__re__.__type__,r)[0]},{im:coerce(r.__type__,t.__im__.__type__,t.__im__)[0],re:coerce(r.__type__,t.__re__.__type__,t.__re__)[0]}]}}};function r(t){return function(e,r){return[{im:coerce(t,e.__im__.__type__,0,e.__im__)[1],re:coerce(t,e.__re__.__type__,0,e.__re__)[1]},{im:coerce(t,e.__im__.__type__,0,0)[1],re:coerce(t,r.__type__,0,r)[1]}]}}}();function coerce(e,r,t,n){return matrix[e][r](t,n)}LNumber.coerce=function(e,r){var t=LNumber.getType(e);var n=LNumber.getType(r);if(!matrix[t]){throw new Error("LNumber::coerce unknown lhs type ".concat(t))}else if(!matrix[t][n]){throw new Error("LNumber::coerce unknown rhs type ".concat(n))}var i=matrix[t][n](e,r);return i.map(function(e){return LNumber(e,true)})};LNumber.prototype.coerce=function(e){if(!(typeof e==="number"||e instanceof LNumber)){throw new Error("LNumber: you can't coerce ".concat(type(e)))}if(typeof e==="number"){e=LNumber(e)}return LNumber.coerce(this,e)};LNumber.getType=function(e){if(e instanceof LNumber){return e.__type__}if(LNumber.isFloat(e)){return"float"}if(LNumber.isComplex(e)){return"complex"}if(LNumber.isRational(e)){return"rational"}if(typeof e==="number"){return"integer"}if(typeof BigInt!=="undefined"&&typeof e!=="bigint"||typeof BN!=="undefined"&&!(e instanceof BN)){return"bigint"}};LNumber.prototype.isFloat=function(){return!!(LNumber.isFloat(this.__value__)||this["float"])};var mapping={add:"+",sub:"-",mul:"*",div:"/",rem:"%",or:"|",and:"&",neg:"~",shl:">>",shr:"<<"};var rev_mapping={};Object.keys(mapping).forEach(function(r){rev_mapping[mapping[r]]=r;LNumber.prototype[r]=function(e){return this.op(mapping[r],e)}});LNumber._ops={"*":function e(r,t){return r*t},"+":function e(r,t){return r+t},"-":function e(r,t){if(typeof t==="undefined"){return-r}return r-t},"/":function e(r,t){return r/t},"%":function e(r,t){return r%t},"|":function e(r,t){return r|t},"&":function e(r,t){return r&t},"~":function e(r){return~r},">>":function e(r,t){return r>>t},"<<":function e(r,t){return r<1&&arguments[1]!==undefined$1?arguments[1]:false;if(typeof this!=="undefined"&&!(this instanceof LComplex)||typeof this==="undefined"){return new LComplex(e,r)}if(e instanceof LComplex){return LComplex({im:e.__im__,re:e.__re__})}if(LNumber.isNumber(e)&&r){if(!r){return Number(e)}}else if(!LNumber.isComplex(e)){throw new Error("Invalid constructor call for LComplex")}var t=e.im instanceof LNumber?e.im:LNumber(e.im);var n=e.re instanceof LNumber?e.re:LNumber(e.re);this.constant(t,n)}LComplex.prototype=Object.create(LNumber.prototype);LComplex.prototype.constructor=LComplex;LComplex.prototype.constant=function(e,r){Object.defineProperty(this,"__im__",{value:e,enumerable:true});Object.defineProperty(this,"__re__",{value:r,enumerable:true});Object.defineProperty(this,"__type__",{value:"complex",enumerable:true})};LComplex.prototype.toRational=function(e){if(LNumber.isFloat(this.__im__)&&LNumber.isFloat(this.__re__)){var r=LFloat(this.__im__).toRational(e);var t=LFloat(this.__re__).toRational(e);return LComplex({im:r,re:t})}return this};LComplex.prototype.add=function(e){return this.complex_op("add",e,function(e,r,t,n){return{re:e.add(r),im:t.add(n)}})};LComplex.prototype.factor=function(){if(this.__im__ instanceof LFloat||this.__im__ instanceof LFloat){var e=this.__re__,r=this.__im__;var t,n;if(e instanceof LFloat){t=e.toRational().mul(e.toRational())}else{t=e.mul(e)}if(r instanceof LFloat){n=r.toRational().mul(r.toRational())}else{n=r.mul(r)}return t.add(n)}else{return this.__re__.mul(this.__re__).add(this.__im__.mul(this.__im__))}};LComplex.prototype.modulus=function(){return this.factor().sqrt()};LComplex.prototype.conjugate=function(){return LComplex({re:this.__re__,im:this.__im__.sub()})};LComplex.prototype.sqrt=function(){var e=this.modulus();var r,t;if(e.cmp(0)===0){r=t=e}else if(this.__re__.cmp(0)===1){r=LFloat(.5).mul(e.add(this.__re__)).sqrt();t=this.__im__.div(r).div(2)}else{t=LFloat(.5).mul(e.sub(this.__re__)).sqrt();if(this.__im__.cmp(0)===-1){t=t.sub()}r=this.__im__.div(t).div(2)}return LComplex({im:t,re:r})};LComplex.prototype.div=function(e){if(LNumber.isNumber(e)&&!LNumber.isComplex(e)){if(!(e instanceof LNumber)){e=LNumber(e)}var r=this.__re__.div(e);var t=this.__im__.div(e);return LComplex({re:r,im:t})}else if(!LNumber.isComplex(e)){throw new Error("[LComplex::div] Invalid value")}var n=this.coerce(e),i=slicedToArray(n,2),a=i[0],u=i[1];var o=u.factor();var c=a.mul(u.conjugate());var s=c.__re__.op("/",o);var l=c.__im__.op("/",o);return LComplex({re:s,im:l})};LComplex.prototype.sub=function(e){return this.complex_op("sub",e,function(e,r,t,n){return{re:e.sub(r),im:t.sub(n)}})};LComplex.prototype.mul=function(e){return this.complex_op("mul",e,function(e,r,t,n){var i={re:e.mul(r).sub(t.mul(n)),im:e.mul(n).add(r.mul(t))};return i})};LComplex.prototype.complex_op=function(e,r,i){var a=this;var t=function e(r,t){var n=i(a.__re__,r,a.__im__,t);if("im"in n&&"re"in n){if(n.im.cmp(0)===0&&!LNumber.isFloat(n.im)){return n.re}return LComplex(n,true)}return n};if(typeof r==="undefined"){return t()}if(LNumber.isNumber(r)&&!LNumber.isComplex(r)){if(!(r instanceof LNumber)){r=LNumber(r)}var n=r.asType(0);r={__im__:n,__re__:r}}else if(!LNumber.isComplex(r)){throw new Error("[LComplex::".concat(e,"] Invalid value"))}var u=r.__re__ instanceof LNumber?r.__re__:this.__re__.asType(r.__re__);var o=r.__im__ instanceof LNumber?r.__im__:this.__im__.asType(r.__im__);return t(u,o)};LComplex._op={"+":"add","-":"sub","*":"mul","/":"div"};LComplex.prototype._op=function(e,r){var t=LComplex._op[e];return this[t](r)};LComplex.prototype.cmp=function(e){var r=this.coerce(e),t=slicedToArray(r,2),n=t[0],i=t[1];var a=n.__re__.coerce(i.__re__),u=slicedToArray(a,2),o=u[0],c=u[1];var s=o.cmp(c);if(s!==0){return s}else{var l=n.__im__.coerce(i.__im__),f=slicedToArray(l,2),_=f[0],p=f[1];return _.cmp(p)}};LComplex.prototype.valueOf=function(){return[this.__re__,this.__im__].map(function(e){return e.valueOf()})};LComplex.prototype.toString=function(){var e;if(this.__re__.cmp(0)!==0){e=[toString(this.__re__)]}else{e=[]}var r=this.__im__.valueOf();var t=[Number.NEGATIVE_INFINITY,Number.POSITIVE_INFINITY].includes(r);var n=toString(this.__im__);if(!t&&!Number.isNaN(r)){var i=this.__im__.cmp(0);if(i<0||i===0&&this.__im__._minus){e.push("-")}else{e.push("+")}n=n.replace(/^-/,"")}e.push(n);e.push("i");return e.join("")};function LFloat(e){if(typeof this!=="undefined"&&!(this instanceof LFloat)||typeof this==="undefined"){return new LFloat(e)}if(!LNumber.isNumber(e)){throw new Error("Invalid constructor call for LFloat")}if(e instanceof LNumber){return LFloat(e.valueOf())}if(typeof e==="number"){if(Object.is(e,-0)){Object.defineProperty(this,"_minus",{value:true})}this.constant(e,"float")}}LFloat.prototype=Object.create(LNumber.prototype);LFloat.prototype.constructor=LFloat;LFloat.prototype.toString=function(){if(this.__value__===Number.NEGATIVE_INFINITY){return"-inf.0"}if(this.__value__===Number.POSITIVE_INFINITY){return"+inf.0"}if(Number.isNaN(this.__value__)){return"+nan.0"}var e=this.__value__.toString();if(!LNumber.isFloat(this.__value__)&&!e.match(/e/i)){var r=e+".0";return this._minus?"-"+r:r}return e.replace(/^([0-9]+)e/,"$1.0e")};LFloat.prototype._op=function(e,r){if(r instanceof LNumber){r=r.__value__}var t=LNumber._ops[e];if(e==="/"&&this.__value__===0&&r===0){return NaN}return LFloat(t(this.__value__,r))};LFloat.prototype.toRational=function(){var e=arguments.length>0&&arguments[0]!==undefined$1?arguments[0]:null;if(e===null){return toRational(this.__value__.valueOf())}return approxRatio(e.valueOf())(this.__value__.valueOf())};var toRational=approxRatio(1e-10);function approxRatio(n){return function(e){var r=function e(n,r,t){var i=function e(r,t){return t0){i=simplest_rational2(n,t)}else if(n.cmp(t)<=0){i=t}else if(t.cmp(0)>0){i=simplest_rational2(t,n)}else if(r.cmp(0)<0){i=LNumber(simplest_rational2(n.sub(),t.sub())).sub()}else{i=LNumber(0)}if(LNumber.isFloat(r)||LNumber.isFloat(e)){return LFloat(i)}return i}function simplest_rational2(e,r){var t=LNumber(e).floor();var n=LNumber(r).floor();if(e.cmp(t)<1){return t}else if(t.cmp(n)===0){var i=LNumber(1).div(r.sub(n));var a=LNumber(1).div(e.sub(t));return t.add(LNumber(1).div(simplest_rational2(i,a)))}else{return t.add(LNumber(1))}}function LRational(e){var r=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:false;if(typeof this!=="undefined"&&!(this instanceof LRational)||typeof this==="undefined"){return new LRational(e,r)}if(!LNumber.isRational(e)){throw new Error("Invalid constructor call for LRational")}var t,n;if(e instanceof LRational){t=LNumber(e.__num__);n=LNumber(e.__denom__)}else{t=LNumber(e.num);n=LNumber(e.denom)}if(!r&&n.cmp(0)!==0){var i=t.op("%",n).cmp(0)===0;if(i){return LNumber(t.div(n))}}this.constant(t,n)}LRational.prototype=Object.create(LNumber.prototype);LRational.prototype.constructor=LRational;LRational.prototype.constant=function(e,r){Object.defineProperty(this,"__num__",{value:e,enumerable:true});Object.defineProperty(this,"__denom__",{value:r,enumerable:true});Object.defineProperty(this,"__type__",{value:"rational",enumerable:true})};LRational.prototype.pow=function(e){var r=e.cmp(0);if(r===0){return LNumber(1)}if(r===-1){e=e.sub();var t=this.__denom__.pow(e);var n=this.__num__.pow(e);return LRational({num:t,denom:n})}var i=this;e=e.valueOf();while(e>1){i=i.mul(this);e--}return i};LRational.prototype.sqrt=function(){var e=this.__num__.sqrt();var r=this.__denom__.sqrt();if(e instanceof LFloat){e=(readOnlyError("num"),e.toRational())}if(r instanceof LFloat){r=(readOnlyError("denom"),r.toRational())}return LRational({num:e,denom:r})};LRational.prototype.abs=function(){var e=this.__num__;var r=this.__denom__;if(e.cmp(0)===-1){e=e.sub()}if(r.cmp(0)!==1){r=r.sub()}return LRational({num:e,denom:r})};LRational.prototype.cmp=function(e){return LNumber(this.valueOf(),true).cmp(e)};LRational.prototype.toString=function(){var e=this.__num__.gcd(this.__denom__);var r,t;if(e.cmp(1)!==0){r=this.__num__.div(e);if(r instanceof LRational){r=LNumber(r.valueOf(true))}t=this.__denom__.div(e);if(t instanceof LRational){t=LNumber(t.valueOf(true))}}else{r=this.__num__;t=this.__denom__}var n=this.cmp(0)<0;if(n){if(r.abs().cmp(t.abs())===0){return r.toString()}}else if(r.cmp(t)===0){return r.toString()}return r.toString()+"/"+t.toString()};LRational.prototype.valueOf=function(e){if(this.__denom__.cmp(0)===0){if(this.__num__.cmp(0)<0){return Number.NEGATIVE_INFINITY}return Number.POSITIVE_INFINITY}if(e){return LNumber._ops["/"](this.__num__.value,this.__denom__.value)}return LFloat(this.__num__.valueOf()).div(this.__denom__.valueOf())};LRational.prototype.mul=function(e){if(!(e instanceof LNumber)){e=LNumber(e)}if(LNumber.isRational(e)){var r=this.__num__.mul(e.__num__);var t=this.__denom__.mul(e.__denom__);return LRational({num:r,denom:t})}var n=LNumber.coerce(this,e),i=slicedToArray(n,2),a=i[0],u=i[1];return a.mul(u)};LRational.prototype.div=function(e){if(!(e instanceof LNumber)){e=LNumber(e)}if(LNumber.isRational(e)){var r=this.__num__.mul(e.__denom__);var t=this.__denom__.mul(e.__num__);return LRational({num:r,denom:t})}var n=LNumber.coerce(this,e),i=slicedToArray(n,2),a=i[0],u=i[1];var o=a.div(u);return o};LRational.prototype._op=function(e,r){return this[rev_mapping[e]](r)};LRational.prototype.sub=function(e){if(typeof e==="undefined"){return this.mul(-1)}if(!(e instanceof LNumber)){e=LNumber(e)}if(LNumber.isRational(e)){var r=e.__num__.sub();var t=e.__denom__;return this.add(LRational({num:r,denom:t}))}if(!(e instanceof LNumber)){e=LNumber(e).sub()}else{e=e.sub()}var n=LNumber.coerce(this,e),i=slicedToArray(n,2),a=i[0],u=i[1];return a.add(u)};LRational.prototype.add=function(e){if(!(e instanceof LNumber)){e=LNumber(e)}if(LNumber.isRational(e)){var r=this.__denom__;var t=e.__denom__;var n=this.__num__;var i=e.__num__;var a,u;if(r!==t){u=t.mul(n).add(i.mul(r));a=r.mul(t)}else{u=n.add(i);a=r}return LRational({num:u,denom:a})}if(LNumber.isFloat(e)){return LFloat(this.valueOf()).add(e)}var o=LNumber.coerce(this,e),c=slicedToArray(o,2),s=c[0],l=c[1];return s.add(l)};function LBigInteger(e,r){if(typeof this!=="undefined"&&!(this instanceof LBigInteger)||typeof this==="undefined"){return new LBigInteger(e,r)}if(e instanceof LBigInteger){return LBigInteger(e.__value__,e._native)}if(!LNumber.isBigInteger(e)){throw new Error("Invalid constructor call for LBigInteger")}this.constant(e,"bigint");Object.defineProperty(this,"_native",{value:r})}LBigInteger.prototype=Object.create(LNumber.prototype);LBigInteger.prototype.constructor=LBigInteger;LBigInteger.bn_op={"+":"iadd","-":"isub","*":"imul","/":"idiv","%":"imod","|":"ior","&":"iand","~":"inot","<<":"ishrn",">>":"ishln"};LBigInteger.prototype._op=function(e,r){if(typeof r==="undefined"){if(LNumber.isBN(this.__value__)){e=LBigInteger.bn_op[e];return LBigInteger(this.__value__.clone()[e](),false)}return LBigInteger(LNumber._ops[e](this.__value__),true)}if(LNumber.isBN(this.__value__)&&LNumber.isBN(r.__value__)){e=LBigInteger.bn_op[e];return LBigInteger(this.__value__.clone()[e](r),false)}var t=LNumber._ops[e](this.__value__,r.__value__);if(e==="/"){var n=this.op("%",r).cmp(0)===0;if(n){return LNumber(t)}return LRational({num:this,denom:r})}return LBigInteger(t,true)};LBigInteger.prototype.sqrt=function(){var e;var r=this.cmp(0)<0;if(LNumber.isNative(this.__value__)){e=LNumber(Math.sqrt(r?-this.valueOf():this.valueOf()))}else if(LNumber.isBN(this.__value__)){e=r?this.__value__.neg().sqrt():this.__value__.sqrt()}if(r){return LComplex({re:0,im:e})}return e};function InputPort(e){var n=this;if(typeof this!=="undefined"&&!(this instanceof InputPort)||typeof this==="undefined"){return new InputPort(e)}typecheck("InputPort",e,"function");read_only(this,"__type__",text_port);var i;Object.defineProperty(this,"__parser__",{enumerable:true,get:function e(){return i},set:function e(r){typecheck("InputPort::__parser__",r,"parser");i=r}});this._read=e;this._with_parser=this._with_init_parser.bind(this,asyncToGenerator(regenerator.mark(function e(){var t;return regenerator.wrap(function e(r){while(1){switch(r.prev=r.next){case 0:if(n.char_ready()){r.next=5;break}r.next=3;return n._read();case 3:t=r.sent;i=new Parser(t,{env:n});case 5:return r.abrupt("return",n.__parser__);case 6:case"end":return r.stop()}}},e)})));this.char_ready=function(){return!!this.__parser__&&this.__parser__.__lexer__.peek()!==eof};this._make_defaults()}InputPort.prototype._make_defaults=function(){this.read=this._with_parser(function(e){return e.read_object()});this.read_line=this._with_parser(function(e){return e.__lexer__.read_line()});this.read_char=this._with_parser(function(e){return e.__lexer__.read_char()});this.read_string=this._with_parser(function(e,r){if(!LNumber.isInteger(r)){var t=LNumber.getType(r);typeErrorMessage("read-string",t,"integer")}return e.__lexer__.read_string(r.valueOf())});this.peek_char=this._with_parser(function(e){return e.__lexer__.peek_char()})};InputPort.prototype._with_init_parser=function(o,c){var s=this;return function(){var e=asyncToGenerator(regenerator.mark(function e(){var t,n,i,a,u=arguments;return regenerator.wrap(function e(r){while(1){switch(r.prev=r.next){case 0:r.next=2;return o.call(s);case 2:t=r.sent;for(n=u.length,i=new Array(n),a=0;a"};function OutputPort(e){if(typeof this!=="undefined"&&!(this instanceof OutputPort)||typeof this==="undefined"){return new OutputPort(e)}typecheck("OutputPort",e,"function");read_only(this,"__type__",text_port);this.write=e}OutputPort.prototype.is_open=function(){return this._closed!==true};OutputPort.prototype.close=function(){Object.defineProperty(this,"_closed",{get:function e(){return true},set:function e(){},configurable:false,enumerable:false});this.write=function(){throw new Error("output-port: port is closed")}};OutputPort.prototype.toString=function(){return"#"};function OutputStringPort(r){var t=this;if(typeof this!=="undefined"&&!(this instanceof OutputStringPort)||typeof this==="undefined"){return new OutputStringPort(r)}typecheck("OutputStringPort",r,"function");read_only(this,"__type__",text_port);read_only(this,"__buffer__",[]);this.write=function(e){if(!LString.isString(e)){e=r(e)}else{e=e.valueOf()}t.__buffer__.push(e)}}OutputStringPort.prototype=Object.create(OutputPort.prototype);OutputStringPort.prototype.constructor=OutputStringPort;OutputStringPort.prototype.toString=function(){return"#"};OutputStringPort.prototype.valueOf=function(){return this.__buffer__.map(function(e){return e.valueOf()}).join("")};function OutputFilePort(e,r){var t=this;if(typeof this!=="undefined"&&!(this instanceof OutputFilePort)||typeof this==="undefined"){return new OutputFilePort(e,r)}typecheck("OutputFilePort",e,"string");read_only(this,"__filename__",e);read_only(this,"_fd",r.valueOf(),{hidden:true});read_only(this,"__type__",text_port);this.write=function(e){if(!LString.isString(e)){e=toString(e)}else{e=e.valueOf()}t.fs().write(t._fd,e,function(e){if(e){throw e}})}}OutputFilePort.prototype=Object.create(OutputPort.prototype);OutputFilePort.prototype.constructor=OutputFilePort;OutputFilePort.prototype.fs=function(){if(!this._fs){this._fs=this.internal("fs")}return this._fs};OutputFilePort.prototype.internal=function(e){return user_env.get("**internal-env**").get(e)};OutputFilePort.prototype.close=function(){var n=this;return new Promise(function(r,t){n.fs().close(n._fd,function(e){if(e){t(e)}else{read_only(n,"_fd",null,{hidden:true});OutputPort.prototype.close.call(n);r()}})})};OutputFilePort.prototype.toString=function(){return"#")};function InputStringPort(e,r){var t=this;if(typeof this!=="undefined"&&!(this instanceof InputStringPort)||typeof this==="undefined"){return new InputStringPort(e)}typecheck("InputStringPort",e,"string");r=r||global_env;e=e.valueOf();this._with_parser=this._with_init_parser.bind(this,function(){if(!t.__parser__){t.__parser__=new Parser(e,{env:r})}return t.__parser__});read_only(this,"__type__",text_port);this._make_defaults()}InputStringPort.prototype.char_ready=function(){return true};InputStringPort.prototype=Object.create(InputPort.prototype);InputStringPort.prototype.constructor=InputStringPort;InputStringPort.prototype.toString=function(){return"#"};function InputByteVectorPort(e){if(typeof this!=="undefined"&&!(this instanceof InputByteVectorPort)||typeof this==="undefined"){return new InputByteVectorPort(e)}typecheck("InputByteVectorPort",e,"uint8array");read_only(this,"__vector__",e);read_only(this,"__type__",binary_port);var t=0;Object.defineProperty(this,"__index__",{enumerable:true,get:function e(){return t},set:function e(r){typecheck("InputByteVectorPort::__index__",r,"number");if(r instanceof LNumber){r=r.valueOf()}if(typeof r==="bigint"){r=Number(r)}if(Math.floor(r)!==r){throw new Error("InputByteVectorPort::__index__ value is "+"not integer")}t=r}})}InputByteVectorPort.prototype=Object.create(InputPort.prototype);InputByteVectorPort.prototype.constructor=InputByteVectorPort;InputByteVectorPort.prototype.toString=function(){return"#"};InputByteVectorPort.prototype.close=function(){var r=this;read_only(this,"__vector__",nil);["read_u8","close","peek_u8","read_u8_vector"].forEach(function(e){r[e]=function(){throw new Error("Input-binary-port: port is closed")}});this.char_ready=function(){return false}};InputByteVectorPort.prototype.u8_ready=function(){return true};InputByteVectorPort.prototype.peek_u8=function(){if(this.__index__>=this.__vector__.length){return eof}return this.__vector__[this.__index__]};InputByteVectorPort.prototype.skip=function(){if(this.__index__<=this.__vector__.length){++this.__index__}};InputByteVectorPort.prototype.read_u8=function(){var e=this.peek_u8();this.skip();return e};InputByteVectorPort.prototype.read_u8_vector=function(e){if(typeof e==="undefined"){e=this.__vector__.length}else if(e>this.__index__+this.__vector__.length){e=this.__index__+this.__vector__.length}if(this.peek_u8()===eof){return eof}return this.__vector__.slice(this.__index__,e)};function OutputByteVectorPort(){if(typeof this!=="undefined"&&!(this instanceof OutputByteVectorPort)||typeof this==="undefined"){return new OutputByteVectorPort}read_only(this,"__type__",binary_port);read_only(this,"_buffer",[],{hidden:true});this.write=function(e){typecheck("write",e,["number","uint8array"]);if(LNumber.isNumber(e)){this._buffer.push(e.valueOf())}else{var r;(r=this._buffer).push.apply(r,toConsumableArray(Array.from(e)))}};Object.defineProperty(this,"__buffer__",{enumerable:true,get:function e(){return Uint8Array.from(this._buffer)}})}OutputByteVectorPort.prototype=Object.create(OutputPort.prototype);OutputByteVectorPort.prototype.constructor=OutputByteVectorPort;OutputByteVectorPort.prototype.close=function(){OutputPort.prototype.close.call(this);read_only(this,"_buffer",null,{hidden:true})};OutputByteVectorPort.prototype._close_guard=function(){if(this._closed){throw new Error("output-port: binary port is closed")}};OutputByteVectorPort.prototype.write_u8=function(e){typecheck("OutputByteVectorPort::write_u8",e,"number");this.write(e)};OutputByteVectorPort.prototype.write_u8_vector=function(e){typecheck("OutputByteVectorPort::write_u8_vector",e,"uint8array");this.write(e)};OutputByteVectorPort.prototype.toString=function(){return"#"};OutputByteVectorPort.prototype.valueOf=function(){return this.__buffer__};function InputFilePort(e,r){if(typeof this!=="undefined"&&!(this instanceof InputFilePort)||typeof this==="undefined"){return new InputFilePort(e,r)}InputStringPort.call(this,e);typecheck("InputFilePort",r,"string");read_only(this,"__filename__",r)}InputFilePort.prototype=Object.create(InputStringPort.prototype);InputFilePort.prototype.constructor=InputFilePort;InputFilePort.prototype.toString=function(){return"#")};function InputBinaryFilePort(e,r){if(typeof this!=="undefined"&&!(this instanceof InputBinaryFilePort)||typeof this==="undefined"){return new InputBinaryFilePort(e,r)}InputByteVectorPort.call(this,e);typecheck("InputBinaryFilePort",r,"string");read_only(this,"__filename__",r)}InputBinaryFilePort.prototype=Object.create(InputByteVectorPort.prototype);InputBinaryFilePort.prototype.constructor=InputBinaryFilePort;InputBinaryFilePort.prototype.toString=function(){return"#")};function OutputBinaryFilePort(e,r){if(typeof this!=="undefined"&&!(this instanceof OutputBinaryFilePort)||typeof this==="undefined"){return new OutputBinaryFilePort(e,r)}typecheck("OutputBinaryFilePort",e,"string");read_only(this,"__filename__",e);read_only(this,"_fd",r.valueOf(),{hidden:true});read_only(this,"__type__",binary_port);var a,t;this.write=function(e){var n=this;typecheck("write",e,["number","uint8array"]);var i;if(!a){a=this.internal("fs")}if(!t){t=this.internal("Buffer")}if(LNumber.isNumber(e)){i=t.from([e.valueOf()])}else{i=t.from(Array.from(e))}return new Promise(function(r,t){a.write(n._fd,i,function(e){if(e){t(e)}else{r()}})})}}OutputBinaryFilePort.prototype=Object.create(OutputFilePort.prototype);OutputBinaryFilePort.prototype.constructor=OutputBinaryFilePort;OutputBinaryFilePort.prototype.write_u8=function(e){typecheck("OutputByteVectorPort::write_u8",e,"number");this.write(e)};OutputBinaryFilePort.prototype.write_u8_vector=function(e){typecheck("OutputByteVectorPort::write_u8_vector",e,"uint8array");this.write(e)};var binary_port=Symbol["for"]("binary");var text_port=Symbol["for"]("text");var eof=new EOF;function EOF(){}EOF.prototype.toString=function(){return"#"};function Interpreter(e){var r=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:{},t=r.stderr,n=r.stdin,i=r.stdout,a=objectWithoutProperties(r,["stderr","stdin","stdout"]);if(typeof this!=="undefined"&&!(this instanceof Interpreter)||typeof this==="undefined"){return new Interpreter(e,_objectSpread({stdin:n,stdout:i,stderr:t},a))}if(typeof e==="undefined"){e="anonymous"}this.__env__=user_env.inherit(e,a);var u="**interaction-environment-defaults**";this.set(u,get_props(a).concat(u));var o=internal_env.inherit("internal-".concat(e));if(is_port(n)){o.set("stdin",n)}if(is_port(t)){o.set("stderr",t)}if(is_port(i)){o.set("stdout",i)}set_interaction_env(this.__env__,o)}Interpreter.prototype.exec=function(e){var r=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:false;var t=arguments.length>2&&arguments[2]!==undefined$1?arguments[2]:null;typecheck("Interpreter::exec",e,"string",1);typecheck("Interpreter::exec",r,"boolean",2);global_env.set("**interaction-environment**",this.__env__);if(t===null){t=this.__env__}return exec(e,t,r?t:false)};Interpreter.prototype.get=function(e){var r=this.__env__.get(e);if(is_function(r)){return r.bind(this.__env__)}return r};Interpreter.prototype.set=function(e,r){return this.__env__.set(e,r)};Interpreter.prototype.constant=function(e,r){return this.__env__.constant(e,r)};function Environment(e,r,t){if(arguments.length===1){if(_typeof_1(arguments[0])==="object"){e=arguments[0];r=null}else if(typeof arguments[0]==="string"){e={};r=null;t=arguments[0]}}this.__docs__=new Map;this.__env__=e;this.__parent__=r;this.__name__=t||"anonymous"}Environment.prototype.list=function(){return get_props(this.__env__)};Environment.prototype.fs=function(){return this.get("**fs**")};Environment.prototype.unset=function(e){if(e instanceof LSymbol){e=e.valueOf()}if(e instanceof LString){e=e.valueOf()}delete this.__env__[e]};Environment.prototype.inherit=function(e){var r=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:{};if(_typeof_1(e)==="object"){r=e}if(!e||_typeof_1(e)==="object"){e="child of "+(this.__name__||"unknown")}return new Environment(r||{},this,e)};Environment.prototype.doc=function(e){var r=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:null;var t=arguments.length>2&&arguments[2]!==undefined$1?arguments[2]:false;if(e instanceof LSymbol){e=e.__name__}if(e instanceof LString){e=e.valueOf()}if(r){if(!t){r=trim_lines(r)}this.__docs__.set(e,r);return this}if(this.__docs__.has(e)){return this.__docs__.get(e)}if(this.__parent__){return this.__parent__.doc(e)}};Environment.prototype.newFrame=function(e,r){var n=this.inherit("__frame__");n.set("parent.frame",doc("parent.frame",function(){var e=arguments.length>0&&arguments[0]!==undefined$1?arguments[0]:1;e=e.valueOf();var r=n.__parent__;if(!(r instanceof Environment)){return nil}if(e<=0){return r}var t=r.get("parent.frame");return t(e-1)},global_env.__env__["parent.frame"].__doc__));r.callee=e;n.set("arguments",r);return n};Environment.prototype._lookup=function(e){if(e instanceof LSymbol){e=e.__name__}if(e instanceof LString){e=e.valueOf()}if(this.__env__.hasOwnProperty(e)){return Value(this.__env__[e])}if(this.__parent__){return this.__parent__._lookup(e)}};Environment.prototype.toString=function(){return"#"};Environment.prototype.clone=function(){var r=this;var t={};Object.keys(this.__env__).forEach(function(e){t[e]=r.__env__[e]});return new Environment(t,this.__parent__,this.__name__)};Environment.prototype.merge=function(e){var r=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:"merge";typecheck("Environment::merge",e,"environment");return this.inherit(r,e.__env__)};function Value(e){if(typeof this!=="undefined"&&!(this instanceof Value)||typeof this==="undefined"){return new Value(e)}this.value=e}Value.isUndefined=function(e){return e instanceof Value&&typeof e.value==="undefined"};Value.prototype.valueOf=function(){return this.value};function Values(e){if(e.length){if(e.length===1){return e[0]}}if(typeof this!=="undefined"&&!(this instanceof Values)||typeof this==="undefined"){return new Values(e)}this.__values__=e}Values.prototype.toString=function(){return this.__values__.map(function(e){return toString(e)}).join("\n")};Values.prototype.valueOf=function(){return this.__values__};Environment.prototype.get=function(e){var r=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:{};typecheck("Environment::get",e,["symbol","string"]);var t=r.throwError,n=t===void 0?true:t;var i=e;if(i instanceof LSymbol||i instanceof LString){i=i.valueOf()}var a=this._lookup(i);if(a instanceof Value){if(Value.isUndefined(a)){return undefined$1}return patch_value(a.valueOf())}if(typeof i==="string"){var u=i.split(".").filter(Boolean);if(u.length>0){var o=toArray(u),c=o[0],s=o.slice(1);a=this._lookup(c);if(s.length){try{if(a instanceof Value){a=a.valueOf()}else{a=get(root,c);if(is_function(a)){a=unbind(a)}}return get.apply(void 0,[a].concat(toConsumableArray(s)))}catch(e){}}else if(a instanceof Value){return patch_value(a.valueOf())}}a=get(root,i)}if(typeof a!=="undefined"){return a}if(n){throw new Error("Unbound variable `"+i.toString()+"'")}};Environment.prototype.set=function(e,r){var t=arguments.length>2&&arguments[2]!==undefined$1?arguments[2]:null;typecheck("Environment::set",e,["string","symbol"]);if(LNumber.isNumber(r)){r=LNumber(r)}if(e instanceof LSymbol){e=e.__name__}if(e instanceof LString){e=e.valueOf()}this.__env__[e]=r;if(t){this.doc(e,t)}return this};Environment.prototype.constant=function(r,e){var t=this;if(this.__env__.hasOwnProperty(r)){throw new Error("Environment::constant: ".concat(r," already exists"))}if(arguments.length===1&&is_plain_object(arguments[0])){var n=arguments[0];Object.keys(n).forEach(function(e){t.constant(r,n[e])})}else{Object.defineProperty(this.__env__,r,{value:e,enumerable:true})}return this};Environment.prototype.has=function(e){return this.__env__.hasOwnProperty(e)};Environment.prototype.ref=function(e){var r=this;while(true){if(!r){break}if(r.has(e)){return r}r=r.__parent__}};Environment.prototype.parents=function(){var e=this;var r=[];while(e){r.unshift(e);e=e.__parent__}return r};function quote(e){if(is_promise(e)){return e.then(quote)}if(e instanceof Pair||e instanceof LSymbol){e[__data__]=true}return e}var native_lambda=parse(tokenize('(lambda ()\n "[native code]"\n (throw "Invalid Invocation"))'))[0];var get=doc(function e(r){for(var t=arguments.length,n=new Array(t>1?t-1:0),i=1;i0&&arguments[0]!==undefined$1?arguments[0]:null;if(e===null){e=internal(this,"stdin")}typecheck_text_port("peek-char",e,"input-port");return e.peek_char()},"(peek-char port)\n\n Function get character from string port or EOF object if no more\n data in string port."),"read-line":doc("read-line",function(){var e=arguments.length>0&&arguments[0]!==undefined$1?arguments[0]:null;if(e===null){e=internal(this,"stdin")}typecheck_text_port("read-line",e,"input-port");return e.read_line()},"(read-char port)\n\n Function read next character from input port."),"read-char":doc("read-char",function(){var e=arguments.length>0&&arguments[0]!==undefined$1?arguments[0]:null;if(e===null){e=internal(this,"stdin")}typecheck_text_port("read-char",e,"input-port");return e.read_char()},"(read-char port)\n\n Function read next character from input port."),read:doc(function(){var e=asyncToGenerator(regenerator.mark(function e(){var t,n,i,a,u,o,c,s,l,f=arguments;return regenerator.wrap(function e(r){while(1){switch(r.prev=r.next){case 0:t=f.length>0&&f[0]!==undefined$1?f[0]:null;if(!LString.isString(t)){r.next=35;break}n=true;i=false;r.prev=4;u=asyncIterator(parse(t,this));case 6:r.next=8;return u.next();case 8:o=r.sent;n=o.done;r.next=12;return o.value;case 12:c=r.sent;if(n){r.next=19;break}s=c;return r.abrupt("return",s);case 16:n=true;r.next=6;break;case 19:r.next=25;break;case 21:r.prev=21;r.t0=r["catch"](4);i=true;a=r.t0;case 25:r.prev=25;r.prev=26;if(!(!n&&u["return"]!=null)){r.next=30;break}r.next=30;return u["return"]();case 30:r.prev=30;if(!i){r.next=33;break}throw a;case 33:return r.finish(30);case 34:return r.finish(25);case 35:if(t===null){l=internal(this,"stdin")}else{l=t}typecheck_text_port("read",l,"input-port");return r.abrupt("return",l.read.call(this));case 38:case"end":return r.stop()}}},e,this,[[4,21,25,35],[26,,30,34]])}));function r(){return e.apply(this,arguments)}return r}(),"(read [string])\n\n Function if used with string will parse the string and return\n list structure of LIPS code. If called without an argument it\n will read string from standard input (using browser prompt or\n user defined way) and call itself with that string (parse is)\n function can be used together with eval to evaluate code from\n string"),pprint:doc(function e(r){if(r instanceof Pair){r=new lips.Formatter(r.toString(true))["break"]().format();global_env.get("display").call(global_env,r)}else{global_env.get("write").call(global_env,r)}global_env.get("newline").call(global_env)},"(pprint expression)\n\n Pretty print list expression, if called with non-pair it just call\n print function with passed argument."),print:doc(function e(){var r=global_env.get("display");var t=global_env.get("newline");for(var n=arguments.length,i=new Array(n),a=0;a1?t-1:0),i=1;in.length){throw new Error("Not enough arguments")}var o=0;var c=global_env.get("repr");r=r.replace(a,function(e){var r=e[1];if(r==="~"){return"~"}else if(r==="%"){return"\n"}else{var t=n[o++];if(r==="a"){return c(t)}else{return c(t,true)}}});u=r.match(/~([\S])/);if(u){throw new Error("format: Unrecognized escape seqence ".concat(u[1]))}return r},"(format string n1 n2 ...)\n\n Function accepts string template and replacing any escape sequences\n by arguments:\n\n * ~a value as if printed with display\n * ~s value as if printed with write\n * ~% newline character\n * ~~ literal tilde '~' is inserted\n\n if there missing arguments or other escape character it throw exception."),display:doc(function e(r){var t=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:null;if(t===null){t=internal(this,"stdout")}else{typecheck("display",t,"output-port")}var n=global_env.get("repr")(r);t.write.call(global_env,n)},"(display arg [port])\n\n Function send string to standard output or provied port."),error:doc(function e(){var r=internal(this,"stderr");var t=global_env.get("repr");for(var n=arguments.length,i=new Array(n),a=0;a1&&arguments[1]!==undefined$1?arguments[1]:{},t=r.dynamic_scope,n=r.error;if(t){t=this}var i=this;var u;var o=_evaluate(e.cdr.car,{env:this,dynamic_scope:t,error:n});o=resolve_promises(o);function c(r,t,n){if(is_promise(r)){return r.then(function(e){return c(r,e,n)})}if(is_promise(t)){return t.then(function(e){return c(r,e,n)})}if(is_promise(n)){return n.then(function(e){return c(r,t,e)})}i.get("set-obj!").call(i,r,t,n);return n}if(e.car instanceof Pair&&LSymbol.is(e.car.car,".")){var s=e.car.cdr.car;var l=e.car.cdr.cdr.car;var f=_evaluate(s,{env:this,dynamic_scope:t,error:n});var _=_evaluate(l,{env:this,dynamic_scope:t,error:n});return c(f,_,o)}if(!(e.car instanceof LSymbol)){throw new Error("set! first argument need to be a symbol or "+"dot accessor that evaluate to object.")}var p=e.car.valueOf();u=this.ref(e.car.__name__);return unpromise(o,function(e){if(!u){var r=p.split(".");if(r.length>1){var t=r.pop();var n=r.join(".");var i=a.get(n,{throwError:false});if(i){c(i,t,e);return}}throw new Error("Unbound variable `"+p+"'")}u.set(p,e)})}),"(set! name value)\n\n Macro that can be used to set the value of the variable (mutate)\n it search the scope chain until it finds first non emtpy slot and set it."),"unset!":doc(new Macro("set!",function(e){if(!(e.car instanceof LSymbol)){throw new Error("unset! first argument need to be a symbol or "+"dot accessor that evaluate to object.")}var r=e.car;var t=this.ref(r);if(t){delete t.__env__[r.__name__]}}),"(unset! name)\n\n Function delete specified name from environment."),"set-car!":doc("set-car!",function(e,r){typecheck("set-car!",e,"pair");e.car=r},"(set-car! obj value)\n\n Function that set car (head) of the list/pair to specified value.\n It can destroy the list. Old value is lost."),"set-cdr!":doc("set-cdr!",function(e,r){typecheck("set-cdr!",e,"pair");e.cdr=r},"(set-cdr! obj value)\n\n Function that set cdr (tail) of the list/pair to specified value.\n It can destroy the list. Old value is lost."),"empty?":doc("empty?",function(e){return typeof e==="undefined"||e===nil},"(empty? object)\n\n Function return true if value is undfined empty list."),gensym:doc("gensym",gensym,"(gensym)\n\n Function generate unique symbol, to use with macros as meta name."),load:doc(function e(r,t){typecheck("load",r,"string");var n=this;if(n.__name__==="__frame__"){n=n.__parent__}if(!(t instanceof Environment)){if(n===global_env){t=n}else{t=this.get("**interaction-environment**")}}var i="**module-path**";var a=global_env.get(i,{throwError:false});r=r.valueOf();if(!r.match(/.[^.]+$/)){r+=".scm"}function u(e){if(type(e)==="buffer"){e=e.toString()}return exec(e.replace(/^#!.*/,""),t)}if(is_node()){return new Promise(function(t,n){var e=nodeRequire("path");if(a){a=a.valueOf();r=e.join(a,r)}global_env.set(i,e.dirname(r));nodeRequire("fs").readFile(r,function(e,r){if(e){n(e);global_env.set(i,a)}else{try{u(r).then(function(){t();global_env.set(i,a)})["catch"](n)}catch(e){n(e)}}})})}if(a){a=a.valueOf();r=a+"/"+r.replace(/^\.?\/?/,"")}return root.fetch(r).then(function(e){return e.text()}).then(function(e){global_env.set(i,r.replace(/\/[^/]*$/,""));return u(e)}).then(function(){})["finally"](function(){global_env.set(i,a)})},"(load filename)\n (load filename environment)\n\n Function fetch the file and evaluate its content as LIPS code,\n If second argument is provided and it's environment the evaluation\n will happen in that environment."),do:doc(new Macro("do",function(){var t=asyncToGenerator(regenerator.mark(function e(t,n){var i,a,u,o,c,s,l,f,_,p,h;return regenerator.wrap(function e(r){while(1){switch(r.prev=r.next){case 0:i=n.dynamic_scope,a=n.error;u=this;if(i){i=u}o=u.inherit("do");c=t.car;s=t.cdr.car;l=t.cdr.cdr;if(l!==nil){l=new Pair(LSymbol("begin"),l)}f={env:u,dynamic_scope:i,error:a};_=c;case 10:if(!(_!==nil)){r.next=21;break}p=_.car;r.t0=o;r.t1=p.car;r.next=16;return _evaluate(p.cdr.car,f);case 16:r.t2=r.sent;r.t0.set.call(r.t0,r.t1,r.t2);_=_.cdr;r.next=10;break;case 21:f={env:o,dynamic_scope:i,error:a};h=regenerator.mark(function e(){var t,n,i,a,u;return regenerator.wrap(function e(r){while(1){switch(r.prev=r.next){case 0:if(!(l!==nil)){r.next=3;break}r.next=3;return lips.evaluate(l,f);case 3:t=c;n={};case 5:if(!(t!==nil)){r.next=15;break}i=t.car;if(!(i.cdr.cdr!==nil)){r.next=12;break}r.next=10;return _evaluate(i.cdr.cdr.car,f);case 10:a=r.sent;n[i.car.valueOf()]=a;case 12:t=t.cdr;r.next=5;break;case 15:u=Object.getOwnPropertySymbols(n);Object.keys(n).concat(u).forEach(function(e){o.set(e,n[e])});case 17:case"end":return r.stop()}}},e)});case 23:r.next=25;return _evaluate(s.car,f);case 25:r.t3=r.sent;if(!(r.t3===false)){r.next=30;break}return r.delegateYield(h(),"t4",28);case 28:r.next=23;break;case 30:if(!(s.cdr!==nil)){r.next=34;break}r.next=33;return _evaluate(s.cdr.car,f);case 33:return r.abrupt("return",r.sent);case 34:case"end":return r.stop()}}},e,this)}));return function(e,r){return t.apply(this,arguments)}}()),"(do (( )) (test expression) . body)\n\n Iteration macro that evaluate the expression body in scope of the variables.\n On Eeach loop it increase the variables according to next expression and run\n test to check if the loop should continue. If test is signle call the macro\n will not return anything. If the test is pair of expression and value the\n macro will return that value after finish."),if:doc(new Macro("if",function(t,e){var n=e.dynamic_scope,i=e.error;if(n){n=this}var a=this;var r=function e(r){if(r===false){return _evaluate(t.cdr.cdr.car,{env:a,dynamic_scope:n,error:i})}else{return _evaluate(t.cdr.car,{env:a,dynamic_scope:n,error:i})}};if(t===nil){throw new Error("too few expressions for `if`")}var u=_evaluate(t.car,{env:a,dynamic_scope:n,error:i});return unpromise(u,r)}),"(if cond true-expr false-expr)\n\n Macro evaluate condition expression and if the value is true, it\n evaluate and return true expression if not it evaluate and return\n false expression"),"let-env":new Macro("let-env",function(r){var e=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:{};var t=e.dynamic_scope,n=e.error;typecheck("let-env",r,"pair");var i=_evaluate(r.car,{env:this,dynamic_scope:t,error:n});return unpromise(i,function(e){typecheck("let-env",e,"environment");return _evaluate(Pair(LSymbol("begin"),r.cdr),{env:e,dynamic_scope:t,error:n})})},"(let-env env . body)\n\n Special macro that evaluate body in context of given environment\n object."),letrec:doc(let_macro(Symbol["for"]("letrec")),"(letrec ((a value-a) (b value-b)) body)\n\n Macro that creates new environment, then evaluate and assign values to\n names and then evaluate the body in context of that environment.\n Values are evaluated sequentialy and next value can access to\n previous values/names."),"letrec*":doc(let_macro(Symbol["for"]("letrec")),"(letrec* ((a value-a) (b value-b)) body)\n\n Same as letrec but the order of execution of the binding is guaranteed,\n so use can use recursive code as well as reference previous binding.\n In LIPS both letrec and letrec* behave the same."),"let*":doc(let_macro(Symbol["for"]("let*")),"(let* ((a value-a) (b value-b)) body)\n\n Macro similar to `let` but next argument get environment\n from previous let variable, so they you can define one variable,\n and use in next argument."),let:doc(let_macro(Symbol["for"]("let")),"(let ((a value-a) (b value-b)) body)\n\n Macro that creates new environment, then evaluate and assign values to\n names and then evaluate the body in context of that environment.\n Values are evaluated sequentialy but you can't access\n previous values/names when next are evaluated. You can only get them\n from body of let expression."),"begin*":doc(pararel("begin*",function(e){return e.pop()}),"(begin* . expr)\n\n This macro is parallel version of begin. It evaluate each expression and\n if it's a promise it will evaluate it in parallel and return value\n of last expression."),begin:doc(new Macro("begin",function(e,r){var n=Object.assign({},r);var i=global_env.get("list->array")(e);if(n.dynamic_scope){n.dynamic_scope=this}n.env=this;var a;return function r(){if(i.length){var e=i.shift();var t=_evaluate(e,n);return unpromise(t,function(e){a=e;return r()})}else{return a}}()}),"(begin . args)\n\n Macro runs list of expression and return valuate of the list one.\n It can be used in place where you can only have single exression,\n like if expression."),ignore:new Macro("ignore",function(e,r){var t=r.dynamic_scope,n=r.error;var i={env:this,error:n};if(t){i.dynamic_scope=this}_evaluate(new Pair(new LSymbol("begin"),e),i)},"(ignore expression)\n\n Macro that will evaluate expression and swallow any promises that may\n be created. It wil run and ignore any value that may be returned by\n expression. The code should have side effects and/or when it's promise\n it should resolve to undefined."),define:doc(Macro.defmacro("define",function(t,e){var n=this;if(t.car instanceof Pair&&t.car.car instanceof LSymbol){var r=new Pair(new LSymbol("define"),new Pair(t.car.car,new Pair(new Pair(new LSymbol("lambda"),new Pair(t.car.cdr,t.cdr)))));return r}else if(e.macro_expand){return}if(e.dynamic_scope){e.dynamic_scope=this}e.env=n;var i=t.cdr.car;var a;if(i instanceof Pair){i=_evaluate(i,e);a=true}else if(i instanceof LSymbol){i=n.get(i)}typecheck("define",t.car,"symbol");return unpromise(i,function(e){if(n.__name__===Syntax.__merge_env__){n=n.__parent__}if(a&&(is_function(e)&&e[__lambda__]||e instanceof Syntax)){e.__name__=t.car.valueOf();if(e.__name__ instanceof LString){e.__name__=e.__name__.valueOf()}}var r;if(t.cdr.cdr instanceof Pair&&LString.isString(t.cdr.cdr.car)){r=t.cdr.cdr.car.valueOf()}n.set(t.car,e,r,true)})}),"(define name expression)\n (define (function-name . args) body)\n\n Macro for defining values. It can be used to define variables,\n or function. If first argument is list it will create function\n with name beeing first element of the list. The macro evalute\n code `(define function (lambda args body))`"),"set-obj!":doc("set-obj!",function(e,r,t){var n=_typeof_1(e);if(is_null(e)||n!=="object"&&n!=="function"){var i=typeErrorMessage("set-obj!",type(e),["object","function"]);throw new Error(i)}e=unbind(e);r=r.valueOf();if(arguments.length===2){delete e[r]}else if(is_prototype(e)&&is_function(t)){e[r]=unbind(t);e[r][__prototype__]=true}else if(is_function(t)||is_native(t)||t===nil){e[r]=t}else{e[r]=t?t.valueOf():t}},"(set-obj! obj key value)\n\n Function set property of JavaScript object"),"null-environment":doc("null-environment",function(){return global_env.inherit("null")},"(null-environment)\n\n Function return new base environment with std lib."),values:doc(function e(){for(var r=arguments.length,t=new Array(r),n=0;n1&&arguments[1]!==undefined$1?arguments[1]:{},_=e.dynamic_scope,p=e.error;var h=this;var d;if(f.cdr instanceof Pair&&LString.isString(f.cdr.car)&&f.cdr.cdr!==nil){d=f.cdr.car.valueOf()}function m(){var e;if(_){if(!(this instanceof Environment)){e=h}else{e=this}}else{e=h}e=e.inherit("lambda");var r=f.car;var t=0;var n;if(typeof this!=="undefined"&&!(this instanceof Environment)){if(this&&!this.__instance__){Object.defineProperty(this,"__instance__",{enumerable:false,get:function e(){return true},set:function e(){},configurable:false})}e.set("this",this)}for(var i=arguments.length,a=new Array(i),u=0;u2&&arguments[2]!==undefined$1?arguments[2]:a;if(e instanceof Pair){var n=e.car;var i=e.cdr;if(t(n)){n=r(n)}if(t(i)){i=r(i)}if(is_promise(n)||is_promise(i)){return Promise.all([n,i]).then(function(e){var r=slicedToArray(e,2),t=r[0],n=r[1];return new Pair(t,n)})}else{return new Pair(n,i)}}return e}function u(e,r){if(e instanceof Pair){if(r!==nil){e.append(r)}}else{e=new Pair(e,r)}return e}function t(e){return!!e.filter(function(e){return e instanceof Pair&&LSymbol.is(e.car,/^(unquote|unquote-splicing)$/)}).length}function f(e,n,i){return e.reduce(function(e,r){if(!(r instanceof Pair)){e.push(r);return e}if(LSymbol.is(r.car,"unquote-splicing")){var t;if(n+11){var r="You can't splice multiple atoms inside list";throw new Error(r)}if(!(i.cdr instanceof Pair&&t[0]===nil)){return t[0]}}t=t.map(function(e){if(h.has(e)){return e.clone()}else{h.add(e);return e}});var n=d(i.cdr,0,1);if(n===nil&&t[0]===nil){return undefined$1}return unpromise(n,function(e){if(t[0]===nil){return e}if(t.length===1){return u(t[0],e)}var r=t.reduce(function(e,r){return u(e,r)});return u(r,e)})})}(i.car.cdr)}var h=new Set;function d(e,r,t){if(e instanceof Pair){if(LSymbol.is(e.car.car,"unquote-splicing")){return p(e,r+1,t)}if(LSymbol.is(e.car,"quasiquote")){var n=d(e.cdr,r,t+1);return new Pair(e.car,n)}if(LSymbol.is(e.car.car,"unquote")){if(r+2===t&&e.car.cdr instanceof Pair&&e.car.cdr.car instanceof Pair&&LSymbol.is(e.car.cdr.car.car,"unquote-splicing")){var i=e.car.cdr;return new Pair(new Pair(new LSymbol("unquote"),p(i,r+2,t)),nil)}else if(e.car.cdr instanceof Pair&&e.car.cdr.cdr!==nil){if(e.car.cdr.car instanceof Pair){var a=[];return function r(t){if(t===nil){return Pair.fromArray(a)}return unpromise(_evaluate(t.car,{env:s,dynamic_scope:o,error:c}),function(e){a.push(e);return r(t.cdr)})}(e.car.cdr)}else{return e.car.cdr}}}if(LSymbol.is(e.car,"quote")){return new Pair(e.car,d(e.cdr,r,t))}if(LSymbol.is(e.car,"unquote")){r++;if(rt){throw new Error("You can't call `unquote` outside "+"of quasiquote")}if(e.cdr instanceof Pair){if(e.cdr.cdr!==nil){if(e.cdr.car instanceof Pair){var u=[];return function r(t){if(t===nil){return Pair.fromArray(u)}return unpromise(_evaluate(t.car,{env:s,dynamic_scope:o,error:c}),function(e){u.push(e);return r(t.cdr)})}(e.cdr)}else{return e.cdr}}else{return _evaluate(e.cdr.car,{env:s,dynamic_scope:o,error:c})}}else{return e.cdr}}return l(e,function(e){return d(e,r,t)})}else if(is_plain_object(e)){return _(e,r,t)}else if(e instanceof Array){return f(e,r,t)}return e}function n(e){if(e instanceof Pair){delete e[__data__];if(!e.haveCycles("car")){n(e.car)}if(!e.haveCycles("cdr")){n(e.cdr)}}}if(is_plain_object(e.car)&&!t(Object.values(e.car))){return quote(e.car)}if(Array.isArray(e.car)&&!t(e.car)){return quote(e.car)}if(e.car instanceof Pair&&!e.car.find("unquote")&&!e.car.find("unquote-splicing")&&!e.car.find("quasiquote")){return quote(e.car)}var i=d(e.car,0,1);return unpromise(i,function(e){n(e);return quote(e)})},"(quasiquote list ,value ,@value)\n\n Similar macro to `quote` but inside it you can use special\n expressions unquote abbreviated to , that will evaluate expresion inside\n and return its value or unquote-splicing abbreviated to ,@ that will\n evaluate expression but return value without parenthesis (it will join)\n the list with its value. Best used with macros but it can be used outside"),clone:doc(function e(r){typecheck("clone",r,"pair");return r.clone()},"(clone list)\n\n Function return clone of the list."),append:doc(function e(){var r;for(var t=arguments.length,n=new Array(t),i=0;iarray")(r).reverse();return global_env.get("array->list")(t)}else if(!(r instanceof Array)){throw new Error(typeErrorMessage("reverse",type(r),"array or pair"))}else{return r.reverse()}},"(reverse list)\n\n Function will reverse the list or array. If value is not a list\n or array it will throw exception."),nth:doc(function e(r,t){typecheck("nth",r,"number");typecheck("nth",t,["array","pair"]);if(t instanceof Pair){var n=t;var i=0;while(iarray")(t).join(r)},"(join separator list)\n\n Function return string by joining elements of the list"),split:doc(function e(r,t){typecheck("split",r,["regex","string"]);typecheck("split",t,"string");return global_env.get("array->list")(t.split(r))},"(split separator string)\n\n Function create list by splitting string by separatar that can\n be a string or regular expression."),replace:doc(function e(r,t,n){typecheck("replace",r,["regex","string"]);typecheck("replace",t,["string","function"]);typecheck("replace",n,"string");return n.replace(r,t)},"(replace pattern replacement string)\n\n Function change pattern to replacement inside string. Pattern can be string\n or regex and replacement can be function or string."),match:doc(function e(r,t){typecheck("match",r,["regex","string"]);typecheck("match",t,"string");var n=t.match(r);return n?global_env.get("array->list")(n):nil},"(match pattern string)\n\n function return match object from JavaScript as list."),search:doc(function e(r,t){typecheck("search",r,["regex","string"]);typecheck("search",t,"string");return t.search(r)},"(search pattern string)\n\n Function return first found index of the pattern inside a string"),repr:doc(function e(r,t){return toString(r,t)},"(repr obj)\n\n Function return string LIPS representation of an object as string."),"escape-regex":doc("escape-regex",function(e){typecheck("escape-regex",e,"string");return escape_regex(e.valueOf())},"(escape-regex string)\n\n Function return new string where all special operators used in regex,\n are escaped with slash so they can be used in RegExp constructor\n to match literal string"),env:doc(function e(e){e=e||this;var r=Object.keys(e.__env__).map(LSymbol);var t;if(r.length){t=Pair.fromArray(r)}else{t=nil}if(e.__parent__ instanceof Environment){return global_env.get("env")(e.__parent__).append(t)}return t},"(env)\n (env obj)\n\n Function return list of values (functions, macros and variables)\n inside environment and it's parents."),new:doc("new",function(e){for(var r=arguments.length,t=new Array(r>1?r-1:0),n=1;n2&&arguments[2]!==undefined$1?arguments[2]:specials.LITERAL;typecheck("set-special!",e,"string",1);typecheck("set-special!",r,"symbol",2);specials.append(e.valueOf(),r,t)},'(set-special! symbol name [type])\n\n Add special symbol to the list of transforming operators by the parser.\n e.g.: `(add-special! "#" \'x)` will allow to use `#(1 2 3)` and it will be\n transformed into (x (1 2 3)) so you can write x macro that will process\n the list. 3rd argument is optional and it can be constant value\n lips.specials.SPLICE if this constant is used it will transform\n `#(1 2 3)` into (x 1 2 3) that is required by # that define vectors.'),get:get,".":get,unbind:doc(unbind,"(unbind fn)\n\n Function remove bidning from function so you can get props from it."),type:doc(type,"(type object)\n\n Function return type of an object as string."),debugger:doc("debugger",function(){debugger},"(debugger)\n\n Function stop JavaScript code in debugger."),in:doc("in",function(e,r){if(e instanceof LSymbol||e instanceof LString||e instanceof LNumber){e=e.valueOf()}return e in unbox(r)},"(in key value)\n\n Function use is in operator to check if value is in object."),instanceof:doc("instanceof",function(e,r){return r instanceof unbind(e)},"(instanceof type obj)\n\n Function check of object is instance of object."),"prototype?":doc("prototype?",is_prototype,"(prototype? obj)\n\n Function check if value is JavaScript Object prototype."),"macro?":doc("macro?",function(e){return e instanceof Macro},"(macro? expression)\n\n Function check if value is a macro."),"function?":doc("function?",is_function,"(function? expression)\n\n Function check if value is a function."),"real?":doc("real?",function(e){if(type(e)!=="number"){return false}if(e instanceof LNumber){return e.isFloat()}return LNumber.isFloat(e)},"(real? number)\n\n Function check if value is real number."),"number?":doc("number?",function(e){return Number.isNaN(e)||LNumber.isNumber(e)},"(number? expression)\n\n Function check if value is a number or NaN value."),"string?":doc("string?",function(e){return LString.isString(e)},"(string? expression)\n\n Function check if value is a string."),"pair?":doc("pair?",function(e){return e instanceof Pair},"(pair? expression)\n\n Function check if value is a pair or list structure."),"regex?":doc(function(e){return e instanceof RegExp},"(regex? expression)\n\n Function check if value is regular expression."),"null?":doc("null?",function(e){return is_null(e)},"(null? expression)\n\n Function check if value is nulish."),"boolean?":doc("boolean?",function(e){return typeof e==="boolean"},"(boolean? expression)\n\n Function check if value is boolean."),"symbol?":doc("symbol?",function(e){return e instanceof LSymbol},"(symbol? expression)\n\n Function check if value is LIPS symbol"),"array?":doc("array?",function(e){return e instanceof Array},"(array? expression)\n\n Function check if value is an arrray."),"object?":doc("object?",function(e){return e!==nil&&e!==null&&!(e instanceof LCharacter)&&!(e instanceof RegExp)&&!(e instanceof LString)&&!(e instanceof Pair)&&!(e instanceof LNumber)&&_typeof_1(e)==="object"&&!(e instanceof Array)},"(object? expression)\n\n Function check if value is an plain object."),flatten:doc(function e(r){typecheck("flatten",r,"pair");return r.flatten()},"(flatten list)\n\n Return shallow list from tree structure (pairs)."),"array->list":doc("array->list",function(e){typecheck("array->list",e,"array");return Pair.fromArray(e)},"(array->list array)\n\n Function convert JavaScript array to LIPS list."),"tree->array":doc("tree->array",to_array("tree->array",true),"(tree->array list)\n\n Function convert LIPS list structure into JavaScript array."),"list->array":doc("list->array",to_array("list->array"),"(list->array list)\n\n Function convert LIPS list into JavaScript array."),apply:doc(function e(r){for(var t=arguments.length,n=new Array(t>1?t-1:0),i=1;iarray").call(this,a));return r.apply(this,prepare_fn_args(r,n))},"(apply fn list)\n\n Function that call function with list of arguments."),length:doc(function e(r){if(!r){return LNumber(0)}if(r instanceof Pair){return LNumber(r.length())}if("length"in r){return LNumber(r.length)}},"(length expression)\n\n Function return length of the object, the object can be list\n or any object that have length property."),"string->number":doc("string->number",function(e){var r=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:10;typecheck("string->number",e,"string",1);typecheck("string->number",r,"number",2);e=e.valueOf();r=r.valueOf();if(e.match(rational_bare_re)||e.match(rational_re)){return parse_rational(e,r)}else if(e.match(complex_bare_re)||e.match(complex_re)){return parse_complex(e,r)}else{var t=r===10&&!e.match(/e/i)||r===16;if(e.match(int_bare_re)&&t||e.match(int_re)){return parse_integer(e,r)}if(e.match(float_re)){return parse_float(e)}}return false},"(string->number number [radix])\n\n Function convert string to number."),try:doc(new Macro("try",function(r,e){var s=this;var l=e.dynamic_scope,f=e.error;return new Promise(function(i,n){var a,u;if(LSymbol.is(r.cdr.car.car,"catch")){a=r.cdr.car;if(r.cdr.cdr instanceof Pair&&LSymbol.is(r.cdr.cdr.car.car,"finally")){u=r.cdr.cdr.car}}else if(LSymbol.is(r.cdr.car.car,"finally")){u=r.cdr.car}if(!(u||a)){throw new Error("try: invalid syntax")}var o=i;if(u){o=function e(r,t){o=n;unpromise(_evaluate(new Pair(new LSymbol("begin"),u.cdr),c),function(){t(r)})}}var c={env:s,error:function e(r){var t=s.inherit("try");if(a){t.set(a.cdr.car.car,r);var n={env:t,error:f};if(l){n.dynamic_scope=s}unpromise(_evaluate(new Pair(new LSymbol("begin"),a.cdr.cdr),n),function(e){o(e,i)})}else{o(r,f)}}};if(l){c.dynamic_scope=s}var e=_evaluate(r.car,c);if(is_promise(e)){e.then(function(e){o(e,i)})["catch"](c.error)}else{o(e,i)}})}),"(try expr (catch (e) code))\n (try expr (catch (e) code) (finally code))\n (try expr (finally code))\n\n Macro execute user code and catch exception. If catch is provided\n it's executed when expression expr throw error. If finally is provide\n it's always executed at the end."),throw:doc("throw",function(e){throw new Error(e)},"(throw string)\n\n Throw new expection."),find:doc(function r(t,n){typecheck("find",t,["regex","function"]);typecheck("find",n,["pair","nil"]);if(is_null(n)){return nil}var e=matcher("find",t);return unpromise(e(n.car),function(e){if(e&&e!==nil){return n.car}return r(t,n.cdr)})},"(find fn list)\n (find regex list)\n\n Higher order Function find first value for which function return true.\n If called with regex it will create matcher function."),"for-each":doc("for-each",function(e){var r;typecheck("for-each",e,"function");for(var t=arguments.length,n=new Array(t>1?t-1:0),i=1;i1?r-1:0),a=1;a3?n-3:0),a=3;a3?i-3:0),u=3;uarray")(t);var a=[];var u=matcher("filter",r);return function r(t){function e(e){if(e&&e!==nil){a.push(n)}return r(++t)}if(t===i.length){return Pair.fromArray(a)}var n=i[t];return unpromise(u(n),e)}(0)},"(filter fn list)\n (filter regex list)\n\n Higher order function that call `fn` for each element of the list\n and return list for only those elements for which funtion return\n true value. If called with regex it will create matcher function."),compose:doc(compose,"(compose . fns)\n\n Higher order function and create new function that apply all functions\n From right to left and return it's value. Reverse of compose.\n e.g.:\n ((compose (curry + 2) (curry * 3)) 3)\n 11\n "),pipe:doc(pipe,"(pipe . fns)\n\n Higher order function and create new function that apply all functions\n From left to right and return it's value. Reverse of compose.\n e.g.:\n ((pipe (curry + 2) (curry * 3)) 3)\n 15"),curry:doc(curry,"(curry fn . args)\n\n Higher order function that create curried version of the function.\n The result function will have parially applied arguments and it\n will keep returning functions until all arguments are added\n\n e.g.:\n (define (add a b c d) (+ a b c d))\n (define add1 (curry add 1))\n (define add12 (add 2))\n (display (add12 3 4))"),gcd:doc(function e(){for(var r=arguments.length,t=new Array(r),n=0;no?a%=o:o%=a}a=abs(c*t[u])/(a+o)}return LNumber(a)},"(lcm n1 n2 ...)\n\n Function return the least common multiple of their arguments."),"odd?":doc("odd?",singleMathOp(function(e){return LNumber(e).isOdd()}),"(odd? number)\n\n Function check if number os odd."),"even?":doc("even?",singleMathOp(function(e){return LNumber(e).isEven()}),"(even? number)\n\n Function check if number is even."),"*":doc("*",reduceMathOp(function(e,r){return LNumber(e).mul(r)},LNumber(1)),"(* . numbers)\n\n Multiplicate all numbers passed as arguments. If single value is passed\n it will return that value."),"+":doc("+",reduceMathOp(function(e,r){return LNumber(e).add(r)},LNumber(0)),"(+ . numbers)\n\n Sum all numbers passed as arguments. If single value is passed it will\n return that value."),"-":doc("-",function(){for(var e=arguments.length,r=new Array(e),t=0;t":doc(">",function(){for(var e=arguments.length,r=new Array(e),t=0;t",r,"number");return seq_compare(function(e,r){return LNumber(e).cmp(r)===1},r)},"(> x1 x2 ...)\n\n Function compare its numerical arguments and check if they are\n monotonically increasing"),"<":doc("<",function(){for(var e=arguments.length,r=new Array(e),t=0;t=":doc(">=",function(){for(var e=arguments.length,r=new Array(e),t=0;t=",r,"number");return seq_compare(function(e,r){return[0,1].includes(LNumber(e).cmp(r))},r)},"(>= x1 x2 ...)\n\n Function compare its numerical arguments and check if they are\n monotonically nondecreasing"),"eq?":doc("eq?",equal,"(eq? a b)\n\n Function compare two values if they are identical."),or:doc(new Macro("or",function(e,r){var i=r.dynamic_scope,a=r.error;var u=global_env.get("list->array")(e);var o=this;if(i){i=o}if(!u.length){return false}var c;return function r(){function e(e){c=e;if(c!==false){return c}else{return r()}}if(!u.length){if(c!==false){return c}else{return false}}else{var t=u.shift();var n=_evaluate(t,{env:o,dynamic_scope:i,error:a});return unpromise(n,e)}}()}),"(or . expressions)\n\n Macro execute the values one by one and return the one that is truthy value.\n If there are no expression that evaluate to true it return false."),and:doc(new Macro("and",function(e){var r=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:{},i=r.dynamic_scope,a=r.error;var u=global_env.get("list->array")(e);var o=this;if(i){i=o}if(!u.length){return true}var c;return function r(){function e(e){c=e;if(c===false){return false}else{return r()}}var t=u.shift();if(typeof t==="undefined"){if(c!==false){return c}else{return false}}else{var n=_evaluate(t,{env:o,dynamic_scope:i,error:a});return unpromise(n,e)}}()}),"(and . expressions)\n\n Macro evalute each expression in sequence if any value return false it will\n return false. If each value return true it will return the last value.\n If it's called without arguments it will return true."),"|":doc("|",function(e,r){return LNumber(e).or(r)},"(& a b)\n\n Function calculate or bit operation."),"&":doc("&",function(e,r){return LNumber(e).and(r)},"(& a b)\n\n Function calculate and bit operation."),"~":doc("~",function(e){return LNumber(e).neg()},"(~ number)\n\n Function negate the value."),">>":doc(">>",function(e,r){return LNumber(e).shr(r)},"(>> a b)\n\n Function right shit the value a by value b."),"<<":doc(function(e,r){return LNumber(e).shl(r)},"(<< a b)\n\n Function left shit the value a by value b."),not:doc(function e(r){if(is_null(r)){return true}return!r},"(not object)\n\n Function return negation of the argument.")},undefined$1,"global");var user_env=global_env.inherit("user-env");function set_interaction_env(e,r){e.constant("**internal-env**",r);e.doc("**internal-env**","**internal-env**\n\n Constant used to hide stdin, stdout and stderr so they don't interfere\n with variables with the same name. Constants are internal type\n of variables that can't be redefined, defining variable with same name\n will throw an error.");global_env.set("**interaction-environment**",e)}set_interaction_env(user_env,internal_env);global_env.doc("**interaction-environment**","**interaction-environment**\n\n Internal dynamic, global variable used to find interpreter environment.\n It's used so the read and write functions can locate **internal-env**\n that contain references to stdin, stdout and stderr.");(function(){var e={ceil:"ceiling"};["floor","round","ceil"].forEach(function(r){var t=e[r]?e[r]:r;global_env.set(t,doc(t,function(e){typecheck(t,e,"number");if(e instanceof LNumber){return e[r]()}},"(".concat(t," number)\n\n Function calculate ").concat(t," of a number.")))})})();function allPossibleCases(e){if(e.length===1){return e[0]}else{var r=[];var t=allPossibleCases(e.slice(1));for(var n=0;n3&&arguments[3]!==undefined$1?arguments[3]:null;var i=e?" in expression `".concat(e,"`"):"";if(n!==null){i+=" (argument ".concat(n,")")}if(t instanceof Array){if(t.length===1){t=t[0]}else{var a=t[t.length-1];t=t.slice(0,-1).join(", ")+" or "+a}}return"Expecting ".concat(t,", got ").concat(r).concat(i)}function typecheck_args(t,e,n){e.forEach(function(e,r){typecheck(t,e,n,r+1)})}function typecheck_text_port(e,r,t){typecheck(e,r,t);if(r.__type__===binary_port){throw new Error(typeErrorMessage(e,"binary-port","textual-port"))}}function typecheck(e,r,t){var n=arguments.length>3&&arguments[3]!==undefined$1?arguments[3]:null;e=e.valueOf();var i=type(r).toLowerCase();var a=false;if(t instanceof Pair){t=t.to_array()}if(t instanceof Array){t=t.map(function(e){return e.valueOf()})}if(t instanceof Array){t=t.map(function(e){return e.valueOf().toLowerCase()});if(t.includes(i)){a=true}}else{t=t.valueOf().toLowerCase()}if(!a&&i!==t){throw new Error(typeErrorMessage(e,i,t,n))}}function self_evaluated(e){var r=_typeof_1(e);return["string","function"].includes(r)||_typeof_1(e)==="symbol"||e instanceof LSymbol||e instanceof LNumber||e instanceof LString||e instanceof RegExp}function is_native(e){return e instanceof LNumber||e instanceof LString||e instanceof LCharacter}function has_own_symbol(e,r){if(e===null){return false}return _typeof_1(e)==="object"&&r in Object.getOwnPropertySymbols(e)}function is_iterator(e,r){if(has_own_symbol(e,r)||has_own_symbol(e.__proto__,r)){return is_function(e[r])}}function type(e){var r={pair:Pair,symbol:LSymbol,character:LCharacter,values:Values,"input-port":InputPort,"output-port":OutputPort,number:LNumber,regex:RegExp,syntax:Syntax,macro:Macro,string:LString,array:Array,"native-symbol":Symbol};if(Number.isNaN(e)){return"NaN"}if(e===nil){return"nil"}if(e===null){return"null"}for(var t=0,n=Object.entries(r);t2&&arguments[2]!==undefined$1?arguments[2]:{},a=r.env,u=r.dynamic_scope,t=r.error,o=t===void 0?function(){}:t;e=evaluate_args(e,{env:a,dynamic_scope:u,error:o});return unpromise(e,function(e){if(is_raw_lambda(i)){i=unbind(i)}e=prepare_fn_args(i,e);var r=e.slice();var t=(u||a).newFrame(i,r);var n=resolve_promises(i.apply(t,e));return unpromise(n,function(e){if(e instanceof Pair){e.markCycles();return quote(e)}if(Number.isNaN(e)){return e}if(typeof e==="number"){return LNumber(e)}if(typeof e==="string"){return LString(e)}return e},o)})}function _evaluate(r){var e=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:{},t=e.env,n=e.dynamic_scope,i=e.error,a=i===void 0?function(){}:i;try{if(n===true){t=n=t||global_env}else if(t===true){t=n=global_env}else{t=t||global_env}var u={env:t,dynamic_scope:n,error:a};var o;if(is_null(r)){return r}if(r instanceof LSymbol){return t.get(r)}if(!(r instanceof Pair)){return r}var c=r.car;var s=r.cdr;if(c instanceof Pair){o=resolve_promises(_evaluate(c,u));if(is_promise(o)){return o.then(function(e){return _evaluate(new Pair(e,r.cdr),u)})}else if(!is_function(o)){throw new Error(type(o)+" "+t.get("repr")(o)+" is not a function while evaluating "+r.toString())}}if(c instanceof LSymbol){o=t.get(c)}else if(is_function(c)){o=c}var l;if(o instanceof Syntax){l=evaluate_syntax(o,r,u)}else if(o instanceof Macro){l=evaluate_macro(o,s,u)}else if(is_function(o)){l=apply(o,s,u)}else if(r instanceof Pair){o=c&&c.toString();throw new Error("".concat(type(c)," ").concat(o," is not a function"))}else if(!is_function(o)){if(o){var f="".concat(type(o)," `").concat(o,"' is not a function");throw new Error(f)}throw new Error("Unknown function `".concat(c.toString(),"'"))}else{return r}var _=t.get(Symbol["for"]("__promise__"),{throwError:false});if(_===true&&is_promise(l)){l=l.then(function(e){if(e instanceof Pair&&!o[__data__]){return _evaluate(e,u)}return e});return new QuotedPromise(l)}return l}catch(e){a&&a.call(t,e,r)}}function exec(e,r,t){return _exec.apply(this,arguments)}function _exec(){_exec=asyncToGenerator(regenerator.mark(function e(t,n,i){var a,u,o,c,s,l,f,_,p;return regenerator.wrap(function e(r){while(1){switch(r.prev=r.next){case 0:if(i===true){n=i=n||user_env}else if(n===true){n=i=user_env}else{n=n||user_env}a=[];u=true;o=false;r.prev=4;s=asyncIterator(parse(t));case 6:r.next=8;return s.next();case 8:l=r.sent;u=l.done;r.next=12;return l.value;case 12:f=r.sent;if(u){r.next=28;break}_=f;p=_evaluate(_,{env:n,dynamic_scope:i,error:function e(r,t){if(r&&r.message){if(r.message.match(/^Error:/)){r.message=r.message.replace(/.*:\s*([^:]+:\s*)/,"$1")}else{r.message="Error: ".concat(r.message)}if(t){if(!(r.__code__ instanceof Array)){r.__code__=[]}r.__code__.push(t.toString(true))}}throw r}});if(is_promise(p)){r.next=20;break}a.push(p);r.next=25;break;case 20:r.t0=a;r.next=23;return p;case 23:r.t1=r.sent;r.t0.push.call(r.t0,r.t1);case 25:u=true;r.next=6;break;case 28:r.next=34;break;case 30:r.prev=30;r.t2=r["catch"](4);o=true;c=r.t2;case 34:r.prev=34;r.prev=35;if(!(!u&&s["return"]!=null)){r.next=39;break}r.next=39;return s["return"]();case 39:r.prev=39;if(!o){r.next=42;break}throw c;case 42:return r.finish(39);case 43:return r.finish(34);case 44:return r.abrupt("return",a);case 45:case"end":return r.stop()}}},e,null,[[4,30,34,44],[35,,39,43]])}));return _exec.apply(this,arguments)}function balanced(e){var r={"[":"]","(":")"};var t;if(typeof e==="string"){t=tokenize(e)}else{t=e.map(function(e){return e&&e.token?e.token:e})}var n=Object.keys(r);var i=Object.values(r).concat(n);t=t.filter(function(e){return i.includes(e)});var a=new Stack;var u=_createForOfIteratorHelper(t),o;try{for(u.s();!(o=u.n()).done;){var c=o.value;if(n.includes(c)){a.push(c)}else if(!a.is_empty()){var s=a.top();var l=r[s];if(c===l){a.pop()}else{throw new Error("Syntax error: missing closing ".concat(l))}}else{throw new Error("Syntax error: not matched closing ".concat(c))}}}catch(e){u.e(e)}finally{u.f()}return a.is_empty()}function fworker(e){var r="("+e.toString()+")()";var t=window.URL||window.webkitURL;var n;try{n=new Blob([r],{type:"application/javascript"})}catch(e){var i=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder;n=new i;n.append(r);n=n.getBlob()}return new root.Worker(t.createObjectURL(n))}function is_dev(){return lips.version.match(/^(\{\{VER\}\}|DEV)$/)}function bootstrap(){var e=arguments.length>0&&arguments[0]!==undefined$1?arguments[0]:"";if(e===""){if(is_dev()){e="https://cdn.jsdelivr.net/gh/jcubic/lips@devel/"}else{e="https://cdn.jsdelivr.net/npm/@jcubic/lips@".concat(lips.version,"/")}}else if(!e.match(/\/$/)){e+="/"}var r=global_env.get("load");return r.call(lips.env,"".concat(e,"dist/std.scm"),global_env)}function Worker(e){this.url=e;var u=this.worker=fworker(function(){var u;var o;self.addEventListener("message",function(e){var t=e.data;var r=t.id;if(t.type!=="RPC"||r===null){return}function n(e){self.postMessage({id:r,type:"RPC",result:e})}function i(e){self.postMessage({id:r,type:"RPC",error:e})}if(t.method==="eval"){if(!o){i("Worker RPC: LIPS not initilized, call init first");return}o.then(function(){var e=t.params[0];var r=t.params[1];u.exec(e,r).then(function(e){e=e.map(function(e){return e&&e.valueOf()});n(e)})["catch"](function(e){i(e)})})}else if(t.method==="init"){var a=t.params[0];if(typeof a!=="string"){i("Worker RPC: url is not a string")}else{importScripts("".concat(a,"/dist/lips.min.js"));u=new lips.Interpreter("worker");o=bootstrap(a);o.then(function(){n(true)})}}})});this.rpc=function(){var n=0;return function e(r,t){var a=++n;return new Promise(function(n,i){u.addEventListener("message",function e(r){var t=r.data;if(t&&t.type==="RPC"&&t.id===a){if(t.error){i(t.error)}else{n(t.result)}u.removeEventListener("message",e)}});u.postMessage({type:"RPC",method:r,id:a,params:t})})}}();this.rpc("init",[e])["catch"](function(e){console.error(e)});this.exec=function(e){var r=arguments.length>1&&arguments[1]!==undefined$1?arguments[1]:false;return this.rpc("eval",[e,r])}}Pair.unDry=function(e){return new Pair(e.car,e.cdr)};Pair.prototype.toDry=function(){return{value:{car:this.car,cdr:this.cdr}}};Nil.prototype.toDry=function(){return{value:null}};Nil.unDry=function(){return nil};LSymbol.prototype.toDry=function(){return{value:{name:this.__name__}}};LSymbol.unDry=function(e){return new LSymbol(e.__name__)};function execError(e){console.error(e.message||e);if(e.code){console.error(e.code.map(function(e,r){return"[".concat(r+1,"]: ").concat(e)}))}}function init(){var u=["text/x-lips","text/x-scheme"];var o;function c(t){return new Promise(function(r){var e=t.getAttribute("src");if(e){return fetch(e).then(function(e){return e.text()}).then(exec).then(r)["catch"](function(e){execError(e);r()})}else{return exec(t.innerHTML).then(r)["catch"](function(e){execError(e);r()})}})}function e(){return new Promise(function(i){var a=Array.from(document.querySelectorAll("script"));return function e(){var r=a.shift();if(!r){i()}else{var t=r.getAttribute("type");if(u.includes(t)){var n=r.getAttribute("bootstrap");if(!o&&typeof n==="string"){bootstrap(n).then(function(){return c(r)}).then(e)}else{c(r).then(e)}}else if(t&&t.match(/lips|lisp/)){console.warn("Expecting "+u.join(" or ")+" found "+t)}return e()}}()})}if(!window.document){return Promise.resolve()}else if(currentScript){var r=currentScript;var t=r.getAttribute("bootstrap");if(typeof t==="string"){return bootstrap(t).then(function(){o=true;return e()})}}return e()}var currentScript=typeof window!=="undefined"&&window.document&&document.currentScript;if(typeof window!=="undefined"){contentLoaded(window,init)}var banner=function(){var e=LString("Tue, 16 Mar 2021 12:52:41 +0000").valueOf();var r=e==="{{"+"DATE}}"?new Date:new Date(e);var t=function e(r){return r.toString().padStart(2,"0")};var n=r.getFullYear();var i=[n,t(r.getMonth()+1),t(r.getDate())].join("-");var a="\n __ __ __\n / / \\ \\ _ _ ___ ___ \\ \\\n| | \\ \\ | | | || . \\/ __> | |\n| | > \\ | |_ | || _/\\__ \\ | |\n| | / ^ \\ |___||_||_| <___/ | |\n \\_\\ /_/ \\_\\ /_/\n\nLIPS Interpreter DEV (".concat(i,") \nCopyright (c) 2018-").concat(n," Jakub T. Jankiewicz\n\nType (env) to see environment with functions macros and variables.\nYou can also use (help name) to display help for specic function or macro and\n(apropos name) to display list of matched names in environment.\n").replace(/^.*\n/,"");return a}();Ahead.__class__="ahead";Pattern.__class__="pattern";Formatter.__class__="formatter";Macro.__class__="macro";Syntax.__class__="syntax";Environment.__class__="environment";InputPort.__class__="input-port";OutputPort.__class__="output-port";OutputStringPort.__class__="output-string-port";InputStringPort.__class__="input-string-port";InputFilePort.__class__="input-file-port";OutputFilePort.__class__="output-file-port";LNumber.__class__="number";LCharacter.__class__="character";LString.__class__="string";QuotedPromise.__class__="promise";var lips={version:"DEV",banner:banner,date:"Tue, 16 Mar 2021 12:52:41 +0000",exec:exec,parse:compose(uniterate_async,parse),tokenize:tokenize,evaluate:_evaluate,bootstrap:bootstrap,Environment:Environment,env:user_env,Worker:Worker,Interpreter:Interpreter,balanced_parenthesis:balanced,balancedParenthesis:balanced,balanced:balanced,Macro:Macro,Syntax:Syntax,Pair:Pair,Values:Values,QuotedPromise:QuotedPromise,quote:quote,InputPort:InputPort,OutputPort:OutputPort,InputFilePort:InputFilePort,OutputFilePort:OutputFilePort,InputStringPort:InputStringPort,OutputStringPort:OutputStringPort,InputByteVectorPort:InputByteVectorPort,OutputByteVectorPort:OutputByteVectorPort,InputBinaryFilePort:InputBinaryFilePort,OutputBinaryFilePort:OutputBinaryFilePort,Formatter:Formatter,Parser:Parser,Lexer:Lexer,specials:specials,repr:repr,nil:nil,eof:eof,LSymbol:LSymbol,LNumber:LNumber,LFloat:LFloat,LComplex:LComplex,LRational:LRational,LBigInteger:LBigInteger,LCharacter:LCharacter,LString:LString,rationalize:rationalize};global_env.set("lips",lips);return lips})})(); \ No newline at end of file diff --git a/dist/std.min.scm b/dist/std.min.scm new file mode 100644 index 00000000..adfb67c0 --- /dev/null +++ b/dist/std.min.scm @@ -0,0 +1,354 @@ +(define (%doc string fn) (typecheck "%doc" fn "function") (typecheck "%doc" string "string") (set-obj! fn (quote __doc__) (--> string (replace #/^ +/gm ""))) fn) +(define-macro (let-syntax vars . body) "(let-syntax ((name fn)) body)\u000A\u000A Macro works like combination of let and define-syntax. It creaates\u000A local macros and evaluate body in context of those macros.\u000A The macro to letrec-syntax is like letrec is to let." (quasiquote (let (unquote vars) (unquote-splicing (map (lambda (rule) (quasiquote (typecheck "let-syntax" (unquote (car rule)) "syntax"))) vars)) (unquote-splicing body)))) +(define-macro (letrec-syntax vars . body) "(letrec-syntax ((name fn)) body)\u000A\u000A Macro works like combination of letrec and define-syntax. It creaates\u000A local macros and evaluate body in context of those macros." (quasiquote (letrec (unquote vars) (unquote-splicing (map (lambda (rule) (quasiquote (typecheck "letrec-syntax" (unquote (car rule)) "syntax"))) vars)) (unquote-splicing body)))) +(define-macro (define-syntax name expr . rest) "(define-syntax name expression [__doc__])\u000A\u000AMacro define new hygienic macro using syntax-rules with optional documentation" (let ((expr-name (gensym "expr-name"))) (quasiquote (define (unquote name) (let (((unquote expr-name) (unquote expr))) (typecheck "define-syntax" (unquote expr-name) "syntax") (unquote expr-name)) (unquote-splicing rest))))) +(define (quoted-symbol? x) "(quoted-symbol? code)\u000A\u000AHelper function that test if value is quoted symbol. To be used in macros\u000Athat pass literal code that is transformed by parser.\u000A\u000Ausage:\u000A\u000A (define-macro (test x)\u000A (if (quoted-symbol? x)\u000A `',(cadr x)))\u000A\u000A (list 'hello (test 'world))" (and (pair? x) (eq? (car x) (quote quote)) (symbol? (cadr x)) (null? (cddr x)))) +(define-macro (--> expr . code) "Helper macro that simplify calling methods on objects. It work with chaining\u000A\u000Ausage: (--> ($ \"body\")\u000A (css \"color\" \"red\")\u000A (on \"click\" (lambda () (display \"click\"))))\u000A\u000A (--> document (querySelectorAll \"div\"))\u000A\u000A (--> (fetch \"https://jcubic.pl\")\u000A (text)\u000A (match #/([^<]+)<\\/title>/)\u000A 1)\u000A \u000A (--> document\u000A (querySelectorAll \".cmd-prompt\")\u000A 0\u000A 'innerHTML\u000A (replace #/<(\"[^\"]+\"|[^>])+>/g \"\"))\u000A\u000A (--> document.body\u000A (style.setProperty \"--color\" \"red\"))" (let ((obj (gensym "obj"))) (quasiquote (let* (((unquote obj) (unquote expr))) (unquote-splicing (map (lambda (code) (let ((value (gensym "value"))) (quasiquote (let* (((unquote value) (unquote (let ((name (cond ((quoted-symbol? code) (symbol->string (cadr code))) ((pair? code) (symbol->string (car code))) (#t code)))) (if (string? name) (quasiquote (. (unquote obj) (unquote-splicing (split "." name)))) (quasiquote (. (unquote obj) (unquote name)))))))) (unquote (if (and (pair? code) (not (quoted-symbol? code))) (quasiquote (set! (unquote obj) ((unquote value) (unquote-splicing (cdr code))))) (quasiquote (set! (unquote obj) (unquote value))))))))) code)) (unquote obj))))) +(define-macro (define-global first . rest) "(define-global var value)\u000A(define-global (name . args) body)\u000A\u000AMacro that define functions or variables in global context, so they can be used\u000Ainside let and get let variables in closure, Useful for universal macros." (if (pair? first) (let ((name (car first))) (quasiquote (--> lips.env (set (unquote (symbol->string name)) (lambda (unquote (cdr first)) (unquote-splicing rest)))))) (quasiquote (--> lips.env (set (unquote (symbol->string first)) (unquote (car rest))))))) +(define-macro (globalize expr . rest) "(globalize expr)\u000A\u000A Macro will get the value of the expression and add each method as function to global\u000A scope." (let* ((env (current-environment)) (obj (eval expr env)) (name (gensym "name")) (env-name (gensym "env-name")) (make-name (if (pair? rest) (let ((pre (symbol->string (car rest)))) (lambda (name) (string->symbol (concat pre name)))) string->symbol))) (quasiquote (let (((unquote name) (unquote expr))) (unquote-splicing (filter pair? (map (lambda (key) (if (and (not (match /^_/ key)) (function? (. obj key))) (let* ((args (gensym "args"))) (quasiquote (define-global ((unquote (make-name key)) unquote args) (apply (. (unquote name) (unquote key)) (unquote args))))))) (array->list (--> Object (keys obj)))))))))) +(define (single list) "(single list)\u000A\u000AFunction check if argument is list with single element" (and (pair? list) (not (cdr list)))) +(define (iterator? x) "(iterator? x)\u000A\u000A Function check if value is JavaScript iterator object" (and (object? x) (procedure? (. x Symbol.iterator)))) +(define-macro (.. expr) "(.. foo.bar.baz)\u000A\u000AMacro that gets value from nested object where argument is comma separated symbol" (if (not (symbol? expr)) expr (let ((parts (split "." (symbol->string expr)))) (if (single parts) expr (quasiquote (. (unquote (string->symbol (car parts))) (unquote-splicing (cdr parts)))))))) +(set-special! "#:" (quote gensym-interal)) +(define (gensym-interal symbol) "(gensym-interal symbol)\u000A\u000AParser extension that create new quoted named gensym." (quasiquote (quote (unquote (gensym symbol))))) +(define (plain-object? x) "(plain-object? x)\u000A\u000AFunction check if value is plain JavaScript object. Created using object macro." (and (== (--> (type x) (cmp "object")) 0) (eq? (. x (quote constructor)) Object))) +(define typed-array? (let ((TypedArray (Object.getPrototypeOf Uint8Array))) (lambda (o) "(typed-array? o)\u000A\u000AFunction test if argumnet is JavaScript typed array (Scheme byte vector)." (instanceof TypedArray o)))) +(define (symbol->string s) "(symbol->string symbol)\u000A\u000AFunction convert LIPS symbol to string." (if (symbol? s) (let ((name s.__name__)) (if (string? name) name (--> name (toString)))))) +(define (string->symbol string) "(string->symbol string)\u000A\u000AFunction convert string to LIPS symbol." (and (string? string) (%as.data (new (. lips "LSymbol") string)))) +(define (alist->object alist) "(alist->object alist)\u000A\u000AFunction convert alist pairs to JavaScript object." (if (pair? alist) (alist.to_object) (alist->object (new lips.Pair undefined ())))) +(define (parent.frames) "(parent.frames)\u000A\u000AFuncion return list of environments from parent frames (lambda function calls)" (let iter ((result (quote ())) (frame (parent.frame 1))) (if (eq? frame (interaction-environment)) (cons frame result) (if (null? frame) result (let ((parent.frame (--> frame (get (quote parent.frame) (object :throwError #f))))) (if (function? parent.frame) (iter (cons frame result) (parent.frame 0)) result)))))) +(define-macro (wait time . expr) "(wait time . expr)\u000A\u000AFunction return promise that will resolve with evaluating the expression after delay." (quasiquote (promise (timer (unquote time) (resolve (begin (unquote-splicing expr))))))) +(define (pair-map fn seq-list) "(pair-map fn list)\u000A\u000AFunction call fn argument for pairs in a list and return combined list with\u000Avalues returned from function fn. It work like the map but take two items from list" (let iter ((seq-list seq-list) (result (quote ()))) (if (null? seq-list) result (if (and (pair? seq-list) (pair? (cdr seq-list))) (let* ((first (car seq-list)) (second (cadr seq-list)) (value (fn first second))) (if (null? value) (iter (cddr seq-list) result) (iter (cddr seq-list) (cons value result)))))))) +(define (object-expander readonly expr . rest) "(object-expander reaonly '(:foo (:bar 10) (:baz (1 2 3))))\u000A\u000ARecursive function helper for defining LIPS code for create objects\u000Ausing key like syntax." (let ((name (gensym "name")) (quot (if (null? rest) #f (car rest)))) (if (null? expr) (quasiquote (alist->object ())) (quasiquote (let (((unquote name) (alist->object (quote ())))) (unquote-splicing (pair-map (lambda (key value) (if (not (key? key)) (let ((msg (string-append (type key) " " (repr key) " is not a symbol!"))) (throw msg)) (let ((prop (key->string key))) (if (and (pair? value) (key? (car value))) (quasiquote (set-obj! (unquote name) (unquote prop) (unquote (object-expander readonly value)))) (if quot (quasiquote (set-obj! (unquote name) (unquote prop) (quote (unquote value)))) (quasiquote (set-obj! (unquote name) (unquote prop) (unquote value)))))))) expr)) (unquote (if readonly (quasiquote (Object.freeze (unquote name))))) (unquote name)))))) +(define-macro (object . expr) "(object :name value)\u000A\u000AMacro that create JavaScript object using key like syntax." (try (object-expander #f expr) (catch (e) (error e.message)))) +(define-macro (object-literal . expr) "(object-literal :name value)\u000A\u000AMacro that create JavaScript object using key like syntax. This is similar,\u000Ato object but all values are quoted. This macro is used with & object literal." (try (object-expander #t expr #t) (catch (e) (error e.message)))) +(define (alist->assign desc . sources) "(alist->assign alist . list-of-alists)\u000A\u000AFunction that work like Object.assign but for LIPS alist." (for-each (lambda (source) (for-each (lambda (pair) (let* ((key (car pair)) (value (cdr pair)) (d-pair (assoc key desc))) (if (pair? d-pair) (set-cdr! d-pair value) (append! desc (list pair))))) source)) sources) desc) +(define (key? symbol) "(key? symbol)\u000A\u000AFunction check if symbol is key symbol, have colon as first character." (and (symbol? symbol) (== (--> (substring (symbol->string symbol) 0 1) (cmp ":")) 0))) +(define (key->string symbol) "(key->string symbol)\u000A\u000AIf symbol is key it convert that to string - remove colon." (if (key? symbol) (substring (symbol->string symbol) 1))) +(define (%as.data obj) "(%as.data obj)\u000A\u000AMark object as data to stop evaluation." (if (object? obj) (begin (set-obj! obj (quote data) #t) obj))) +(define (%hidden-props obj) "(%hidden-props obj)\u000A\u000AFunction return hidden names of an object, for ES6 class prototype\u000Ait return all methods since they are indistinguishable from hidden property\u000Acreated using defineProperty." (let* ((descriptors (Object.getOwnPropertyDescriptors obj)) (names (Object.keys descriptors))) (--> names (filter (lambda (name) (let ((descriptor (. descriptors name))) (eq? descriptor.enumerable #f))))))) +(define (dir obj . rest) "(dir obj)\u000A\u000AFunction return all props on the object including those in prototype chain." (if (or (null? obj) (eq? obj Object.prototype)) () (let ((proto (if (null? rest) #f (car rest))) (names (Object.getOwnPropertyNames obj))) (if (not proto) (let ((hidden (%hidden-props obj))) (set! names (--> names (filter (lambda (name) (not (hidden.includes name)))))))) (append (array->list (--> names (map (unary string->symbol)))) (dir (Object.getPrototypeOf obj) #t))))) +(define (tree-map f tree) "(tree-map fn tree)\u000A\u000ATree version of map. Function is invoked on every leaf." (if (pair? tree) (cons (tree-map f (car tree)) (tree-map f (cdr tree))) (f tree))) +(define (native.number x) "(native.number obj)\u000A\u000AIf argument is number it will convert to native number." (if (number? x) (value x) x)) +(define (value obj) "(value obj)\u000A\u000AFunction unwrap LNumbers and convert nil value to undefined." (if (eq? obj ()) undefined (if (number? obj) ((. obj "valueOf")) obj))) +(define-macro (define-formatter-rule . patterns) "(rule-pattern pattern)\u000A\u000AAnaphoric Macro for defining patterns for formatter. With Ahead, Pattern and * defined values." (let ((rules (gensym "rules"))) (quasiquote (let (((unquote rules) lips.Formatter.rules) (Ahead (lambda (pattern) (let ((Ahead (.. lips.Formatter.Ahead))) (new Ahead (if (string? pattern) (new RegExp pattern) pattern))))) (* (Symbol.for "*")) (Pattern (lambda (pattern flag) (new lips.Formatter.Pattern (list->array pattern) (if (null? flag) undefined flag))))) (unquote-splicing (map (lambda (pattern) (quasiquote (--> (unquote rules) (push (tree->array (tree-map native.number (unquote-splicing pattern))))))) patterns)))))) +(define-syntax cond (syntax-rules (=> else) ((cond (else else1 else2 ...)) (if #t (begin else1 else2 ...))) ((cond (test => receiver) more-clause ...) (let ((t test)) (cond/maybe-more t (receiver t) more-clause ...))) ((cond (generator guard => receiver) more-clause ...) (call-with-values (lambda () generator) (lambda t (cond/maybe-more (apply guard t) (apply receiver t) more-clause ...)))) ((cond (test) more-clause ...) (let ((t test)) (cond/maybe-more t t more-clause ...))) ((cond (test body1 body2 ...) more-clause ...) (cond/maybe-more test (begin body1 body2 ...) more-clause ...))) "(cond (predicate? . body)\u000A (predicate? . body)\u000A (else . body))\u000A\u000AMacro for condition checks. For usage instead of nested ifs.") +(define-syntax cond/maybe-more (syntax-rules () ((cond/maybe-more test consequent) (if test consequent)) ((cond/maybe-more test consequent clause ...) (if test consequent (cond clause ...)))) "(cond/maybe-more test consequent ...)\u000A\u000AHelper macro used by cond.") +(define-macro (cond . list) "(cond (predicate? . body)\u000A (predicate? . body))\u000AMacro for condition check. For usage instead of nested ifs." (if (pair? list) (let* ((item (car list)) (first (car item)) (forms (cdr item)) (rest (cdr list))) (quasiquote (if (unquote first) (begin (unquote-splicing forms)) (unquote (if (and (pair? rest) (or (eq? (caar rest) #t) (eq? (caar rest) (quote else)))) (quasiquote (begin (unquote-splicing (cdar rest)))) (if (not (null? rest)) (quasiquote (cond (unquote-splicing rest))))))))) ())) +(define (%r re . rest) "(%r re)\u000A\u000ACreate new regular expression from string, to not break Emacs formatting" (if (null? rest) (new RegExp re) (new RegExp re (car rest)))) +(define (interaction-environment) "(interaction-environment)\u000A\u000AFunction return interaction environement equal to lips.env can be overwritten,\u000Awhen creating new interpreter with lips.Interpreter." **interaction-environment**) +(define (current-output-port) "(current-output-port)\u000A\u000AFunction return default stdout port." (let-env (interaction-environment) (--> **internal-env** (get (quote stdout))))) +(define (current-error-port) "(current-output-port)\u000A\u000AFunction return default stdout port." (let-env (interaction-environment) (--> **internal-env** (get (quote stderr))))) +(define (current-input-port) "current-input-port)\u000A\u000AFunction return default stdin port." (let-env (interaction-environment) (--> **internal-env** (get (quote stdin))))) +(define (regex? x) "(regex? x)\u000A\u000AFunction return true of value is regular expression, it return false otherwise." (== (--> (type x) (cmp "regex")) 0)) +(define (set-repr! type fn) "(add-repr! type fn)\u000A\u000AFunction add string represention to the type, which should be constructor function.\u000A\u000AFunction fn should have args (obj q) and it should return string, obj is vlaue that\u000Aneed to be converted to string, if the object is nested and you need to use `repr`,\u000Ait should pass second parameter q to repr, so string will be quoted when it's true.\u000A\u000Ae.g.: (lambda (obj q) (string-append \"<\" (repr obj q) \">\"))" (typecheck "add-repr!" type "function") (typecheck "add-repr!" fn "function") (ignore (--> lips.repr (set type fn)))) +(define (unset-repr! type) "(unset-repr! type)\u000A\u000AFunction remove string represention to the type, which should be constructor function,\u000Aadded by add-repr! function." (typecheck "unset-repr!" type "function") (ignore (--> lips.repr (delete type)))) +(set-special! "&" (quote object-literal) lips.specials.SPLICE) +(set-repr! Object (lambda (x q) (concat "&(" (--> (Object.getOwnPropertyNames x) (map (lambda (key) (concat ":" key " " (repr (. x key) q)))) (join " ")) ")"))) +(define (bound? x . rest) "(bound? x [env])\u000A\u000AFunction check if variable is defined in given environement or interaction environment\u000Aif not specified." (let ((env (if (null? rest) (interaction-environment) (car rest)))) (try (begin (--> env (get x)) #t) (catch (e) #f)))) +(define (environment-bound? env x) "(environment-bound? env symbol)\u000A\u000AFunction check if symbol is bound variable similar to bound?." (typecheck "environment-bound?" env "environment" 1) (typecheck "environment-bound?" x "symbol" 2) (bound? x env)) +(define (qsort e predicate) "(qsort list predicate)\u000A\u000ASort the list using quick sort alorithm according to predicate." (if (or (null? e) (<= (length e) 1)) e (let loop ((left ()) (right ()) (pivot (car e)) (rest (cdr e))) (if (null? rest) (append (append (qsort left predicate) (list pivot)) (qsort right predicate)) (if (predicate (car rest) pivot) (loop (append left (list (car rest))) right pivot (cdr rest)) (loop left (append right (list (car rest))) pivot (cdr rest))))))) +(define (sort list . rest) "(sort list [predicate])\u000A\u000ASort the list using optional predicate function. if not function is specified\u000Ait will use <= and sort in increasing order." (let ((predicate (if (null? rest) <= (car rest)))) (typecheck "sort" list "pair") (typecheck "sort" predicate "function") (qsort list predicate))) +(define (every fn list) "(every fn list)\u000A\u000AFunction call function fn on each item of the list, if every value is true\u000Ait will return true otherwise it return false." (if (null? list) #t (and (fn (car list)) (every fn (cdr list))))) +(define (zip . args) "(zip list1 list2 ...)\u000A\u000ACreate one list by taking each element of each list." (if (null? args) () (if (some null? args) () (cons (map car args) (apply zip (map cdr args)))))) +(define-macro (promise . body) "(promise . body)\u000A\u000AAnaphoric macro that expose resolve and reject functions from JS promise" (quasiquote (new Promise (lambda (resolve reject) (try (begin (unquote-splicing body)) (catch (e) (error (.. e.message)))))))) +(define-macro (timer time . body) "(timer time . body)\u000A\u000AMacro evaluate expression after delay, it return timer. To clear the timer you can use\u000Anative JS clearTimeout function." (quasiquote (setTimeout (lambda () (try (begin (unquote-splicing body)) (catch (e) (error (.. e.message))))) (unquote time)))) +(define (defmacro? obj) "(defmacro? expression)\u000A\u000AFunction check if object is macro and it's expandable." (and (macro? obj) (. obj (quote defmacro)))) +(define (n-ary n fn) "(n-ary n fn)\u000A\u000AReturn new function that limit number of arguments to n." (lambda args (apply fn (take n args)))) +(define (take n lst) "(take n list)\u000A\u000AReturn n first values of the list." (let iter ((result (quote ())) (i n) (lst lst)) (if (or (null? lst) (<= i 0)) (reverse result) (iter (cons (car lst) result) (- i 1) (cdr lst))))) +(define unary (%doc "(unary fn)\u000A\u000AFunction return new function with arguments limited to one." (curry n-ary 1))) +(define binary (%doc "(binary fn)\u000A\u000AFunction return new function with arguments limited to two." (curry n-ary 2))) +(define (%class-lambda expr) "(class-lambda expr)\u000A\u000AReturn lambda expression where input expression lambda have `this` as first argument." (let ((args (gensym (quote args)))) (quasiquote (lambda (unquote args) (apply (unquote (cadr expr)) this (unquote args)))))) +(define (%class-lambda expr) "(%class-lambda expr)\u000A\u000ADefine lambda that have self is first argument. The expr is in a form:\u000A(constructor (lambda (self ...) . body)) as given by define-class macro." (let ((args (cdadadr expr))) (quasiquote (lambda ((unquote-splicing args)) ((unquote (cadr expr)) this (unquote-splicing args)))))) +(define (%class-method-name expr) "(%class-method-name expr)\u000A\u000AHelper function that allow to use [Symbol.asyncIterator] inside method name." (if (pair? expr) (car expr) (list (quote quote) expr))) +(define-macro (define-class name parent . body) "(define-class name parent . body)\u000A\u000ADefine class - JavaScript function constructor with prototype.\u000A\u000Ausage:\u000A\u000A (define-class Person Object\u000A (constructor (lambda (self name)\u000A (set-obj! self '_name name)))\u000A (hi (lambda (self)\u000A (display (string-append self._name \" say hi\"))\u000A (newline))))\u000A (define jack (new Person \"Jack\"))\u000A (jack.hi)" (let iter ((functions (quote ())) (constructor (quote ())) (lst body)) (if (null? lst) (quasiquote (begin (define (unquote name) (unquote (if (null? constructor) (quasiquote (lambda ())) (%class-lambda constructor)))) (set-obj! (unquote name) (Symbol.for "__class__") #t) (unquote (if (and (not (null? parent)) (not (eq? parent (quote Object)))) (quasiquote (begin (set-obj! (unquote name) (quote prototype) (Object.create (. (unquote parent) (quote prototype)))) (set-obj! (. (unquote name) (quote prototype)) (quote constructor) (unquote name)))))) (unquote-splicing (map (lambda (fn) (quasiquote (set-obj! (. (unquote name) (quote prototype)) (unquote (%class-method-name (car fn))) (unquote (%class-lambda fn))))) functions)))) (let ((item (car lst))) (if (eq? (car item) (quote constructor)) (iter functions item (cdr lst)) (iter (cons item functions) constructor (cdr lst))))))) +(define-syntax class (syntax-rules () ((_) (error "class: parent required")) ((_ parent body ...) (let () (define-class temp parent body ...) temp))) "(class <parent> body ...)\u000A\u000AMacro allow to create anonymous classes. See define-class for details.") +(define (make-tags expr) "(make-tags expression)\u000A\u000AFunction that return list structure of code with better syntax then raw LIPS" (quasiquote (h (unquote (let ((val (car expr))) (if (key? val) (key->string val) val))) (alist->object ((unquote (quote quasiquote)) (unquote (pair-map (lambda (car cdr) (quasiquote ((unquote (key->string car)) (unquote (quote unquote)) (unquote cdr)))) (cadr expr))))) (unquote (if (not (null? (cddr expr))) (if (and (pair? (caddr expr)) (let ((s (caaddr expr))) (and (symbol? s) (eq? s (quote list))))) (quasiquote (list->array (list (unquote-splicing (map make-tags (cdaddr expr)))))) (caddr expr))))))) +(define (%sxml h expr) "(%sxml h expr)\u000A\u000AHelper function that render expression using create element function." (let* ((have-attrs (and (not (null? (cdr expr))) (pair? (cadr expr)) (eq? (caadr expr) (quote @)))) (attrs (if have-attrs (cdadr expr) ())) (rest (if have-attrs (cddr expr) (cdr expr)))) (quasiquote ((unquote h) (unquote (let* ((symbol (car expr)) (name (symbol->string symbol))) (if (char-lower-case? (car (string->list name))) name symbol))) (alist->object ((unquote (quote quasiquote)) (unquote (map (lambda (pair) (cons (symbol->string (car pair)) (list (quote unquote) (cadr pair)))) attrs)))) (unquote-splicing (if (null? rest) () (let ((first (car rest))) (if (pair? first) (map (lambda (expr) (%sxml h expr)) rest) (list first))))))))) +(define-macro (pragma->sxml pragma) (quasiquote (define-macro (sxml expr) "(sxml expr)\u000A\u000AMacro for JSX like syntax but with SXML.\u000Ae.g. usage:\u000A\u000A(sxml (div (@ (data-foo \"hello\")\u000A (id \"foo\"))\u000A (span \"hello\")\u000A (span \"world\")))" (%sxml (quote (unquote pragma)) expr)))) +(pragma->sxml h) +(define-macro (with-tags expr) "(with-tags expression)\u000A\u000AMacro that evalute LIPS shorter code for S-Expression equivalent of JSX.\u000Ae.g.:\u000A\u000A(with-tags (:div (:class \"item\" :id \"item-1\")\u000A (list (:span () \"Random Item\")\u000A (:a (:onclick (lambda (e) (alert \"close\")))\u000A \"close\"))))\u000A\u000AAbove expression can be passed to function that renders JSX (like render in React, Preact)\u000ATo get the string from the macro you can use vhtml library from npm." (make-tags expr)) +(define (get-script url) "(get-script url)\u000A\u000ALoad JavaScript file in browser by adding script tag to head of the current document." (if (not (bound? (quote document))) (throw (new Error "get-script: document not defined")) (let ((script (document.createElement "script"))) (new Promise (lambda (resolve reject) (set-obj! script (quote src) url) (set-obj! script (quote onload) (lambda () (resolve))) (set-obj! script (quote onerror) (lambda () (reject "get-script: Failed to load"))) (if document.head (document.head.appendChild script))))))) +(define (gensym? value) "(gensym? value)\u000A\u000AFunction return #t if value is symbol and it's gensym. It returns #f otherwise." (and (symbol? value) (--> value (is_gensym)))) +(define (degree->radians x) "(degree->radians x)\u000A\u000AConvert degree to radians." (* x (/ Math.PI 180))) +(define (radians->degree x) "(radians->degree x)\u000A\u000AConvert radians to degree." (* x (/ 180 Math.PI))) +(define-syntax while (syntax-rules () ((_ predicate body ...) (do () ((not predicate)) body ...))) "(while cond . body)\u000A\u000AMacro that create a loop, it exectue body until cond expression is false.") +(define-syntax ++ (syntax-rules () ((++ x) (let ((tmp (+ x 1))) (set! x tmp) tmp))) "(++ variable)\u000A\u000AMacro that work only on variables and increment the value by one.") +(define-syntax -- (syntax-rules () ((-- x) (let ((tmp (- x 1))) (set! x tmp) tmp))) "(-- variable)\u000A\u000AMacro that decrement the value it work only on symbols") +(define (pretty-format pair) "(pretty-format pair)\u000A\u000AFunction return pretty printed string from pair expression." (typecheck "pretty-pair" pair "pair") (--> (new lips.Formatter (repr pair #t)) (break) (format))) +(define (reset) "(reset)\u000A\u000AFunction reset environment and remove all user defined variables." (let-env **interaction-environment** (let ((defaults **interaction-environment-defaults**) (env **interaction-environment**)) (--> env (list) (forEach (lambda (name) (if (not (--> defaults (includes name))) (--> env (unset name))))))))) +(define (make-list n . rest) (if (or (not (integer? n)) (<= n 0)) (throw (new Error "make-list: first argument need to be integer larger then 0")) (let ((fill (if (null? rest) undefined (car rest)))) (array->list (--> (new Array n) (fill fill)))))) +(define (range n) "(range n)\u000A\u000AFunction return list of n numbers from 0 to n - 1" (typecheck "range" n "number") (array->list (--> (new Array n) (fill 0) (map (lambda (_ i) i))))) +(define-macro (do-iterator spec cond . body) "(do-iterator (var expr) (test) body ...)\u000A\u000AMacro iterate over iterators (e.g. create with JavaScript generator function)\u000Ait works with normal and async iterators. You can loop over infinite iterators\u000Aand break the loop if you want, using expression like in do macro, long sync iterators\u000Awill block main thread (you can't print 1000 numbers from inf iterators,\u000Abecause it will freeze the browser), but if you use async iterators you can process\u000Athe values as they are generated." (let ((gen (gensym "name")) (name (car spec)) (async (gensym "async")) (sync (gensym "sync")) (iterator (gensym "iterator")) (test (if (null? cond) #f (car cond))) (next (gensym "next")) (stop (gensym "stop")) (item (gensym "item"))) (quasiquote (let* (((unquote gen) (unquote (cadr spec))) ((unquote sync) (. (unquote gen) Symbol.iterator)) ((unquote async) (. (unquote gen) Symbol.asyncIterator)) ((unquote iterator)) ((unquote next) (lambda () ((. (unquote iterator) "next"))))) (if (or (procedure? (unquote sync)) (procedure? (unquote async))) (begin (set! (unquote iterator) (if (procedure? (unquote sync)) ((unquote sync)) ((unquote async)))) (let* (((unquote item) ((unquote next))) ((unquote stop) #f) ((unquote name) (. (unquote item) "value"))) (while (not (or (eq? (. (unquote item) "done") #t) (unquote stop))) (if (unquote test) (set! (unquote stop) #t) (begin (unquote-splicing body))) (set! (unquote item) ((unquote next))) (set! (unquote name) (. (unquote item) "value")))))))))) +(set-repr! Set (lambda () "#<Set>")) +(set-repr! Map (lambda () "#<Met>")) +(define (native-symbol? x) "(native-symbol? object)\u000A\u000AFunction check if value is JavaScript symbol." (and (string=? (type x) "symbol") (not (symbol? x)))) +(set-special! "’" (quote warn-quote)) +(define-macro (warn-quote) "(warn-quote)\u000A\u000ASimple macro that throw error, when you try to use ’ symbol as quote in code" (throw (new Error (string-append "You're using invalid quote character run: " "(set-special! \"’\" 'quote)" " to allow running this type of quote")))) +(define-macro (quote-promise expr) "(quote-promise expr)\u000A'>expr\u000A\u000AMacro used to escape promise the whole expression, will be wrapped\u000Awith JavaScript class that behave like Promise but will not\u000Aauto resolve like normal promise." (quasiquote (let ((env)) (set! env (current-environment)) (env.set (Symbol.for "__promise__") #t) (unquote expr)))) +(define (await value) (if (instanceof lips.QuotedPromise value) (value.valueOf) value)) +(define-macro (let-env-values env spec . body) "(let-env-values env ((name var)) . body)\u000A\u000AMacro add mapping for variables var from specified env,\u000AMacro work similar to let-env but lexical scope is working with it." (let ((env-name (gensym (quote env)))) (quasiquote (let (((unquote env-name) (unquote env))) (let (unquote (map (lambda (pair) (quasiquote ((unquote (car pair)) (--> (unquote env-name) (get (quote (unquote (cadr pair)))))))) spec)) (unquote-splicing body)))))) +(define (apropos name) "(apropos name)\u000A\u000ASearch environment and display names that match the given name.\u000Aname can be regex, string or symbol." (typecheck "apropos" name (quote ("string" "regex" "symbol"))) (let ((regex (lambda (string) (new RegExp (escape-regex string))))) (filter (cond ((string? name) (regex name)) ((symbol? name) (regex (symbol->string name))) (else name)) (env)))) +(define (promisify fn) "(promisify fn)\u000A\u000ASimple function for adding promises to NodeJS callback based function.\u000AFunction tested only with fs module." (lambda args (new Promise (lambda (resolve reject) (apply fn (append args (list (lambda (err data) (if (null? err) (resolve data) (reject err)))))))))) +(define-macro (list* . args) "(list* arg1 ...)\u000A\u000AParallel version of list." (let ((result (gensym "result"))) (quasiquote (let (((unquote result) (vector))) (unquote-splicing (map (lambda (arg) (quasiquote (--> (unquote result) (push (quote-promise (unquote arg)))))) args)) (map await (vector->list (unquote result))))))) +(define-macro (%not-implemented name) "(not-implemented name)\u000A\u000AReturns new function taht throw exception that function is not implmeneted" (let ((str-name (symbol->string name))) (quasiquote (lambda () (unquote (string-append "(" str-name ")\u000A\u000AThis function is not yet implemented.")) (throw (new Error (unquote (string-append str-name " has not beed implemented")))))))) +(define-macro (%make-env name . names) "(%make-env name f1 f2 ...)\u000A\u000ACreate new Environment with given name and defined symbols in it from global env.\u000AIf given function name f1 f2 ... don't exists, it will define function that\u000Athrow exception that function is not yet implemented." (quasiquote (new lips.Environment (alist->object (list (unquote-splicing (map (lambda (name) (quasiquote (cons (quote (unquote name)) (unquote (let ((ref (lips.env.ref name))) (if (null? ref) (quasiquote (%not-implemented (unquote name))) (quasiquote (lips.env.get (quote (unquote name)))))))))) names)))) null (unquote name)))) +(define Y (lambda (h) "(Y f)\u000A\u000A _ __ __ _ _ _ _ __ __ _ _ _\u000A / \\ \\ / / / __ / ____ \\ / \\ \\ / / ____ \\ \\ \\\u000A+ \\ v / + \\ \\ + / ___| + + \\ v / / ___| + + +\u000A| \\ / | \\ \\ | | |__ | | \\ / | |__ | | |\u000A| | | | / \\ | | __| | | | | | __| | | |\u000A| | | | / /\\ \\ | | | | | | | | | | | |\u000A+ |_| + /_/ \\_\\ + |_| + + |_| |_| + + +\u000A \\_ \\_ \\_ _/ \\_ _/ _/ _/" ((lambda (x) (x x)) (lambda (g) (h (lambda args (apply (g g) args))))))) +(define (indexed-db?) "(indexed-db?)\u000A\u000AFunction test if indexedDB is available." (let* ((any (lambda args (let iter ((args args)) (if (null? args) #f (if (not (null? (car args))) (car args) (iter (cdr args))))))) (indexedDB (any window.indexedDB window.indexedDB window.mozIndexedDB window.webkitIndexedDB))) (if (not (null? indexedDB)) (try (begin (window.indexedDB.open "MyTestDatabase" 3) #t) (catch (e) #f)) #f))) +(let* ((fs (cond ((eq? self global) (require "fs")) ((and (not (null? self.BrowserFS)) (indexed-db?)) (new Promise (lambda (resolve reject) (BrowserFS.configure &(:options &() :fs "IndexedDB") (lambda (e) (if (null? e) (resolve (BrowserFS.BFSRequire "fs")) (reject e))))))) ((not (null? self.BrowserFS)) (console.warn (string-append "BrowserFS not initilalized " "IndexedDB is not available")) ()))) (Buffer (cond ((eq? self global) self.Buffer) ((not (null? self.BrowserFS)) (. (BrowserFS.BFSRequire "buffer") (quote Buffer)))))) (let ((internal (lips.env.get (quote **internal-env**)))) (if (not (null? Buffer)) (internal.set "Buffer" Buffer)) (if (not (null? fs)) (internal.set "fs" fs)))) +(define (environment? obj) "(environment? obj)\u000A\u000AFunction check if object is LIPS environment." (instanceof lips.Environment obj)) +(define %read-file (let ((read-file #f) (fetch-url #f)) (lambda (binary path) "(%read-file binary path)\u000A\u000ARead file from url or file system. If binary is false it will return\u000Astring that contain all the content. For HTTP requests, If binary\u000Ais false it will: when in browser return ArrayBuffer and in Node\u000Ait will return Buffer object. When reading from file system\u000Ain both cases it will return Buffer objects.\u000A\u000AThe code that use those function, in binary mode, need to check\u000Aif the result is ArrayBuffer or Node.js/BrowserFS Buffer object." (if (not read-file) (let ((fs (--> lips.env (get (quote **internal-env**)) (get (quote fs))))) (if (null? fs) (throw (new Error "open-input-file: fs not defined")) (let ((*read-file* (promisify fs.readFile))) (set! read-file (lambda (path binary) (let ((buff (*read-file* path))) (if binary (if (eq? self window) (new Blob (vector buff)) buff) (--> buff (toString)))))))))) (if (not fetch-url) (set! fetch-url (lambda (url binary) (if (eq? self window) (let ((res (fetch url))) (if binary (res.arrayBuffer) (res.text))) (http-get url binary))))) (cond ((char=? (string-ref path 0) #\/) (if (not (file-exists? path)) (throw (new Error (string-append "file " path " don't exists"))) (read-file path binary))) ((--> #/^https?:\/\// (test path)) (fetch-url path binary)) (else (%read-file binary (string-append (current-directory) path))))))) +(define %read-binary-file (curry %read-file #t)) +(define %read-text-file (curry %read-file #f)) +(define (%fs-promisify-proc fn message) "(%fs-promisify-proc fn string)\u000A\u000AFunction return promisified version of fs function or throw exception\u000Aif fs is not available." (let ((fs (--> lips.env (get (quote **internal-env**)) (get (quote fs))))) (if (null? fs) (throw (new Error (string-append message ": fs not defined"))) (promisify (. fs fn))))) +(define (response->content binary res) "(response->text binary res)\u000A\u000AFunction read all text from Node.js HTTP response object. If binary argument\u000Ais true it will return Buffer object that can be converted to u8vector.\u000A\u000A***Warrning:*** it may overflow the stack (part of Node) when converting\u000Awhole buffer to u8vector." (let ((result (vector)) (append (if binary (lambda (chunk) (result.push (Buffer.from chunk "binary"))) (lambda (chunk) (result.push chunk))))) (res.setEncoding (if binary "binary" "utf8")) (new Promise (lambda (resolve) (res.on "data" append) (res.on "end" (lambda () (if binary (resolve (Buffer.concat result)) (resolve (result.join ""))))))))) +(define response->buffer (curry response->content #t)) +(define response->text (curry response->content #f)) +(define http-get (if (eq? self window) (lambda (url binary) "(http-get url)\u000A\u000ANode.js Function that send HTTP Request and return string or\u000Abinary Buffer object." (throw (new Error "http-get: function is Node.js only."))) (let* ((http (. (require "http") (quote get))) (https (. (require "https") (quote get)))) (lambda (url binary) "(http-get url)\u000A\u000ANode.js Function that send HTTP Request and return string or\u000Abinary Buffer object." (let ((request (if (null? (url.match #/^https/)) http https))) (new Promise (lambda (resolve reject) (--> (request url (lambda (res) (if (= res.statusCode 200) (resolve (response->content binary res)) (let ((code res.statusCode)) (res.resume) (reject (string-append "Request return " (number->string code))))))) (on "error" reject))))))))) +(define (buffer->u8vector bin) "(buffer->u8vector bin)\u000A\u000ACross platform function that can be used in both Node and Browser.\u000AIt can be used together with %read-file or %read-binary-file and convert\u000Athe result ArrayBuffer or Buffer to u8vector." (if (instanceof ArrayBuffer bin) (new Uint8Array bin) (Uint8Array.from bin))) +(define string-append concat) +(define = ==) +(define remainder %) +(define -inf.0 Number.NEGATIVE_INFINITY) +(define +inf.0 Number.POSITIVE_INFINITY) +(define procedure? function?) +(define expt **) +(define list->vector list->array) +(define vector->list array->list) +(define-macro (define-symbol-macro type spec . rest) "(define-symbol-macro type (name . args) . body)\u000A\u000AMacro that creates special symbol macro for evaluator similar to build in , or `.\u000AIt's like alias for real macro. Similar to CL reader macros but it receive already\u000Aparsed code like normal macros. Type can be SPLICE or LITERAL symbols.\u000AALL default symbol macros are literal." (let* ((name (car spec)) (symbol (cadr spec)) (args (cddr spec))) (quasiquote (begin (set-special! (unquote symbol) (quote (unquote name)) (unquote (string->symbol (concat "lips.specials." (symbol->string type))))) (define-macro ((unquote name) (unquote-splicing args)) (unquote-splicing rest)))))) +(set-special! "#" (quote vector-literal) lips.specials.SPLICE) +(define-macro (vector-literal . args) (if (not (or (pair? args) (eq? args ()))) (throw (new Error (concat "Parse Error: vector require pair got " (type args) " in " (repr args)))) (let ((v (list->array args))) (Object.freeze v) v))) +(define-syntax vector (syntax-rules () ((_ arg ...) (list->array (list arg ...)))) "(vector 1 2 3 (+ 3 1))\u000A#(1 2 3 4)\u000A\u000AMacro for defining vectors (JavaScript arrays). Vectors literals are\u000Aautomatically quoted. So you can use expressions inside them. Only other\u000Aliterals, like other vectors or object.") +(set-repr! Array (lambda (arr q) (let ((result (--> (Array.from arr) (map (lambda (x i) (if (not (in i arr)) "#<empty>" (repr (. arr i) q))))))) (concat "#(" (--> result (join " ")) ")")))) +(define (eqv? a b) "(eqv? a b)\u000A\u000AFunction compare the values. It return true if they are the same, they\u000Aneed to have same type" (if (string=? (type a) (type b)) (cond ((number? a) (or (and (exact? a) (exact? b) (= a b)) (and (inexact? a) (inexact? b) (cond ((a.isNaN) (b.isNaN)) ((and (zero? a) (zero? b)) (eq? a._minus b._minus)) ((and (complex? a) (complex? b)) (let ((re.a (real-part a)) (re.b (real-part b)) (im.a (imag-part a)) (im.b (imag-part b))) (and (if (and (zero? re.a) (zero? re.b)) (eq? (. re.a (quote _minus)) (. re.b (quote _minus))) #t) (if (and (zero? im.a) (zero? im.b)) (eq? (. im.a (quote _minus)) (. im.b (quote _minus))) #t) (or (= re.a re.b) (and (--> re.a (isNaN)) (--> re.b (isNaN)))) (or (= im.a im.b) (and (--> im.a (isNaN)) (--> im.b (isNaN))))))) (else (= a b)))))) ((pair? a) (and (null? a) (null? b))) (else (eq? a b))) #f)) +(define (equal? a b) "(equal? a b)\u000A\u000AFunction check if values are equal if both are pair or array\u000Ait compares the their elements recursivly." (cond ((and (pair? a)) (and (pair? b) (equal? (car a) (car b)) (equal? (cdr a) (cdr b)))) ((symbol? a) (and (symbol? b) (equal? a.__name__ b.__name__))) ((regex? a) (and (regex? b) (equal? (. a (quote source)) (. b (quote source))))) ((typed-array? a) (and (typed-array? b) (equal? (Array.from a) (Array.from b)))) ((vector? a) (and (vector? b) (= (length a) (length b)) (--> a (every (lambda (item i) (equal? item (vector-ref b i))))))) ((string? a) (and (string? b) (string=? a b))) ((function? a) (and (function? b) (%same-functions a b))) ((array? a) (and (array? b) (eq? (length a) (length b)) (= (--> a (filter (lambda (item i) (equal? item (. b i)))) (quote length)) (length a)))) ((plain-object? a) (and (plain-object? b) (let ((keys_a (--> (Object.keys a) (sort))) (keys_b (--> (Object.keys b) (sort)))) (and (= (length keys_a) (length keys_b)) (equal? keys_a keys_b) (equal? (--> keys_a (map (lambda (key) (. a key)))) (--> keys_b (map (lambda (key) (. b key))))))))) (else (eqv? a b)))) +(define make-promise (lambda (proc) "(make-promise fn)\u000A\u000AFunction create promise from a function." (typecheck "make-promise" proc "function") (let ((result-ready? #f) (result #f)) (let ((promise (lambda () (if result-ready? result (let ((x (proc))) (if result-ready? result (begin (set! result-ready? #t) (set! result x) result))))))) (set-obj! promise (Symbol.for "promise") #t) (set! promise.toString (lambda () (string-append "#<promise - " (if result-ready? (string-append "forced with " (type result)) "not forced") ">"))) promise)))) +(define-macro (delay expression) "(delay expression)\u000A\u000AMacro will create a promise from expression that can be forced with (force)." (quasiquote (make-promise (lambda () (unquote expression))))) +(define (force promise) "(force promise)\u000A\u000AFunction force the promise and evaluate delayed expression." (promise)) +(define (promise? obj) "(promise? obj)\u000A\u000AFunction check if value is a promise created with delay or make-promise." (string=? (type obj) "promise")) +(define (positive? x) "(positive? x)\u000A\u000AFunction check if number is larger then 0" (typecheck "positive?" x "number") (> x 0)) +(define (negative? x) "(negative? x)\u000A\u000AFunction check if number is smaller then 0" (typecheck "negative?" x "number") (< x 0)) +(define (zero? x) "(zero? x)\u000A\u000AFunction check if number is equal to 0" (typecheck "zero?" x "number") (= x 0)) +(define (quotient a b) "(quotient a b)\u000A\u000AReturn quotient from divition as integer." (typecheck "quotient" a "number") (typecheck "quotient" b "number") (if (zero? b 0) (throw (new Error "quotient: divition by zero")) (let ((quotient (/ a b))) (if (integer? quotient) quotient (if (> quotient 0) (floor quotient) (ceiling quotient)))))) +(define (number->string x . rest) "(number->string x [radix])\u000A\u000AFunction convert number to string with optional radix (number base)." (typecheck "number->string" x "number" 1) (let ((radix (if (null? rest) 10 (car rest)))) (typecheck "number->string" radix "number" 2) (--> x (toString (--> radix (valueOf)))))) +(define (boolean? x) "(boolean? x)\u000A\u000AFunction return true if value is boolean." (string=? (type x) "boolean")) +(define (vector-ref vector i) "(vector-ref vector i)\u000A\u000AReturn i element from vector." (typecheck "number->string" vector "array" 1) (typecheck "number->string" i "number" 2) (. vector i)) +(define (vector-set! vector i obj) "(vector-set! vector i obj)\u000A\u000ASet obj as value in vector at position 1." (typecheck "vector-set!" vector "array" 1) (typecheck "vector-set!" i "number" 2) (set-obj! vector i obj)) +(define (%number-type type x) (typecheck "%number-type" type (vector "string" "pair")) (typecheck "%number-type" x "number") (let* ((t x.__type__) (typeof (lambda (type) (string=? t type)))) (and (number? x) (if (pair? type) (some typeof type) (typeof type))))) +(define (real? x) "(real? x)\u000A\u000AFunction check if argument x is real." (and (number? x) (or (eq? x NaN) (eq? x Number.NEGATIVE_INFINITY) (eq? x Number.POSITIVE_INFINITY) (and (%number-type "complex" x) (let ((i (imag-part x))) (and (zero? i) (exact? i)))) (%number-type (quote ("float" "bigint" "rational")) x)))) +(define (integer? x) "(integer? x)\u000A\u000AFunction check if argument x is integer." (and (number? x) (not (eq? x NaN)) (not (eq? x Number.NEGATIVE_INFINITY)) (not (eq? x Number.POSITIVE_INFINITY)) (or (%number-type "bigint" x) (and (%number-type "float" x) (= (modulo x 2) 1))))) +(define (complex? x) "(complex? x)\u000A\u000AFunction check if argument x is complex." (and (number? x) (or (eq? x NaN) (eq? x Number.NEGATIVE_INFINITY) (eq? x Number.POSITIVE_INFINITY) (%number-type (quote ("complex" "float" "bigint" "rational")) x)))) +(define (rational? x) "(rational? x)\u000A\u000AFunction check if value is rational." (and (number? x) (not (eq? x NaN)) (not (eq? x Number.NEGATIVE_INFINITY)) (not (eq? x Number.POSITIVE_INFINITY)) (or (%number-type "rational" x) (integer? x)))) +(define (typecheck-args _type name _list) "(typecheck-args args type)\u000A\u000AFunction check if all items in array are of same type." (let iter ((n 1) (_list _list)) (if (pair? _list) (begin (typecheck name (car _list) _type n) (iter (+ n 1) (cdr _list)))))) +(define numbers? (curry typecheck-args "number")) +(define (max . args) "(max n1 n2 ...)\u000A\u000AReturn maximum of it's arguments." (numbers? "max" args) (apply (.. Math.max) args)) +(define (min . args) "(min n1 n2 ...)\u000A\u000AReturn minimum of it's arguments." (numbers? "min" args) (apply (.. Math.min) args)) +(define (make-rectangular re im) "(make-rectangular im re)\u000A\u000ACreate complex number from imaginary and real part." (let ((value (quasiquote ((re unquote re) (im unquote im))))) (lips.LComplex (--> value (to_object #t))))) +(define (exact? n) "(exact? n)" (typecheck "exact?" n "number") (let ((type n.__type__)) (or (string=? type "bigint") (string=? type "rational") (and (string=? type "complex") (exact? n.__im__) (exact? n.__re__))))) +(define (inexact? n) "(inexact? n)" (typecheck "inexact?" n "number") (not (exact? n))) +(define (exact->inexact n) "(exact->inexact n)\u000A\u000AConvert exact number to inexact." (typecheck "exact->inexact" n "number") (if (%number-type "complex" n) (lips.LComplex (object :im (exact->inexact (. n (quote __im__))) :re (exact->inexact (. n (quote __re__))))) (if (or (rational? n) (integer? n)) (lips.LFloat (--> n (valueOf)) #t) n))) +(define (inexact->exact n) "(inexact->exact number)\u000A\u000AFuncion convert real number to exact ratioanl number." (typecheck "inexact->exact" n "number") (if (or (real? n) (%number-type "complex" n)) (--> n (toRational)) n)) +(define _maths (list "exp" "log" "sin" "cos" "tan" "asin" "acos" "atan" "atan")) +(define _this_env (current-environment)) +(let iter ((fns _maths)) (if (not (null? fns)) (let* ((name (car fns)) (LNumber (.. lips.LNumber)) (op (. Math name)) (fn (lambda (n) (LNumber (op n))))) (--> _this_env (set name fn)) (set-obj! fn (quote __doc__) (concat "(" name " n)\u000A\u000AFunction calculate " name " math operation (it call JavaScript Math)." name " function.")) (iter (cdr fns))))) +(define (modulo a b) "(modulo a b)\u000A\u000AFunction return modulo operation on it's argumennts." (typecheck "modulo" a "number" 1) (typecheck "modulo" b "number" 2) (- a (* b (floor (/ a b))))) +(define (remainder__ a b) "(modulo a b)\u000A\u000AFunction return reminder from division operation." (typecheck "remainder" a "number" 1) (typecheck "remainder" b "number" 2) (- a (* b (truncate (/ a b))))) +(define (list-tail l k) "(list-tail list k)\u000A\u000AReturns the sublist of list obtained by omitting the first k elements." (typecheck "list-tail" l (quote ("pair" "nil"))) (if (< k 0) (throw (new Error "list-ref: index out of range")) (let ((l l) (k k)) (while (> k 0) (if (null? l) (throw (new Error "list-tail: not enough elements in the list"))) (set! l (cdr l)) (set! k (- k 1))) l))) +(define (list-ref l k) "(list-ref list n)\u000A\u000AReturns n element of a list." (typecheck "list-ref" l (quote ("pair" "nil"))) (if (< k 0) (throw (new Error "list-ref: index out of range")) (let ((l l) (k k)) (while (> k 0) (if (or (null? (cdr l)) (null? l)) (throw (new Error "list-ref: not enough elements in the list"))) (set! l (cdr l)) (set! k (- k 1))) (if (null? l) l (car l))))) +(define (not x) "(not x)\u000A\u000AFunction return true if value is false and false otherwise." (if x #f #t)) +(define (rationalize number tolerance) "(rationalize number tolerance)\u000A\u000AFunction returns simplest rational number differing from number by no more\u000Athan the tolerance." (typecheck "rationalize" number "number" 1) (typecheck "rationalize" tolerance "number" 2) (lips.rationalize number tolerance)) +(define (%mem/search access op obj list) "(%member obj list function)\u000A\u000AHelper method to get first list where car equal to obj\u000Ausing provied functions as comparator." (if (null? list) #f (if (op (access list) obj) list (%mem/search access op obj (cdr list))))) +(define (memq obj list) "(memq obj list)\u000A\u000AFunction return first object in the list that match using eq? function." (typecheck "memq" list (quote ("nil" "pair"))) (%mem/search car eq? obj list)) +(define (memv obj list) "(memv obj list)\u000A\u000AFunction return first object in the list that match using eqv? function." (typecheck "memv" list (quote ("nil" "pair"))) (%mem/search car eqv? obj list)) +(define (member obj list) "(member obj list)\u000A\u000AFunction return first object in the list that match using equal? function." (typecheck "member" list (quote ("nil" "pair"))) (%mem/search car equal? obj list)) +(define (%assoc/acessor name) "(%assoc/acessor name)\u000A\u000AFunction return carr with typecheck using give name." (lambda (x) (typecheck name x "pair") (caar x))) +(define (%assoc/search op obj alist) "(%assoc/search op obj alist)\u000A\u000AGeneric function that used in assoc functions with defined comparator\u000Afunction." (typecheck "assoc" alist (vector "nil" "pair")) (let ((ret (%mem/search (%assoc/acessor "assoc") op obj alist))) (if ret (car ret) ret))) +(define assoc (%doc "(assoc obj alist)\u000A\u000AFunction return pair from alist that match given key using equal? check." (curry %assoc/search equal?))) +(define assq (%doc "(assq obj alist)\u000A\u000AFunction return pair from alist that match given key using eq? check." (curry %assoc/search eq?))) +(define assv (%doc "(assv obj alist)\u000A\u000AFunction return pair from alist that match given key using eqv? check." (curry %assoc/search eqv?))) +(define (make-string k . rest) "(make-string k [char])\u000A\u000AFunction return new string with k elements, if char is provied\u000Ait's filled with that character." (let ((char (if (null? rest) #\space (car rest)))) (typecheck "make-string" k "number" 1) (typecheck "make-string" char "character" 2) (let iter ((result (quote ())) (k k)) (if (<= k 0) (list->string result) (iter (cons char result) (- k 1)))))) +(define (string . args) "(string chr1 chr2 ...)\u000A\u000AFunction create new string from it's arguments. Each argument\u000ANeed to be a character object." (for-each (lambda (x) (typecheck "string" x "character")) args) (list->string args)) +(define (string-copy string) "(string-copy string)\u000A\u000AReturns a copy of the given string." (typecheck "string-copy" string "string") (--> string (clone))) +(define (string-fill! string char) "(string-fill! symbol char)\u000A\u000AFunction destructively fill the string with given character." (typecheck "string-fill!" string "string" 1) (typecheck "string-fill!" char "character" 2) (--> string (fill char))) +(define (identity n) "(identity n)\u000A\u000ANo op function. it just returns its argument." n) +(define (string-copy x) "(string-copy x)\u000A\u000ACreate new string based of given argument." (typecheck "string-copy" x "string") (lips.LString x)) +(define (list->string _list) "(list->string _list)\u000A\u000AFunction return string from list of characters." (let ((array (list->array (map (lambda (x) (typecheck "list->string" x "character") (x.valueOf)) _list)))) (--> array (join "")))) +(define (string->list string) "(string->list string)\u000A\u000AFunction return list of characters created from string." (typecheck "string->list" string "string") (array->list (--> string (split "") (map (lambda (x) (lips.LCharacter x)))))) +(define-macro (string-set! object index char) "(string-set! object index char)\u000A\u000AMacro that replace character in string in given index, it create new JavaScript\u000Astring and replace old value. Object need to be symbol that point to variable\u000Athat hold the string." (typecheck "string-set!" object "symbol") (let ((chars (gensym "chars"))) (quasiquote (begin (typecheck "string-set!" (unquote object) "string") (typecheck "string-set!" (unquote index) "number") (typecheck "string-set!" (unquote char) "character") (let (((unquote chars) (list->vector (string->list (unquote object))))) (set-obj! (unquote chars) (unquote index) (unquote char)) (set! (unquote object) (list->string (vector->list (unquote chars))))))))) +(define (string-length string) "(string-length string)\u000A\u000AFunction return length of the string." (typecheck "string-ref" string "string") (. string (quote length))) +(define (string-ref string k) "(string-ref string k)\u000A\u000AFunction return character inside string at given zero-based index." (typecheck "string-ref" string "string" 1) (typecheck "string-ref" k "number" 2) (lips.LCharacter (--> string (get k)))) +(define (%string-cmp name string1 string2) "(%string-cmp name a b)\u000A\u000AFunction compare two strings and return 0 if they are equal,\u000A-1 second is smaller and 1 if is larget. The function compare\u000Athe codepoints of the character." (typecheck name string1 "string" 1) (typecheck name string2 "string" 2) (--> string1 (cmp string2))) +(define (string=? string1 string2) "(string=? string1 string2)\u000A\u000AFunction check if two string s are equal." (= (%string-cmp "string=?" string1 string2) 0)) +(define (string<? string1 string2) "(string<? string1 string2)\u000A\u000AFunction return true if second string is smaller then the first one." (= (%string-cmp "string<?" string1 string2) -1)) +(define (string>? string1 string2) "(string<? string1 string2)\u000A\u000AFunction return true if second string is larger then the first one." (= (%string-cmp "string>?" string1 string2) 1)) +(define (string<=? string1 string2) "(string<? string1 string2)\u000A\u000AFunction return true if second string is not larger then the first one." (< (%string-cmp "string<=?" string1 string2) 1)) +(define (string>=? string1 string2) "(string<? string1 string2)\u000A\u000AFunction return true if second character is not smaller then the first one." (> (%string-cmp "string>=?" string1 string2) -1)) +(define (%string-ci-cmp name string1 string2) "(%string-ci-cmp name a b)\u000A\u000AFunction compare two strings ingoring case and return 0 if they are equal,\u000A-1 second is smaller and 1 if is larget. The function compare\u000Athe codepoints of the character." (typecheck name string1 "string" 1) (typecheck name string2 "string" 2) (--> string1 (lower) (cmp (--> string2 (lower))))) +(define (string-ci=? string1 string2) "(string-ci=? string1 string2)\u000A\u000AFunction check if two string s are equal." (= (%string-ci-cmp "string-ci=?" string1 string2) 0)) +(define (string-ci<? string1 string2) "(string-ci<? string1 string2)\u000A\u000AFunction return true if second string is smaller then the first one." (= (%string-ci-cmp "string-ci<?" string1 string2) -1)) +(define (string-ci>? string1 string2) "(string-ci<? string1 string2)\u000A\u000AFunction return true if second string is larger then the first one." (= (%string-ci-cmp "string-ci>?" string1 string2) 1)) +(define (string-ci<=? string1 string2) "(string-ci<? string1 string2)\u000A\u000AFunction return true if second string is not larger then the first one." (< (%string-ci-cmp "string-ci<=?" string1 string2) 1)) +(define (string-ci>=? string1 string2) "(string-ci>=? string1 string2)\u000A\u000AFunction return true if second character is not smaller then the first one." (> (%string-ci-cmp "string-ci>=?" string1 string2) -1)) +(define char? (%doc "(char? obj)\u000A\u000AFunction check if object is character." (curry instanceof lips.LCharacter))) +(define (char->integer chr) "(char->integer chr)\u000A\u000AFunction return codepoint of Unicode character." (typecheck "char->integer" chr "character") (--> chr.__char__ (codePointAt 0))) +(define (integer->char n) "(integer->char chr)\u000A\u000AFunction convert number argument to chararacter." (typecheck "integer->char" n "number") (if (integer? n) (string-ref (String.fromCodePoint n) 0) (throw "argument to integer->char need to be integer."))) +(define-macro (%define-chr-re spec str re) "(%define-chr-re (name chr) sring re)\u000A\u000AMacro define procedure that test character agains regular expression." (quasiquote (define (unquote spec) (unquote str) (typecheck (unquote (symbol->string (car spec))) (unquote (cadr spec)) "character") (not (null? (--> chr (toString) (match (unquote re)))))))) +(%define-chr-re (char-whitespace? chr) "(char-whitespace? chr)\u000A\u000AFunction return true if character is whitespace." (let-env (interaction-environment) (--> **internal-env** (get (quote space-unicode-regex))))) +(%define-chr-re (char-numeric? chr) "(char-numeric? chr)\u000A\u000AFunction return true if character is number." (let-env (interaction-environment) (--> **internal-env** (get (quote numeral-unicode-regex))))) +(%define-chr-re (char-alphabetic? chr) "(char-alphabetic? chr)\u000A\u000AFunction return true if character is leter of the ASCII alphabet." (let-env (interaction-environment) (--> **internal-env** (get (quote letter-unicode-regex))))) +(define (%char-cmp name chr1 chr2) "(%char-cmp name a b)\u000A\u000AFunction compare two characters and return 0 if they are equal,\u000A-1 second is smaller and 1 if is larget. The function compare\u000Athe codepoints of the character." (typecheck name chr1 "character" 1) (typecheck name chr2 "character" 2) (let ((a (char->integer chr1)) (b (char->integer chr2))) (cond ((= a b) 0) ((< a b) -1) (else 1)))) +(define (char=? chr1 chr2) "(char=? chr1 chr2)\u000A\u000AFunction check if two characters are equal." (= (%char-cmp "char=?" chr1 chr2) 0)) +(define (char<? chr1 chr2) "(char<? chr1 chr2)\u000A\u000AFunction return true if second character is smaller then the first one." (= (%char-cmp "char<?" chr1 chr2) -1)) +(define (char>? chr1 chr2) "(char<? chr1 chr2)\u000A\u000AFunction return true if second character is larger then the first one." (= (%char-cmp "char>?" chr1 chr2) 1)) +(define (char<=? chr1 chr2) "(char<? chr1 chr2)\u000A\u000AFunction return true if second character is not larger then the first one." (< (%char-cmp "char<=?" chr1 chr2) 1)) +(define (char>=? chr1 chr2) "(char<? chr1 chr2)\u000A\u000AFunction return true if second character is not smaller then the first one." (> (%char-cmp "char>=?" chr1 chr2) -1)) +(define (%char-ci-cmp name chr1 chr2) "(%char-cmp name a b)\u000A\u000AFunction compare two characters and return 0 if they are equal,\u000A-1 second is smaller and 1 if is larget. The function compare\u000Athe codepoints of the character." (typecheck name chr1 "character" 1) (typecheck name chr2 "character" 2) (%char-cmp name (char-downcase chr1) (char-downcase chr2))) +(define (char-ci=? chr1 chr2) "(char-ci=? chr1 chr2)\u000A\u000AFunction check if two characters are equal." (= (%char-ci-cmp "char-ci=?" chr1 chr2) 0)) +(define (char-ci<? chr1 chr2) "(char-ci<? chr1 chr2)\u000A\u000AFunction return true if second character is smaller then the first one." (= (%char-ci-cmp "char-ci<?" chr1 chr2) -1)) +(define (char-ci>? chr1 chr2) "(char-ci<? chr1 chr2)\u000A\u000AFunction return true if second character is larger then the first one." (= (%char-ci-cmp "char-ci>?" chr1 chr2) 1)) +(define (char-ci<=? chr1 chr2) "(char-ci<? chr1 chr2)\u000A\u000AFunction return true if second character is not larger then the first one." (< (%char-ci-cmp "char-ci<=?" chr1 chr2) 1)) +(define (char-ci>=? chr1 chr2) "(char-ci<? chr1 chr2)\u000A\u000AFunction return true if second character is not smaller then the first one." (> (%char-ci-cmp "char-ci>=?" chr1 chr2) -1)) +(define (char-upcase char) "(char-upcase char)\u000A\u000ACreate uppercase version of the character." (typecheck "char-upcase" char "character") (char.toUpperCase)) +(define (char-downcase char) "(char-downcase chr)\u000A\u000ACreate lowercase version of the character." (typecheck "char-upcase" char "character") (char.toLowerCase)) +(define (char-upper-case? char) "(char-upper-case? char)\u000A\u000AFunction check if character is upper case." (typecheck "char-upper-case?" char "character") (and (char-alphabetic? char) (char=? (char-upcase char) char))) +(define (char-lower-case? char) "(char-upper-case? char)\u000A\u000AFunction check if character is lower case." (typecheck "char-lower-case?" char "character") (and (char-alphabetic? char) (char=? (char-downcase char) char))) +(define (newline . rest) "(newline [port])\u000A\u000AWrite newline character to standard output or given port" (let ((port (if (null? rest) (current-output-port) (car rest)))) (display "\u000A" port))) +(define (write obj . rest) "(write obj [port])\u000A\u000AWrite object to standard output or give port. For strings it will include\u000Awrap in quotes." (let ((port (if (null? rest) (current-output-port) (car rest)))) (display (repr obj #t) port))) +(define (write-char char . rest) "(write-char char [port])\u000A\u000AWrite single character to given port using write function." (typecheck "write-char" char "character") (if (not (null? rest)) (typecheck "write-char" (car rest) "output-port")) (apply display (cons (char.valueOf) rest))) +(define fold-right reduce) +(define fold-left fold) +(define (make-vector n . rest) "(make-vector n [fill])\u000A\u000ACreate new vector with n empty elements. If fill is specified it will set\u000Aall elements of the vector to that value." (let ((result (new Array n))) (if (not (null? rest)) (--> result (fill (car rest))) result))) +(define (vector? n) "(vector? n)\u000A\u000AFunction return true of value is vector and false if not." (string=? (type n) "array")) +(define (vector-ref vec n) "(vector-ref vec n)\u000A\u000AFunction return nth element of the vector vec." (typecheck "vector-ref" vec "array" 1) (typecheck "vector-ref" n "number" 2) (. vec n)) +(define (vector-set! vec n value) "(vector-set! vec n value)\u000A\u000AFunction set nth item of the vector to value." (typecheck "vector-ref" vec "array" 1) (typecheck "vector-ref" n "number" 2) (set-obj! vec n value)) +(define (vector-fill! vec value) "(vector-fill! vec value)\u000A\u000ASet every element of the vector to given value." (typecheck "vector-ref" vec "array") (let recur ((n (- (length vec) 1))) (if (>= n 0) (begin (set-obj! vec n value) (recur (- n 1)))))) +(define (vector-length vec) "(vector-length vec)\u000A\u000AFunction return length of the vector. If argument is not vector it throw exception." (typecheck "vector-length" vec "array") (length vec)) +(define-syntax case (syntax-rules (else =>) ((case (key ...) clauses ...) (let ((atom-key (key ...))) (case atom-key clauses ...))) ((case key (else => result)) (result key)) ((case key (else result1 result2 ...)) (begin result1 result2 ...)) ((case key ((atoms ...) result1 result2 ...)) (if (memv key (quote (atoms ...))) (begin result1 result2 ...))) ((case key ((atoms ...) => result)) (if (memv key (quote (atoms ...))) (result key))) ((case key ((atoms ...) => result) clause clauses ...) (if (memv key (quote (atoms ...))) (result key) (case key clause clauses ...))) ((case key ((atoms ...) result1 result2 ...) clause clauses ...) (if (memv key (quote (atoms ...))) (begin result1 result2 ...) (case key clause clauses ...)))) "(case value\u000A ((<items>) result1)\u000A ((<items>) result2)\u000A [else result3])\u000A\u000AMacro for switch case statement. It test if value is any of the item. If\u000Aitem match the value it will return coresponding result expression value.\u000AIf no value match and there is else it will return that result.") +(--> lips.Formatter.defaults.exceptions.specials (push "case")) +(define (numerator n) "(numerator n)\u000A\u000AReturn numberator of rational or same number if n is not rational." (typecheck "numerator" n "number") (if (and (rational? n) (not (integer? n))) n.num n)) +(define (denominator n) "(denominator n)\u000A\u000AReturn denominator of rational or same number if one is not rational." (typecheck "denominator" n "number") (if (and (rational? n) (not (integer? n))) n.denom (if (exact? n) 1 1.0))) +(define (imag-part n) "(imag-part n)\u000A\u000AReturn imaginary part of the complex number n." (typecheck "imag-part" n "number") (if (%number-type "complex" n) n.__im__ 0)) +(define (real-part n) "(real-part n)\u000A\u000AReturn real part of the complex number n." (typecheck "real-part" n "number") (if (%number-type "complex" n) n.__re__ n)) +(define (make-polar r angle) "(make-polar magnitude angle)\u000A\u000ACreate new complex number from polar parameters." (typecheck "make-polar" r "number") (typecheck "make-polar" angle "number") (if (or (complex? r) (complex? angle)) (error "make-polar: argument can't be complex") (let ((re (* r (sin angle))) (im (* r (cos angle)))) (make-rectangular im re)))) +(define (angle x) "(angle x)\u000A\u000AReturns angle of the complex number in polar coordinate system." (if (not (%number-type "complex" x)) (error "angle: number need to be complex") (Math.atan2 x.__im__ x.__re__))) +(define (magnitude x) "(magnitude x)\u000A\u000AReturns magnitude of the complex number in polar coordinate system." (if (not (%number-type "complex" x)) (error "magnitude: number need to be complex") (sqrt (+ (* x.__im__ x.__im__) (* x.__re__ x.__re__))))) +(define random (let ((a 69069) (c 1) (m (expt 2 32)) (seed 19380110)) (lambda new-seed "(random)\u000A(random seed)\u000A\u000AFunction generate new random real number using Knuth algorithm." (if (pair? new-seed) (set! seed (car new-seed)) (set! seed (modulo (+ (* seed a) c) m))) (exact->inexact (/ seed m))))) +(define (eof-object? obj) "(eof-object? arg)\u000A\u000AFunction check if value is eof object, returned from input string\u000Aport when there are no more data to read." (eq? obj eof)) +(define (output-port? obj) "(output-port? arg)\u000A\u000AFunction return true if argument is output port." (instanceof lips.OutputPort obj)) +(define (input-port? obj) "(input-port? arg)\u000A\u000AFunction return true if argument is input port." (instanceof lips.InputPort obj)) +(define (char-ready? . rest) "(char-ready?)\u000A(char-ready? port)\u000A\u000AFunction check it characters is ready in input port. This is usefull mostly\u000Afor interactive ports that return false if it would wait for user input.\u000AIt return false if port is closed." (let ((port (if (null? rest) (current-input-port) (car rest)))) (typecheck "char-ready?" port "input-port") (port.char_ready))) +(define open-input-file (let ((readFile #f)) (lambda (filename) "(open-input-file filename)\u000A\u000AFunction return new Input Port with given filename. In Browser user need to\u000Aprovide global fs variable that is instance of FS interface." (let ((fs (--> lips.env (get (quote **internal-env**)) (get (quote fs))))) (if (null? fs) (throw (new Error "open-input-file: fs not defined")) (begin (if (not (procedure? readFile)) (let ((_readFile (promisify fs.readFile))) (set! readFile (lambda (filename) (--> (_readFile filename) (toString)))))) (new lips.InputFilePort (readFile filename) filename))))))) +(define (close-input-port port) "(close-input-port port)\u000A\u000AProcedure close port that was opened with open-input-file. After that\u000Ait no longer accept reading from that port." (typecheck "close-input-port" port "input-port") (port.close)) +(define (close-output-port port) "(close-output-port port)\u000A\u000AProcedure close port that was opened with open-output-file. After that\u000Ait no longer accept write to that port." (typecheck "close-output-port" port "output-port") (port.close)) +(define (call-with-input-file filename proc) "(call-with-input-file filename proc)\u000A\u000AProcedure open file for reading, call user defined procedure with given port\u000Aand then close the port. It return value that was returned by user proc\u000Aand it close the port even if user proc throw exception." (let ((p (open-input-file filename))) (try (proc p) (finally (close-input-port p))))) +(define (call-with-output-file filename proc) "(call-with-output-file filename proc)\u000A\u000AProcedure open file for writing, call user defined procedure with port\u000Aand then close the port. It return value that was returned by user proc and it close the port\u000Aeven if user proc throw exception." (let ((p (open-output-file filename))) (try (proc p) (finally (close-output-port p))))) +(define (with-input-from-file string thunk) "(with-input-from-file string thunk)\u000A\u000AProcedure open file and make it current-input-port then thunk is executed.\u000AAfter thunk is executed current-input-port is restored and file port\u000Ais closed." (let* ((port (open-input-file string)) (env **interaction-environment**) (internal-env (env.get (quote **internal-env**))) (old-stdin (internal-env.get "stdin"))) (internal-env.set "stdin" port) (try (thunk) (finally (internal-env.set "stdin" old-stdin) (close-input-port port))))) +(define (with-output-to-file string thunk) (let* ((port (open-output-file string)) (env **interaction-environment**) (internal-env (env.get (quote **internal-env**))) (old-stdout (internal-env.get "stdout"))) (internal-env.set "stdout" port) (try (thunk) (finally (internal-env.set "stdout" old-stdout) (close-output-port port))))) +(define (file-exists? filename) (new Promise (lambda (resolve) (let ((fs (--> lips.env (get (quote **internal-env**)) (get (quote fs))))) (if (null? fs) (throw (new Error "file-exists?: fs not defined")) (fs.stat filename (lambda (err stat) (if (null? err) (resolve (stat.isFile)) (resolve #f))))))))) +(define open-output-file (let ((open)) (lambda (filename) "(open-output-file filename)\u000A\u000AFunction open file and return port that can be used for writing. If file\u000Aexists it will throw an Error." (typecheck "open-output-file" filename "string") (if (not (procedure? open)) (set! open (%fs-promisify-proc (quote open) "open-output-file"))) (if (file-exists? filename) (throw (new Error "open-output-file: file exists")) (lips.OutputFilePort filename (open filename "w")))))) +(define (scheme-report-environment version) "(scheme-report-environment version)\u000A\u000AFunction return new Environment object for given Scheme Spec version.\u000AOnly argument 5 is supported that create environemnt for R5RS." (typecheck "scheme-report-environment" version "number") (case version ((5) (%make-env "R5RS" * + - / < <= = > >= abs acos and angle append apply asin assoc assq assv atan begin boolean? caaaar caaadr caaar caadar caaddr caadr caar cadaar cadadr cadar caddar cadddr caddr cadr call-with-current-continuation call-with-input-file call-with-output-file call-with-values car case cdaaar cdaadr cdaar cdadar cdaddr cdadr cdar cddaar cddadr cddar cdddar cddddr cdddr cddr cdr ceiling char->integer char-alphabetic? char-ci<=? char-ci<? char-ci=? char-ci>=? char-ci>? char-downcase char-lower-case? char-numeric? char-ready? char-upcase char-upper-case? char-whitespace? char<=? char<? char=? char>=? char>? char? close-input-port close-output-port complex? cond cons cos current-input-port current-output-port define define-syntax delay denominator display do dynamic-wind eof-object? eq? equal? eqv? eval even? exact->inexact exact? exp expt floor for-each force gcd if imag-part inexact->exact inexact? input-port? integer->char integer? interaction-environment lambda lcm length let let* let-syntax letrec letrec-syntax list list->string list->vector list-ref list-tail list? load log magnitude make-polar make-rectangular make-string make-vector map max member memq memv min modulo negative? newline not null-environment null? number->string number? numerator odd? open-input-file open-output-file or output-port? pair? peek-char positive? procedure? quasiquote quote quotient rational? rationalize read read-char real-part real? remainder reverse round scheme-report-environment set! set-car! set-cdr! sin sqrt string string->list string->number string->symbol string-append string-ci<=? string-ci<? string-ci=? string-ci>=? string-ci>? string-copy string-fill! string-length string-ref string-set! string<=? string<? string=? string>=? string>? string? substring symbol->string symbol? tan truncate values vector vector->list vector-fill! vector-length vector-ref vector-set! vector? with-input-from-file with-output-to-file write write-char zero?)) ((7) (throw (new Error "not yet implemented"))) (else (throw (new Error (string-append "scheme-report-environment: version " (number->string version) " not supported")))))) +(define-macro (%make-vector prefix type help) "(%make-vector prefix type help)\u000A\u000AMega helper macro that create list of functions for single byte vector\u000Abased on typed array from JavaScript" (letrec ((prefix-str (symbol->string prefix)) (type-str (symbol->string type)) (l-type (--> type-str (toLowerCase))) (static (lambda (name) (string->symbol (format "~a.~a" type-str name)))) (TypedArray.from (static "from")) (fn-name (lambda (str) (string->symbol (format str prefix-str)))) (type-vector (fn-name "~avector")) (make-vector (fn-name "make-~avector")) (vector? (fn-name "~avector?")) (vector-in-range? (fn-name "%~avector-in-range?")) (vector-ref (fn-name "~avector-ref")) (repr-str (format "#~a" prefix-str)) (vector-length (fn-name "~avector-length")) (vector->list (fn-name "~avector->list")) (vector-set! (fn-name "~avector-set!")) (list->tvector (fn-name "list->~avector")) (vector->tvector (fn-name "vector->~avector"))) (quasiquote (begin (define ((unquote type-vector) . args) (unquote (format "(~a v1 v2 ...)\u000A\u000ACreate ~a from give arguments." type-vector help)) ((unquote TypedArray.from) (list->vector args))) (define ((unquote vector-length) v) (unquote (format "(~a v)\u000A\u000Areturn length of ~a." vector-length help)) (typecheck (unquote (symbol->string vector-length)) v (unquote l-type)) v.length) (define ((unquote make-vector) k . fill) (unquote (format "(~a k fill)\u000A\u000AAllocate new ~a of length k, with optional initial values." make-vector help)) (let ((v (new (unquote type) k))) (if (not (null? fill)) (--> v (fill (car fill)))) v)) (define ((unquote vector?) x) (unquote (format "(~a x)\u000A\u000AFunction return #t of argument is ~a otherwise it return #f." vector? help)) (and (object? x) (equal? (. x (quote constructor)) (unquote type)))) (define ((unquote vector-in-range?) vector k) (unquote (format "(~a vector k)\u000A\u000AFunction test if index is range for ~a." vector-in-range? help)) (typecheck (unquote (symbol->string vector-in-range?)) vector (unquote l-type)) (typecheck (unquote (symbol->string vector-in-range?)) k "number") (let ((len (length vector))) (and (>= k 0) (< k len)))) (define ((unquote vector-ref) vector k) (unquote (format "(~a vector k)\u000A\u000AFunction return value frome vector at index k. If index is out of range it throw exception." vector-ref help)) (typecheck (unquote (symbol->string vector-ref)) vector (unquote l-type)) (typecheck (unquote (symbol->string vector-ref)) k "number") (if (not ((unquote vector-in-range?) vector k)) (throw (new Error (unquote (format "~a index out of range" vector-ref)))) (. vector k))) (define ((unquote vector->list) vector) (typecheck (unquote (symbol->string vector->list)) vector (unquote l-type)) (vector->list (Array.from vector))) (define ((unquote vector-set!) vector k v) (unquote (format "(~a vector k)\u000A\u000AFunction set value of ~a at index k. If index is out of range it throw exception." vector-set! help)) (typecheck (unquote (symbol->string vector-set!)) vector (unquote l-type)) (typecheck (unquote (symbol->string vector-set!)) k "number") (if (not ((unquote vector-in-range?) vector k)) (throw (new Error (unquote (format "~a index out of range" vector-set!)))) (set-obj! vector k v))) (define ((unquote list->tvector) lst) (typecheck (unquote (symbol->string list->tvector)) lst "pair") (apply (unquote vector) lst)) (define ((unquote vector->tvector) vector) (typecheck (unquote (symbol->string vector->tvector)) vector "array") ((unquote TypedArray.from) vector)) (set-special! (unquote repr-str) (quote (unquote type-vector)) lips.specials.SPLICE) (set-repr! (unquote type) (lambda (x _quote) (string-append (unquote repr-str) (repr ((unquote vector->list) x) _quote)))))))) +(%make-vector u8 Uint8Array "usigned 8-bit integer vector") +(%make-vector s8 Int8Array "signed 8-bit integer vector") +(%make-vector u16 Uint16Array "usigned 16-bit integer vector") +(%make-vector s16 Int16Array "signed 16-bit integer vector") +(%make-vector u32 Uint16Array "usigned 32-bit integer vector") +(%make-vector s32 Int16Array "signed 32-bit integer vector") +(%make-vector f32 Float32Array "32-bit IEEE floating point number vector") +(%make-vector f64 Float64Array "64-bit IEEE floating point number vector") +(define (list-match? predicate list) "(list-match? predicate list)\u000A\u000AFunction check if consecutive elements of the list match the predicate function." (typecheck "list-match?" predicate #("function" "macro")) (typecheck "list-match?" list "pair") (or (or (null? list) (null? (cdr list))) (and (predicate (car list) (cadr list)) (list-match? predicate (cdr list))))) +(define (symbol=? . args) "(symbol=? s1 s2 ...)\u000A\u000AFunction check if each value is symbol and it's the same acording to string=? predicate." (list-match? (lambda (a b) (and (symbol? a) (symbol? b) (equal? a b))) args)) +(define (values-ref values n) "(values-ref values n)\u000A\u000AFunction return n value of values object which is result of value function." (typecheck "values-ref" values "values" 1) (typecheck "values-ref" n "number" 1) (--> values (valueOf) n)) +(define-syntax let-values (syntax-rules () ((_ ()) ()) ((_ () body ...) (begin body ...)) ((_ (((x ...) values) ...) body ...) (apply (lambda (x ... ...) body ...) (vector->list (apply vector-append (map (lambda (x) ((. x "valueOf"))) (list values ...))))))) "(let-values binding body ...)\u000A\u000AThe macro work similar to let but variable is list of values and value\u000Aneed to evaluate to result of calling values.") +(define (vector-append . args) "(vector-append v1 v2 ...)\u000A\u000AFunction return new vector by combining it's arguments that should be vectors." (if (null? args) (vector) (begin (typecheck "vector-append" (car args) "array") (--> (car args) (concat (apply vector-append (cdr args))))))) +(define-macro (%range-function spec . body) "(%range-function spec . body)\u000A\u000AMacro that creates R7RS vector functions that have range start end." (let* ((name (car spec)) (name-str (symbol->string name)) (args (append (cdr spec) (quote rest)))) (quasiquote (define ((unquote name) (unquote-splicing args)) (unquote (if (string? (car body)) (car body))) (let ((start (if (null? rest) 0 (car rest))) (end (if (or (null? rest) (null? (cdr rest))) (. (unquote (car args)) (quote length)) (cadr rest)))) (typecheck (unquote name-str) start "number") (typecheck (unquote name-str) end "number") (unquote-splicing (if (string? (car body)) (cdr body) body))))))) +(%range-function (vector->list vector) "(vector->list vector)\u000A(vector->list vector start)\u000A(vector->list vector start end)\u000A\u000AFunction copy given range of vector to list. If no start is specified it use\u000Astart of the vector, if no end is specified it convert to the end of the vector." (typecheck "vector->list" vector "array") (array->list (vector.slice start end))) +(%range-function (string->vector string) "(string->list string)\u000A(string->list string start)\u000A(string->list string start end)\u000A\u000AFunction copy given range of string to list. If no start is specified it use\u000Astart of the string, if no end is specified it convert to the end of the string." (typecheck "string->vector" string "string") (--> (string.substring start end) (split "") (map (unary lips.LCharacter)))) +(%range-function (vector->string vector) "(vector->string vector)\u000A(vector->string vector start)\u000A(vector->string vector start end)\u000A\u000AFunction return new string created from vector of characters in given range.\u000AIf no start is given it create string from 0, if no end is given it return\u000Astring to the end." (typecheck "vector->string" vector "array") (--> vector (slice start end) (map (lambda (char) (char.valueOf))) (join ""))) +(%range-function (vector-fill! vector fill) "(vector-fill! vector fill)\u000A(vector-fill! vector fill start)\u000A(vector-fill! vector fill start end)\u000A\u000AFill vector with a given value in given range. If start is not given is start\u000Aat 0. If end is not given it fill till the end if the vector." (typecheck "vector->fill!" vector "array") (let recur ((n (- end start))) (if (>= n start) (begin (set-obj! vector n fill) (recur (- n 1)))))) +(define-syntax let*-values (syntax-rules () ((_ ()) ()) ((_ () body ...) (begin body ...)) ((_ ((bind values) rest ...) . body) (apply (lambda bind (let*-values (rest ...) . body)) (vector->list ((. values "valueOf")))))) "(let*-values binding body ...)\u000A\u000AThe macro work similar to let* but variable is list of values and value\u000Aneed to evaluate to result of calling values.") +(define (quotient&remainder x y) (values (quotient x y) (remainder x y))) +(define (floor/ x y) (let ((q (quotient x y)) (r (remainder x y))) (if (>= x 0) (if (or (> y 0) (zero? r)) (values q r) (values (- q 1) (+ r y))) (if (and (> y 0) (not (zero? r))) (values (- q 1) (+ r y)) (values q r))))) +(define (floor-quotient x y) (values-ref (floor/ x y) 0)) +(define (floor-remainder x y) (modulo x y)) +(define (truncate/ x y) (quotient&remainder x y)) +(define (truncate-quotient x y) (quotient x y)) +(define (truncate-remainder x y) (remainder x y)) +(define-syntax case-lambda (syntax-rules () ((case-lambda (params body0 ...) ...) (lambda args (let ((len (length args))) (letrec-syntax ((cl (syntax-rules ::: () ((cl) (error "no matching clause")) ((cl ((p :::) . body) . rest) (if (= len (length (quote (p :::)))) (apply (lambda (p :::) . body) args) (cl . rest))) ((cl ((p ::: . tail) . body) . rest) (if (>= len (length (quote (p :::)))) (apply (lambda (p ::: . tail) . body) args) (cl . rest)))))) (cl (params body0 ...) ...)))))) "(case-lambda expr ...)\u000A\u000AMacro create new function with different version of the function depend on\u000Anumber of arguments. Each expression is similar to single lambda.\u000A\u000Ae.g.:\u000A\u000A (define sum\u000A (case-lambda\u000A ((x) x)\u000A ((x y) (+ x y))\u000A ((x y z) (+ x y z))))\u000A\u000A (sum 1)\u000A (sum 1 2)\u000A (sum 1 2 3)\u000A\u000AMore arguments will give error.") +(define (boolean=? . args) "(boolean=? b1 b2 ...)\u000A\u000AFunction check if all arguments are boolean and if they are the same." (if (< (length args) 2) (error "boolean=?: too few arguments") (reduce (lambda (acc item) (and (boolean? item) (eq? acc item))) (car args) (cdr args)))) +(define (port? x) "(port? x)\u000A\u000AFunction return true of argumet is nput or output port port object." (or (output-port? x) (input-port? x))) +(define (square x) "(square z)\u000A\u000AReturns the square of z. This is equivalent to (* z z)." (* x x)) +(define-syntax when (syntax-rules () ((when test result1 result2 ...) (if test (begin result1 result2 ...)))) "(when test body ...)\u000A\u000AMacro execute body when test expression is true.") +(define-syntax unless (syntax-rules () ((unless test result1 result2 ...) (if (not test) (begin result1 result2 ...)))) "(unless test body ...)\u000A\u000AMacro execute body when test expression is false.") +(define inexact exact->inexact) +(define exact inexact->exact) +(define (exact-integer? n) "(exact-integer? n)\u000A\u000AFunction returns #t if z is both exact and an integer; otherwise\u000Areturns #f." (and (integer? n) (exact? n))) +(define (vector-map fn . rest) "(vector-map fn vector1 vector2 ...)\u000A\u000AFunction return new vector from applying function fn to each element\u000Aof the vectors, similar to map for lists." (if (or (= (length rest) 0) (not (every vector? rest))) (error "vector-map: function require at least 1 vector") (let ((len (apply min (map vector-length rest))) (result (vector))) (do ((i 0 (+ i 1))) ((= i len) result) (let* ((args (map (lambda (v) (vector-ref v i)) rest)) (value (apply fn args))) (--> result (push value))))))) +(define (string-map fn . rest) "(string-map fn string1 stringr2 ...)\u000A\u000AFunction return new string from applying function fn to each element\u000Aof the strings, similar to map for lists." (if (or (= (length rest) 0) (not (every string? rest))) (error "string-map: function require at least 1 string") (vector->string (apply vector-map fn (map string->vector rest))))) +(define (dynamic-wind before thunk after) "(dynamic-wind before thunk after)\u000A\u000AFunction accept 3 procedures/lambdas and execute thunk with before and always\u000Aafter even if error accur" (before) (let ((result (try (thunk) (catch (e) (error e))))) (after) result)) +(define (with-exception-handler handler thunk) "(with-exception-handler handler thunk)\u000A\u000AProcedure call and return value of thunk function, if exception happen\u000Ait call handler procedure." (try (thunk) (catch (e) (handler e)))) +(define raise throw) +(define-syntax define-values (syntax-rules () ((define-values () expr) (define dummy (call-with-values (lambda () expr) (lambda args #f)))) ((define-values (var) expr) (define var expr)) ((define-values (var0 var1 ... varn) expr) (begin (define var0 (call-with-values (lambda () expr) list)) (define var1 (let ((v (cadr var0))) (set-cdr! var0 (cddr var0)) v)) ... (define varn (let ((v (cadr var0))) (set! var0 (car var0)) v)))) ((define-values (var0 var1 ... . varn) expr) (begin (define var0 (call-with-values (lambda () expr) list)) (define var1 (let ((v (cadr var0))) (set-cdr! var0 (cddr var0)) v)) ... (define varn (let ((v (cdr var0))) (set! var0 (car var0)) v)))) ((define-values var expr) (define var (call-with-values (lambda () expr) list)))) "(define-values (a b ...) expr)\u000A\u000AFunction evaluate expression expr and if it evaluates to result of values\u000Athen it will defined each value as variable like with define.") +(define-macro (include . files) "(include file ...)\u000A\u000AMacro that load at least one file content and insert them into one,\u000Abody expression." (if (null? files) (throw (new Error "include: at least one file path required")) (let ((result (vector)) (env (interaction-environment))) (if (eq? self global) (let* ((fs (require "fs")) (readFile (lambda (file) (new Promise (lambda (resolve reject) (fs.readFile file (lambda (err data) (if (null? err) (resolve (--> data (toString))) (reject err))))))))) (for-each (lambda (file) (let* ((expr (lips.parse (readFile file) env))) (set! result (--> result (concat expr))))) files)) (for-each (lambda (file) (let* ((text (--> (fetch file) (text))) (expr (lips.parse text env))) (set! result (--> result (concat expr))))) files)) (if (> result.length 0) (quasiquote (begin (unquote-splicing (vector->list result)))))))) +(define-syntax syntax-error (syntax-rules () ((_ "step" arg ...) (join " " (vector->list (vector (repr arg) ...)))) ((_ message arg ...) (raise (new Error (format "~a ~a" message (_ "step" arg ...))))))) +(define-syntax cond-expand (syntax-rules (and or not else r7rs srfi-0 srfi-2 srfi-4 srfi-6 srfi-10 srfi-22 srfi-23 srfi-46 srfi-176 lips complex full-unicode ieee-float ratios exact-complex full-numeric-tower) ((cond-expand) (syntax-error "Unfulfilled cond-expand")) ((cond-expand (else body ...)) (begin body ...)) ((cond-expand ((and) body ...) more-clauses ...) (begin body ...)) ((cond-expand ((and req1 req2 ...) body ...) more-clauses ...) (cond-expand (req1 (cond-expand ((and req2 ...) body ...) more-clauses ...)) more-clauses ...)) ((cond-expand ((or) body ...) more-clauses ...) (cond-expand more-clauses ...)) ((cond-expand ((or req1 req2 ...) body ...) more-clauses ...) (cond-expand (req1 (begin body ...)) (else (cond-expand ((or req2 ...) body ...) more-clauses ...)))) ((cond-expand ((not req) body ...) more-clauses ...) (cond-expand (req (cond-expand more-clauses ...)) (else body ...))) ((cond-expand (r7rs body ...) more-clauses ...) (begin body ...)) ((cond-expand (srfi-0 body ...) more-clauses ...) (begin body ...)) ((cond-expand (srfi-2 body ...) more-clauses ...) (begin body ...)) ((cond-expand (srfi-4 body ...) more-clauses ...) (begin body ...)) ((cond-expand (srfi-6 body ...) more-clauses ...) (begin body ...)) ((cond-expand (srfi-10 body ...) more-clauses ...) (begin body ...)) ((cond-expand (srfi-22 body ...) more-clauses ...) (begin body ...)) ((cond-expand (srfi-23 body ...) more-clauses ...) (begin body ...)) ((cond-expand (srfi-46 body ...) more-clauses ...) (begin body ...)) ((cond-expand (srfi-176 body ...) more-clauses ...) (begin body ...)) ((cond-expand (lips body ...) more-clauses ...) (begin body ...)) ((cond-expand (complex body ...) more-clauses ...) (begin body ...)) ((cond-expand (full-unicode body ...) more-clauses ...) (begin body ...)) ((cond-expand (ieee-float body ...) more-clauses ...) (begin body ...)) ((cond-expand (ratios body ...) more-clauses ...) (begin body ...)) ((cond-expand (exact-complex body ...) more-clauses ...) (begin body ...)) ((cond-expand (full-numeric-tower body ...) more-clauses ...) (begin body ...)))) +(define (features) (quote (r7rs srfi-0 srfi-2 srfi-4 srfi-6 srfi-10 srfi-22 srfi-23 srfi-46 srfi-176 lips complex full-unicode ieee-float ratios exact-complex full-numeric-tower))) +(define *zero-number-chars* #(48 1632 1776 1984 2406 2534 2662 2790 2918 3046 3174 3302 3430 3558 3664 3792 3872 4160 4240 6112 6160 6470 6608 6784 6800 6992 7088 7232 7248 42528 43216 43264 43472 43504 43600 44016 65296 66720 68912 69734 69872 69942 70096 70384 70736 70864 71248 71360 71472 71904 72016 72784 73040 73120 92768 93008 120782 120792 120802 120812 120822 123200 123632 125264 130032)) +(define (digit-value chr) "(digit-value chr)\u000A\u000AReturn digit number if character is numeral (as per char-numeric?)\u000Aor #f otherwise." (typecheck "digit-value" chr "character") (if (char-numeric? chr) (let ((ord (char->integer chr))) (do ((i (vector-length *zero-number-chars*) (- i 1)) (found #f) (result #f)) ((or (zero? i) found) result) (let* ((zero (vector-ref *zero-number-chars* (- i 1))) (diff (- ord zero))) (if (and (>= diff 0) (<= diff 9)) (begin (set! result diff) (set! found #t)))))) #f)) +(define make-bytevector make-u8vector) +(define bytevector u8vector) +(define bytevector? u8vector?) +(define bytevector-length u8vector-length) +(define bytevector-u8-ref u8vector-ref) +(define bytevector-u8-set! u8vector-set!) +(define (bytevector-append v1 . rest) "(bytevector-append v1 ...)\u000A\u000ACreate new bytevector u8vector that is created from joining each argument." (typecheck "bytevector-append" v1 "uint8array" 1) (map (lambda (arg) (typecheck "bytevector-append" arg "uint8array")) rest) (if (null? rest) v1 (new Uint8Array (apply vector-append (Array.from v1) (map Array.from rest))))) +(define (bytevector-copy v . rest) "(bytevector-copy v)\u000A(bytevector-copy v start)\u000A(bytevector-copy v start end)\u000A\u000AFunction and return new vector from start to end. If no start and end is provided\u000Awhole vector is copied and returned." (if (null? rest) (new Uint8Array v) (let ((start (car rest))) (if (null? (cdr rest)) (v.slice start) (v.slice start (cadr rest)))))) +(define (bytevector-copy! to at from . rest) "(bytevector-copy! to at from)\u000A(bytevector-copy! to at from start)\u000A(bytevector-copy! to at from start end)\u000A\u000ACopies the bytes of bytevector from between start and end to bytevector to,\u000Astarting at at." (typecheck "bytevector-copy!" to "uint8array") (typecheck "bytevector-copy!" from "uint8array") (cond ((< at 0) (throw (new Error "bytevector-copy! `at` need to be positive"))) ((> at (bytevector-length to)) (throw (new Error "bytevector-copy! `at` need to be less then byte vector length")))) (let* ((start (if (null? rest) 0 (car rest))) (end (if (or (null? rest) (null? (cdr rest))) (- (bytevector-length from) start) (cadr rest)))) (let ((i at) (j start)) (while (and (< i (bytevector-length to)) (< i (bytevector-length from)) (< j (+ start end))) (bytevector-u8-set! to i (bytevector-u8-ref from j)) (set! i (+ i 1)) (set! j (+ j 1)))))) +(define string->utf8 (let ((encoder (new TextEncoder "utf-8"))) (lambda (string . rest) "(string->utf8 string)\u000A(string->utf8 string start)\u000A(string->utf8 string start end)\u000A\u000AFunction converts string into u8 bytevector using utf8 encoding.\u000AThe start and end is the range of the input string for the conversion." (typecheck "string->utf8" string "string") (if (null? rest) (encoder.encode string) (let* ((start (car rest)) (len (--> (Array.from string) (quote length))) (end (if (null? (cdr rest)) len (cadr rest)))) (encoder.encode (substring string start end))))))) +(define utf8->string (let ((decoder (new TextDecoder "utf-8"))) (lambda (v . rest) "(utf8->string u8vector)\u000A(utf8->string u8vector start)\u000A(utf8->string u8vector start end)\u000A\u000AFunction converts u8 bytevector into string using utf8 encoding.\u000AThe start and end is the range of the input byte vector for the conversion." (typecheck "utf8->string" v "uint8array") (if (null? rest) (decoder.decode v) (let* ((start (car rest)) (len (--> (Array.from string) (quote length))) (end (if (null? (cdr rest)) len (cadr rest)))) (decoder.decode (v.slice start end))))))) +(define (open-input-string string) "(open-input-string string)\u000A\u000AFunction create new string port as input that can be used to\u000Aread S-exressions from this port using `read` function." (typecheck "open-input-string" string "string") (new lips.InputStringPort string (interaction-environment))) +(define (open-output-string) "(open-output-string)\u000A\u000AFunction create new output port that can used to write string into\u000Aand after finish get the whole string using `get-output-string`." (new lips.OutputStringPort repr)) +(define (open-output-bytevector) "(open-output-bytevector)\u000A\u000ACreate new output port that can be used to write binary data.\u000AAfter done with the data the output buffer can be obtained by calling\u000A`get-output-bytevector` function." (new lips.OutputByteVectorPort)) +(define (get-output-bytevector port) "(get-output-string port)\u000A\u000AFunction get full string from string port. If nothing was wrote\u000Ato given port it will return empty string." (if (not (instanceof lips.OutputByteVectorPort port)) (throw (new Error (string-append "get-output-bytevector: expecting output-bytevector-port get " (type port)))) (port.valueOf))) +(define (get-output-string port) "(get-output-string port)\u000A\u000AFunction get full string from string port. If nothing was wrote\u000Ato given port it will return empty string." (if (not (instanceof lips.OutputStringPort port)) (throw (new Error (string-append "get-output-string: expecting output-string-port get " (type port)))) (port.valueOf))) +(define (open-input-bytevector bytevector) "(open-input-bytevector bytevector)\u000A\u000ACreate new input binary port with given bytevector" (typecheck "open-input-bytevector" bytevector "uint8array") (new lips.InputByteVectorPort bytevector)) +(define (open-binary-input-file filename) "(open-binary-input-file filename)\u000A\u000AFunction return new Input Binary Port with given filename. In Browser\u000Auser need to provide global fs variable that is instance of FS interface." (let ((u8vector (buffer->u8vector (%read-binary-file filename)))) (new lips.InputBinaryFilePort u8vector filename))) +(define (binary-port? port) "(binary-port? port)\u000A\u000AFunction test if argument is binary port." (and (port? port) (eq? port.__type__ (Symbol.for "binary")))) +(define (textual-port? port) "(textual-port? port)\u000A\u000AFunction test if argument is string port." (and (port? port) (eq? port.__type__ (Symbol.for "text")))) +(define-macro (%define-binary-input-lambda name docstring fn) (let ((port (gensym)) (name-str (symbol->string name))) (quasiquote (define ((unquote name) . rest) (unquote docstring) (let (((unquote port) (if (null? rest) (current-input-port) (car rest)))) (typecheck (unquote name-str) (unquote port) "input-port") (if (not (binary-port? (unquote port))) (throw (new Error (string-append (unquote name-str) " invalid port. Binary port required."))) ((unquote fn) (unquote port)))))))) +(%define-binary-input-lambda peek-u8 "(peek-u8)\u000A(peek-u8 port)\u000A\u000AReturn next byte from input-binary port. If there are no more bytes\u000Ait return eof object." (lambda (port) (port.peek_u8))) +(%define-binary-input-lambda read-u8 "(read-u8)\u000A(read-u8 port)\u000A\u000ARead next byte from input-binary port. If there are no more bytes\u000Ait return eof object." (lambda (port) (port.read_u8))) +(%define-binary-input-lambda u8-ready? "(u8-ready?)\u000A(u8-ready? port)\u000A\u000AReturns #t if a byte is ready on the binary input port and returns #f otherwise.\u000AIf u8-ready? returns #t then the next read-u8 operation on the given port is\u000Aguaranteed not to hang. If the port is at end of file then u8-ready? returns #t." (lambda (port) (port.u8_ready))) +(define (read-bytevector k . rest) "(read-bytevector k)\u000A(read-bytevector k port)\u000A\u000ARead next n bytes from input-binary port. If there are no more bytes\u000Ait returns eof object. If there are less then n bytes in port it\u000Areturn the only bytes that are available" (let ((port (if (null? rest) (current-input-port) (car rest)))) (typecheck "read-bytevector" port "input-port") (if (not (binary-port? port)) (throw (new Error "read-bytevector: invalid port")) (port.read_u8_vector k)))) +(define-macro (%define-binary-output-lambda name type docstring fn) (let ((port (gensym (quote port))) (data (gensym (quote data))) (name-str (symbol->string name))) (quasiquote (define ((unquote name) (unquote data) . rest) (unquote docstring) (let (((unquote port) (if (null? rest) (current-output-port) (car rest)))) (typecheck (unquote name-str) (unquote port) "output-port") (typecheck (unquote name-str) (unquote data) (unquote type)) (if (not (binary-port? (unquote port))) (throw (new Error (string-append (unquote name-str) " invalid port. Binary port required."))) ((unquote fn) (unquote data) (unquote port)))))))) +(%define-binary-output-lambda write-u8 "number" "(write-u8 byte)\u000A(write-u8 byte port)\u000A\u000AWrite byte into binary output port." (lambda (data port) (port.write_u8 data))) +(%define-binary-output-lambda write-bytevector "uint8array" "(write-bytevector bytevector)\u000A(write-bytevector bytevector port)\u000A\u000AWrite byte vector into binary output port." (lambda (data port) (port.write_u8_vector data))) +(define open-binary-output-file (let ((open)) (lambda (filename) "(open-binary-output-file filename)\u000A\u000AFunction open file and return port that can be used for writing. If file\u000Aexists it will throw an Error." (typecheck "open-output-file" filename "string") (if (not (procedure? open)) (set! open (%fs-promisify-proc (quote open) "open-binary-output-file"))) (if (file-exists? filename) (throw (new Error "open-binary-output-file: file exists")) (lips.OutputBinaryFilePort filename (open filename "w")))))) +(define (read-bytevector! vector . rest) "(read-bytevector! bytevector)\u000A(read-bytevector! bytevector port)\u000A(read-bytevector! bytevector port start)\u000A(read-bytevector! bytevector port start end)\u000A\u000AFunction read next bytes from binary input port and write them into byte vector.\u000Aif not start is specified it start to write into 0 position of the vector until\u000Athe end or end the vector if no end is specified." (typecheck "read-bytevector!" vector "uint8array") (let ((port (if (null? rest) (current-input-port) (car rest))) (start (if (or (null? rest) (null? (cdr rest))) 0 (cadr rest))) (end (if (or (null? rest) (null? (cdr rest)) (null? (cddr rest))) (bytevector-length vector) (caddr rest)))) (typecheck "read-bytevector!" port "input-port") (if (not (binary-port? port)) (throw (new Error "read-bytevector!: invalid port. Binary port required.")) (begin (typecheck "read-bytevector!" start "number") (typecheck "read-bytevector!" end "number") (let ((out (read-bytevector (- end start) port))) (vector.set out start end)))))) +(define delete-file (let ((unlink #f)) (lambda (filename) "(delete-file filename)\u000A\u000AFunction delete the file of given name." (typecheck "delete-file" filename "string") (if (not (procedure? unlink)) (set! unlink (%fs-promisify-proc (quote unlink) "delete-file"))) (unlink filename)))) +(define (call-with-port port proc) "(call-with-port port proc)\u000A\u000AProc is executed with given port and after it returns, the port is closed." (try (proc port) (finally (if (procedure? port.close) (port.close))))) +(define (close-port port) "(close-port port)\u000A\u000AClose input or output port." (typecheck "close-port" port #("input-port" "output-port")) (port.close)) +(define (eof-object) "(eof-object)\u000A\u000AProcedure returns eof object that indicate end of the port" lips.eof) +(define (output-port-open? port) "(output-port-open? port)\u000A\u000AFunction check if argument is output-port and if you can write to it." (and (output-port? port) (port.is_open))) +(define (input-port-open? port) "(input-port-open? port)\u000A\u000AFunction check if argument is input-port and if you can read from it." (and (input-port? port) (port.is_open))) +(define (flush-output-port port) "(flush-output-port port)\u000A\u000AFunctio do nothing, flush is not needed in LIPS in both NodeJS and Browser.\u000AThe function is added, so it don't throw exception when using R7RS code." (if #f #f)) +(define (write-string string . rest) "(write-string string)\u000A(write-string string port)\u000A(write-string string port start)\u000A(write-string string port start end)\u000A\u000AWrites the characters of string from start to end in left-toright order\u000Ato the textual output port." (typecheck "write-string" string "string") (let ((port (if (null? rest) (current-output-port) (car rest))) (start (if (or (null? rest) (null? (cdr rest))) 0 (cadr rest))) (end (if (or (null? rest) (null? (cdr rest)) (null? (cddr rest))) (string-length string) (caddr rest)))) (typecheck "write-string" port "output-port") (typecheck "write-string" start "number") (typecheck "write-string" end "number") (display (substring string start end) port))) +(define (write-char char . rest) "(write-char string)\u000A(write-char string port)\u000A\u000AWrites the character char (not an external representation of the character)\u000Ato the given textual output port and returns an unspecified value." (typecheck "write-char" char "character") (let ((port (if (null? rest) (current-output-port) (car rest)))) (typecheck "write-char" port "output-port") (display (string char) port))) +(define (read-string k . rest) "(read-string k)\u000A(read-string k port)\u000A\u000AReads the next k characters, or as many as are available\u000Abefore the end of file, from the textual input port into a\u000Anewly allocated string in left-to-right order and returns the\u000Astring. If no characters are available before the end of file,\u000Aan end-of-file object is returned." (typecheck "read-string" k "number") (let ((port (if (null? rest) (current-input-port) (car rest)))) (typecheck "read-string" port "input-port") (port.read_string k))) +(define (list-copy obj) "(list-copy obj)\u000A\u000ACopy the object passed as argument but only if it's list. The car elements\u000Aof the list are not copied, they are passed as is." (typecheck "list-copy" obj #("pair" "nil")) (if (null? obj) obj (obj.clone #f))) +(define-macro (define-record-type name constructor pred . fields) "(define-record-type name constructor pred . fields)\u000A\u000AMacro for defining records. Example of usage:\u000A\u000A (define-record-type <pare>\u000A (kons x y)\u000A pare?\u000A (x kar set-kar!)\u000A (y kdr set-kdr!))\u000A\u000A(define p (kons 1 2))\u000A(print (kar p))\u000A;; 1\u000A(set-kdr! p 3)\u000A(print (kdr p))\u000A;; 3" (let ((class-name (gensym)) (obj-name (gensym)) (value-name (gensym))) (quasiquote (begin (define (unquote class-name) (class Object (constructor (lambda (self (unquote-splicing (cdr constructor))) (unquote-splicing (map (lambda (field) (let* ((name (symbol->string field)) (prop (string-append "self." name))) (quasiquote (set! (unquote (string->symbol prop)) (unquote field))))) (cdr constructor))))) (toType (lambda (self) "record")) (toString (lambda (self) (unquote (symbol->string name)))))) (define (unquote constructor) (new (unquote class-name) (unquote-splicing (cdr constructor)))) (define ((unquote pred) obj) (instanceof (unquote class-name) obj)) (unquote-splicing (map (lambda (field) (let ((prop-name (car field)) (get (cadr field)) (set (if (null? (cddr field)) () (caddr field)))) (quasiquote (begin (define ((unquote get) (unquote obj-name)) (typecheck (unquote (symbol->string get)) (unquote obj-name) "record") (if (not ((unquote pred) (unquote obj-name))) (throw (new Error (unquote (string-append "object is not record of type " (symbol->string name))))) (. (unquote obj-name) (quote (unquote prop-name))))) (unquote (if (not (null? set)) (quasiquote (define ((unquote set) (unquote obj-name) (unquote value-name)) (typecheck (unquote (symbol->string get)) (unquote obj-name) "record") (if (not ((unquote pred) (unquote obj-name))) (throw (new Error (unquote (string-append "object is not record of type " (symbol->string name))))) (set-obj! (unquote obj-name) (quote (unquote prop-name)) (unquote value-name))))))))))) fields)))))) +(define (nan? x) "(nan? x)\u000A\u000AFunction check if argument x is Not a Number (NaN) value." (and (number? x) (or (x.isNaN) (and (%number-type "complex" x) (or (nan? (real-part x)) (nan? (imag-part x))))))) +(define (infinite? x) "(infinite? x)\u000A\u000AFunction check if value is infinite." (or (eq? x Number.NEGATIVE_INFINITY) (eq? x Number.POSITIVE_INFINITY) (and (number? x) (not (eq? x NaN)) (%number-type "complex" x) (or (infinite? (real-part x)) (infinite? (imag-part x)))))) +(define (finite? x) "(finite? x)\u000A\u000AFunction check if value is finite." (not (infinite? x))) +(define-class %Library Object (constructor (lambda (self name) (set! self.__namespace__ &()) (set! self.__name__ name))) (append (lambda (self namespace env) (if (environment? (. self.__namespace__ namespace)) (throw (new Error (string-append "namespace " namespace " already exists in library " self.__name__))) (set-obj! self.__namespace__ namespace env)))) (env (lambda (self namespace) (let ((env (. self.__namespace__ namespace))) (if (not (environment? env)) (throw (new Error (string-append "namespace " namespace " sdon't exists"))) env)))) (get (lambda (self namespace name) (--> (self.env namespace) (get name)))) (set (lambda (self namespace name value) (--> (self.env namespace) (set name value)))) (toString (lambda (self) (string-append "#<Library(" self.__name__ ")>")))) +(define (%import-name library namespace names) (quasiquote (begin (unquote-splicing (map (lambda (name) (quasiquote (define (unquote name) (--> (unquote library) (get (quote (unquote namespace)) (quote (unquote name))))))) names))))) +(define-macro (import . specs) "(import (library namespace))\u000A(import (only (library namespace) name1 name2))\u000A\u000AMacro for importing names from library." (let ((parent (current-environment))) (quasiquote (begin (unquote-splicing (map (lambda (spec) (if (not (pair? spec)) (throw (new Error "import: invalid syntax")) (cond ((symbol=? (car spec) (quote only)) (let ((lib (caadr spec)) (namespace (caaddr spec))) (if (pair? (cadr spec)) (%import-name (unquote lib) (quote (unquote namespace)) (quote (unquote (caddr spec)))) (throw (new Error "import: invalid syntax"))))) (else (let* ((lib-name (car spec)) (lib (parent.get lib-name)) (namespace (cadr spec))) (%import-name lib-name namespace (env (lib.env namespace)))))))) specs)))))) +(define (new-library name namespace) "(new-library name)\u000A\u000ACreate new empty library object with empty namespace." (let* ((parent (. (current-environment) (quote __parent__))) (lib (let ((lib (--> parent (get name &(:throwError #f))))) (if (null? lib) (new %Library name) lib))) (x (new lips.Environment (string-append "library-" (--> name (toLowerCase)) "-" (--> namespace (toLowerCase)))))) (lib.append namespace x) lib)) +(define (%export module namespace specs) (quasiquote (begin (unquote-splicing (map (lambda (expr) (cond ((symbol? expr) (quasiquote (--> (unquote module) (set (quote (unquote namespace)) (quote (unquote expr)) (unquote expr))))) ((and (pair? expr) (symbol=? (car expr) (quote rename))) (quasiquote (--> (unquote module) (set (quote (unquote namespace)) (quote (unquote (cadr expr))) (unquote (caddr expr)))))))) specs))))) +(define-macro (define-library spec . body) "(define-library (library (name namespace) . body)\u000A\u000AMacro for defining modules inside you can use define to create functions.\u000AAnd use export name to add that name to defined environment." (let ((parent (. (current-environment) (quote __parent__))) (module-var (gensym)) (namespace-var (gensym)) (name (car spec)) (namespace (cadr spec))) (quasiquote (let (((unquote module-var) (new-library (unquote (symbol->string name)) (unquote (symbol->string namespace)))) ((unquote namespace-var) (quote (unquote namespace)))) (define-macro (export . body) (%export (unquote module-var) (unquote namespace-var) body)) (unquote-splicing body) (--> (unquote parent) (set (quote (unquote name)) (unquote module-var))))))) +(define-values (current-directory set-current-directory!) (if (eq? self window) (let ((cwd (string-append location.origin (--> location.pathname (replace #/\/[^/]+$/ "/"))))) (values (lambda () "(current-directory)\u000A\u000AReturn corrent working directory, default it's corrent URL." cwd) (lambda (value) "(set-current-directory! string)\u000A\u000AFunction change current working directory to provided string." (typecheck "set-current-directory!" value "string") (set! cwd value)))) (let ((process (require "process"))) (values (lambda () "(current-directory)\u000A\u000AReturn corrent working directory, default it's path from where\u000Athe script was executed." (string-append (process.cwd) "/")) (lambda (value) "(set-current-directory! string)\u000A\u000AFunction change current working directory to provided string." (typecheck "set-current-directory!" value "string") (process.chdir value)))))) +(define-syntax and-let* (syntax-rules () ((_ ()) #t) ((_ () body ...) (let () body ...)) ((_ ((expression))) expression) ((_ ((symbol expression)) body ...) (let ((symbol expression)) (if symbol (begin body ...)))) ((_ ((symbol expression) expr ...) body ...) (let ((symbol expression)) (and symbol (and-let* (expr ...) body ...)))) ((_ ((expression) expr ...) body ...) (and expression (and-let* (expr ...) body ...)))) "(and-let* ((name expression) expression ...) body)\u000A\u000AMacro that combine let and and. First expression need to be in form of let.\u000ASymbol expression the rest can be boolean expression or name expreession.\u000AThis is implementation of SRFI-2.") +(set-special! "#," (quote sharp-comma)) +(define **reader-ctor-list** (quote ())) +(define (define-reader-ctor symbol fn) "(define-reader-ctor symbol fn)\u000A\u000ADefine the value for #, syntax. SRFI-10\u000AExample:\u000A\u000A(define-reader-ctor '+ +)\u000A(print #,(+ 1 2))" (let ((node (assoc symbol **reader-ctor-list**))) (if (pair? node) (set-cdr! node fn) (set! **reader-ctor-list** (cons (cons symbol fn) **reader-ctor-list**))))) +(define-syntax sharp-comma (syntax-rules () ((_ (fn arg ...)) (let ((node (assoc (quote fn) **reader-ctor-list**))) (if (pair? node) ((cdr node) (quote arg) ...) (syntax-error (string-append "Invalid symbol " (symbol->string (quote fn)) " in expression " (repr (quote (fn arg ...))))))))) "(sharp-comma expr)\u000A#,(ctor ...)\u000A\u000AThis is syntax extension for SRFI-10. To define the function to be used with\u000AThis syntax you need to call `define-reader-ctor` function and define\u000Asymbol function mapping.") diff --git a/dist/std.scm b/dist/std.scm index cfcf6e79..dd3c9c13 100644 --- a/dist/std.scm +++ b/dist/std.scm @@ -82,14 +82,18 @@ (on \"click\" (lambda () (display \"click\")))) (--> document (querySelectorAll \"div\")) + (--> (fetch \"https://jcubic.pl\") (text) (match #/<title>([^<]+)<\\/title>/) 1) + (--> document (querySelectorAll \".cmd-prompt\") 0 - \"innerText\") + 'innerHTML + (replace #/<(\"[^\"]+\"|[^>])+>/g \"\")) + (--> document.body (style.setProperty \"--color\" \"red\"))" (let ((obj (gensym "obj"))) @@ -170,7 +174,17 @@ expr `(. ,(string->symbol (car parts)) ,@(cdr parts)))))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- +(set-special! "#:" 'gensym-interal) + +;; ----------------------------------------------------------------------------- +(define (gensym-interal symbol) + "(gensym-interal symbol) + + Parser extension that create new quoted named gensym." + `(quote ,(gensym symbol))) + +;; ----------------------------------------------------------------------------- (define (plain-object? x) "(plain-object? x) @@ -178,7 +192,7 @@ ;; here we don't use string=? or equal? because it may not be defined (and (== (--> (type x) (cmp "object")) 0) (eq? (. x 'constructor) Object))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define typed-array? (let ((TypedArray (Object.getPrototypeOf Uint8Array))) (lambda (o) @@ -211,7 +225,7 @@ Function convert alist pairs to JavaScript object." (if (pair? alist) - (alist.toObject) + (alist.to_object) (alist->object (new lips.Pair undefined nil)))) ;; ----------------------------------------------------------------------------- @@ -351,7 +365,7 @@ ;; ----------------------------------------------------------------------------- (define (%hidden-props obj) "(%hidden-props obj) - + Function return hidden names of an object, for ES6 class prototype it return all methods since they are indistinguishable from hidden property created using defineProperty." @@ -375,9 +389,10 @@ (set! names (--> names (filter (lambda (name) (not (hidden.includes name)))))))) - (append (array->list names) (dir (Object.getPrototypeOf obj) true))))) + (append (array->list (--> names (map (unary string->symbol)))) + (dir (Object.getPrototypeOf obj) true))))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (tree-map f tree) "(tree-map fn tree) @@ -485,7 +500,7 @@ Helper macro used by cond.") - +;; ----------------------------------------------------------------------------- (define-macro (cond . list) "(cond (predicate? . body) (predicate? . body)) @@ -675,7 +690,7 @@ nil (cons (map car args) (apply zip (map cdr args)))))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define-macro (promise . body) "(promise . body) @@ -685,7 +700,7 @@ (catch (e) (error (.. e.message))))))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define-macro (timer time . body) "(timer time . body) @@ -693,14 +708,14 @@ native JS clearTimeout function." `(setTimeout (lambda () (try (begin ,@body) (catch (e) (error (.. e.message))))) ,time)) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (defmacro? obj) "(defmacro? expression) Function check if object is macro and it's expandable." (and (macro? obj) (. obj 'defmacro))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (n-ary n fn) "(n-ary n fn) @@ -708,7 +723,7 @@ (lambda args (apply fn (take n args)))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (take n lst) "(take n list) @@ -718,21 +733,21 @@ (reverse result) (iter (cons (car lst) result) (- i 1) (cdr lst))))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define unary (%doc "(unary fn) Function return new function with arguments limited to one." (curry n-ary 1))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define binary (%doc "(binary fn) Function return new function with arguments limited to two." (curry n-ary 2))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- ;; LIPS Object System -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (%class-lambda expr) "(class-lambda expr) @@ -755,7 +770,7 @@ `(lambda (,@args) (,(cadr expr) this ,@args)))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (%class-method-name expr) "(%class-method-name expr) @@ -764,7 +779,7 @@ (car expr) (list 'quote expr))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define-macro (define-class name parent . body) "(define-class name parent . body) @@ -801,7 +816,7 @@ (iter functions item (cdr lst)) (iter (cons item functions) constructor (cdr lst))))))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define-syntax class (syntax-rules () ((_) @@ -814,7 +829,7 @@ Macro allow to create anonymous classes. See define-class for details.") -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (make-tags expr) "(make-tags expression) @@ -829,7 +844,7 @@ `(list->array (list ,@(map make-tags (cdaddr expr)))) (caddr expr))))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (%sxml h expr) "(%sxml h expr) @@ -861,20 +876,24 @@ rest) (list first))))))) -;; --------------------------------------------------------------------------------------- -(define-macro (sxml expr) - "(sxml expr) +;; ----------------------------------------------------------------------------- +(define-macro (pragma->sxml pragma) + `(define-macro (sxml expr) + "(sxml expr) + + Macro for JSX like syntax but with SXML. + e.g. usage: - Macro for JSX like syntax but with SXML. - e.g. usage: + (sxml (div (@ (data-foo \"hello\") + (id \"foo\")) + (span \"hello\") + (span \"world\")))" + (%sxml ',pragma expr))) - (sxml (div (@ (data-foo \"hello\") - (id \"foo\")) - (span \"hello\") - (span \"world\")))" - (%sxml 'h expr)) +;; ----------------------------------------------------------------------------- +(pragma->sxml h) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define-macro (with-tags expr) "(with-tags expression) @@ -890,7 +909,7 @@ To get the string from the macro you can use vhtml library from npm." (make-tags expr)) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (get-script url) "(get-script url) @@ -907,28 +926,28 @@ (if document.head (document.head.appendChild script))))))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (gensym? value) "(gensym? value) Function return #t if value is symbol and it's gensym. It returns #f otherwise." (and (symbol? value) (--> value (is_gensym)))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (degree->radians x) "(degree->radians x) Convert degree to radians." (* x (/ Math.PI 180))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (radians->degree x) "(radians->degree x) Convert radians to degree." (* x (/ 180 Math.PI))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define-syntax while (syntax-rules () ((_ predicate body ...) @@ -939,7 +958,7 @@ Macro that create a loop, it exectue body until cond expression is false.") -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define-syntax ++ (syntax-rules () ((++ x) @@ -950,7 +969,7 @@ Macro that work only on variables and increment the value by one.") -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define-syntax -- (syntax-rules () ((-- x) @@ -961,7 +980,7 @@ Macro that decrement the value it work only on symbols") -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (pretty-format pair) "(pretty-format pair) @@ -969,7 +988,7 @@ (typecheck "pretty-pair" pair "pair") (--> (new lips.Formatter (repr pair true)) (break) (format))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (reset) "(reset) @@ -981,14 +1000,14 @@ (if (not (--> defaults (includes name))) (--> env (unset name))))))))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (make-list n . rest) (if (or (not (integer? n)) (<= n 0)) (throw (new Error "make-list: first argument need to be integer larger then 0")) (let ((fill (if (null? rest) undefined (car rest)))) (array->list (--> (new Array n) (fill fill)))))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (range n) "(range n) @@ -996,7 +1015,7 @@ (typecheck "range" n "number") (array->list (--> (new Array n) (fill 0) (map (lambda (_ i) i))))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define-macro (do-iterator spec cond . body) "(do-iterator (var expr) (test) body ...) @@ -1035,21 +1054,21 @@ (set! ,item (,next)) (set! ,name (. ,item "value"))))))))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (set-repr! Set (lambda () "#<Set>")) (set-repr! Map (lambda () "#<Met>")) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (native-symbol? x) "(native-symbol? object) Function check if value is JavaScript symbol." (and (string=? (type x) "symbol") (not (symbol? x)))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (set-special! "’" 'warn-quote) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define-macro (warn-quote) "(warn-quote) @@ -1058,7 +1077,7 @@ "(set-special! \"’\" 'quote)" " to allow running this type of quote")))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define-macro (quote-promise expr) "(quote-promise expr) '>expr @@ -1071,13 +1090,13 @@ (env.set (Symbol.for "__promise__") true) ,expr)) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (await value) (if (instanceof lips.QuotedPromise value) (value.valueOf) value)) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define-macro (let-env-values env spec . body) "(let-env-values env ((name var)) . body) @@ -1090,52 +1109,19 @@ spec) ,@body)))) -;; --------------------------------------------------------------------------------------- -(define-macro (let-std spec . body) - "(let-std ((name var)) . body) - - Macro that create aliases for variables in global environment. - This is needed so user don't change constants like stdin or stdout - that use taken from lexical scope. The function still can use those - from interaction-environment." - `(let-env-values lips.env.__parent__ ,spec ,@body)) - -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (apropos name) "(apropos name) Search environment and display names that match the given name. - name can be regex or string." - (typecheck "apropos" name '("string" "regex")) - (filter (if (string? name) - (new RegExp name) - name) - (env))) - -;; --------------------------------------------------------------------------------------- -;; SRFI-10 https://srfi.schemers.org/srfi-10/srfi-10.html -;; --------------------------------------------------------------------------------------- -(set-special! "#," 'sharp-comma) - -(define **reader-ctor-list** '()) - -;; --------------------------------------------------------------------------------------- -(define (define-reader-ctor symbol fn) - (let ((node (assoc symbol **reader-ctor-list**))) - (if (pair? node) - (set-cdr! node fn) - (set! **reader-ctor-list** (cons (cons symbol fn) - **reader-ctor-list**))))) - -;; --------------------------------------------------------------------------------------- -(define-syntax sharp-comma - (syntax-rules () - ((_ (fn arg ...)) - (let ((node (assoc 'fn **reader-ctor-list**))) - (if (pair? node) - ((cdr node) 'arg ...) - (syntax-error (string-append "Invalid symbol " (symbol->string 'fn) - " in expression " (repr '(fn arg ...))))))))) + name can be regex, string or symbol." + (typecheck "apropos" name '("string" "regex" "symbol")) + (let ((regex (lambda (string) + (new RegExp (escape-regex string))))) + (filter (cond ((string? name) (regex name)) + ((symbol? name) (regex (symbol->string name))) + (else name)) + (env)))) ;; ----------------------------------------------------------------------------- (define (promisify fn) @@ -1150,7 +1136,7 @@ (resolve data) (reject err)))))))))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define-macro (list* . args) "(list* arg1 ...) @@ -1162,7 +1148,7 @@ args) (map await (vector->list ,result))))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define-macro (%not-implemented name) "(not-implemented name) @@ -1172,7 +1158,7 @@ ,(string-append "(" str-name ")\n\nThis function is not yet implemented.") (throw (new Error ,(string-append str-name " has not beed implemented")))))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define-macro (%make-env name . names) "(%make-env name f1 f2 ...) @@ -1188,7 +1174,7 @@ null ,name)) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define Y (lambda (h) "(Y f) @@ -1205,7 +1191,195 @@ (lambda (g) (h (lambda args (apply (g g) args))))))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- +(define (indexed-db?) + "(indexed-db?) + + Function test if indexedDB is available." + (let* ((any (lambda args + (let iter ((args args)) + (if (null? args) + false + (if (not (null? (car args))) + (car args) + (iter (cdr args))))))) + (indexedDB (any window.indexedDB + window.indexedDB + window.mozIndexedDB + window.webkitIndexedDB))) + (if (not (null? indexedDB)) + (try + (begin + ;; open will fail in about:blank + (window.indexedDB.open "MyTestDatabase" 3) + true) + (catch (e) + false)) + false))) + +;; ----------------------------------------------------------------------------- +;; init internal fs for LIPS Scheme Input/Output functions +;; ----------------------------------------------------------------------------- +(let* ((fs (cond ((eq? self global) (require "fs")) + ((and (not (null? self.BrowserFS)) (indexed-db?)) + (new Promise (lambda (resolve reject) + (BrowserFS.configure + &(:fs "IndexedDB" + :options &()) + (lambda (e) + (if (null? e) + (resolve (BrowserFS.BFSRequire "fs")) + (reject e))))))) + ((not (null? self.BrowserFS)) + (console.warn (string-append "BrowserFS not initilalized " + "IndexedDB is not available")) + nil))) + (Buffer (cond ((eq? self global) + self.Buffer) + ((not (null? self.BrowserFS)) + (. (BrowserFS.BFSRequire "buffer") 'Buffer))))) + (let ((internal (lips.env.get '**internal-env**))) + (if (not (null? Buffer)) + (internal.set "Buffer" Buffer)) + (if (not (null? fs)) + (internal.set "fs" fs)))) + +;; ----------------------------------------------------------------------------- +(define (environment? obj) + "(environment? obj) + + Function check if object is LIPS environment." + (instanceof lips.Environment obj)) + +;; ----------------------------------------------------------------------------- +(define %read-file + (let ((read-file #f) (fetch-url #f)) + (lambda (binary path) + "(%read-file binary path) + + Read file from url or file system. If binary is false it will return + string that contain all the content. For HTTP requests, If binary + is false it will: when in browser return ArrayBuffer and in Node + it will return Buffer object. When reading from file system + in both cases it will return Buffer objects. + + The code that use those function, in binary mode, need to check + if the result is ArrayBuffer or Node.js/BrowserFS Buffer object." + (if (not read-file) + (let ((fs (--> lips.env (get '**internal-env**) (get 'fs)))) + (if (null? fs) + (throw (new Error "open-input-file: fs not defined")) + (let ((*read-file* (promisify fs.readFile))) + (set! read-file (lambda (path binary) + (let ((buff (*read-file* path))) + (if binary + (if (eq? self window) + (new Blob (vector buff)) + buff) + (--> buff (toString)))))))))) + (if (not fetch-url) + (set! fetch-url (lambda (url binary) + (if (eq? self window) + (let ((res (fetch url))) + (if binary + (res.arrayBuffer) + (res.text))) + (http-get url binary))))) + (cond ((char=? (string-ref path 0) #\/) + (if (not (file-exists? path)) + (throw (new Error (string-append "file " + path + " don't exists"))) + (read-file path binary))) + ((--> #/^https?:\/\// (test path)) + (fetch-url path binary)) + (else + (%read-file binary (string-append (current-directory) path))))))) + +;; ----------------------------------------------------------------------------- +(define %read-binary-file (curry %read-file true)) +(define %read-text-file (curry %read-file false)) + +;; ----------------------------------------------------------------------------- +(define (%fs-promisify-proc fn message) + "(%fs-promisify-proc fn string) + + Function return promisified version of fs function or throw exception + if fs is not available." + (let ((fs (--> lips.env (get '**internal-env**) (get 'fs)))) + (if (null? fs) + (throw (new Error (string-append message ": fs not defined"))) + (promisify (. fs fn))))) + +;; ----------------------------------------------------------------------------- +(define (response->content binary res) + "(response->text binary res) + + Function read all text from Node.js HTTP response object. If binary argument + is true it will return Buffer object that can be converted to u8vector. + + ***Warrning:*** it may overflow the stack (part of Node) when converting + whole buffer to u8vector." + (let ((result (vector)) + (append (if binary + (lambda (chunk) + (result.push (Buffer.from chunk "binary"))) + (lambda (chunk) + (result.push chunk))))) + (res.setEncoding (if binary "binary" "utf8")) + (new Promise (lambda (resolve) + (res.on "data" append) + (res.on "end" (lambda () + (if binary + (resolve (Buffer.concat result)) + (resolve (result.join ""))))))))) + +;; ----------------------------------------------------------------------------- +(define response->buffer (curry response->content true)) +(define response->text (curry response->content false)) + +;; ----------------------------------------------------------------------------- +(define http-get + (if (eq? self window) + (lambda (url binary) + "(http-get url) + + Node.js Function that send HTTP Request and return string or + binary Buffer object." + (throw (new Error "http-get: function is Node.js only."))) + (let* ((http (. (require "http") 'get)) + (https (. (require "https") 'get))) + (lambda (url binary) + "(http-get url) + + Node.js Function that send HTTP Request and return string or + binary Buffer object." + (let ((request (if (null? (url.match #/^https/)) http https))) + (new Promise + (lambda (resolve reject) + (--> (request url + (lambda (res) + (if (= res.statusCode 200) + (resolve (response->content binary res)) + (let ((code res.statusCode)) + (res.resume) + (reject (string-append + "Request return " + (number->string code))))))) + (on "error" reject))))))))) + +;; ----------------------------------------------------------------------------- +(define (buffer->u8vector bin) + "(buffer->u8vector bin) + + Cross platform function that can be used in both Node and Browser. + It can be used together with %read-file or %read-binary-file and convert + the result ArrayBuffer or Buffer to u8vector." + (if (instanceof ArrayBuffer bin) + (new Uint8Array bin) + (Uint8Array.from bin))) + +;; ----------------------------------------------------------------------------- ;; __ __ __ ;; / / \ \ _ _ ___ ___ \ \ ;; | | \ \ | | | || . \/ __> | | @@ -1282,9 +1456,16 @@ ;; ----------------------------------------------------------------------------- (set-repr! Array - (lambda (x q) - (let ((arr (--> x (map (lambda (x) (repr x q)))))) - (concat "#(" (--> arr (join " ")) ")")))) + (lambda (arr q) + ;; Array.from is used to convert emtpy to undefined + ;; but we can't use the value because Array.from call + ;; valueOf on its arguments + (let ((result (--> (Array.from arr) + (map (lambda (x i) + (if (not (in i arr)) + "#<empty>" + (repr (. arr i) q))))))) + (concat "#(" (--> result (join " ")) ")")))) ;; ----------------------------------------------------------------------------- (define (eqv? a b) @@ -1293,7 +1474,32 @@ Function compare the values. It return true if they are the same, they need to have same type" (if (string=? (type a) (type b)) - (cond ((number? a) (= a b)) + (cond ((number? a) + (or (and (exact? a) (exact? b) (= a b)) + (and (inexact? a) + (inexact? b) + (cond ((a.isNaN) (b.isNaN)) + ((and (zero? a) (zero? b)) + (eq? a._minus b._minus)) + ((and (complex? a) (complex? b)) + (let ((re.a (real-part a)) + (re.b (real-part b)) + (im.a (imag-part a)) + (im.b (imag-part b))) + (and + (if (and (zero? re.a) (zero? re.b)) + (eq? (. re.a '_minus) (. re.b '_minus)) + true) + (if (and (zero? im.a) (zero? im.b)) + (eq? (. im.a '_minus) (. im.b '_minus)) + true) + (or (= re.a re.b) + (and (--> re.a (isNaN)) + (--> re.b (isNaN)))) + (or (= im.a im.b) + (and (--> im.a (isNaN)) + (--> im.b (isNaN))))))) + (else (= a b)))))) ((pair? a) (and (null? a) (null? b))) (else (eq? a b))) false)) @@ -1473,6 +1679,7 @@ ;; ----------------------------------------------------------------------------- (define (%number-type type x) (typecheck "%number-type" type (vector "string" "pair")) + (typecheck "%number-type" x "number") (let* ((t x.__type__) (typeof (lambda (type) (string=? t type)))) (and (number? x) @@ -1480,20 +1687,53 @@ (some typeof type) (typeof type))))) + ;; ----------------------------------------------------------------------------- -(define integer? (%doc - "" - (curry %number-type "bigint"))) +(define (real? x) + "(real? x) + + Function check if argument x is real." + (and (number? x) (or (eq? x NaN) + (eq? x Number.NEGATIVE_INFINITY) + (eq? x Number.POSITIVE_INFINITY) + (and (%number-type "complex" x) + (let ((i (imag-part x))) + (and (zero? i) (exact? i)))) + (%number-type '("float" "bigint" "rational") x)))) ;; ----------------------------------------------------------------------------- -(define complex? (%doc - "" - (curry %number-type "complex"))) +(define (integer? x) + "(integer? x) + + Function check if argument x is integer." + (and (number? x) + (not (eq? x NaN)) + (not (eq? x Number.NEGATIVE_INFINITY)) + (not (eq? x Number.POSITIVE_INFINITY)) + (or (%number-type "bigint" x) + (and (%number-type "float" x) + (= (modulo x 2) 1))))) ;; ----------------------------------------------------------------------------- -(define rational? (%doc - "" - (curry %number-type '("rational" "bigint")))) +(define (complex? x) + "(complex? x) + + Function check if argument x is complex." + (and (number? x) (or (eq? x NaN) + (eq? x Number.NEGATIVE_INFINITY) + (eq? x Number.POSITIVE_INFINITY) + (%number-type '("complex" "float" "bigint" "rational") x)))) + +;; ----------------------------------------------------------------------------- +(define (rational? x) + "(rational? x) + + Function check if value is rational." + (and (number? x) + (not (eq? x NaN)) + (not (eq? x Number.NEGATIVE_INFINITY)) + (not (eq? x Number.POSITIVE_INFINITY)) + (or (%number-type "rational" x) (integer? x)))) ;; ----------------------------------------------------------------------------- (define (typecheck-args _type name _list) @@ -1531,14 +1771,7 @@ Create complex number from imaginary and real part." (let ((value `((re . ,re) (im . ,im)))) - (lips.LComplex (--> value (toObject true))))) - -;; ----------------------------------------------------------------------------- -(define (real? n) - "(real? n)" - (and (number? n) (let ((type n.__type__)) - (or (string=? type "float") - (string=? type "bigint"))))) + (lips.LComplex (--> value (to_object true))))) ;; ----------------------------------------------------------------------------- (define (exact? n) @@ -1551,6 +1784,7 @@ (exact? n.__im__) (exact? n.__re__))))) +;; ----------------------------------------------------------------------------- (define (inexact? n) "(inexact? n)" (typecheck "inexact?" n "number") @@ -1562,9 +1796,9 @@ Convert exact number to inexact." (typecheck "exact->inexact" n "number") - (if (complex? n) - ;; make-object (&) will use valueOf so it will be float even if it was rational - (lips.LComplex (object :im (. n 'im) :re (. n 're))) + (if (%number-type "complex" n) + (lips.LComplex (object :im (exact->inexact (. n '__im__)) + :re (exact->inexact (. n '__re__)))) (if (or (rational? n) (integer? n)) (lips.LFloat (--> n (valueOf)) true) n))) @@ -1575,7 +1809,7 @@ Funcion convert real number to exact ratioanl number." (typecheck "inexact->exact" n "number") - (if (or (real? n) (complex? n)) + (if (or (real? n) (%number-type "complex" n)) (--> n (toRational)) n)) @@ -1642,13 +1876,14 @@ (throw (new Error "list-ref: index out of range")) (let ((l l) (k k)) (while (> k 0) - (if (null? l) + (if (or (null? (cdr l)) (null? l)) (throw (new Error "list-ref: not enough elements in the list"))) (set! l (cdr l)) (set! k (- k 1))) (if (null? l) l (car l))))) + ;; ----------------------------------------------------------------------------- (define (not x) "(not x) @@ -2174,6 +2409,8 @@ Write single character to given port using write function." (typecheck "write-char" char "character") + (if (not (null? rest)) + (typecheck "write-char" (car rest) "output-port")) (apply display (cons (char.valueOf) rest))) ;; ----------------------------------------------------------------------------- @@ -2309,7 +2546,7 @@ Return imaginary part of the complex number n." (typecheck "imag-part" n "number") - (if (complex? n) + (if (%number-type "complex" n) n.__im__ 0)) @@ -2319,8 +2556,8 @@ Return real part of the complex number n." (typecheck "real-part" n "number") - (if (complex? n) - n.re + (if (%number-type "complex" n) + n.__re__ n)) ;; ----------------------------------------------------------------------------- @@ -2341,7 +2578,7 @@ "(angle x) Returns angle of the complex number in polar coordinate system." - (if (not (complex? x)) + (if (not (%number-type "complex" x)) (error "angle: number need to be complex") (Math.atan2 x.__im__ x.__re__))) @@ -2350,7 +2587,7 @@ "(magnitude x) Returns magnitude of the complex number in polar coordinate system." - (if (not (complex? x)) + (if (not (%number-type "complex" x)) (error "magnitude: number need to be complex") (sqrt (+ (* x.__im__ x.__im__) (* x.__re__ x.__re__))))) @@ -2403,12 +2640,6 @@ (typecheck "char-ready?" port "input-port") (port.char_ready))) -;; ----------------------------------------------------------------------------- -;; NodeJS filesystem functions -;; ----------------------------------------------------------------------------- -(if (eq? global self) - (set! self.fs (require "fs"))) - ;; ----------------------------------------------------------------------------- (define open-input-file (let ((readFile #f)) @@ -2417,18 +2648,15 @@ Function return new Input Port with given filename. In Browser user need to provide global fs variable that is instance of FS interface." - (if (null? self.fs) - (throw (new Error "open-input-file: fs not defined")) - (begin - (if (not (procedure? readFile)) - (let ((_readFile (promisify fs.readFile))) - (set! readFile (lambda (filename) - "(readFile filename) - - Helper function that return Promise. NodeJS function sometimes give warnings - when using fs.promises on Windows." - (--> (_readFile filename) (toString)))))) - (new lips.InputFilePort (readFile filename) filename)))))) + (let ((fs (--> lips.env (get '**internal-env**) (get 'fs)))) + (if (null? fs) + (throw (new Error "open-input-file: fs not defined")) + (begin + (if (not (procedure? readFile)) + (let ((_readFile (promisify fs.readFile))) + (set! readFile (lambda (filename) + (--> (_readFile filename) (toString)))))) + (new lips.InputFilePort (readFile filename) filename))))))) ;; ----------------------------------------------------------------------------- (define (close-input-port port) @@ -2506,12 +2734,15 @@ ;; ----------------------------------------------------------------------------- (define (file-exists? filename) (new Promise (lambda (resolve) - (if (null? self.fs) - (throw (new Error "file-exists?: fs not defined")) - (fs.stat filename (lambda (err stat) - (if (null? err) - (resolve (stat.isFile)) - (resolve #f)))))))) + (let ((fs (--> lips.env (get '**internal-env**) (get 'fs)))) + (if (null? fs) + (throw (new Error "file-exists?: fs not defined")) + (fs.stat filename (lambda (err stat) + (if (null? err) + (resolve (stat.isFile)) + (resolve #f))))))))) + + ;; ----------------------------------------------------------------------------- (define open-output-file @@ -2522,17 +2753,18 @@ Function open file and return port that can be used for writing. If file exists it will throw an Error." (typecheck "open-output-file" filename "string") - (if (null? self.fs) - (throw (new Error "open-output-file: fs not defined")) - (begin - (if (not (procedure? open)) - (set! open (promisify fs.open))) - (if (file-exists? filename) - (throw (new Error "open-output-file: file exists")) - (lips.OutputFilePort filename (open filename "w")))))))) + (if (not (procedure? open)) + (set! open (%fs-promisify-proc 'open "open-output-file"))) + (if (file-exists? filename) + (throw (new Error "open-output-file: file exists")) + (lips.OutputFilePort filename (open filename "w")))))) ;; ----------------------------------------------------------------------------- (define (scheme-report-environment version) + "(scheme-report-environment version) + + Function return new Environment object for given Scheme Spec version. + Only argument 5 is supported that create environemnt for R5RS." (typecheck "scheme-report-environment" version "number") (case version ((5) (%make-env "R5RS" * + - / < <= = > >= abs acos and angle append apply asin assoc assq assv @@ -2568,12 +2800,12 @@ ;; ----------------------------------------------------------------------------- ;; Implementation of byte vector functions - SRFI-4 ;; -;; original code was ased on https://small.r7rs.org/wiki/NumericVectorsCowan/17/ +;; original code was based on https://small.r7rs.org/wiki/NumericVectorsCowan/17/ ;; it use JavaScript typed arrays ;; https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays ;; ;; This file is part of the LIPS - Scheme based Powerful lisp in JavaScript -;; Copyright (C) 2019-2021 Jakub T. Jankiewicz <https://jcubic.pl> +;; Copyright (C) 2019-2021 Jakub T. Jankiewicz <https://jcubic.pl/me> ;; Released under MIT license ;; @@ -2619,7 +2851,7 @@ v.length) ;; ----------------------------------------------------------------------------- (define (,make-vector k . fill) - ,(format "(~a v1 v2 ...) + ,(format "(~a k fill) Allocate new ~a of length k, with optional initial values." make-vector @@ -2741,11 +2973,6 @@ (and (symbol? a) (symbol? b) (equal? a b))) args)) -;;(define (read-line . rest) -;; (let ((port (if (null? rest) (current-input-port) (car rest)))) -;; (while (let ((char (peek-char port))) -;; (and (not (string? - ;; ----------------------------------------------------------------------------- ;; function for Gauche code ;; ----------------------------------------------------------------------------- @@ -2783,6 +3010,85 @@ (typecheck "vector-append" (car args) "array") (--> (car args) (concat (apply vector-append (cdr args))))))) +;; ----------------------------------------------------------------------------- +(define-macro (%range-function spec . body) + "(%range-function spec . body) + + Macro that creates R7RS vector functions that have range start end." + (let* ((name (car spec)) + (name-str (symbol->string name)) + (args (append (cdr spec) 'rest))) + `(define (,name ,@args) + ,(if (string? (car body)) + (car body)) + (let ((start (if (null? rest) 0 (car rest))) + (end (if (or (null? rest) (null? (cdr rest))) + (. ,(car args) 'length) + (cadr rest)))) + (typecheck ,name-str start "number") + (typecheck ,name-str end "number") + ,@(if (string? (car body)) + (cdr body) + body))))) + +;; ----------------------------------------------------------------------------- +(%range-function + (vector->list vector) + "(vector->list vector) + (vector->list vector start) + (vector->list vector start end) + + Function copy given range of vector to list. If no start is specified it use + start of the vector, if no end is specified it convert to the end of the vector." + (typecheck "vector->list" vector "array") + (array->list (vector.slice start end))) + +;; ----------------------------------------------------------------------------- +(%range-function + (string->vector string) + "(string->list string) + (string->list string start) + (string->list string start end) + + Function copy given range of string to list. If no start is specified it use + start of the string, if no end is specified it convert to the end of the string." + (typecheck "string->vector" string "string") + (--> (string.substring start end) + (split "") + (map (unary lips.LCharacter)))) + +;; ----------------------------------------------------------------------------- +(%range-function + (vector->string vector) + "(vector->string vector) + (vector->string vector start) + (vector->string vector start end) + + Function return new string created from vector of characters in given range. + If no start is given it create string from 0, if no end is given it return + string to the end." + (typecheck "vector->string" vector "array") + (--> vector + (slice start end) + (map (lambda (char) (char.valueOf))) + (join ""))) + +;; ----------------------------------------------------------------------------- +(%range-function + (vector-fill! vector fill) + "(vector-fill! vector fill) + (vector-fill! vector fill start) + (vector-fill! vector fill start end) + + Fill vector with a given value in given range. If start is not given is start + at 0. If end is not given it fill till the end if the vector." + (typecheck "vector->fill!" vector "array") + (let recur ((n (- end start))) + (if (>= n start) + (begin + (set-obj! vector n fill) + (recur (- n 1)))))) + ;; ----------------------------------------------------------------------------- (define-syntax let*-values (syntax-rules () @@ -2921,22 +3227,6 @@ returns #f." (and (integer? n) (exact? n))) -;; ----------------------------------------------------------------------------- -(define (string->vector s) - "(string->vector string) - - Function return vector of characters created from string." - (typecheck "string->list" s "string") - (--> s (split "") (map (lambda (x) (lips.LCharacter x))))) - -;; ----------------------------------------------------------------------------- -(define (vector->string v) - "(vector->string vector) - - Function return new string created from vector of characters." - (typecheck "vector->list" v "array") - (--> v (map (lambda (char) (char.valueOf))) (join ""))) - ;; ----------------------------------------------------------------------------- (define (vector-map fn . rest) "(vector-map fn vector1 vector2 ...) @@ -3080,8 +3370,8 @@ ;; based on https://srfi.schemers.org/srfi-0/srfi-0.html ;; ----------------------------------------------------------------------------- (define-syntax cond-expand - (syntax-rules (and or not else r7rs srfi-0 srfi-4 srfi-6 srfi-10 srfi-22 - srfi-23 srfi-46 srfi-176 lips complex full-unicode + (syntax-rules (and or not else r7rs srfi-0 srfi-2 srfi-4 srfi-6 srfi-10 + srfi-22 srfi-23 srfi-46 srfi-176 lips complex full-unicode ieee-float ratios exact-complex full-numeric-tower) ((cond-expand) (syntax-error "Unfulfilled cond-expand")) ((cond-expand (else body ...)) @@ -3114,6 +3404,8 @@ (begin body ...)) ((cond-expand (srfi-0 body ...) more-clauses ...) (begin body ...)) + ((cond-expand (srfi-2 body ...) more-clauses ...) + (begin body ...)) ((cond-expand (srfi-4 body ...) more-clauses ...) (begin body ...)) ((cond-expand (srfi-6 body ...) more-clauses ...) @@ -3145,7 +3437,7 @@ ;; ----------------------------------------------------------------------------- (define (features) - '(r7rs srfi-0 srfi-4 srfi-6 srfi-10 srfi-22 srfi-23 srfi-46 srfi-176 lips + '(r7rs srfi-0 srfi-2 srfi-4 srfi-6 srfi-10 srfi-22 srfi-23 srfi-46 srfi-176 lips complex full-unicode ieee-float ratios exact-complex full-numeric-tower)) ;; ----------------------------------------------------------------------------- @@ -3248,6 +3540,13 @@ (define string->utf8 (let ((encoder (new TextEncoder "utf-8"))) (lambda (string . rest) + "(string->utf8 string) + (string->utf8 string start) + (string->utf8 string start end) + + Function converts string into u8 bytevector using utf8 encoding. + The start and end is the range of the input string for the conversion." + (typecheck "string->utf8" string "string") (if (null? rest) (encoder.encode string) (let* ((start (car rest)) @@ -3259,6 +3558,13 @@ (define utf8->string (let ((decoder (new TextDecoder "utf-8"))) (lambda (v . rest) + "(utf8->string u8vector) + (utf8->string u8vector start) + (utf8->string u8vector start end) + + Function converts u8 bytevector into string using utf8 encoding. + The start and end is the range of the input byte vector for the conversion." + (typecheck "utf8->string" v "uint8array") (if (null? rest) (decoder.decode v) (let* ((start (car rest)) @@ -3283,6 +3589,27 @@ and after finish get the whole string using `get-output-string`." (new lips.OutputStringPort repr)) +;; ----------------------------------------------------------------------------- +(define (open-output-bytevector) + "(open-output-bytevector) + + Create new output port that can be used to write binary data. + After done with the data the output buffer can be obtained by calling + `get-output-bytevector` function." + (new lips.OutputByteVectorPort)) + +;; ----------------------------------------------------------------------------- +(define (get-output-bytevector port) + "(get-output-string port) + + Function get full string from string port. If nothing was wrote + to given port it will return empty string." + (if (not (instanceof lips.OutputByteVectorPort port)) + (throw (new Error (string-append + "get-output-bytevector: expecting output-bytevector-port get " + (type port)))) + (port.valueOf))) + ;; ----------------------------------------------------------------------------- (define (get-output-string port) "(get-output-string port) @@ -3292,19 +3619,194 @@ (if (not (instanceof lips.OutputStringPort port)) (throw (new Error (string-append "get-output-string: expecting output-string-port get " (type port)))) - (port.getString))) + (port.valueOf))) + +;; ----------------------------------------------------------------------------- +(define (open-input-bytevector bytevector) + "(open-input-bytevector bytevector) + + Create new input binary port with given bytevector" + (typecheck "open-input-bytevector" bytevector "uint8array") + (new lips.InputByteVectorPort bytevector)) + +;; ----------------------------------------------------------------------------- +(define (open-binary-input-file filename) + "(open-binary-input-file filename) + + Function return new Input Binary Port with given filename. In Browser + user need to provide global fs variable that is instance of FS interface." + (let ((u8vector (buffer->u8vector (%read-binary-file filename)))) + (new lips.InputBinaryFilePort u8vector filename))) + +;; ----------------------------------------------------------------------------- +(define (binary-port? port) + "(binary-port? port) + + Function test if argument is binary port." + (and (port? port) (eq? port.__type__ (Symbol.for "binary")))) + +;; ----------------------------------------------------------------------------- +(define (textual-port? port) + "(textual-port? port) + + Function test if argument is string port." + (and (port? port) (eq? port.__type__ (Symbol.for "text")))) + +;; ----------------------------------------------------------------------------- +(define-macro (%define-binary-input-lambda name docstring fn) + (let ((port (gensym)) + (name-str (symbol->string name))) + `(define (,name . rest) + ,docstring + (let ((,port (if (null? rest) + (current-input-port) + (car rest)))) + (typecheck ,name-str ,port "input-port") + (if (not (binary-port? ,port)) + (throw (new Error (string-append ,name-str + " invalid port. Binary port required."))) + (,fn ,port)))))) + +;; ----------------------------------------------------------------------------- +(%define-binary-input-lambda + peek-u8 + "(peek-u8) + (peek-u8 port) + + Return next byte from input-binary port. If there are no more bytes + it return eof object." + (lambda (port) + (port.peek_u8))) + +;; ----------------------------------------------------------------------------- +(%define-binary-input-lambda + read-u8 + "(read-u8) + (read-u8 port) + + Read next byte from input-binary port. If there are no more bytes + it return eof object." + (lambda (port) + (port.read_u8))) + +;; ----------------------------------------------------------------------------- +(%define-binary-input-lambda + u8-ready? + "(u8-ready?) + (u8-ready? port) + + Returns #t if a byte is ready on the binary input port and returns #f otherwise. + If u8-ready? returns #t then the next read-u8 operation on the given port is + guaranteed not to hang. If the port is at end of file then u8-ready? returns #t." + (lambda (port) + (port.u8_ready))) + +;; ----------------------------------------------------------------------------- +(define (read-bytevector k . rest) + "(read-bytevector k) + (read-bytevector k port) + + Read next n bytes from input-binary port. If there are no more bytes + it returns eof object. If there are less then n bytes in port it + return the only bytes that are available" + (let ((port (if (null? rest) + (current-input-port) + (car rest)))) + (typecheck "read-bytevector" port "input-port") + (if (not (binary-port? port)) + (throw (new Error "read-bytevector: invalid port")) + (port.read_u8_vector k)))) + +;; ----------------------------------------------------------------------------- +(define-macro (%define-binary-output-lambda name type docstring fn) + (let ((port (gensym 'port)) + (data (gensym 'data)) + (name-str (symbol->string name))) + `(define (,name ,data . rest) + ,docstring + (let ((,port (if (null? rest) + (current-output-port) + (car rest)))) + (typecheck ,name-str ,port "output-port") + (typecheck ,name-str ,data ,type) + (if (not (binary-port? ,port)) + (throw (new Error (string-append ,name-str + " invalid port. Binary port required."))) + (,fn ,data ,port)))))) + +;; ----------------------------------------------------------------------------- +(%define-binary-output-lambda + write-u8 + "number" + "(write-u8 byte) + (write-u8 byte port) + + Write byte into binary output port." + (lambda (data port) + (port.write_u8 data))) + +;; ----------------------------------------------------------------------------- +(%define-binary-output-lambda + write-bytevector + "uint8array" + "(write-bytevector bytevector) + (write-bytevector bytevector port) + + Write byte vector into binary output port." + (lambda (data port) + (port.write_u8_vector data))) + +;; ----------------------------------------------------------------------------- +(define open-binary-output-file + (let ((open)) + (lambda (filename) + "(open-binary-output-file filename) + + Function open file and return port that can be used for writing. If file + exists it will throw an Error." + (typecheck "open-output-file" filename "string") + (if (not (procedure? open)) + (set! open (%fs-promisify-proc 'open "open-binary-output-file"))) + (if (file-exists? filename) + (throw (new Error "open-binary-output-file: file exists")) + (lips.OutputBinaryFilePort filename (open filename "w")))))) + +;; ----------------------------------------------------------------------------- +(define (read-bytevector! vector . rest) + "(read-bytevector! bytevector) + (read-bytevector! bytevector port) + (read-bytevector! bytevector port start) + (read-bytevector! bytevector port start end) + + Function read next bytes from binary input port and write them into byte vector. + if not start is specified it start to write into 0 position of the vector until + the end or end the vector if no end is specified." + (typecheck "read-bytevector!" vector "uint8array") + (let ((port (if (null? rest) (current-input-port) (car rest))) + (start (if (or (null? rest) (null? (cdr rest))) 0 (cadr rest))) + (end (if (or (null? rest) (null? (cdr rest)) (null? (cddr rest))) + (bytevector-length vector) + (caddr rest)))) + (typecheck "read-bytevector!" port "input-port") + (if (not (binary-port? port)) + (throw (new Error "read-bytevector!: invalid port. Binary port required.")) + (begin + (typecheck "read-bytevector!" start "number") + (typecheck "read-bytevector!" end "number") + (let ((out (read-bytevector (- end start) port))) + (vector.set out start end)))))) ;; ----------------------------------------------------------------------------- (define delete-file (let ((unlink #f)) (lambda (filename) + "(delete-file filename) + + Function delete the file of given name." (typecheck "delete-file" filename "string") - (if (null? self.fs) - (throw (new Error "delete-file: fs not defined")) - (begin - (if (not (procedure? unlink)) - (set! unlink (promisify fs.unlink))) - (unlink filename)))))) + (if (not (procedure? unlink)) + (set! unlink (%fs-promisify-proc 'unlink "delete-file"))) + (unlink filename)))) ;; ----------------------------------------------------------------------------- (define (call-with-port port proc) @@ -3387,7 +3889,6 @@ (display (string char) port))) ;; ----------------------------------------------------------------------------- - (define (read-string k . rest) "(read-string k) (read-string k port) @@ -3401,3 +3902,317 @@ (let ((port (if (null? rest) (current-input-port) (car rest)))) (typecheck "read-string" port "input-port") (port.read_string k))) + +;; ----------------------------------------------------------------------------- +(define (list-copy obj) + "(list-copy obj) + + Copy the object passed as argument but only if it's list. The car elements + of the list are not copied, they are passed as is." + (typecheck "list-copy" obj #("pair" "nil")) + (if (null? obj) + obj + (obj.clone false))) + +;; ----------------------------------------------------------------------------- +(define-macro (define-record-type name constructor pred . fields) + "(define-record-type name constructor pred . fields) + + Macro for defining records. Example of usage: + + (define-record-type <pare> + (kons x y) + pare? + (x kar set-kar!) + (y kdr set-kdr!)) + + (define p (kons 1 2)) + (print (kar p)) + ;; 1 + (set-kdr! p 3) + (print (kdr p)) + ;; 3" + (let ((class-name (gensym)) + (obj-name (gensym)) + (value-name (gensym))) + `(begin + (define ,class-name (class Object + (constructor (lambda (self ,@(cdr constructor)) + ,@(map (lambda (field) + (let* ((name (symbol->string field)) + (prop (string-append "self." + name))) + `(set! ,(string->symbol prop) ,field))) + (cdr constructor)))) + (toType (lambda (self) + "record")) + (toString (lambda (self) + ,(symbol->string name))))) + (define ,constructor + (new ,class-name ,@(cdr constructor))) + (define (,pred obj) + (instanceof ,class-name obj)) + ,@(map (lambda (field) + (let ((prop-name (car field)) + (get (cadr field)) + (set (if (null? (cddr field)) + nil + (caddr field)))) + `(begin + (define (,get ,obj-name) + (typecheck ,(symbol->string get) ,obj-name "record") + (if (not (,pred ,obj-name)) + (throw (new Error ,(string-append "object is not record of type " + (symbol->string name)))) + (. ,obj-name ',prop-name))) + ,(if (not (null? set)) + `(define (,set ,obj-name ,value-name) + (typecheck ,(symbol->string get) ,obj-name "record") + (if (not (,pred ,obj-name)) + (throw (new Error ,(string-append "object is not record of type " + (symbol->string name)))) + (set-obj! ,obj-name ',prop-name ,value-name))))))) + fields)))) + +;; ----------------------------------------------------------------------------- +(define (nan? x) + "(nan? x) + + Function check if argument x is Not a Number (NaN) value." + (and (number? x) + (or (x.isNaN) + (and (%number-type "complex" x) + (or (nan? (real-part x)) + (nan? (imag-part x))))))) + +;; ----------------------------------------------------------------------------- +(define (infinite? x) + "(infinite? x) + + Function check if value is infinite." + (or (eq? x Number.NEGATIVE_INFINITY) + (eq? x Number.POSITIVE_INFINITY) + (and (number? x) + (not (eq? x NaN)) + (%number-type "complex" x) + (or (infinite? (real-part x)) + (infinite? (imag-part x)))))) + +;; ----------------------------------------------------------------------------- +(define (finite? x) + "(finite? x) + + Function check if value is finite." + (not (infinite? x))) + +;; ----------------------------------------------------------------------------- +(define-class %Library Object + (constructor + (lambda (self name) + (set! self.__namespace__ &()) + (set! self.__name__ name))) + (append + (lambda (self namespace env) + (if (environment? (. self.__namespace__ namespace)) + (throw (new Error (string-append "namespace " namespace + " already exists in library " + self.__name__))) + (set-obj! self.__namespace__ namespace env)))) + (env + (lambda (self namespace) + (let ((env (. self.__namespace__ namespace))) + (if (not (environment? env)) + (throw (new Error (string-append "namespace " namespace " sdon't exists"))) + env)))) + (get + (lambda (self namespace name) + (--> (self.env namespace) (get name)))) + (set + (lambda (self namespace name value) + (--> (self.env namespace) (set name value)))) + (toString + (lambda (self) + (string-append "#<Library(" self.__name__ ")>")))) + +;; ----------------------------------------------------------------------------- +(define (%import-name library namespace names) + `(begin + ,@(map (lambda (name) + `(define ,name (--> ,library (get ',namespace ',name)))) + names))) + +;; ----------------------------------------------------------------------------- +(define-macro (import . specs) + "(import (library namespace)) + (import (only (library namespace) name1 name2)) + + Macro for importing names from library." + (let ((parent (current-environment))) + `(begin + ,@(map (lambda (spec) + (if (not (pair? spec)) + (throw (new Error "import: invalid syntax")) + (cond ((symbol=? (car spec) + 'only) + (let ((lib (caadr spec)) + (namespace (caaddr spec))) + (if (pair? (cadr spec)) + (%import-name ,lib + ',namespace + ',(caddr spec)) + (throw (new Error "import: invalid syntax"))))) + (else + (let* ((lib-name (car spec)) + (lib (parent.get lib-name)) + (namespace (cadr spec))) + (%import-name lib-name + namespace + (env (lib.env namespace)))))))) + specs)))) + +;; ----------------------------------------------------------------------------- +(define (new-library name namespace) + "(new-library name) + + Create new empty library object with empty namespace." + (let* ((parent (. (current-environment) '__parent__)) + (lib (let ((lib (--> parent (get name &(:throwError false))))) + (if (null? lib) + (new %Library name) + lib))) + (x (new lips.Environment + (string-append "library-" + (--> name (toLowerCase)) + "-" + (--> namespace (toLowerCase)))))) + (lib.append namespace x) + lib)) + +;; ----------------------------------------------------------------------------- +(define (%export module namespace specs) + `(begin + ,@(map (lambda (expr) + (cond ((symbol? expr) + `(--> ,module (set ',namespace + ',expr + ,expr))) + ((and (pair? expr) (symbol=? (car expr) + 'rename)) + `(--> ,module (set ',namespace + ',(cadr expr) + ,(caddr expr)))))) + specs))) + +;; ----------------------------------------------------------------------------- +(define-macro (define-library spec . body) + "(define-library (library (name namespace) . body) + + Macro for defining modules inside you can use define to create functions. + And use export name to add that name to defined environment." + (let ((parent (. (current-environment) '__parent__)) + (module-var (gensym)) + (namespace-var (gensym)) + (name (car spec)) + (namespace (cadr spec))) + `(let ((,module-var (new-library ,(symbol->string name) + ,(symbol->string namespace))) + (,namespace-var ',namespace)) + (define-macro (export . body) + (%export ,module-var ,namespace-var body)) + ,@body + (--> ,parent (set ',name ,module-var))))) + +;; ----------------------------------------------------------------------------- +(define-values (current-directory set-current-directory!) + (if (eq? self window) + (let ((cwd (string-append location.origin (--> location.pathname + (replace #/\/[^/]+$/ "/"))))) + (values + (lambda () + "(current-directory) + + Return corrent working directory, default it's corrent URL." + cwd) + (lambda (value) + "(set-current-directory! string) + + Function change current working directory to provided string." + (typecheck "set-current-directory!" value "string") + (set! cwd value)))) + (let ((process (require "process"))) + (values + (lambda () + "(current-directory) + + Return corrent working directory, default it's path from where + the script was executed." + (string-append (process.cwd) "/")) + (lambda (value) + "(set-current-directory! string) + + Function change current working directory to provided string." + (typecheck "set-current-directory!" value "string") + (process.chdir value)))))) + +;; ----------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- +;; SRFI-2 https://srfi.schemers.org/srfi-2/srfi-2.html +;; ----------------------------------------------------------------------------- +(define-syntax and-let* + (syntax-rules () + ((_ ()) #t) + ((_ () body ...) + (let () body ...)) + ((_ ((expression))) ;; last/single expression + expression) + ((_ ((symbol expression)) body ...) ;; last/single pair + (let ((symbol expression)) + (if symbol (begin body ...)))) + ((_ ((symbol expression) expr ...) body ...) ;; lead pair + (let ((symbol expression)) + (and symbol (and-let* (expr ...) body ...)))) + ((_ ((expression) expr ...) body ...) ;; lead expression + (and expression (and-let* (expr ...) body ...)))) + "(and-let* ((name expression) expression ...) body) + + Macro that combine let and and. First expression need to be in form of let. + Symbol expression the rest can be boolean expression or name expreession. + This is implementation of SRFI-2.") + +;; ----------------------------------------------------------------------------- +;; SRFI-10 https://srfi.schemers.org/srfi-10/srfi-10.html +;; ----------------------------------------------------------------------------- +(set-special! "#," 'sharp-comma) + +(define **reader-ctor-list** '()) + +;; ----------------------------------------------------------------------------- +(define (define-reader-ctor symbol fn) + "(define-reader-ctor symbol fn) + + Define the value for #, syntax. SRFI-10 + Example: + + (define-reader-ctor '+ +) + (print #,(+ 1 2))" + (let ((node (assoc symbol **reader-ctor-list**))) + (if (pair? node) + (set-cdr! node fn) + (set! **reader-ctor-list** (cons (cons symbol fn) + **reader-ctor-list**))))) + +;; ----------------------------------------------------------------------------- +(define-syntax sharp-comma + (syntax-rules () + ((_ (fn arg ...)) + (let ((node (assoc 'fn **reader-ctor-list**))) + (if (pair? node) + ((cdr node) 'arg ...) + (syntax-error (string-append "Invalid symbol " (symbol->string 'fn) + " in expression " (repr '(fn arg ...)))))))) + "(sharp-comma expr) + #,(ctor ...) + + This is syntax extension for SRFI-10. To define the function to be used with + This syntax you need to call `define-reader-ctor` function and define + symbol function mapping.") diff --git a/examples/app.scm b/examples/app.scm deleted file mode 100644 index 3e8d85bf..00000000 --- a/examples/app.scm +++ /dev/null @@ -1,50 +0,0 @@ -;; -*- scheme -*- -;; This is example hyperapp application written in LIPS -;; -;; This file is part of the LIPS - Scheme implementation in JavaScript -;; Copyriht (C) 2019-2020 Jakub T. Jankiewicz <https://jcubic.pl> -;; Released under MIT license -;; - -(define h (.. hyperapp.h)) -(define app (.. hyperapp.app)) - -;; helper for this specific app - hyperapp action generator that create new state - -(define (update fn) - "(update fn) - - Function create new action that create new state with updated alist value - that is returned from function." - (lambda (value) - (lambda (state) - (let* ((alist (. state "counter")) - (old (cdr (assoc 'count alist)))) - (make-object :counter (alist->assign '() alist `((count . ,(fn old value))))))))) - - -;; ----------------------------------------------------------------------------- -;; MAIN APPLICATION CODE -;; ----------------------------------------------------------------------------- - -;; Hyper app actions -(define actions (make-object :up (update +) - :down (update -))) - - -;; inital state -(define state (make-object :counter '((count . 0)))) - -(define (Counter obj) - (with-tags (:h1 () (concat "Counter: " (. obj 'count))))) - -(define (view state actions) - "hyperapp view" - (let ((counter (. state "counter"))) - (with-tags (:div () - (list (Counter (:count (cdr (assoc 'count counter)))) - (:button (:onclick (lambda () (--> actions (down 1)))) "-") - (:button (:onclick (lambda () (--> actions (up 1)))) "+")))))) - -;; main hyper app -(define main (app state actions view (--> document (querySelector "#app")))) diff --git a/examples/common.css b/examples/common.css deleted file mode 100644 index 9a429aa6..00000000 --- a/examples/common.css +++ /dev/null @@ -1,49 +0,0 @@ -.tabs .panels > :not(.active) { - display: none; -} -.tabs ul { - list-style: none; - padding: 0; - margin: 0; - overflow: hidden; -} -.tabs .panels { - clear: both; -} -.tabs li { - display: block; - float: left; - position: relative; - border-radius: 10px 10px 0 0; -} -.tabs li:hover { -/* Permalink - use to edit and share this gradient: http://colorzilla.com/gradient-editor/#e5e5e5+0,ffffff+100 */ -background: #e5e5e5; /* Old browsers */ -background: -moz-linear-gradient(-45deg, #e5e5e5 0%, #ffffff 100%); /* FF3.6-15 */ -background: -webkit-linear-gradient(-45deg, #e5e5e5 0%,#ffffff 100%); /* Chrome10-25,Safari5.1-6 */ -background: linear-gradient(135deg, #e5e5e5 0%,#ffffff 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */ -filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#e5e5e5', endColorstr='#ffffff',GradientType=1 ); /* IE6-9 fallback on horizontal gradient */ -} -.tabs li.active:after { - content: ''; - display: block; - border-bottom: 5px solid #295ee5; - position: absolute; - width: 100%; - bottom: 0; -} -.tabs li a { - text-decoration: none; - padding: 10px; - display: inline-block; - border: 1px solid black; - border-radius: 10px 10px 0 0; - border-bottom: none; -} -.tabs li + li a { - border-left: none; -} -code[class*="language-"], pre[class*="language-"] { - white-space: pre-wrap; - word-break: break-word; -} diff --git a/examples/defstruct.scm b/examples/defstruct.scm index 48a897a9..2f2df7cf 100644 --- a/examples/defstruct.scm +++ b/examples/defstruct.scm @@ -34,7 +34,7 @@ (define (defstruct:alist->object arg) "Function create JavaScript object from AList" (typecheck "defstruct:every" arg "pair") - (--> arg (toObject))) + (--> arg (to_object))) (define (defstruct:every fn list) "return true if every element return true for a function applied to every element" diff --git a/examples/hyper.html b/examples/hyper.html deleted file mode 100644 index fcbbf68a..00000000 --- a/examples/hyper.html +++ /dev/null @@ -1,19 +0,0 @@ -<!DOCTYPE HTML> -<html xmlns="http://www.w3.org/1999/xhtml"> -<head> - <meta charset="utf-8" /> - <title>Demo LIPS Hyperapp app - - - - - - - -
- - - - diff --git a/examples/index.html b/examples/index.html deleted file mode 100644 index e64a3d84..00000000 --- a/examples/index.html +++ /dev/null @@ -1,178 +0,0 @@ - - - - - HyperApp LIPS Demo - - - - - - - - - - - - - - - - - - - - - - -
-

Hyperapp LIPS demo

-
- -
-
-

README

-

- This is example applictation using Hyperapp - together with LIPS interpter. Main application code is in app.lips file. The - rest of the files are just helper macros and functions. -

-

This demo

-

- This page is created using jQuery code and in JavaScript but the hyper app is created using only - LIPS code. It's inserted into iframe. Terminal on this is page can interact with lips instance - from iframe.

-

Playing with terminal

-

You can execute example codes:

-

-;; this will call up method on main app object
-;; --> is macro defined in helpers.lips
-(--> main (up 10))
-      
-

Hyperapp

-

LIPS code for the hyperapp is based on example from readme. I've used direct calls of h function in form:

-

-import { h } from "hyperapp"
-
-export const view = (state, actions) =>
-  h("div", {}, [
-    h("h1", {}, state.count),
-    h("button", { onclick: () => actions.down(1) }, "-"),
-    h("button", { onclick: () => actions.up(1) }, "+")
-  ])
-      
-
-
-
-
    -
    -
    -
    -
    -
    -
    - - diff --git a/examples/io.scm b/examples/io.scm new file mode 100644 index 00000000..718f5e47 --- /dev/null +++ b/examples/io.scm @@ -0,0 +1,21 @@ +(let ((fname "tmp.txt")) + (if (file-exists? fname) + (raise (string-append "file " fname " exists"))) + (call-with-output-file fname + (lambda (output-port) + (display "hello, world" output-port) + (newline output-port))) + + (call-with-input-file fname + (lambda (input-port) + (let loop ((x (read-char input-port))) + (if (not (eof-object? x)) + (begin + (display x) + (loop (read-char input-port))))))) + + (delete-file fname)) + + + + diff --git a/examples/preact.html b/examples/preact.html index acf2a378..d8c12303 100644 --- a/examples/preact.html +++ b/examples/preact.html @@ -8,14 +8,8 @@ - - - + + diff --git a/examples/reader-macros.js b/examples/reader-macros.js index e1239faf..aaa32d9d 100644 --- a/examples/reader-macros.js +++ b/examples/reader-macros.js @@ -45,7 +45,7 @@ return obj; }); return new Pair(car, cdr); - }).toObject(); + }).to_object(); })); env.set('object->string', function(obj) { return JSON.stringify(obj); diff --git a/examples/scheme-detect.scm b/examples/scheme-detect.scm index 44ee8ab6..4be03194 100755 --- a/examples/scheme-detect.scm +++ b/examples/scheme-detect.scm @@ -64,7 +64,7 @@ (ikarus (#f #f #f #t #f #t #f #t #f #f #f #f #t #f #f #t #t #t #f #f)) (scheme48 (#f #f #f #t #t #t #f #t #t #t #t #t #t #t #t #t #t #f #f #f)) (mit-scheme (#t #t #t #t #t #f #t #t #t #f #t #f #f #f #f #t #t #f #t #f)) - (lips (#t #f #f #t #f #t #f #t #t #f #f #f #t #t #t #t #t #t #t #f)) + (lips (#t #f #f #t #f #t #f #t #t #f #f #f #t #t #f #f #f #t #t #f)) (gauche (#f #f #f #t #f #f #f #t #t #f #f #f #f #f #f #t #t #f #f #f)))) ;; DETECT:MATCH-SIGNATURE @@ -73,15 +73,17 @@ ;; against a table of known signatures. (define (detect:match-signature) (let ((signature (detect:signature))) - ; Loop over the DETECT:KNOWN-SIGNATURES list + ;; Loop over the DETECT:KNOWN-SIGNATURES list (let test ((siglist detect:known-signatures)) (if (equal? '() siglist) - ; Return 'UNKNOWN if we're stumped - 'unknown - (let ((testsig (car siglist))) - (if (equal? (cadr testsig) signature) - (car testsig) - (test (cdr siglist)))))))) + ;; Return 'UNKNOWN if we're stumped + (begin + (print signature) + 'unknown) + (let ((testsig (car siglist))) + (if (equal? (cadr testsig) signature) + (car testsig) + (test (cdr siglist)))))))) ;; DETECT:NAME ;; Memoized form of DETECT:MATCH-SIGNATURE diff --git a/examples/zero.scm b/examples/zero.scm new file mode 100755 index 00000000..cf6a42b3 --- /dev/null +++ b/examples/zero.scm @@ -0,0 +1,17 @@ +#!/usr/bin/env -S lips -t + +(define fs (require "fs")) + +(define (read-zero n) + (new Promise (lambda (resolve reject) + (fs.open "/dev/zero" "r" (lambda (err fd) + (if (null? err) + (let* ((buffer (Buffer.from (new Array n))) + (return (lambda (err num) + (if (null? err) + (resolve buffer) + (reject err))))) + (fs.read fd buffer 0 buffer.length 0 return)) + (reject err))))))) + +(console.log (read-zero 8)) diff --git a/lib/R5RS.scm b/lib/R5RS.scm index 0257b25d..9028250e 100755 --- a/lib/R5RS.scm +++ b/lib/R5RS.scm @@ -74,9 +74,16 @@ ;; ----------------------------------------------------------------------------- (set-repr! Array - (lambda (x q) - (let ((arr (--> x (map (lambda (x) (repr x q)))))) - (concat "#(" (--> arr (join " ")) ")")))) + (lambda (arr q) + ;; Array.from is used to convert emtpy to undefined + ;; but we can't use the value because Array.from call + ;; valueOf on its arguments + (let ((result (--> (Array.from arr) + (map (lambda (x i) + (if (not (in i arr)) + "#" + (repr (. arr i) q))))))) + (concat "#(" (--> result (join " ")) ")")))) ;; ----------------------------------------------------------------------------- (define (eqv? a b) @@ -85,7 +92,32 @@ Function compare the values. It return true if they are the same, they need to have same type" (if (string=? (type a) (type b)) - (cond ((number? a) (= a b)) + (cond ((number? a) + (or (and (exact? a) (exact? b) (= a b)) + (and (inexact? a) + (inexact? b) + (cond ((a.isNaN) (b.isNaN)) + ((and (zero? a) (zero? b)) + (eq? a._minus b._minus)) + ((and (complex? a) (complex? b)) + (let ((re.a (real-part a)) + (re.b (real-part b)) + (im.a (imag-part a)) + (im.b (imag-part b))) + (and + (if (and (zero? re.a) (zero? re.b)) + (eq? (. re.a '_minus) (. re.b '_minus)) + true) + (if (and (zero? im.a) (zero? im.b)) + (eq? (. im.a '_minus) (. im.b '_minus)) + true) + (or (= re.a re.b) + (and (--> re.a (isNaN)) + (--> re.b (isNaN)))) + (or (= im.a im.b) + (and (--> im.a (isNaN)) + (--> im.b (isNaN))))))) + (else (= a b)))))) ((pair? a) (and (null? a) (null? b))) (else (eq? a b))) false)) @@ -265,6 +297,7 @@ ;; ----------------------------------------------------------------------------- (define (%number-type type x) (typecheck "%number-type" type (vector "string" "pair")) + (typecheck "%number-type" x "number") (let* ((t x.__type__) (typeof (lambda (type) (string=? t type)))) (and (number? x) @@ -272,20 +305,53 @@ (some typeof type) (typeof type))))) + ;; ----------------------------------------------------------------------------- -(define integer? (%doc - "" - (curry %number-type "bigint"))) +(define (real? x) + "(real? x) + + Function check if argument x is real." + (and (number? x) (or (eq? x NaN) + (eq? x Number.NEGATIVE_INFINITY) + (eq? x Number.POSITIVE_INFINITY) + (and (%number-type "complex" x) + (let ((i (imag-part x))) + (and (zero? i) (exact? i)))) + (%number-type '("float" "bigint" "rational") x)))) + +;; ----------------------------------------------------------------------------- +(define (integer? x) + "(integer? x) + + Function check if argument x is integer." + (and (number? x) + (not (eq? x NaN)) + (not (eq? x Number.NEGATIVE_INFINITY)) + (not (eq? x Number.POSITIVE_INFINITY)) + (or (%number-type "bigint" x) + (and (%number-type "float" x) + (= (modulo x 2) 1))))) ;; ----------------------------------------------------------------------------- -(define complex? (%doc - "" - (curry %number-type "complex"))) +(define (complex? x) + "(complex? x) + + Function check if argument x is complex." + (and (number? x) (or (eq? x NaN) + (eq? x Number.NEGATIVE_INFINITY) + (eq? x Number.POSITIVE_INFINITY) + (%number-type '("complex" "float" "bigint" "rational") x)))) ;; ----------------------------------------------------------------------------- -(define rational? (%doc - "" - (curry %number-type '("rational" "bigint")))) +(define (rational? x) + "(rational? x) + + Function check if value is rational." + (and (number? x) + (not (eq? x NaN)) + (not (eq? x Number.NEGATIVE_INFINITY)) + (not (eq? x Number.POSITIVE_INFINITY)) + (or (%number-type "rational" x) (integer? x)))) ;; ----------------------------------------------------------------------------- (define (typecheck-args _type name _list) @@ -323,14 +389,7 @@ Create complex number from imaginary and real part." (let ((value `((re . ,re) (im . ,im)))) - (lips.LComplex (--> value (toObject true))))) - -;; ----------------------------------------------------------------------------- -(define (real? n) - "(real? n)" - (and (number? n) (let ((type n.__type__)) - (or (string=? type "float") - (string=? type "bigint"))))) + (lips.LComplex (--> value (to_object true))))) ;; ----------------------------------------------------------------------------- (define (exact? n) @@ -343,6 +402,7 @@ (exact? n.__im__) (exact? n.__re__))))) +;; ----------------------------------------------------------------------------- (define (inexact? n) "(inexact? n)" (typecheck "inexact?" n "number") @@ -354,9 +414,9 @@ Convert exact number to inexact." (typecheck "exact->inexact" n "number") - (if (complex? n) - ;; make-object (&) will use valueOf so it will be float even if it was rational - (lips.LComplex (object :im (. n 'im) :re (. n 're))) + (if (%number-type "complex" n) + (lips.LComplex (object :im (exact->inexact (. n '__im__)) + :re (exact->inexact (. n '__re__)))) (if (or (rational? n) (integer? n)) (lips.LFloat (--> n (valueOf)) true) n))) @@ -367,7 +427,7 @@ Funcion convert real number to exact ratioanl number." (typecheck "inexact->exact" n "number") - (if (or (real? n) (complex? n)) + (if (or (real? n) (%number-type "complex" n)) (--> n (toRational)) n)) @@ -434,13 +494,14 @@ (throw (new Error "list-ref: index out of range")) (let ((l l) (k k)) (while (> k 0) - (if (null? l) + (if (or (null? (cdr l)) (null? l)) (throw (new Error "list-ref: not enough elements in the list"))) (set! l (cdr l)) (set! k (- k 1))) (if (null? l) l (car l))))) + ;; ----------------------------------------------------------------------------- (define (not x) "(not x) @@ -966,6 +1027,8 @@ Write single character to given port using write function." (typecheck "write-char" char "character") + (if (not (null? rest)) + (typecheck "write-char" (car rest) "output-port")) (apply display (cons (char.valueOf) rest))) ;; ----------------------------------------------------------------------------- @@ -1101,7 +1164,7 @@ Return imaginary part of the complex number n." (typecheck "imag-part" n "number") - (if (complex? n) + (if (%number-type "complex" n) n.__im__ 0)) @@ -1111,8 +1174,8 @@ Return real part of the complex number n." (typecheck "real-part" n "number") - (if (complex? n) - n.re + (if (%number-type "complex" n) + n.__re__ n)) ;; ----------------------------------------------------------------------------- @@ -1133,7 +1196,7 @@ "(angle x) Returns angle of the complex number in polar coordinate system." - (if (not (complex? x)) + (if (not (%number-type "complex" x)) (error "angle: number need to be complex") (Math.atan2 x.__im__ x.__re__))) @@ -1142,7 +1205,7 @@ "(magnitude x) Returns magnitude of the complex number in polar coordinate system." - (if (not (complex? x)) + (if (not (%number-type "complex" x)) (error "magnitude: number need to be complex") (sqrt (+ (* x.__im__ x.__im__) (* x.__re__ x.__re__))))) @@ -1195,12 +1258,6 @@ (typecheck "char-ready?" port "input-port") (port.char_ready))) -;; ----------------------------------------------------------------------------- -;; NodeJS filesystem functions -;; ----------------------------------------------------------------------------- -(if (eq? global self) - (set! self.fs (require "fs"))) - ;; ----------------------------------------------------------------------------- (define open-input-file (let ((readFile #f)) @@ -1209,18 +1266,15 @@ Function return new Input Port with given filename. In Browser user need to provide global fs variable that is instance of FS interface." - (if (null? self.fs) - (throw (new Error "open-input-file: fs not defined")) - (begin - (if (not (procedure? readFile)) - (let ((_readFile (promisify fs.readFile))) - (set! readFile (lambda (filename) - "(readFile filename) - - Helper function that return Promise. NodeJS function sometimes give warnings - when using fs.promises on Windows." - (--> (_readFile filename) (toString)))))) - (new lips.InputFilePort (readFile filename) filename)))))) + (let ((fs (--> lips.env (get '**internal-env**) (get 'fs)))) + (if (null? fs) + (throw (new Error "open-input-file: fs not defined")) + (begin + (if (not (procedure? readFile)) + (let ((_readFile (promisify fs.readFile))) + (set! readFile (lambda (filename) + (--> (_readFile filename) (toString)))))) + (new lips.InputFilePort (readFile filename) filename))))))) ;; ----------------------------------------------------------------------------- (define (close-input-port port) @@ -1298,12 +1352,15 @@ ;; ----------------------------------------------------------------------------- (define (file-exists? filename) (new Promise (lambda (resolve) - (if (null? self.fs) - (throw (new Error "file-exists?: fs not defined")) - (fs.stat filename (lambda (err stat) - (if (null? err) - (resolve (stat.isFile)) - (resolve #f)))))))) + (let ((fs (--> lips.env (get '**internal-env**) (get 'fs)))) + (if (null? fs) + (throw (new Error "file-exists?: fs not defined")) + (fs.stat filename (lambda (err stat) + (if (null? err) + (resolve (stat.isFile)) + (resolve #f))))))))) + + ;; ----------------------------------------------------------------------------- (define open-output-file @@ -1314,17 +1371,18 @@ Function open file and return port that can be used for writing. If file exists it will throw an Error." (typecheck "open-output-file" filename "string") - (if (null? self.fs) - (throw (new Error "open-output-file: fs not defined")) - (begin - (if (not (procedure? open)) - (set! open (promisify fs.open))) - (if (file-exists? filename) - (throw (new Error "open-output-file: file exists")) - (lips.OutputFilePort filename (open filename "w")))))))) + (if (not (procedure? open)) + (set! open (%fs-promisify-proc 'open "open-output-file"))) + (if (file-exists? filename) + (throw (new Error "open-output-file: file exists")) + (lips.OutputFilePort filename (open filename "w")))))) ;; ----------------------------------------------------------------------------- (define (scheme-report-environment version) + "(scheme-report-environment version) + + Function return new Environment object for given Scheme Spec version. + Only argument 5 is supported that create environemnt for R5RS." (typecheck "scheme-report-environment" version "number") (case version ((5) (%make-env "R5RS" * + - / < <= = > >= abs acos and angle append apply asin assoc assq assv diff --git a/lib/R7RS.scm b/lib/R7RS.scm index 52c577ef..e28320a9 100755 --- a/lib/R7RS.scm +++ b/lib/R7RS.scm @@ -37,11 +37,6 @@ (and (symbol? a) (symbol? b) (equal? a b))) args)) -;;(define (read-line . rest) -;; (let ((port (if (null? rest) (current-input-port) (car rest)))) -;; (while (let ((char (peek-char port))) -;; (and (not (string? - ;; ----------------------------------------------------------------------------- ;; function for Gauche code ;; ----------------------------------------------------------------------------- @@ -79,6 +74,85 @@ (typecheck "vector-append" (car args) "array") (--> (car args) (concat (apply vector-append (cdr args))))))) +;; ----------------------------------------------------------------------------- +(define-macro (%range-function spec . body) + "(%range-function spec . body) + + Macro that creates R7RS vector functions that have range start end." + (let* ((name (car spec)) + (name-str (symbol->string name)) + (args (append (cdr spec) 'rest))) + `(define (,name ,@args) + ,(if (string? (car body)) + (car body)) + (let ((start (if (null? rest) 0 (car rest))) + (end (if (or (null? rest) (null? (cdr rest))) + (. ,(car args) 'length) + (cadr rest)))) + (typecheck ,name-str start "number") + (typecheck ,name-str end "number") + ,@(if (string? (car body)) + (cdr body) + body))))) + +;; ----------------------------------------------------------------------------- +(%range-function + (vector->list vector) + "(vector->list vector) + (vector->list vector start) + (vector->list vector start end) + + Function copy given range of vector to list. If no start is specified it use + start of the vector, if no end is specified it convert to the end of the vector." + (typecheck "vector->list" vector "array") + (array->list (vector.slice start end))) + +;; ----------------------------------------------------------------------------- +(%range-function + (string->vector string) + "(string->list string) + (string->list string start) + (string->list string start end) + + Function copy given range of string to list. If no start is specified it use + start of the string, if no end is specified it convert to the end of the string." + (typecheck "string->vector" string "string") + (--> (string.substring start end) + (split "") + (map (unary lips.LCharacter)))) + +;; ----------------------------------------------------------------------------- +(%range-function + (vector->string vector) + "(vector->string vector) + (vector->string vector start) + (vector->string vector start end) + + Function return new string created from vector of characters in given range. + If no start is given it create string from 0, if no end is given it return + string to the end." + (typecheck "vector->string" vector "array") + (--> vector + (slice start end) + (map (lambda (char) (char.valueOf))) + (join ""))) + +;; ----------------------------------------------------------------------------- +(%range-function + (vector-fill! vector fill) + "(vector-fill! vector fill) + (vector-fill! vector fill start) + (vector-fill! vector fill start end) + + Fill vector with a given value in given range. If start is not given is start + at 0. If end is not given it fill till the end if the vector." + (typecheck "vector->fill!" vector "array") + (let recur ((n (- end start))) + (if (>= n start) + (begin + (set-obj! vector n fill) + (recur (- n 1)))))) + ;; ----------------------------------------------------------------------------- (define-syntax let*-values (syntax-rules () @@ -217,22 +291,6 @@ returns #f." (and (integer? n) (exact? n))) -;; ----------------------------------------------------------------------------- -(define (string->vector s) - "(string->vector string) - - Function return vector of characters created from string." - (typecheck "string->list" s "string") - (--> s (split "") (map (lambda (x) (lips.LCharacter x))))) - -;; ----------------------------------------------------------------------------- -(define (vector->string v) - "(vector->string vector) - - Function return new string created from vector of characters." - (typecheck "vector->list" v "array") - (--> v (map (lambda (char) (char.valueOf))) (join ""))) - ;; ----------------------------------------------------------------------------- (define (vector-map fn . rest) "(vector-map fn vector1 vector2 ...) @@ -376,8 +434,8 @@ ;; based on https://srfi.schemers.org/srfi-0/srfi-0.html ;; ----------------------------------------------------------------------------- (define-syntax cond-expand - (syntax-rules (and or not else r7rs srfi-0 srfi-4 srfi-6 srfi-10 srfi-22 - srfi-23 srfi-46 srfi-176 lips complex full-unicode + (syntax-rules (and or not else r7rs srfi-0 srfi-2 srfi-4 srfi-6 srfi-10 + srfi-22 srfi-23 srfi-46 srfi-176 lips complex full-unicode ieee-float ratios exact-complex full-numeric-tower) ((cond-expand) (syntax-error "Unfulfilled cond-expand")) ((cond-expand (else body ...)) @@ -410,6 +468,8 @@ (begin body ...)) ((cond-expand (srfi-0 body ...) more-clauses ...) (begin body ...)) + ((cond-expand (srfi-2 body ...) more-clauses ...) + (begin body ...)) ((cond-expand (srfi-4 body ...) more-clauses ...) (begin body ...)) ((cond-expand (srfi-6 body ...) more-clauses ...) @@ -441,7 +501,7 @@ ;; ----------------------------------------------------------------------------- (define (features) - '(r7rs srfi-0 srfi-4 srfi-6 srfi-10 srfi-22 srfi-23 srfi-46 srfi-176 lips + '(r7rs srfi-0 srfi-2 srfi-4 srfi-6 srfi-10 srfi-22 srfi-23 srfi-46 srfi-176 lips complex full-unicode ieee-float ratios exact-complex full-numeric-tower)) ;; ----------------------------------------------------------------------------- @@ -544,6 +604,13 @@ (define string->utf8 (let ((encoder (new TextEncoder "utf-8"))) (lambda (string . rest) + "(string->utf8 string) + (string->utf8 string start) + (string->utf8 string start end) + + Function converts string into u8 bytevector using utf8 encoding. + The start and end is the range of the input string for the conversion." + (typecheck "string->utf8" string "string") (if (null? rest) (encoder.encode string) (let* ((start (car rest)) @@ -555,6 +622,13 @@ (define utf8->string (let ((decoder (new TextDecoder "utf-8"))) (lambda (v . rest) + "(utf8->string u8vector) + (utf8->string u8vector start) + (utf8->string u8vector start end) + + Function converts u8 bytevector into string using utf8 encoding. + The start and end is the range of the input byte vector for the conversion." + (typecheck "utf8->string" v "uint8array") (if (null? rest) (decoder.decode v) (let* ((start (car rest)) @@ -579,6 +653,27 @@ and after finish get the whole string using `get-output-string`." (new lips.OutputStringPort repr)) +;; ----------------------------------------------------------------------------- +(define (open-output-bytevector) + "(open-output-bytevector) + + Create new output port that can be used to write binary data. + After done with the data the output buffer can be obtained by calling + `get-output-bytevector` function." + (new lips.OutputByteVectorPort)) + +;; ----------------------------------------------------------------------------- +(define (get-output-bytevector port) + "(get-output-string port) + + Function get full string from string port. If nothing was wrote + to given port it will return empty string." + (if (not (instanceof lips.OutputByteVectorPort port)) + (throw (new Error (string-append + "get-output-bytevector: expecting output-bytevector-port get " + (type port)))) + (port.valueOf))) + ;; ----------------------------------------------------------------------------- (define (get-output-string port) "(get-output-string port) @@ -588,19 +683,194 @@ (if (not (instanceof lips.OutputStringPort port)) (throw (new Error (string-append "get-output-string: expecting output-string-port get " (type port)))) - (port.getString))) + (port.valueOf))) + +;; ----------------------------------------------------------------------------- +(define (open-input-bytevector bytevector) + "(open-input-bytevector bytevector) + + Create new input binary port with given bytevector" + (typecheck "open-input-bytevector" bytevector "uint8array") + (new lips.InputByteVectorPort bytevector)) + +;; ----------------------------------------------------------------------------- +(define (open-binary-input-file filename) + "(open-binary-input-file filename) + + Function return new Input Binary Port with given filename. In Browser + user need to provide global fs variable that is instance of FS interface." + (let ((u8vector (buffer->u8vector (%read-binary-file filename)))) + (new lips.InputBinaryFilePort u8vector filename))) + +;; ----------------------------------------------------------------------------- +(define (binary-port? port) + "(binary-port? port) + + Function test if argument is binary port." + (and (port? port) (eq? port.__type__ (Symbol.for "binary")))) + +;; ----------------------------------------------------------------------------- +(define (textual-port? port) + "(textual-port? port) + + Function test if argument is string port." + (and (port? port) (eq? port.__type__ (Symbol.for "text")))) + +;; ----------------------------------------------------------------------------- +(define-macro (%define-binary-input-lambda name docstring fn) + (let ((port (gensym)) + (name-str (symbol->string name))) + `(define (,name . rest) + ,docstring + (let ((,port (if (null? rest) + (current-input-port) + (car rest)))) + (typecheck ,name-str ,port "input-port") + (if (not (binary-port? ,port)) + (throw (new Error (string-append ,name-str + " invalid port. Binary port required."))) + (,fn ,port)))))) + +;; ----------------------------------------------------------------------------- +(%define-binary-input-lambda + peek-u8 + "(peek-u8) + (peek-u8 port) + + Return next byte from input-binary port. If there are no more bytes + it return eof object." + (lambda (port) + (port.peek_u8))) + +;; ----------------------------------------------------------------------------- +(%define-binary-input-lambda + read-u8 + "(read-u8) + (read-u8 port) + + Read next byte from input-binary port. If there are no more bytes + it return eof object." + (lambda (port) + (port.read_u8))) + +;; ----------------------------------------------------------------------------- +(%define-binary-input-lambda + u8-ready? + "(u8-ready?) + (u8-ready? port) + + Returns #t if a byte is ready on the binary input port and returns #f otherwise. + If u8-ready? returns #t then the next read-u8 operation on the given port is + guaranteed not to hang. If the port is at end of file then u8-ready? returns #t." + (lambda (port) + (port.u8_ready))) + +;; ----------------------------------------------------------------------------- +(define (read-bytevector k . rest) + "(read-bytevector k) + (read-bytevector k port) + + Read next n bytes from input-binary port. If there are no more bytes + it returns eof object. If there are less then n bytes in port it + return the only bytes that are available" + (let ((port (if (null? rest) + (current-input-port) + (car rest)))) + (typecheck "read-bytevector" port "input-port") + (if (not (binary-port? port)) + (throw (new Error "read-bytevector: invalid port")) + (port.read_u8_vector k)))) + +;; ----------------------------------------------------------------------------- +(define-macro (%define-binary-output-lambda name type docstring fn) + (let ((port (gensym 'port)) + (data (gensym 'data)) + (name-str (symbol->string name))) + `(define (,name ,data . rest) + ,docstring + (let ((,port (if (null? rest) + (current-output-port) + (car rest)))) + (typecheck ,name-str ,port "output-port") + (typecheck ,name-str ,data ,type) + (if (not (binary-port? ,port)) + (throw (new Error (string-append ,name-str + " invalid port. Binary port required."))) + (,fn ,data ,port)))))) + +;; ----------------------------------------------------------------------------- +(%define-binary-output-lambda + write-u8 + "number" + "(write-u8 byte) + (write-u8 byte port) + + Write byte into binary output port." + (lambda (data port) + (port.write_u8 data))) + +;; ----------------------------------------------------------------------------- +(%define-binary-output-lambda + write-bytevector + "uint8array" + "(write-bytevector bytevector) + (write-bytevector bytevector port) + + Write byte vector into binary output port." + (lambda (data port) + (port.write_u8_vector data))) + +;; ----------------------------------------------------------------------------- +(define open-binary-output-file + (let ((open)) + (lambda (filename) + "(open-binary-output-file filename) + + Function open file and return port that can be used for writing. If file + exists it will throw an Error." + (typecheck "open-output-file" filename "string") + (if (not (procedure? open)) + (set! open (%fs-promisify-proc 'open "open-binary-output-file"))) + (if (file-exists? filename) + (throw (new Error "open-binary-output-file: file exists")) + (lips.OutputBinaryFilePort filename (open filename "w")))))) + +;; ----------------------------------------------------------------------------- +(define (read-bytevector! vector . rest) + "(read-bytevector! bytevector) + (read-bytevector! bytevector port) + (read-bytevector! bytevector port start) + (read-bytevector! bytevector port start end) + + Function read next bytes from binary input port and write them into byte vector. + if not start is specified it start to write into 0 position of the vector until + the end or end the vector if no end is specified." + (typecheck "read-bytevector!" vector "uint8array") + (let ((port (if (null? rest) (current-input-port) (car rest))) + (start (if (or (null? rest) (null? (cdr rest))) 0 (cadr rest))) + (end (if (or (null? rest) (null? (cdr rest)) (null? (cddr rest))) + (bytevector-length vector) + (caddr rest)))) + (typecheck "read-bytevector!" port "input-port") + (if (not (binary-port? port)) + (throw (new Error "read-bytevector!: invalid port. Binary port required.")) + (begin + (typecheck "read-bytevector!" start "number") + (typecheck "read-bytevector!" end "number") + (let ((out (read-bytevector (- end start) port))) + (vector.set out start end)))))) ;; ----------------------------------------------------------------------------- (define delete-file (let ((unlink #f)) (lambda (filename) + "(delete-file filename) + + Function delete the file of given name." (typecheck "delete-file" filename "string") - (if (null? self.fs) - (throw (new Error "delete-file: fs not defined")) - (begin - (if (not (procedure? unlink)) - (set! unlink (promisify fs.unlink))) - (unlink filename)))))) + (if (not (procedure? unlink)) + (set! unlink (%fs-promisify-proc 'unlink "delete-file"))) + (unlink filename)))) ;; ----------------------------------------------------------------------------- (define (call-with-port port proc) @@ -683,7 +953,6 @@ (display (string char) port))) ;; ----------------------------------------------------------------------------- - (define (read-string k . rest) "(read-string k) (read-string k port) @@ -697,3 +966,256 @@ (let ((port (if (null? rest) (current-input-port) (car rest)))) (typecheck "read-string" port "input-port") (port.read_string k))) + +;; ----------------------------------------------------------------------------- +(define (list-copy obj) + "(list-copy obj) + + Copy the object passed as argument but only if it's list. The car elements + of the list are not copied, they are passed as is." + (typecheck "list-copy" obj #("pair" "nil")) + (if (null? obj) + obj + (obj.clone false))) + +;; ----------------------------------------------------------------------------- +(define-macro (define-record-type name constructor pred . fields) + "(define-record-type name constructor pred . fields) + + Macro for defining records. Example of usage: + + (define-record-type + (kons x y) + pare? + (x kar set-kar!) + (y kdr set-kdr!)) + + (define p (kons 1 2)) + (print (kar p)) + ;; 1 + (set-kdr! p 3) + (print (kdr p)) + ;; 3" + (let ((class-name (gensym)) + (obj-name (gensym)) + (value-name (gensym))) + `(begin + (define ,class-name (class Object + (constructor (lambda (self ,@(cdr constructor)) + ,@(map (lambda (field) + (let* ((name (symbol->string field)) + (prop (string-append "self." + name))) + `(set! ,(string->symbol prop) ,field))) + (cdr constructor)))) + (toType (lambda (self) + "record")) + (toString (lambda (self) + ,(symbol->string name))))) + (define ,constructor + (new ,class-name ,@(cdr constructor))) + (define (,pred obj) + (instanceof ,class-name obj)) + ,@(map (lambda (field) + (let ((prop-name (car field)) + (get (cadr field)) + (set (if (null? (cddr field)) + nil + (caddr field)))) + `(begin + (define (,get ,obj-name) + (typecheck ,(symbol->string get) ,obj-name "record") + (if (not (,pred ,obj-name)) + (throw (new Error ,(string-append "object is not record of type " + (symbol->string name)))) + (. ,obj-name ',prop-name))) + ,(if (not (null? set)) + `(define (,set ,obj-name ,value-name) + (typecheck ,(symbol->string get) ,obj-name "record") + (if (not (,pred ,obj-name)) + (throw (new Error ,(string-append "object is not record of type " + (symbol->string name)))) + (set-obj! ,obj-name ',prop-name ,value-name))))))) + fields)))) + +;; ----------------------------------------------------------------------------- +(define (nan? x) + "(nan? x) + + Function check if argument x is Not a Number (NaN) value." + (and (number? x) + (or (x.isNaN) + (and (%number-type "complex" x) + (or (nan? (real-part x)) + (nan? (imag-part x))))))) + +;; ----------------------------------------------------------------------------- +(define (infinite? x) + "(infinite? x) + + Function check if value is infinite." + (or (eq? x Number.NEGATIVE_INFINITY) + (eq? x Number.POSITIVE_INFINITY) + (and (number? x) + (not (eq? x NaN)) + (%number-type "complex" x) + (or (infinite? (real-part x)) + (infinite? (imag-part x)))))) + +;; ----------------------------------------------------------------------------- +(define (finite? x) + "(finite? x) + + Function check if value is finite." + (not (infinite? x))) + +;; ----------------------------------------------------------------------------- +(define-class %Library Object + (constructor + (lambda (self name) + (set! self.__namespace__ &()) + (set! self.__name__ name))) + (append + (lambda (self namespace env) + (if (environment? (. self.__namespace__ namespace)) + (throw (new Error (string-append "namespace " namespace + " already exists in library " + self.__name__))) + (set-obj! self.__namespace__ namespace env)))) + (env + (lambda (self namespace) + (let ((env (. self.__namespace__ namespace))) + (if (not (environment? env)) + (throw (new Error (string-append "namespace " namespace " sdon't exists"))) + env)))) + (get + (lambda (self namespace name) + (--> (self.env namespace) (get name)))) + (set + (lambda (self namespace name value) + (--> (self.env namespace) (set name value)))) + (toString + (lambda (self) + (string-append "#")))) + +;; ----------------------------------------------------------------------------- +(define (%import-name library namespace names) + `(begin + ,@(map (lambda (name) + `(define ,name (--> ,library (get ',namespace ',name)))) + names))) + +;; ----------------------------------------------------------------------------- +(define-macro (import . specs) + "(import (library namespace)) + (import (only (library namespace) name1 name2)) + + Macro for importing names from library." + (let ((parent (current-environment))) + `(begin + ,@(map (lambda (spec) + (if (not (pair? spec)) + (throw (new Error "import: invalid syntax")) + (cond ((symbol=? (car spec) + 'only) + (let ((lib (caadr spec)) + (namespace (caaddr spec))) + (if (pair? (cadr spec)) + (%import-name ,lib + ',namespace + ',(caddr spec)) + (throw (new Error "import: invalid syntax"))))) + (else + (let* ((lib-name (car spec)) + (lib (parent.get lib-name)) + (namespace (cadr spec))) + (%import-name lib-name + namespace + (env (lib.env namespace)))))))) + specs)))) + +;; ----------------------------------------------------------------------------- +(define (new-library name namespace) + "(new-library name) + + Create new empty library object with empty namespace." + (let* ((parent (. (current-environment) '__parent__)) + (lib (let ((lib (--> parent (get name &(:throwError false))))) + (if (null? lib) + (new %Library name) + lib))) + (x (new lips.Environment + (string-append "library-" + (--> name (toLowerCase)) + "-" + (--> namespace (toLowerCase)))))) + (lib.append namespace x) + lib)) + +;; ----------------------------------------------------------------------------- +(define (%export module namespace specs) + `(begin + ,@(map (lambda (expr) + (cond ((symbol? expr) + `(--> ,module (set ',namespace + ',expr + ,expr))) + ((and (pair? expr) (symbol=? (car expr) + 'rename)) + `(--> ,module (set ',namespace + ',(cadr expr) + ,(caddr expr)))))) + specs))) + +;; ----------------------------------------------------------------------------- +(define-macro (define-library spec . body) + "(define-library (library (name namespace) . body) + + Macro for defining modules inside you can use define to create functions. + And use export name to add that name to defined environment." + (let ((parent (. (current-environment) '__parent__)) + (module-var (gensym)) + (namespace-var (gensym)) + (name (car spec)) + (namespace (cadr spec))) + `(let ((,module-var (new-library ,(symbol->string name) + ,(symbol->string namespace))) + (,namespace-var ',namespace)) + (define-macro (export . body) + (%export ,module-var ,namespace-var body)) + ,@body + (--> ,parent (set ',name ,module-var))))) + +;; ----------------------------------------------------------------------------- +(define-values (current-directory set-current-directory!) + (if (eq? self window) + (let ((cwd (string-append location.origin (--> location.pathname + (replace #/\/[^/]+$/ "/"))))) + (values + (lambda () + "(current-directory) + + Return corrent working directory, default it's corrent URL." + cwd) + (lambda (value) + "(set-current-directory! string) + + Function change current working directory to provided string." + (typecheck "set-current-directory!" value "string") + (set! cwd value)))) + (let ((process (require "process"))) + (values + (lambda () + "(current-directory) + + Return corrent working directory, default it's path from where + the script was executed." + (string-append (process.cwd) "/")) + (lambda (value) + "(set-current-directory! string) + + Function change current working directory to provided string." + (typecheck "set-current-directory!" value "string") + (process.chdir value)))))) + +;; ----------------------------------------------------------------------------- diff --git a/lib/bootstrap.scm b/lib/bootstrap.scm old mode 100644 new mode 100755 index 919c96ac..389151e8 --- a/lib/bootstrap.scm +++ b/lib/bootstrap.scm @@ -82,14 +82,18 @@ (on \"click\" (lambda () (display \"click\")))) (--> document (querySelectorAll \"div\")) + (--> (fetch \"https://jcubic.pl\") (text) (match #/([^<]+)<\\/title>/) 1) + (--> document (querySelectorAll \".cmd-prompt\") 0 - \"innerText\") + 'innerHTML + (replace #/<(\"[^\"]+\"|[^>])+>/g \"\")) + (--> document.body (style.setProperty \"--color\" \"red\"))" (let ((obj (gensym "obj"))) @@ -170,7 +174,17 @@ expr `(. ,(string->symbol (car parts)) ,@(cdr parts)))))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- +(set-special! "#:" 'gensym-interal) + +;; ----------------------------------------------------------------------------- +(define (gensym-interal symbol) + "(gensym-interal symbol) + + Parser extension that create new quoted named gensym." + `(quote ,(gensym symbol))) + +;; ----------------------------------------------------------------------------- (define (plain-object? x) "(plain-object? x) @@ -178,7 +192,7 @@ ;; here we don't use string=? or equal? because it may not be defined (and (== (--> (type x) (cmp "object")) 0) (eq? (. x 'constructor) Object))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define typed-array? (let ((TypedArray (Object.getPrototypeOf Uint8Array))) (lambda (o) @@ -211,7 +225,7 @@ Function convert alist pairs to JavaScript object." (if (pair? alist) - (alist.toObject) + (alist.to_object) (alist->object (new lips.Pair undefined nil)))) ;; ----------------------------------------------------------------------------- @@ -351,7 +365,7 @@ ;; ----------------------------------------------------------------------------- (define (%hidden-props obj) "(%hidden-props obj) - + Function return hidden names of an object, for ES6 class prototype it return all methods since they are indistinguishable from hidden property created using defineProperty." @@ -375,9 +389,10 @@ (set! names (--> names (filter (lambda (name) (not (hidden.includes name)))))))) - (append (array->list names) (dir (Object.getPrototypeOf obj) true))))) + (append (array->list (--> names (map (unary string->symbol)))) + (dir (Object.getPrototypeOf obj) true))))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (tree-map f tree) "(tree-map fn tree) @@ -485,7 +500,7 @@ Helper macro used by cond.") - +;; ----------------------------------------------------------------------------- (define-macro (cond . list) "(cond (predicate? . body) (predicate? . body)) @@ -675,7 +690,7 @@ nil (cons (map car args) (apply zip (map cdr args)))))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define-macro (promise . body) "(promise . body) @@ -685,7 +700,7 @@ (catch (e) (error (.. e.message))))))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define-macro (timer time . body) "(timer time . body) @@ -693,14 +708,14 @@ native JS clearTimeout function." `(setTimeout (lambda () (try (begin ,@body) (catch (e) (error (.. e.message))))) ,time)) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (defmacro? obj) "(defmacro? expression) Function check if object is macro and it's expandable." (and (macro? obj) (. obj 'defmacro))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (n-ary n fn) "(n-ary n fn) @@ -708,7 +723,7 @@ (lambda args (apply fn (take n args)))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (take n lst) "(take n list) @@ -718,21 +733,21 @@ (reverse result) (iter (cons (car lst) result) (- i 1) (cdr lst))))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define unary (%doc "(unary fn) Function return new function with arguments limited to one." (curry n-ary 1))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define binary (%doc "(binary fn) Function return new function with arguments limited to two." (curry n-ary 2))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- ;; LIPS Object System -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (%class-lambda expr) "(class-lambda expr) @@ -755,7 +770,7 @@ `(lambda (,@args) (,(cadr expr) this ,@args)))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (%class-method-name expr) "(%class-method-name expr) @@ -764,7 +779,7 @@ (car expr) (list 'quote expr))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define-macro (define-class name parent . body) "(define-class name parent . body) @@ -801,7 +816,7 @@ (iter functions item (cdr lst)) (iter (cons item functions) constructor (cdr lst))))))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define-syntax class (syntax-rules () ((_) @@ -814,7 +829,7 @@ Macro allow to create anonymous classes. See define-class for details.") -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (make-tags expr) "(make-tags expression) @@ -829,7 +844,7 @@ `(list->array (list ,@(map make-tags (cdaddr expr)))) (caddr expr))))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (%sxml h expr) "(%sxml h expr) @@ -861,20 +876,24 @@ rest) (list first))))))) -;; --------------------------------------------------------------------------------------- -(define-macro (sxml expr) - "(sxml expr) +;; ----------------------------------------------------------------------------- +(define-macro (pragma->sxml pragma) + `(define-macro (sxml expr) + "(sxml expr) - Macro for JSX like syntax but with SXML. - e.g. usage: + Macro for JSX like syntax but with SXML. + e.g. usage: - (sxml (div (@ (data-foo \"hello\") - (id \"foo\")) - (span \"hello\") - (span \"world\")))" - (%sxml 'h expr)) + (sxml (div (@ (data-foo \"hello\") + (id \"foo\")) + (span \"hello\") + (span \"world\")))" + (%sxml ',pragma expr))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- +(pragma->sxml h) + +;; ----------------------------------------------------------------------------- (define-macro (with-tags expr) "(with-tags expression) @@ -890,7 +909,7 @@ To get the string from the macro you can use vhtml library from npm." (make-tags expr)) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (get-script url) "(get-script url) @@ -907,28 +926,28 @@ (if document.head (document.head.appendChild script))))))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (gensym? value) "(gensym? value) Function return #t if value is symbol and it's gensym. It returns #f otherwise." (and (symbol? value) (--> value (is_gensym)))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (degree->radians x) "(degree->radians x) Convert degree to radians." (* x (/ Math.PI 180))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (radians->degree x) "(radians->degree x) Convert radians to degree." (* x (/ 180 Math.PI))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define-syntax while (syntax-rules () ((_ predicate body ...) @@ -939,7 +958,7 @@ Macro that create a loop, it exectue body until cond expression is false.") -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define-syntax ++ (syntax-rules () ((++ x) @@ -950,7 +969,7 @@ Macro that work only on variables and increment the value by one.") -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define-syntax -- (syntax-rules () ((-- x) @@ -961,7 +980,7 @@ Macro that decrement the value it work only on symbols") -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (pretty-format pair) "(pretty-format pair) @@ -969,7 +988,7 @@ (typecheck "pretty-pair" pair "pair") (--> (new lips.Formatter (repr pair true)) (break) (format))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (reset) "(reset) @@ -981,14 +1000,14 @@ (if (not (--> defaults (includes name))) (--> env (unset name))))))))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (make-list n . rest) (if (or (not (integer? n)) (<= n 0)) (throw (new Error "make-list: first argument need to be integer larger then 0")) (let ((fill (if (null? rest) undefined (car rest)))) (array->list (--> (new Array n) (fill fill)))))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (range n) "(range n) @@ -996,7 +1015,7 @@ (typecheck "range" n "number") (array->list (--> (new Array n) (fill 0) (map (lambda (_ i) i))))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define-macro (do-iterator spec cond . body) "(do-iterator (var expr) (test) body ...) @@ -1035,21 +1054,21 @@ (set! ,item (,next)) (set! ,name (. ,item "value"))))))))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (set-repr! Set (lambda () "#<Set>")) (set-repr! Map (lambda () "#<Met>")) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (native-symbol? x) "(native-symbol? object) Function check if value is JavaScript symbol." (and (string=? (type x) "symbol") (not (symbol? x)))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (set-special! "’" 'warn-quote) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define-macro (warn-quote) "(warn-quote) @@ -1058,7 +1077,7 @@ "(set-special! \"’\" 'quote)" " to allow running this type of quote")))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define-macro (quote-promise expr) "(quote-promise expr) '>expr @@ -1071,13 +1090,13 @@ (env.set (Symbol.for "__promise__") true) ,expr)) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (await value) (if (instanceof lips.QuotedPromise value) (value.valueOf) value)) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define-macro (let-env-values env spec . body) "(let-env-values env ((name var)) . body) @@ -1090,52 +1109,19 @@ spec) ,@body)))) -;; --------------------------------------------------------------------------------------- -(define-macro (let-std spec . body) - "(let-std ((name var)) . body) - - Macro that create aliases for variables in global environment. - This is needed so user don't change constants like stdin or stdout - that use taken from lexical scope. The function still can use those - from interaction-environment." - `(let-env-values lips.env.__parent__ ,spec ,@body)) - -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define (apropos name) "(apropos name) Search environment and display names that match the given name. - name can be regex or string." - (typecheck "apropos" name '("string" "regex")) - (filter (if (string? name) - (new RegExp name) - name) - (env))) - -;; --------------------------------------------------------------------------------------- -;; SRFI-10 https://srfi.schemers.org/srfi-10/srfi-10.html -;; --------------------------------------------------------------------------------------- -(set-special! "#," 'sharp-comma) - -(define **reader-ctor-list** '()) - -;; --------------------------------------------------------------------------------------- -(define (define-reader-ctor symbol fn) - (let ((node (assoc symbol **reader-ctor-list**))) - (if (pair? node) - (set-cdr! node fn) - (set! **reader-ctor-list** (cons (cons symbol fn) - **reader-ctor-list**))))) - -;; --------------------------------------------------------------------------------------- -(define-syntax sharp-comma - (syntax-rules () - ((_ (fn arg ...)) - (let ((node (assoc 'fn **reader-ctor-list**))) - (if (pair? node) - ((cdr node) 'arg ...) - (syntax-error (string-append "Invalid symbol " (symbol->string 'fn) - " in expression " (repr '(fn arg ...))))))))) + name can be regex, string or symbol." + (typecheck "apropos" name '("string" "regex" "symbol")) + (let ((regex (lambda (string) + (new RegExp (escape-regex string))))) + (filter (cond ((string? name) (regex name)) + ((symbol? name) (regex (symbol->string name))) + (else name)) + (env)))) ;; ----------------------------------------------------------------------------- (define (promisify fn) @@ -1150,7 +1136,7 @@ (resolve data) (reject err)))))))))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define-macro (list* . args) "(list* arg1 ...) @@ -1162,7 +1148,7 @@ args) (map await (vector->list ,result))))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define-macro (%not-implemented name) "(not-implemented name) @@ -1172,7 +1158,7 @@ ,(string-append "(" str-name ")\n\nThis function is not yet implemented.") (throw (new Error ,(string-append str-name " has not beed implemented")))))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define-macro (%make-env name . names) "(%make-env name f1 f2 ...) @@ -1188,7 +1174,7 @@ null ,name)) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- (define Y (lambda (h) "(Y f) @@ -1205,4 +1191,192 @@ (lambda (g) (h (lambda args (apply (g g) args))))))) -;; --------------------------------------------------------------------------------------- +;; ----------------------------------------------------------------------------- +(define (indexed-db?) + "(indexed-db?) + + Function test if indexedDB is available." + (let* ((any (lambda args + (let iter ((args args)) + (if (null? args) + false + (if (not (null? (car args))) + (car args) + (iter (cdr args))))))) + (indexedDB (any window.indexedDB + window.indexedDB + window.mozIndexedDB + window.webkitIndexedDB))) + (if (not (null? indexedDB)) + (try + (begin + ;; open will fail in about:blank + (window.indexedDB.open "MyTestDatabase" 3) + true) + (catch (e) + false)) + false))) + +;; ----------------------------------------------------------------------------- +;; init internal fs for LIPS Scheme Input/Output functions +;; ----------------------------------------------------------------------------- +(let* ((fs (cond ((eq? self global) (require "fs")) + ((and (not (null? self.BrowserFS)) (indexed-db?)) + (new Promise (lambda (resolve reject) + (BrowserFS.configure + &(:fs "IndexedDB" + :options &()) + (lambda (e) + (if (null? e) + (resolve (BrowserFS.BFSRequire "fs")) + (reject e))))))) + ((not (null? self.BrowserFS)) + (console.warn (string-append "BrowserFS not initilalized " + "IndexedDB is not available")) + nil))) + (Buffer (cond ((eq? self global) + self.Buffer) + ((not (null? self.BrowserFS)) + (. (BrowserFS.BFSRequire "buffer") 'Buffer))))) + (let ((internal (lips.env.get '**internal-env**))) + (if (not (null? Buffer)) + (internal.set "Buffer" Buffer)) + (if (not (null? fs)) + (internal.set "fs" fs)))) + +;; ----------------------------------------------------------------------------- +(define (environment? obj) + "(environment? obj) + + Function check if object is LIPS environment." + (instanceof lips.Environment obj)) + +;; ----------------------------------------------------------------------------- +(define %read-file + (let ((read-file #f) (fetch-url #f)) + (lambda (binary path) + "(%read-file binary path) + + Read file from url or file system. If binary is false it will return + string that contain all the content. For HTTP requests, If binary + is false it will: when in browser return ArrayBuffer and in Node + it will return Buffer object. When reading from file system + in both cases it will return Buffer objects. + + The code that use those function, in binary mode, need to check + if the result is ArrayBuffer or Node.js/BrowserFS Buffer object." + (if (not read-file) + (let ((fs (--> lips.env (get '**internal-env**) (get 'fs)))) + (if (null? fs) + (throw (new Error "open-input-file: fs not defined")) + (let ((*read-file* (promisify fs.readFile))) + (set! read-file (lambda (path binary) + (let ((buff (*read-file* path))) + (if binary + (if (eq? self window) + (new Blob (vector buff)) + buff) + (--> buff (toString)))))))))) + (if (not fetch-url) + (set! fetch-url (lambda (url binary) + (if (eq? self window) + (let ((res (fetch url))) + (if binary + (res.arrayBuffer) + (res.text))) + (http-get url binary))))) + (cond ((char=? (string-ref path 0) #\/) + (if (not (file-exists? path)) + (throw (new Error (string-append "file " + path + " don't exists"))) + (read-file path binary))) + ((--> #/^https?:\/\// (test path)) + (fetch-url path binary)) + (else + (%read-file binary (string-append (current-directory) path))))))) + +;; ----------------------------------------------------------------------------- +(define %read-binary-file (curry %read-file true)) +(define %read-text-file (curry %read-file false)) + +;; ----------------------------------------------------------------------------- +(define (%fs-promisify-proc fn message) + "(%fs-promisify-proc fn string) + + Function return promisified version of fs function or throw exception + if fs is not available." + (let ((fs (--> lips.env (get '**internal-env**) (get 'fs)))) + (if (null? fs) + (throw (new Error (string-append message ": fs not defined"))) + (promisify (. fs fn))))) + +;; ----------------------------------------------------------------------------- +(define (response->content binary res) + "(response->text binary res) + + Function read all text from Node.js HTTP response object. If binary argument + is true it will return Buffer object that can be converted to u8vector. + + ***Warrning:*** it may overflow the stack (part of Node) when converting + whole buffer to u8vector." + (let ((result (vector)) + (append (if binary + (lambda (chunk) + (result.push (Buffer.from chunk "binary"))) + (lambda (chunk) + (result.push chunk))))) + (res.setEncoding (if binary "binary" "utf8")) + (new Promise (lambda (resolve) + (res.on "data" append) + (res.on "end" (lambda () + (if binary + (resolve (Buffer.concat result)) + (resolve (result.join ""))))))))) + +;; ----------------------------------------------------------------------------- +(define response->buffer (curry response->content true)) +(define response->text (curry response->content false)) + +;; ----------------------------------------------------------------------------- +(define http-get + (if (eq? self window) + (lambda (url binary) + "(http-get url) + + Node.js Function that send HTTP Request and return string or + binary Buffer object." + (throw (new Error "http-get: function is Node.js only."))) + (let* ((http (. (require "http") 'get)) + (https (. (require "https") 'get))) + (lambda (url binary) + "(http-get url) + + Node.js Function that send HTTP Request and return string or + binary Buffer object." + (let ((request (if (null? (url.match #/^https/)) http https))) + (new Promise + (lambda (resolve reject) + (--> (request url + (lambda (res) + (if (= res.statusCode 200) + (resolve (response->content binary res)) + (let ((code res.statusCode)) + (res.resume) + (reject (string-append + "Request return " + (number->string code))))))) + (on "error" reject))))))))) + +;; ----------------------------------------------------------------------------- +(define (buffer->u8vector bin) + "(buffer->u8vector bin) + + Cross platform function that can be used in both Node and Browser. + It can be used together with %read-file or %read-binary-file and convert + the result ArrayBuffer or Buffer to u8vector." + (if (instanceof ArrayBuffer bin) + (new Uint8Array bin) + (Uint8Array.from bin))) + +;; ----------------------------------------------------------------------------- diff --git a/lib/byte-vectors.scm b/lib/byte-vectors.scm index 28e297b5..5037e2ad 100644 --- a/lib/byte-vectors.scm +++ b/lib/byte-vectors.scm @@ -1,11 +1,11 @@ ;; Implementation of byte vector functions - SRFI-4 ;; -;; original code was ased on https://small.r7rs.org/wiki/NumericVectorsCowan/17/ +;; original code was based on https://small.r7rs.org/wiki/NumericVectorsCowan/17/ ;; it use JavaScript typed arrays ;; https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays ;; ;; This file is part of the LIPS - Scheme based Powerful lisp in JavaScript -;; Copyright (C) 2019-2021 Jakub T. Jankiewicz <https://jcubic.pl> +;; Copyright (C) 2019-2021 Jakub T. Jankiewicz <https://jcubic.pl/me> ;; Released under MIT license ;; @@ -51,7 +51,7 @@ v.length) ;; ----------------------------------------------------------------------------- (define (,make-vector k . fill) - ,(format "(~a v1 v2 ...) + ,(format "(~a k fill) Allocate new ~a of length k, with optional initial values." make-vector diff --git a/lib/css/terminal.css b/lib/css/terminal.css index 6e2f2186..9a6f0069 100644 --- a/lib/css/terminal.css +++ b/lib/css/terminal.css @@ -50,6 +50,7 @@ margin: 0; width: 100%; height: auto; + display: block; } .shell-container { position: fixed; diff --git a/lib/js/bookmark.js b/lib/js/bookmark.js old mode 100644 new mode 100755 index 41c448ce..eb95c035 --- a/lib/js/bookmark.js +++ b/lib/js/bookmark.js @@ -102,7 +102,7 @@ javascript:(function(next) { var path = `https://cdn.jsdelivr.net/gh/jcubic/lips@${REF}/`; term.exec([ '(let ((e lips.env.__parent__))', - '(load "' + path + 'dist/std.scm" e))' + '(load "' + path + 'dist/std.min.scm" e))' ].join('\n'), true); } function format_baner(banner) { @@ -113,7 +113,7 @@ javascript:(function(next) { track(); } [ - 'https://cdn.jsdelivr.net/npm/jquery.terminal/css/jquery.terminal.min.css', + 'https://cdn.jsdelivr.net/gh/jcubic/jquery.terminal/css/jquery.terminal.min.css', 'https://cdn.jsdelivr.net/gh/jcubic/lips@devel/lib/css/terminal.css', 'https://cdn.jsdelivr.net/gh/jcubic/terminal-prism/css/prism-coy.css' ].forEach(function(url) { @@ -140,6 +140,7 @@ javascript:(function(next) { `gh/jcubic/lips@${REF}/lib/js/prism.js`, 'npm/js-polyfills/keyboard.js' ].join(','), + 'https://cdn.jsdelivr.net/npm/browserfs@1.x.x/dist/browserfs.min.js' ]; (function recur() { var script = scripts.shift(); diff --git a/lib/js/codemirror.js b/lib/js/codemirror.js index b09efae8..fad7b709 100644 --- a/lib/js/codemirror.js +++ b/lib/js/codemirror.js @@ -11,8 +11,7 @@ mod(CodeMirror); })(function(CodeMirror) { "use strict"; - - + CodeMirror.defineMode("lips", function () { var BUILTIN = "builtin", COMMENT = "comment", STRING = "string", ATOM = "atom", NUMBER = "number", BRACKET = "bracket", REGEX = 'string-2'; @@ -46,7 +45,7 @@ CodeMirror.defineMode("lips", function () { var hexMatcher = new RegExp(/^(?:[-+]i|[-+][\da-f]+#*(?:\/[\da-f]+#*)?i|[-+]?[\da-f]+#*(?:\/[\da-f]+#*)?@[-+]?[\da-f]+#*(?:\/[\da-f]+#*)?|[-+]?[\da-f]+#*(?:\/[\da-f]+#*)?[-+](?:[\da-f]+#*(?:\/[\da-f]+#*)?)?i|[-+]?[\da-f]+#*(?:\/[\da-f]+#*)?)(?=[()\s;"]|$)/i); var decimalMatcher = new RegExp(/^(?:[-+]i|[-+](?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)i|[-+]?(?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)@[-+]?(?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)|[-+]?(?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)[-+](?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)?i|(?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*))(?=[()\s;"]|$)/i); - var re_re = /^\/((?:\\\/|[^/]|\[[^\]]*\/[^\]]*\])+)\/([gimuy]*)(?=[()\s;"]|$)/i; + var re_re = /^#\/((?:\\\/|[^/]|\[[^\]]*\/[^\]]*\])+)\/([gimuy]*)(?=[()\s;"]|$)/i; function isBinaryNumber (stream) { return stream.match(binaryMatcher); } @@ -90,10 +89,6 @@ CodeMirror.defineMode("lips", function () { var returnType = null; switch(state.mode){ - case 'regex': - readRegexp(stream); - returnType = REGEX; - break; case "string": // multi-line string parsing mode var next, escaped = false; while ((next = stream.next()) != null) { @@ -189,10 +184,6 @@ CodeMirror.defineMode("lips", function () { returnType = NUMBER; } } - } else if (stream.match(/^\/[^\s]/)) { - console.log({REGEX}); - state.mode = "regex"; - returnType = REGEX; } else if (/^[-+0-9.]/.test(ch) && isDecimalNumber(stream, true)) { // match non-prefixed number, must be decimal returnType = NUMBER; } else if (ch == ";") { // comment diff --git a/lib/js/prism.js b/lib/js/prism.js old mode 100644 new mode 100755 index 49efe3a7..1e32cafe --- a/lib/js/prism.js +++ b/lib/js/prism.js @@ -39,6 +39,6 @@ var keyword = Prism.languages.scheme.keyword.pattern; Prism.languages.scheme.keyword.pattern = new RegExp(keyword.source.replace(/\|when/, '|when|set-obj!|let-env|try|catch|throw|raise')); // names should be marked so we can show help message on higher order function that have function as argument Prism.languages.scheme.name = { - pattern: /(^|[()[\]\s])[^#][^()\s]*/g, + pattern: /(^|[()[\]\s])[^#()[\]\s][^()\s]+/g, lookbehind: true }; diff --git a/lib/js/terminal.js b/lib/js/terminal.js old mode 100644 new mode 100755 index 8287c883..31467750 --- a/lib/js/terminal.js +++ b/lib/js/terminal.js @@ -8,7 +8,7 @@ * Copyright (C) Jakub T. Jankiewicz <https://jcubic.pl> * Released under MIT license */ -/* global jQuery, clearTimeout, setTimeout */ +/* global jQuery, $, clearTimeout, setTimeout */ function terminal({selector, lips, dynamic = false, name = 'terminal'}, undefined) { var position; @@ -57,7 +57,20 @@ function terminal({selector, lips, dynamic = false, name = 'terminal'}, undefine if (doc !== undefined) { term.echo(doc, { formatters: false }); } - }), lips.env.get('help').__doc__), + }), help.__doc__), + // --------------------------------------------------------------------- + pprint: doc(function(arg) { + if (arg instanceof lips.Pair) { + arg = new lips.Formatter(arg.toString(true)).break().format(); + if ($.terminal.prism) { + arg = $.terminal.prism('scheme', arg, {echo: true}); + } + this.get('display').call(this, arg); + } else { + this.get('write').call(this, arg); + } + this.get('newline').call(this); + }, lips.env.get('pprint').__doc__), // --------------------------------------------------------------------- 'stack-trace': doc(function() { if (strace) { @@ -155,15 +168,10 @@ function terminal({selector, lips, dynamic = false, name = 'terminal'}, undefine var formatter = new lips.Formatter(code); if (!code.match(/\n/)) { formatter.break(); - output = formatter.format({ - offset: prompt.length - }); - } else { - var space = new Array(prompt.length + 1).join(' '); - output = code.split('\n').map(function(line, i) { - return (i === 0 ? '' : space) + line; - }).join('\n'); } + output = formatter.format({ + offset: prompt.length + }); } catch(e) { console.log(e); // boken LIPS code @@ -195,7 +203,7 @@ function terminal({selector, lips, dynamic = false, name = 'terminal'}, undefine // Array.from is need to for jQuery terminal version <2.5.0 // when terminal is outside iframe and lips is inside // jQuery Terminal was using instanceof that don't work between iframes - var env = Array.from(interpreter.get('env')().toArray()); + var env = Array.from(interpreter.get('env')().to_array()); if (!tokens.length) { return env; } diff --git a/lib/srfi.scm b/lib/srfi.scm new file mode 100644 index 00000000..e4227d17 --- /dev/null +++ b/lib/srfi.scm @@ -0,0 +1,61 @@ +;; ----------------------------------------------------------------------------- +;; SRFI-2 https://srfi.schemers.org/srfi-2/srfi-2.html +;; ----------------------------------------------------------------------------- +(define-syntax and-let* + (syntax-rules () + ((_ ()) #t) + ((_ () body ...) + (let () body ...)) + ((_ ((expression))) ;; last/single expression + expression) + ((_ ((symbol expression)) body ...) ;; last/single pair + (let ((symbol expression)) + (if symbol (begin body ...)))) + ((_ ((symbol expression) expr ...) body ...) ;; lead pair + (let ((symbol expression)) + (and symbol (and-let* (expr ...) body ...)))) + ((_ ((expression) expr ...) body ...) ;; lead expression + (and expression (and-let* (expr ...) body ...)))) + "(and-let* ((name expression) expression ...) body) + + Macro that combine let and and. First expression need to be in form of let. + Symbol expression the rest can be boolean expression or name expreession. + This is implementation of SRFI-2.") + +;; ----------------------------------------------------------------------------- +;; SRFI-10 https://srfi.schemers.org/srfi-10/srfi-10.html +;; ----------------------------------------------------------------------------- +(set-special! "#," 'sharp-comma) + +(define **reader-ctor-list** '()) + +;; ----------------------------------------------------------------------------- +(define (define-reader-ctor symbol fn) + "(define-reader-ctor symbol fn) + + Define the value for #, syntax. SRFI-10 + Example: + + (define-reader-ctor '+ +) + (print #,(+ 1 2))" + (let ((node (assoc symbol **reader-ctor-list**))) + (if (pair? node) + (set-cdr! node fn) + (set! **reader-ctor-list** (cons (cons symbol fn) + **reader-ctor-list**))))) + +;; ----------------------------------------------------------------------------- +(define-syntax sharp-comma + (syntax-rules () + ((_ (fn arg ...)) + (let ((node (assoc 'fn **reader-ctor-list**))) + (if (pair? node) + ((cdr node) 'arg ...) + (syntax-error (string-append "Invalid symbol " (symbol->string 'fn) + " in expression " (repr '(fn arg ...)))))))) + "(sharp-comma expr) + #,(ctor ...) + + This is syntax extension for SRFI-10. To define the function to be used with + This syntax you need to call `define-reader-ctor` function and define + symbol function mapping.") diff --git a/scripts/minify.scm b/scripts/minify.scm new file mode 100755 index 00000000..405243fc --- /dev/null +++ b/scripts/minify.scm @@ -0,0 +1,15 @@ +#!/usr/bin/env lips + +(define (dump expr) + (let ((result (open-output-string))) + (write expr result) + (display (--> (get-output-string result) + (replace #/\n/g "\\xA;"))) + (newline) + (close-port result))) + +(if (= process.argv.length 4) + (let ((port (open-input-file (. process.argv 3)))) + (do ((expr (read port) (read port))) + ((eof-object? expr)) + (dump expr)))) \ No newline at end of file diff --git a/scripts/scheme-detect.scm b/scripts/scheme-detect.scm new file mode 100755 index 00000000..cb8ad7f1 --- /dev/null +++ b/scripts/scheme-detect.scm @@ -0,0 +1,5 @@ +#!/usr/bin/env lips + +(load "../examples/scheme-detect.scm") + +(print (detect:name)) diff --git a/spec/lips.spec.js b/spec/lips.spec.js index 425dd71d..90f594af 100644 --- a/spec/lips.spec.js +++ b/spec/lips.spec.js @@ -17,124 +17,6 @@ var { var deps = lips.exec('(load "./lib/bootstrap.scm") (load "./examples/helpers.scm")'); -describe('tokenizer', function() { - it('should create tokens for simple list', function() { - expect(tokenize('(foo bar baz)')).toEqual(['(', 'foo', 'bar', 'baz', ')']); - }); - it('should create tokens for numbers string and regexes', function() { - expect(tokenize('(foo /( \\/)/g "bar baz" 10 1.1 10e2)')).toEqual([ - '(', 'foo', '/( \\/)/g', '"bar baz"', '10', '1.1', '10e2', ')' - ]); - }); - it('should create tokens for alists', function() { - expect(tokenize('((foo . 10) (bar . 20) (baz . 30))')).toEqual([ - '(', '(', 'foo', '.', '10', ')', '(', 'bar', '.', '20', ')', '(', - 'baz', '.', '30', ')', ')' - ]); - }); - it('should ignore comments', function() { - expect(tokenize('(foo bar baz); (baz quux)')).toEqual([ - '(', 'foo', 'bar', 'baz', ')' - ]); - }); - it('should handle semicolon in regexes and strings', function() { - expect(tokenize('(";()" /;;;/g baz); (baz quux)')).toEqual([ - '(', '";()"', '/;;;/g', 'baz', ')' - ]); - }); - it('should tokenize with data', function() { - var code = `(define-macro (defstruct name . fields) - "First Line." "word" 10 - "Second Line." "word" /regex/ - "Third Line." "word" - (let ((names (map (lambda (symbol) (gensym)) fields)) - (struct (gensym)) - (field-arg (gensym))) -`; - var output = [ - { col: 0, line: 0, token: '(', offset: 0 }, - { col: 1, line: 0, token: 'define-macro', offset: 1 }, - { col: 13, line: 0, token: ' ', offset: 13 }, - { col: 14, line: 0, token: '(', offset: 14 }, - { col: 15, line: 0, token: 'defstruct', offset: 15 }, - { col: 24, line: 0, token: ' ', offset: 24 }, - { col: 25, line: 0, token: 'name', offset: 25 }, - { col: 29, line: 0, token: ' ', offset: 29 }, - { col: 30, line: 0, token: '.', offset: 30 }, - { col: 31, line: 0, token: ' ', offset: 31 }, - { col: 32, line: 0, token: 'fields', offset: 32 }, - { col: 38, line: 0, token: ')', offset: 38 }, - { col: 39, line: 0, token: '\n', offset: 39 }, - { col: 0, line: 1, token: ' ', offset: 40 }, - { col: 2, line: 1, token: '"First Line."', offset: 42 }, - { col: 15, line: 1, token: ' ', offset: 55 }, - { col: 16, line: 1, token: '"word"', offset: 56 }, - { col: 22, line: 1, token: ' ', offset: 62 }, - { col: 23, line: 1, token: '10', offset: 63 }, - { col: 25, line: 1, token: '\n', offset: 65 }, - { col: 0, line: 2, token: ' ', offset: 66 }, - { col: 2, line: 2, token: '"Second Line."', offset: 68 }, - { col: 16, line: 2, token: ' ', offset: 82 }, - { col: 20, line: 2, token: '"word"', offset: 86 }, - { col: 26, line: 2, token: ' ', offset: 92 }, - { col: 27, line: 2, token: '/regex/', offset: 93 }, - { col: 34, line: 2, token: '\n', offset: 100 }, - { col: 0, line: 3, token: ' ', offset: 101 }, - { col: 2, line: 3, token: '"Third Line."', offset: 103 }, - { col: 15, line: 3, token: ' ', offset: 116 }, - { col: 20, line: 3, token: '"word"', offset: 121 }, - { col: 26, line: 3, token: '\n', offset: 127 }, - { col: 0, line: 4, token: ' ', offset: 128 }, - { col: 2, line: 4, token: '(', offset: 130 }, - { col: 3, line: 4, token: 'let', offset: 131 }, - { col: 6, line: 4, token: ' ', offset: 134 }, - { col: 7, line: 4, token: '(', offset: 135 }, - { col: 8, line: 4, token: '(', offset: 136 }, - { col: 9, line: 4, token: 'names', offset: 137 }, - { col: 14, line: 4, token: ' ', offset: 142 }, - { col: 15, line: 4, token: '(', offset: 143 }, - { col: 16, line: 4, token: 'map', offset: 144 }, - { col: 19, line: 4, token: ' ', offset: 147 }, - { col: 20, line: 4, token: '(', offset: 148 }, - { col: 21, line: 4, token: 'lambda', offset: 149 }, - { col: 27, line: 4, token: ' ', offset: 155 }, - { col: 28, line: 4, token: '(', offset: 156 }, - { col: 29, line: 4, token: 'symbol', offset: 157 }, - { col: 35, line: 4, token: ')', offset: 163 }, - { col: 36, line: 4, token: ' ', offset: 164 }, - { col: 37, line: 4, token: '(', offset: 165 }, - { col: 38, line: 4, token: 'gensym', offset: 166 }, - { col: 44, line: 4, token: ')', offset: 172 }, - { col: 45, line: 4, token: ')', offset: 173 }, - { col: 46, line: 4, token: ' ', offset: 174 }, - { col: 47, line: 4, token: 'fields', offset: 175 }, - { col: 53, line: 4, token: ')', offset: 181 }, - { col: 54, line: 4, token: ')', offset: 182 }, - { col: 55, line: 4, token: '\n', offset: 183 }, - { col: 0, line: 5, token: ' ', offset: 184 }, - { col: 8, line: 5, token: '(', offset: 192 }, - { col: 9, line: 5, token: 'struct', offset: 193 }, - { col: 15, line: 5, token: ' ', offset: 199 }, - { col: 16, line: 5, token: '(', offset: 200 }, - { col: 17, line: 5, token: 'gensym', offset: 201 }, - { col: 23, line: 5, token: ')', offset: 207 }, - { col: 24, line: 5, token: ')', offset: 208 }, - { col: 25, line: 5, token: '\n', offset: 209 }, - { col: 0, line: 6, token: ' ', offset: 210 }, - { col: 8, line: 6, token: '(', offset: 218 }, - { col: 9, line: 6, token: 'field-arg', offset: 219 }, - { col: 18, line: 6, token: ' ', offset: 228 }, - { col: 19, line: 6, token: '(', offset: 229 }, - { col: 20, line: 6, token: 'gensym', offset: 230 }, - { col: 26, line: 6, token: ')', offset: 236 }, - { col: 27, line: 6, token: ')', offset: 237 }, - { col: 28, line: 6, token: ')', offset: 238 }, - { col: 29, line: 6, token: '\n', offset: 239 } - ]; - expect(tokenize(code, true).slice(0, output.length)).toEqual(output); - }); -}); - function exec(string, env, dynamic_scope) { return evaluate(parse(tokenize(string))[0], { env, dynamic_scope }); } diff --git a/src/lips.js b/src/lips.js index 590c7d75..e44ebca0 100644 --- a/src/lips.js +++ b/src/lips.js @@ -39,7 +39,7 @@ /* * TODO: consider using exec in env.eval or use different maybe_async code */ -/* global define, jQuery, BigInt, Map, Set, Symbol, importScripts */ +/* global define, jQuery, BigInt, Map, Set, Symbol, importScripts, Uint8Array */ (function(root, factory) { if (typeof define === 'function' && define.amd) { @@ -117,7 +117,7 @@ // ---------------------------------------------------------------------- /* istanbul ignore next */ function is_debug() { - return user_env.get('DEBUG', { throwError: false }); + return user_env && user_env.get('DEBUG', { throwError: false }); } if (!root.fetch) { /* istanbul ignore next */ @@ -187,7 +187,7 @@ // TODO: float complex function gen_complex_re(mnemonic, range) { // [+-]i have (?=..) so it don't match +i from +inf.0 - return `${num_mnemicic_re(mnemonic)}(?:[+-]?(?:${range}+/${range}+|${range}+))?(?:[+-]i|[+-]?(?:${range}+/${range}+|${range}+)i)(?=[()[\\]\\s]|$)`; + return `${num_mnemicic_re(mnemonic)}(?:[+-]?(?:${range}+/${range}+|nan.0|inf.0|${range}+))?(?:[+-]i|[+-]?(?:${range}+/${range}+|${range}+|nan.0|inf.0)i)(?=[()[\\]\\s]|$)`; } function gen_integer_re(mnemonic, range) { return `${num_mnemicic_re(mnemonic)}[+-]?${range}+`; @@ -195,7 +195,7 @@ var re_re = /^#\/((?:\\\/|[^/]|\[[^\]]*\/[^\]]*\])+)\/([gimyus]*)$/; var float_stre = '(?:[-+]?(?:[0-9]+(?:[eE][-+]?[0-9]+)|(?:\\.[0-9]+|[0-9]+\\.[0-9]+)(?:[eE][-+]?[0-9]+)?)|[0-9]+\\.)'; // TODO: extend to ([+-]1/2|float)([+-]1/2|float) - var complex_float_stre = `(?:#[ie])?(?:[+-]?(?:[0-9]+/[0-9]+|${float_stre}|[+-]?[0-9]+))?(?:${float_stre}|[+-](?:[0-9]+/[0-9]+|[0-9]+))i`; + var complex_float_stre = `(?:#[ie])?(?:[+-]?(?:[0-9]+/[0-9]+|nan.0|inf.0|${float_stre}|[+-]?[0-9]+))?(?:${float_stre}|[+-](?:[0-9]+/[0-9]+|[0-9]+|nan.0|inf.0))i`; var float_re = new RegExp(`^(#[ie])?${float_stre}$`, 'i'); function make_complex_match_re(mnemonic, range) { // complex need special treatment of 10e+1i when it's hex or decimal @@ -204,7 +204,7 @@ if (mnemonic === '') { fl = '(?:[-+]?(?:[0-9]+(?:[eE][-+]?[0-9]+)|(?:\\.[0-9]+|[0-9]+\\.[0-9]+(?![0-9]))(?:[eE][-+]?[0-9]+)?))'; } - return new RegExp(`^((?:(?:${fl}|[+-]?${range}+/${range}+(?!${range})|[+-]?${range}+)${neg})?)(${fl}|[+-]?${range}+/${range}+|[+-]?${range}+|[+-])i$`, 'i'); + return new RegExp(`^((?:(?:${fl}|[-+]?inf.0|[-+]?nan.0|[+-]?${range}+/${range}+(?!${range})|[+-]?${range}+)${neg})?)(${fl}|[-+]?inf.0|[-+]?nan.0|[+-]?${range}+/${range}+|[+-]?${range}+|[+-])i$`, 'i'); } var complex_list_re = (function() { var result = {}; @@ -410,6 +410,13 @@ return float.toRational(); } return float; + } else if (n.match(/nan.0$/)) { + return LNumber(NaN); + } else if (n.match(/inf.0$/)) { + if (n[0] === '-') { + return LNumber(Number.NEGATIVE_INFINITY); + } + return LNumber(Number.POSITIVE_INFINITY); } else { throw new Error('Internal Parser Error'); } @@ -431,11 +438,12 @@ im = parse_num(parts[2]); if (parts[1]) { re = parse_num(parts[1]); - } else if (im instanceof LFloat) { - re = LFloat(0, true); } else { re = LNumber(0); } + if (im.cmp(0) === 0 && im.__type__ === 'bigint') { + return re; + } return LComplex({ im, re }); } // ---------------------------------------------------------------------- @@ -542,6 +550,8 @@ return parse_float(arg); } else if (arg === 'nil') { return nil; + } else if (['+nan.0', '-nan.0'].includes(arg)) { + return LNumber(NaN); } else if (['true', '#t', '#true'].includes(arg)) { return true; } else if (['false', '#f', '#false'].includes(arg)) { @@ -559,7 +569,7 @@ } // ---------------------------------------------------------------------- function is_symbol_string(str) { - return !(['(', ')'].includes(str) || str.match(re_re) || + return !(['(', ')', '[', ']'].includes(str) || str.match(re_re) || str.match(/^"[\s\S]*"$/) || str.match(int_re) || str.match(float_re) || str.match(complex_re) || str.match(rational_re) || str.match(char_re) || @@ -568,14 +578,13 @@ // ---------------------------------------------------------------------- var string_re = /"(?:\\[\S\s]|[^"])*"?/g; // ---------------------------------------------------------------------- - /* function escape_regex(str) { if (typeof str === 'string') { var special = /([-\\^$[\]()+{}?*.|])/g; return str.replace(special, '\\$1'); } + return str; } - */ // ---------------------------------------------------------------------- // Stack used in balanced function // TODO: use it in parser @@ -797,23 +806,68 @@ // class used to escape promises feature #54 // ---------------------------------------------------------------------- function QuotedPromise(promise) { - // prevent exception on unhandled rejecting when using - // '>(Promise.reject (new Error "zonk")) in REPL - promise.catch(() => {}); + var internal = { + pending: true, + rejected: false, + fulfilled: false, + reason: undefined, + type: undefined + }; + // then added to __promise__ is needed otherwise rejection + // will give UnhandledPromiseRejectionWarning in Node.js + promise = promise.then(v => { + internal.type = type(v); + internal.fulfilled = true; + internal.pending = false; + return v; + }); + // promise without catch, used for valueOf - for rejecting + // that should throw an error when used with await + read_only(this, '_promise', promise, { hidden: true }); + if (is_function(promise.catch)) { + // prevent exception on unhandled rejecting when using + // '>(Promise.reject (new Error "zonk")) in REPL + promise = promise.catch((err) => { + internal.rejected = true; + internal.pending = false; + internal.reason = err; + }); + } + Object.keys(internal).forEach(name => { + Object.defineProperty(this, `__${name}__`, { + enumerable: true, + get: () => internal[name] + }); + }); this.__promise__ = promise; } // ---------------------------------------------------------------------- QuotedPromise.prototype.then = function(fn) { - return new QuotedPromise(this.__promise__.then(fn)); + return new QuotedPromise(this.valueOf().then(fn)); }; // ---------------------------------------------------------------------- QuotedPromise.prototype.catch = function(fn) { - return new QuotedPromise(this.__promise__.catch(fn)); + return new QuotedPromise(this.valueOf().catch(fn)); }; // ---------------------------------------------------------------------- QuotedPromise.prototype.valueOf = function() { - return this.__promise__; + if (!this._promise) { + throw new Error('QuotedPromise: invalid promise created'); + } + return this._promise; + }; + // ---------------------------------------------------------------------- + QuotedPromise.prototype.toString = function() { + if (this.__pending__) { + return QuotedPromise.pending_str; + } + if (this.__rejected__) { + return QuotedPromise.rejected_str; + } + return `#<js-promise resolved (${this.__type__})>`; }; + QuotedPromise.pending_str = '#<js-promise (pending)>'; + QuotedPromise.rejected_str = '#<js-promise (rejected)>'; // ---------------------------------------------------------------------- // :: Parser macros transformers // ---------------------------------------------------------------------- @@ -1058,7 +1112,7 @@ // we don't want to check inside the token (e.g. strings) this._newline = i + 1; } - if (this._whitespace) { + if (this._whitespace && this._state === null) { this._next = i + 1; this._col = this._i - newline; return true; @@ -1151,12 +1205,12 @@ Lexer.symbol = Symbol.for('symbol'); Lexer.comment = Symbol.for('comment'); Lexer.regex = Symbol.for('regex'); + Lexer.regex_class = Symbol.for('regex_class'); Lexer.character = Symbol.for('character'); Lexer.bracket = Symbol.for('bracket'); Lexer.b_symbol = Symbol.for('b_symbol'); Lexer.b_comment = Symbol.for('b_comment'); Lexer.i_comment = Symbol.for('i_comment'); - Lexer.character = Symbol.for('character'); // ---------------------------------------------------------------------- Lexer.boundary = /^$|[\s()[\]]/; // ---------------------------------------------------------------------- @@ -1203,7 +1257,10 @@ // regex [/#/, Lexer.boundary, /\//, null, Lexer.regex], [/[ \t]/, null, null, Lexer.regex, Lexer.regex], + [/\[/, null, null, Lexer.regex, Lexer.regex_class], + [/\]/, /[^\\]/, null, Lexer.regex_class, Lexer.regex], [/[()[\]]/, null, null, Lexer.regex, Lexer.regex], + [/\//, /\\/, null, Lexer.regex, Lexer.regex], [/\//, /[^#]/, Lexer.boundary, Lexer.regex, null], [/[gimyus]/, /\//, Lexer.boundary, Lexer.regex, null], [/[gimyus]/, /\//, /[gimyus]/, Lexer.regex, Lexer.regex], @@ -1280,10 +1337,10 @@ if (arg instanceof LString) { arg = arg.toString(); } - this._formatter = formatter; - this._meta = meta; - this.__lexer__ = new Lexer(arg); - this.__env__ = env; + read_only(this, '_formatter', formatter, { hidden: true }); + read_only(this, '_meta', meta, { hidden: true }); + read_only(this, '__lexer__', new Lexer(arg)); + read_only(this, '__env__', env); } resolve(name) { return this.__env__ && this.__env__.get(name, { throwError: false }); @@ -1318,10 +1375,10 @@ skip() { this.__lexer__.skip(); } - special(token) { + is_special(token) { return specials.names().includes(token); } - builtin(token) { + is_builtin(token) { return specials.builtin.includes(token); } async read() { @@ -1371,7 +1428,7 @@ is_comment(token) { return token.match(/^;/) || (token.match(/^#\|/) && token.match(/\|#$/)); } - _eval(code) { + evaluate(code) { return evaluate(code, { env: this.__env__, error: (e) => { throw e; } }); @@ -1381,7 +1438,7 @@ if (token === eof) { return token; } - if (this.special(token)) { + if (this.is_special(token)) { // bultin parser extensions are mapping short symbol to longer symbol // that can be function or macro, parser don't care // if it's not bultin then the extension can be macro or function @@ -1390,7 +1447,7 @@ // MACRO: if macros are used they are evaluated in place and // result is returned by parser but they are quoted const special = specials.get(token); - const bultin = this.builtin(token); + const bultin = this.is_builtin(token); this.skip(); let expr; const object = await this.read_object(); @@ -1400,7 +1457,7 @@ if (is_literal(token)) { return extension.call(this.__env__, object); } else if (object instanceof Pair) { - return extension.apply(this.__env__, object.toArray(false)); + return extension.apply(this.__env__, object.to_array(false)); } throw new Error('Parser: Invalid parser extension ' + `invocation ${special.symbol}`); @@ -1426,7 +1483,7 @@ } // evaluate parser extension at parse time if (extension instanceof Macro) { - var result = await this._eval(expr); + var result = await this.evaluate(expr); // we need literal quote to make macro that return pair works // because after parser return the value it will be evaluated again // by the interpreter, so we create quoted expression @@ -1513,6 +1570,13 @@ } } return fn(value); + }// ---------------------------------------------------------------------- + function read_only(object, property, value, { hidden = false } = {}) { + Object.defineProperty(object, property, { + value, + configurable: true, + enumerable: !hidden + }); } // ---------------------------------------------------------------------- // :: Function similar to Array.from that work on async iterators @@ -1618,14 +1682,17 @@ // ---------------------------------------------------------------------- // :: token based pattern matching (used by formatter) // ---------------------------------------------------------------------- + /* function nested_pattern(pattern) { return pattern instanceof Array || pattern instanceof Pattern; } + */ // ---------------------------------------------------------------------- function match(pattern, input) { return inner_match(pattern, input) === input.length; function inner_match(pattern, input) { + /* function empty_match() { if (p <= 0 && i <= 0) { return false; @@ -1641,6 +1708,16 @@ return match(prev_pattern, [input[i - 1]]) && (!next_pattern || match(next_pattern, [input[i]])); } + */ + function get_first_match(patterns, input) { + for (let p of patterns) { + const m = inner_match(p, input); + if (m !== -1) { + return m; + } + } + return -1; + } function not_symbol_match() { return pattern[p] === Symbol.for('symbol') && !is_symbol_string(input[i]); } @@ -1661,7 +1738,7 @@ var m; if (['+', '*'].includes(pattern[p].flag)) { while (i < input.length) { - m = inner_match(pattern[p].pattern, input.slice(i)); + m = get_first_match(pattern[p].patterns, input.slice(i)); if (m === -1) { break; } @@ -1671,7 +1748,7 @@ p++; continue; } else if (pattern[p].flag === '?') { - m = inner_match(pattern[p].pattern, input.slice(i)); + m = get_first_match(pattern[p].patterns, input.slice(i)); if (m === -1) { i -= 2; // if not found use same test on same input again } else { @@ -1691,15 +1768,13 @@ if (pattern[p] === Symbol.for('*')) { // ignore S-expressions inside for case when next pattern is ) glob[p] = glob[p] || 0; - var zero_match = empty_match(); + //var zero_match = empty_match(); if (['(', '['].includes(input[i])) { glob[p]++; - } else if ([')', ']'].includes(input[i]) && !zero_match) { + } else if ([')', ']'].includes(input[i])) { glob[p]--; } - if (zero_match) { - i -= 1; - } else if ((typeof pattern[p + 1] !== 'undefined' && + if ((typeof pattern[p + 1] !== 'undefined' && glob[p] === 0 && match_next() === -1) || glob[p] > 0) { continue; @@ -1744,7 +1819,7 @@ exceptions: { specials: [ /* eslint-disable max-len */ - /^(?:#:)?(?:define(?:-values|-syntax|-macro)?|lambda|let*|let-env|try|catch|when|unless|while|syntax-rules|(let|letrec)(-syntax))$/ + /^(?:#:)?(?:define(?:-values|-syntax|-macro|-class|-record-type)?|(?:call-with-(?:input-file|output-file|port))|lambda|let-env|try|catch|when|unless|while|syntax-rules|(let|letrec)(-syntax|\*)?)$/ /* eslint-enable */ ], shift: { @@ -1883,23 +1958,28 @@ return string.match(this.pattern); }; // ---------------------------------------------------------------------- - function Pattern(pattern, flag) { - this.pattern = pattern; + // Pattern have any number of patterns that is match using OR operator + // pattern is in form of array with regular expressions + // ---------------------------------------------------------------------- + function Pattern(...args) { + var flag = args.pop(); + this.patterns = args; this.flag = flag; } - // TODO: make it print Pattern.prototype.toString = function() { - return `#<pattern(${this.pattern} ${this.flag})>`; + var patterns = this.patterns.map(x => toString(x)).join('|'); + return `#<pattern(${patterns} ${this.flag})>`; }; // ---------------------------------------------------------------------- Formatter.Pattern = Pattern; Formatter.Ahead = Ahead; - var p_o = /[[(]/; - var p_e = /[\])]/; + var p_o = /^[[(]$/; + var p_e = /^[\])]$/; var not_p = /[^()[\]]/; const not_close = new Ahead(/[^)\]]/); - const open = new Ahead(/[([]/); + //const open = new Ahead(/[([]/); const glob = Symbol.for('*'); + const sexp_or_atom = new Pattern([p_o, glob, p_e], [not_p], '+'); const sexp = new Pattern([p_o, glob, p_e], '+'); const symbol = new Pattern([Symbol.for('symbol')], '?'); const symbols = new Pattern([Symbol.for('symbol')], '*'); @@ -1911,6 +1991,7 @@ var non_def = /^(?!.*\b(?:[()[\]]|define|let(?:\*|rec|-env|-syntax)?|lambda|syntax-rules)\b).*$/; /* eslint-enable */ var let_re = /^(?:#:)?(let(?:\*|rec|-env|-syntax)?)$/; + // match keyword if it's normal token or gensym (prefixed with #:) function keywords_re(...args) { return new RegExp(`^(?:#:)?(?:${args.join('|')})$`); } @@ -1918,10 +1999,12 @@ Formatter.rules = [ [[p_o, keywords_re('begin')], 1], [[p_o, let_re, symbol, p_o, let_value, p_e], 1], - [[p_o, let_re, p_o, let_value, p_e, sexp], 1, not_close], + [[p_o, let_re, symbol, sexp, sexp_or_atom], 0, not_close], + //[[p_o, let_re, p_o, let_value], 1, not_close], [[p_o, keywords_re('define-syntax'), /.+/], 1], [[p_o, non_def, new Pattern([/[^()[\]]/], '+'), sexp], 1, not_close], - [[p_o, sexp], 1, open], + [[p_o, sexp], 1, not_close], + [[p_o, let_re, sexp], 1, not_close], [[p_o, keywords_re('lambda', 'if'), not_p], 1, not_close], [[p_o, keywords_re('while'), not_p, sexp], 1, not_close], [[p_o, keywords_re('if'), not_p, glob], 1], @@ -1933,13 +2016,16 @@ // ---------------------------------------------------------------------- Formatter.prototype.break = function() { var code = this.__code__.replace(/\n[ \t]*/g, '\n '); + // function that work when calling tokenize with meta data or not const token = t => { - if (t.token.match(string_re)) { + if (t.token.match(string_re) || t.token.match(re_re)) { return t.token; } else { return t.token.replace(/\s+/, ' '); } }; + // tokenize is part of the parser/lexer that split code into tokens and inclue + // meta data like number of column or line var tokens = tokenize(code, true).map(token).filter(t => t !== '\n'); const { rules } = Formatter; for (let i = 1; i < tokens.length; ++i) { @@ -1950,17 +2036,25 @@ var sexp = {}; rules.map(b => b[1]).forEach(count => { count = count.valueOf(); - if (!sexp[count]) { + // some patterns require to check what was before like + // if inside let binding + if (count > 0 && !sexp[count]) { sexp[count] = previousSexp(sub, count); } }); for (let [pattern, count, ext] of rules) { count = count.valueOf(); - var m = match(pattern, sexp[count].filter(t => t.trim())); + // 0 count mean ignore the previous S-Expression + var test_sexp = count > 0 ? sexp[count] : sub; + var m = match(pattern, test_sexp.filter(t => t.trim())); var next = tokens.slice(i).find(t => t.trim()); if (m && (ext instanceof Ahead && ext.match(next) || !ext)) { - tokens.splice(i, 0, '\n'); - i++; + if (!tokens[i - 1].trim()) { + tokens[i - 1] = '\n'; + } else { + tokens.splice(i, 0, '\n'); + i++; + } continue; } } @@ -2059,13 +2153,13 @@ 'This is probably not what you want.'); return undefined; }; - Nil.prototype.toObject = function() { + Nil.prototype.to_object = function() { return {}; }; Nil.prototype.append = function(x) { return new Pair(x, nil); }; - Nil.prototype.toArray = function() { + Nil.prototype.to_array = function() { return []; }; var nil = new Nil(); @@ -2081,7 +2175,7 @@ this.cdr = cdr; } // ---------------------------------------------------------------------- - function toArray(name, deep) { + function to_array(name, deep) { return function recur(list) { typecheck(name, list, ['pair', 'nil']); if (list === nil) { @@ -2111,7 +2205,7 @@ } // ---------------------------------------------------------------------- Pair.prototype.flatten = function() { - return Pair.fromArray(flatten(this.toArray())); + return Pair.fromArray(flatten(this.to_array())); }; // ---------------------------------------------------------------------- Pair.prototype.length = function() { @@ -2150,7 +2244,7 @@ }; // ---------------------------------------------------------------------- - Pair.prototype.clone = function() { + Pair.prototype.clone = function(deep = true) { var visited = new Map(); function clone(node) { if (node instanceof Pair) { @@ -2159,7 +2253,11 @@ } var pair = new Pair(); visited.set(node, pair); - pair.car = clone(node.car); + if (deep) { + pair.car = clone(node.car); + } else { + pair.car = node.car; + } pair.cdr = clone(node.cdr); pair[__cycles__] = node[__cycles__]; return pair; @@ -2170,7 +2268,7 @@ }; // ---------------------------------------------------------------------- - Pair.prototype.lastPair = function() { + Pair.prototype.last_pair = function() { let node = this; while (true) { if (node.cdr === nil) { @@ -2181,11 +2279,11 @@ }; // ---------------------------------------------------------------------- - Pair.prototype.toArray = function(deep = true) { + Pair.prototype.to_array = function(deep = true) { var result = []; if (this.car instanceof Pair) { if (deep) { - result.push(this.car.toArray()); + result.push(this.car.to_array()); } else { result.push(this.car); } @@ -2193,7 +2291,7 @@ result.push(this.car.valueOf()); } if (this.cdr instanceof Pair) { - result = result.concat(this.cdr.toArray()); + result = result.concat(this.cdr.to_array()); } return result; }; @@ -2230,11 +2328,11 @@ }; // ---------------------------------------------------------------------- - // by default toObject was created to create JavaScript objects, + // by default to_object was created to create JavaScript objects, // so it use valueOf to get native values // literal parameter was a hack to allow create LComplex from LIPS code // ---------------------------------------------------------------------- - Pair.prototype.toObject = function(literal = false) { + Pair.prototype.to_object = function(literal = false) { var node = this; var result = {}; while (true) { @@ -2249,7 +2347,7 @@ } var cdr = pair.cdr; if (cdr instanceof Pair) { - cdr = cdr.toObject(literal); + cdr = cdr.to_object(literal); } if (is_native(cdr)) { if (!literal) { @@ -2395,8 +2493,6 @@ // ---------------------------------------------------------------------- var str_mapping = new Map(); [ - [Number.NEGATIVE_INFINITY, '-inf.0'], - [Number.POSITIVE_INFINITY, '+inf.0'], [true, '#t'], [false, '#f'], [null, 'null'], @@ -2467,12 +2563,57 @@ if (has_own_function(fn, 'toString')) { return fn.toString(); } else if (fn.name && !fn[__lambda__]) { - return `#<procedure:${fn.name}>`; + return `#<procedure:${fn.name.trim()}>`; } else { return '#<procedure>'; } } // ---------------------------------------------------------------------- + // instances extracted to make cyclomatic complexity of toString smaller + const instances = new Map(); + // ---------------------------------------------------------------------- + [ + [Error, function(e) { + return e.message; + }], + [Pair, function(pair, { quote, skip_cycles, pair_args }) { + // make sure that repr directly after update set the cycle ref + if (!skip_cycles) { + pair.markCycles(); + } + return pair.toString(quote, ...pair_args); + }], + [LCharacter, function(chr, { quote }) { + if (quote) { + return chr.toString(); + } + return chr.valueOf(); + }], + [LString, function(str, { quote }) { + str = str.toString(); + if (quote) { + return JSON.stringify(str).replace(/\\n/g, '\n'); + } + return str; + }], + [RegExp, function(re) { + return '#' + re.toString(); + }] + ].forEach(([cls, fn]) => { + instances.set(cls, fn); + }); + // ---------------------------------------------------------------------- + const native_types = [ + LSymbol, + LNumber, + Macro, + Values, + InputPort, + OutputPort, + Environment, + QuotedPromise + ]; + // ---------------------------------------------------------------------- function toString(obj, quote, skip_cycles, ...pair_args) { if (typeof jQuery !== 'undefined' && obj instanceof jQuery.fn.init) { @@ -2481,48 +2622,25 @@ if (str_mapping.has(obj)) { return str_mapping.get(obj); } - if (obj instanceof Error) { - return obj.message; - } - if (obj instanceof Pair) { - // make sure that repr directly after update set the cycle ref - if (!skip_cycles) { - obj.markCycles(); + if (obj) { + var cls = obj.constructor; + if (instances.has(cls)) { + return instances.get(cls)(obj, { quote, skip_cycles, pair_args }); } - return obj.toString(quote, ...pair_args); - } - if (Number.isNaN(obj)) { - return '+nan.0'; } - if (obj instanceof LCharacter) { - if (quote) { - return obj.toString(); + // standard objects that have toString + for (let type of native_types) { + if (obj instanceof type) { + return obj.toString(quote); } - return obj.valueOf(); } // constants if ([nil, eof].includes(obj)) { return obj.toString(); } - var types = [LSymbol, LNumber, Macro, Values, InputPort, Environment]; - for (let type of types) { - if (obj instanceof type) { - return obj.toString(quote); - } - } - if (obj instanceof RegExp) { - return '#' + obj.toString(); - } if (is_function(obj)) { return function_to_string(obj); } - if (obj instanceof LString) { - obj = obj.toString(); - if (quote) { - return JSON.stringify(obj).replace(/\\n/g, '\n'); - } - return obj; - } if (obj === root) { return '#<js:global>'; } @@ -2846,16 +2964,28 @@ } else { type = true; } - return type && x.cmp(y) === 0; + if (type && x.cmp(y) === 0) { + if (x.valueOf() === 0) { + return Object.is(x.valueOf(), y.valueOf()); + } + return true; + } } return false; } else if (typeof x === 'number') { if (typeof y !== 'number') { return false; } - x = LNumber(x); - y = LNumber(y); - return x.__type__ === y.__type__ && x.cmp(y) === 0; + if (Number.isNaN(x)) { + return Number.isNaN(y); + } + if (x === Number.NEGATIVE_INFINITY) { + return y === Number.NEGATIVE_INFINITY; + } + if (x === Number.POSITIVE_INFINITY) { + return y === Number.POSITIVE_INFINITY; + } + return equal(LNumber(x), LNumber(y)); } else if (x instanceof LCharacter) { if (!(y instanceof LCharacter)) { return false; @@ -2898,7 +3028,9 @@ return Math.trunc; } else { return function(x) { - if (x < 0) { + if (x === 0) { + return 0; + } else if (x < 0) { return Math.ceil(x); } else { return Math.floor(x); @@ -3102,7 +3234,7 @@ if (pattern.car.cdr instanceof Pair && LSymbol.is(pattern.car.cdr.car, ellipsis_symbol)) { let name = pattern.car.car.valueOf(); - const last = pattern.lastPair(); + const last = pattern.last_pair(); if (LSymbol.is(last.car, ellipsis_symbol)) { bindings['...'].symbols[name] = null; return true; @@ -4183,31 +4315,38 @@ // ------------------------------------------------------------------------- // :: character object representation // ------------------------------------------------------------------------- - function LCharacter(chr) { + function LCharacter(char) { if (typeof this !== 'undefined' && !(this instanceof LCharacter) || typeof this === 'undefined') { - return new LCharacter(chr); + return new LCharacter(char); } - if (chr instanceof LString) { - chr = chr.valueOf(); + if (char instanceof LString) { + char = char.valueOf(); } - if (Array.from(chr).length > 1) { + var name; + if (Array.from(char).length > 1) { // this is name - chr = chr.toLowerCase(); - if (LCharacter.__names__[chr]) { - this.__name__ = chr; - this.__char__ = LCharacter.__names__[chr]; + char = char.toLowerCase(); + if (LCharacter.__names__[char]) { + name = char; + char = LCharacter.__names__[char]; } else { // this should never happen // parser don't alow not defined named characters throw new Error('Internal: Unknown named character'); } } else { - this.__char__ = chr; - const name = LCharacter.__rev_names__[chr]; - if (name) { - this.__name__ = name; - } + name = LCharacter.__rev_names__[char]; + } + Object.defineProperty(this, '__char__', { + value: char, + enumerable: true + }); + if (name) { + Object.defineProperty(this, '__name__', { + value: name, + enumerable: true + }); } } LCharacter.__names__ = characters; @@ -4358,7 +4497,9 @@ } } } - if (typeof BigInt !== 'undefined') { + if (Number.isNaN(n)) { + return LFloat(n); + } else if (typeof BigInt !== 'undefined') { if (typeof n !== 'bigint') { if (parsable) { let prefix; @@ -4402,12 +4543,23 @@ } return LBigInteger(new BN(n)); } else if (parsable) { - this.value = parseInt(str, radix); + this.constant(parseInt(str, radix), 'integer'); } else { - this.value = n; + this.constant(n, 'integer'); } } // ------------------------------------------------------------------------- + LNumber.prototype.constant = function(value, type) { + Object.defineProperty(this, '__value__', { + value, + enumerable: true + }); + Object.defineProperty(this, '__type__', { + value: type, + enumerable: true + }); + }; + // ------------------------------------------------------------------------- LNumber.types = { float: function(n, force = false) { return new LFloat(n, force); @@ -4426,6 +4578,10 @@ } }; // ------------------------------------------------------------------------- + LNumber.prototype.isNaN = function() { + return Number.isNaN(this.__value__); + }; + // ------------------------------------------------------------------------- LNumber.prototype.gcd = function(b) { // ref: https://rosettacode.org/wiki/Greatest_common_divisor#JavaScript var a = this.abs(); @@ -4453,16 +4609,23 @@ // ------------------------------------------------------------------------- LNumber.isNumber = function(n) { return n instanceof LNumber || - (!Number.isNaN(n) && LNumber.isNative(n) || LNumber.isBN(n)); + (LNumber.isNative(n) || LNumber.isBN(n)); }; // ------------------------------------------------------------------------- LNumber.isComplex = function(n) { + if (!n) { + return false; + } var ret = n instanceof LComplex || - (LNumber.isNumber(n.im) && LNumber.isNumber(n.re)); + ((LNumber.isNumber(n.im) || Number.isNaN(n.im)) && + (LNumber.isNumber(n.re) || Number.isNaN(n.re))); return ret; }; // ------------------------------------------------------------------------- LNumber.isRational = function(n) { + if (!n) { + return false; + } return n instanceof LRational || (LNumber.isNumber(n.num) && LNumber.isNumber(n.denom)); }; @@ -4507,10 +4670,13 @@ }; // ------------------------------------------------------------------------- LNumber.prototype.toString = LNumber.prototype.toJSON = function(radix) { + if (Number.isNaN(this.__value__)) { + return '+nan.0'; + } if (radix > 2 && radix < 36) { - return this.value.toString(radix); + return this.__value__.toString(radix); } - return this.value.toString(); + return this.__value__.toString(); }; // ------------------------------------------------------------------------- LNumber.prototype.asType = function(n) { @@ -4519,14 +4685,14 @@ }; // ------------------------------------------------------------------------- LNumber.prototype.isBigNumber = function() { - return typeof this.value === 'bigint' || + return typeof this.__value__ === 'bigint' || typeof BN !== 'undefined' && !(this.value instanceof BN); }; // ------------------------------------------------------------------------- ['floor', 'ceil', 'round'].forEach(fn => { LNumber.prototype[fn] = function() { - if (this.float || LNumber.isFloat(this.value)) { - return LNumber(Math[fn](this.value)); + if (this.float || LNumber.isFloat(this.__value__)) { + return LNumber(Math[fn](this.__value__)); } else { return LNumber(Math[fn](this.valueOf())); } @@ -4534,30 +4700,40 @@ }); // ------------------------------------------------------------------------- LNumber.prototype.valueOf = function() { - if (LNumber.isNative(this.value)) { - return Number(this.value); - } else if (LNumber.isBN(this.value)) { - return this.value.toNumber(); + if (LNumber.isNative(this.__value__)) { + return Number(this.__value__); + } else if (LNumber.isBN(this.__value__)) { + return this.__value__.toNumber(); } }; // ------------------------------------------------------------------------- - var matrix = (function() { + // type coercion matrix + // ------------------------------------------------------------------------- + const matrix = (function() { var i = (a, b) => [a, b]; return { bigint: { - 'bigint': i, - 'float': (a, b) => [LFloat(a.valueOf(), true), b], - 'rational': (a, b) => [{ num: a, denom: 1 }, b], - 'complex': (a, b) => [{ im: 0, re: a }, b] + bigint: i, + float: (a, b) => [LFloat(a.valueOf(), true), b], + rational: (a, b) => [{ num: a, denom: 1 }, b], + complex: (a, b) => [{ im: 0, re: a }, b] + }, + integer: { + integer: i, + float: (a, b) => [LFloat(a.valueOf(), true), b], + rational: (a, b) => [{ num: a, denom: 1 }, b], + complex: (a, b) => [{ im: 0, re: a }, b] }, float: { - 'bigint': (a, b) => [a, b && LFloat(b.valueOf(), true)], - 'float': i, - 'rational': (a, b) => [a, b && LFloat(b.valueOf(), true)], - 'complex': (a, b) => [{ re: a, im: LFloat(0, true) }, b] + bigint: (a, b) => [a, b && LFloat(b.valueOf(), true)], + integer: (a, b) => [a, b && LFloat(b.valueOf(), true)], + float: i, + rational: (a, b) => [a, b && LFloat(b.valueOf(), true)], + complex: (a, b) => [{ re: a, im: LFloat(0, true) }, b] }, complex: { bigint: complex('bigint'), + integer: complex('integer'), float: complex('float'), rational: complex('rational'), complex: (a, b) => { @@ -4571,17 +4747,18 @@ }, rational: { bigint: (a, b) => [a, b && { num: b, denom: 1 }], + integer: (a, b) => [a, b && { num: b, denom: 1 }], float: (a, b) => [LFloat(a.valueOf()), b], rational: i, complex: (a, b) => { return [ { - im: coerce(a.__type__, b.__im__.__type__, 0), - re: coerce(a.__type__, b.__re__.__type__, a) + im: coerce(a.__type__, b.__im__.__type__, 0)[0], + re: coerce(a.__type__, b.__re__.__type__, a)[0] }, { - im: coerce(a.__type__, b.__im__.__type__, b.__im__), - re: coerce(a.__type__, b.__re__.__type__, b.__re__) + im: coerce(a.__type__, b.__im__.__type__, b.__im__)[0], + re: coerce(a.__type__, b.__re__.__type__, b.__re__)[0] } ]; } @@ -4591,37 +4768,32 @@ return (a, b) => { return [ { - im: coerce(type, a.__im__.__type__, a.__im__), - re: coerce(type, a.__re__.__type__, a.__re__) + im: coerce(type, a.__im__.__type__, 0, a.__im__)[1], + re: coerce(type, a.__re__.__type__, 0, a.__re__)[1] }, { - im: coerce(type, a.__im__.__type__, 0), - re: coerce(type, b.__type__, b) + im: coerce(type, a.__im__.__type__, 0, 0)[1], + re: coerce(type, b.__type__, 0, b)[1] } ]; }; } })(); // ------------------------------------------------------------------------- - function coerce(type_a, type_b, a) { - return matrix[type_a][type_b](a)[0]; + function coerce(type_a, type_b, a, b) { + return matrix[type_a][type_b](a, b); } // ------------------------------------------------------------------------- LNumber.coerce = function(a, b) { - function clean(type) { - if (type === 'integer') { - return 'bigint'; - } - return type; - } - const a_type = clean(LNumber.getType(a)); - const b_type = clean(LNumber.getType(b)); + const a_type = LNumber.getType(a); + const b_type = LNumber.getType(b); if (!matrix[a_type]) { throw new Error(`LNumber::coerce unknown lhs type ${a_type}`); } else if (!matrix[a_type][b_type]) { throw new Error(`LNumber::coerce unknown rhs type ${b_type}`); } - return matrix[a_type][b_type](a, b).map(n => LNumber(n, true)); + var tmp = matrix[a_type][b_type](a, b); + return tmp.map(n => LNumber(n, true)); }; // ------------------------------------------------------------------------- LNumber.prototype.coerce = function(n) { @@ -4657,7 +4829,7 @@ }; // ------------------------------------------------------------------------- LNumber.prototype.isFloat = function() { - return !!(LNumber.isFloat(this.value) || this.float); + return !!(LNumber.isFloat(this.__value__) || this.float); }; // ------------------------------------------------------------------------- var mapping = { @@ -4720,6 +4892,13 @@ if (typeof n === 'undefined') { return LNumber(LNumber._ops[op](this.valueOf())); } + if (typeof n === 'number') { + n = LNumber(n); + } + if (Number.isNaN(this.__value__) && !LNumber.isComplex(n) || + !LNumber.isComplex(this) && Number.isNaN(n.__value__)) { + return LNumber(NaN); + } const [a, b] = this.coerce(n); if (a._op) { return a._op(op, b); @@ -4742,17 +4921,17 @@ // ------------------------------------------------------------------------- LNumber.prototype.pow = function(n) { var value; - if (LNumber.isBN(this.value)) { - value = this.value.pow(n.value); + if (LNumber.isBN(this.__value__)) { + value = this.__value__.pow(n.__value__); } else { - value = pow(this.value, n.value); + value = pow(this.__value__, n.__value__); } return LNumber(value); }; // ------------------------------------------------------------------------- LNumber.prototype.abs = function() { - var value = this.value; - if (LNumber.isNative(this.value)) { + var value = this.__value__; + if (LNumber.isNative(this.__value__)) { if (value < 0) { value = -value; } @@ -4763,13 +4942,13 @@ }; // ------------------------------------------------------------------------- LNumber.prototype.isOdd = function() { - if (LNumber.isNative(this.value)) { + if (LNumber.isNative(this.__value__)) { if (this.isBigNumber()) { - return this.value % BigInt(2) === BigInt(1); + return this.__value__ % BigInt(2) === BigInt(1); } - return this.value % 2 === 1; - } else if (LNumber.isBN(this.value)) { - return this.value.isOdd(); + return this.__value__ % 2 === 1; + } else if (LNumber.isBN(this.__value__)) { + return this.__value__.isOdd(); } }; // ------------------------------------------------------------------------- @@ -4780,19 +4959,19 @@ LNumber.prototype.cmp = function(n) { const [a, b] = this.coerce(n); function cmp(a, b) { - if (a.value < b.value) { + if (a.__value__ < b.__value__) { return -1; - } else if (a.value === b.value) { + } else if (a.__value__ === b.__value__) { return 0; } else { return 1; } } if (a.__type__ === 'bigint') { - if (LNumber.isNative(a.value)) { + if (LNumber.isNative(a.__value__)) { return cmp(a, b); - } else if (LNumber.isBN(a.value)) { - return this.value.cmp(b.value); + } else if (LNumber.isBN(a.__value__)) { + return this.__value__.cmp(b.__value__); } } else if (a instanceof LFloat) { return cmp(a, b); @@ -4818,14 +4997,27 @@ } var im = n.im instanceof LNumber ? n.im : LNumber(n.im); var re = n.re instanceof LNumber ? n.re : LNumber(n.re); - this.__im__ = im; - this.__re__ = re; - this.__type__ = 'complex'; + this.constant(im, re); } // ------------------------------------------------------------------------- LComplex.prototype = Object.create(LNumber.prototype); LComplex.prototype.constructor = LComplex; // ------------------------------------------------------------------------- + LComplex.prototype.constant = function(im, re) { + Object.defineProperty(this, '__im__', { + value: im, + enumerable: true + }); + Object.defineProperty(this, '__re__', { + value: re, + enumerable: true + }); + Object.defineProperty(this, '__type__', { + value: 'complex', + enumerable: true + }); + }; + // ------------------------------------------------------------------------- LComplex.prototype.toRational = function(n) { if (LNumber.isFloat(this.__im__) && LNumber.isFloat(this.__re__)) { const im = LFloat(this.__im__).toRational(n); @@ -4836,7 +5028,7 @@ }; // ------------------------------------------------------------------------- LComplex.prototype.add = function(n) { - return this.complex_op(n, function(a_re, b_re, a_im, b_im) { + return this.complex_op('add', n, function(a_re, b_re, a_im, b_im) { return { re: a_re.add(b_re), im: a_im.add(b_im) @@ -4871,6 +5063,10 @@ return this.factor().sqrt(); }; // ------------------------------------------------------------------------- + LComplex.prototype.conjugate = function() { + return LComplex({ re: this.__re__, im: this.__im__.sub() }); + }; + // ------------------------------------------------------------------------- LComplex.prototype.sqrt = function() { const r = this.modulus(); // code based ok Kawa Scheme source code (file DComplex.java) @@ -4894,30 +5090,34 @@ // ------------------------------------------------------------------------- LComplex.prototype.div = function(n) { if (LNumber.isNumber(n) && !LNumber.isComplex(n)) { - n = LComplex({ im: 0, re: n }); + if (!(n instanceof LNumber)) { + n = LNumber(n); + } + const re = this.__re__.div(n); + const im = this.__im__.div(n); + return LComplex({ re, im }); } else if (!LNumber.isComplex(n)) { - throw new Error('[LComplex::add] Invalid value'); + throw new Error('[LComplex::div] Invalid value'); } const [ a, b ] = this.coerce(n); - const conj = LComplex({ re: b.__re__, im: b.__im__.sub() }); - const denom = b.factor().valueOf(); - const num = a.mul(conj); + const denom = b.factor(); + const num = a.mul(b.conjugate()); const re = num.__re__.op('/', denom); const im = num.__im__.op('/', denom); return LComplex({ re, im }); }; // ------------------------------------------------------------------------- LComplex.prototype.sub = function(n) { - return this.complex_op(n, function(a_re, b_re, a_im, b_im) { + return this.complex_op('sub', n, function(a_re, b_re, a_im, b_im) { return { re: a_re.sub(b_re), - im: a_im.add(b_im) + im: a_im.sub(b_im) }; }); }; // ------------------------------------------------------------------------- LComplex.prototype.mul = function(n) { - return this.complex_op(n, function(a_re, b_re, a_im, b_im) { + return this.complex_op('mul', n, function(a_re, b_re, a_im, b_im) { var ret = { re: a_re.mul(b_re).sub(a_im.mul(b_im)), im: a_re.mul(b_im).add(b_re.mul(a_im)) @@ -4926,7 +5126,20 @@ }); }; // ------------------------------------------------------------------------- - LComplex.prototype.complex_op = function(n, fn) { + LComplex.prototype.complex_op = function(name, n, fn) { + const calc = (re, im) => { + var result = fn(this.__re__, re, this.__im__, im); + if ('im' in result && 're' in result) { + if (result.im.cmp(0) === 0 && !LNumber.isFloat(result.im)) { + return result.re; + } + return LComplex(result, true); + } + return result; + }; + if (typeof n === 'undefined') { + return calc(); + } if (LNumber.isNumber(n) && !LNumber.isComplex(n)) { if (!(n instanceof LNumber)) { n = LNumber(n); @@ -4934,16 +5147,11 @@ const im = n.asType(0); n = { __im__: im, __re__: n }; } else if (!LNumber.isComplex(n)) { - throw new Error('[LComplex::add] Invalid value'); + throw new Error(`[LComplex::${name}] Invalid value`); } var re = n.__re__ instanceof LNumber ? n.__re__ : this.__re__.asType(n.__re__); var im = n.__im__ instanceof LNumber ? n.__im__ : this.__im__.asType(n.__im__); - var ret = fn(this.__re__, re, this.__im__, im); - if ('im' in ret && 're' in ret) { - var x = LComplex(ret, true); - return x; - } - return ret; + return calc(re, im); }; // ------------------------------------------------------------------------- LComplex._op = { @@ -4977,12 +5185,24 @@ LComplex.prototype.toString = function() { var result; if (this.__re__.cmp(0) !== 0) { - result = [this.__re__.toString()]; + result = [toString(this.__re__)]; } else { result = []; } - result.push(this.__im__.cmp(0) < 0 ? '-' : '+'); - result.push(this.__im__.toString().replace(/^-/, '')); + // NaN and inf already have sign + var im = this.__im__.valueOf(); + var inf = [Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY].includes(im); + var im_str = toString(this.__im__); + if (!inf && !Number.isNaN(im)) { + var zero_check = this.__im__.cmp(0); + if (zero_check < 0 || (zero_check === 0 && this.__im__._minus)) { + result.push('-'); + } else { + result.push('+'); + } + im_str = im_str.replace(/^-/, ''); + } + result.push(im_str); result.push('i'); return result.join(''); }; @@ -5001,8 +5221,12 @@ return LFloat(n.valueOf()); } if (typeof n === 'number') { - this.value = n; - this.__type__ = 'float'; + if (Object.is(n, -0)) { + Object.defineProperty(this, '_minus', { + value: true + }); + } + this.constant(n, 'float'); } } // ------------------------------------------------------------------------- @@ -5010,30 +5234,40 @@ LFloat.prototype.constructor = LFloat; // ------------------------------------------------------------------------- LFloat.prototype.toString = function() { - var str = this.value.toString(); - if (!LNumber.isFloat(this.value) && !str.match(/e/i)) { - return str + '.0'; + if (this.__value__ === Number.NEGATIVE_INFINITY) { + return '-inf.0'; + } + if (this.__value__ === Number.POSITIVE_INFINITY) { + return '+inf.0'; + } + if (Number.isNaN(this.__value__)) { + return '+nan.0'; + } + var str = this.__value__.toString(); + if (!LNumber.isFloat(this.__value__) && !str.match(/e/i)) { + var result = str + '.0'; + return this._minus ? ('-' + result) : result; } return str.replace(/^([0-9]+)e/, '$1.0e'); }; // ------------------------------------------------------------------------- LFloat.prototype._op = function(op, n) { if (n instanceof LNumber) { - n = n.value; + n = n.__value__; } const fn = LNumber._ops[op]; - if (op === '/' && this.value === 0 && n === 0) { + if (op === '/' && this.__value__ === 0 && n === 0) { return NaN; } - return LFloat(fn(this.value, n), true); + return LFloat(fn(this.__value__, n), true); }; // ------------------------------------------------------------------------- // same aproximation as in guile scheme LFloat.prototype.toRational = function(n = null) { if (n === null) { - return toRational(this.value.valueOf()); + return toRational(this.__value__.valueOf()); } - return approxRatio(n.valueOf())(this.value.valueOf()); + return approxRatio(n.valueOf())(this.__value__.valueOf()); }; // ------------------------------------------------------------------------- // ref: https://rosettacode.org/wiki/Convert_decimal_number_to_rational @@ -5098,22 +5332,41 @@ if (!LNumber.isRational(n)) { throw new Error('Invalid constructor call for LRational'); } - var num = LNumber(n.num); - var denom = LNumber(n.denom); + var num, denom; + if (n instanceof LRational) { + num = LNumber(n.__num__); + denom = LNumber(n.__denom__); + } else { + num = LNumber(n.num); + denom = LNumber(n.denom); + } if (!force && denom.cmp(0) !== 0) { var is_integer = num.op('%', denom).cmp(0) === 0; if (is_integer) { return LNumber(num.div(denom)); } } - this.num = num; - this.denom = denom; - this.__type__ = 'rational'; + this.constant(num, denom); } // ------------------------------------------------------------------------- LRational.prototype = Object.create(LNumber.prototype); LRational.prototype.constructor = LRational; // ------------------------------------------------------------------------- + LRational.prototype.constant = function(num, denom) { + Object.defineProperty(this, '__num__', { + value: num, + enumerable: true + }); + Object.defineProperty(this, '__denom__', { + value: denom, + enumerable: true + }); + Object.defineProperty(this, '__type__', { + value: 'rational', + enumerable: true + }); + }; + // ------------------------------------------------------------------------- LRational.prototype.pow = function(n) { var cmp = n.cmp(0); if (cmp === 0) { @@ -5121,8 +5374,8 @@ } if (cmp === -1) { n = n.sub(); - var num = this.denom.pow(n); - var denom = this.num.pow(n); + var num = this.__denom__.pow(n); + var denom = this.__num__.pow(n); return LRational({ num, denom }); } var result = this; @@ -5135,8 +5388,8 @@ }; // ------------------------------------------------------------------------- LRational.prototype.sqrt = function() { - const num = this.num.sqrt(); - const denom = this.denom.sqrt(); + const num = this.__num__.sqrt(); + const denom = this.__denom__.sqrt(); if (num instanceof LFloat) { num = num.toRational(); } @@ -5147,8 +5400,8 @@ }; // ------------------------------------------------------------------------- LRational.prototype.abs = function() { - var num = this.num; - var denom = this.denom; + var num = this.__num__; + var denom = this.__denom__; if (num.cmp(0) === -1) { num = num.sub(); } @@ -5163,20 +5416,20 @@ }; // ------------------------------------------------------------------------- LRational.prototype.toString = function() { - var gcd = this.num.gcd(this.denom); + var gcd = this.__num__.gcd(this.__denom__); var num, denom; if (gcd.cmp(1) !== 0) { - num = this.num.div(gcd); + num = this.__num__.div(gcd); if (num instanceof LRational) { num = LNumber(num.valueOf(true)); } - denom = this.denom.div(gcd); + denom = this.__denom__.div(gcd); if (denom instanceof LRational) { denom = LNumber(denom.valueOf(true)); } } else { - num = this.num; - denom = this.denom; + num = this.__num__; + denom = this.__denom__; } const minus = this.cmp(0) < 0; if (minus) { @@ -5190,16 +5443,16 @@ }; // ------------------------------------------------------------------------- LRational.prototype.valueOf = function(exact) { - if (this.denom.cmp(0) === 0) { - if (this.num.cmp(0) < 0) { + if (this.__denom__.cmp(0) === 0) { + if (this.__num__.cmp(0) < 0) { return Number.NEGATIVE_INFINITY; } return Number.POSITIVE_INFINITY; } if (exact) { - return LNumber._ops['/'](this.num.value, this.denom.value); + return LNumber._ops['/'](this.__num__.value, this.__denom__.value); } - return LFloat(this.num.valueOf()).div(this.denom.valueOf()); + return LFloat(this.__num__.valueOf()).div(this.__denom__.valueOf()); }; // ------------------------------------------------------------------------- LRational.prototype.mul = function(n) { @@ -5207,8 +5460,8 @@ n = LNumber(n); // handle (--> 1/2 (mul 2)) } if (LNumber.isRational(n)) { - var num = this.num.mul(n.num); - var denom = this.denom.mul(n.denom); + var num = this.__num__.mul(n.__num__); + var denom = this.__denom__.mul(n.__denom__); return LRational({ num, denom }); } const [a, b] = LNumber.coerce(this, n); @@ -5220,8 +5473,8 @@ n = LNumber(n); // handle (--> 1/2 (div 2)) } if (LNumber.isRational(n)) { - var num = this.num.mul(n.denom); - var denom = this.denom.mul(n.num); + var num = this.__num__.mul(n.__denom__); + var denom = this.__denom__.mul(n.__num__); return LRational({ num, denom }); } const [a, b] = LNumber.coerce(this, n); @@ -5241,8 +5494,8 @@ n = LNumber(n); // handle (--> 1/2 (sub 1)) } if (LNumber.isRational(n)) { - var num = n.num.sub(); - var denom = n.denom; + var num = n.__num__.sub(); + var denom = n.__denom__; return this.add(LRational({ num, denom })); } if (!(n instanceof LNumber)) { @@ -5259,10 +5512,10 @@ n = LNumber(n); // handle (--> 1/2 (add 1)) } if (LNumber.isRational(n)) { - const a_denom = this.denom; - const b_denom = n.denom; - const a_num = this.num; - const b_num = n.num; + const a_denom = this.__denom__; + const b_denom = n.__denom__; + const a_num = this.__num__; + const b_num = n.__num__; let denom, num; if (a_denom !== b_denom) { num = b_denom.mul(a_num).add(b_num.mul(a_denom)); @@ -5286,14 +5539,15 @@ return new LBigInteger(n, native); } if (n instanceof LBigInteger) { - return LBigInteger(n.value, n._native); + return LBigInteger(n.__value__, n._native); } if (!LNumber.isBigInteger(n)) { throw new Error('Invalid constructor call for LBigInteger'); } - this.value = n; - this._native = native; - this.__type__ = 'bigint'; + this.constant(n, 'bigint'); + Object.defineProperty(this, '_native', { + value: native + }); } // ------------------------------------------------------------------------- LBigInteger.prototype = Object.create(LNumber.prototype); @@ -5314,17 +5568,17 @@ // ------------------------------------------------------------------------- LBigInteger.prototype._op = function(op, n) { if (typeof n === 'undefined') { - if (LNumber.isBN(this.value)) { + if (LNumber.isBN(this.__value__)) { op = LBigInteger.bn_op[op]; - return LBigInteger(this.value.clone()[op](), false); + return LBigInteger(this.__value__.clone()[op](), false); } - return LBigInteger(LNumber._ops[op](this.value), true); + return LBigInteger(LNumber._ops[op](this.__value__), true); } - if (LNumber.isBN(this.value) && LNumber.isBN(n.value)) { + if (LNumber.isBN(this.__value__) && LNumber.isBN(n.__value__)) { op = LBigInteger.bn_op[op]; - return LBigInteger(this.value.clone()[op](n), false); + return LBigInteger(this.__value__.clone()[op](n), false); } - const ret = LNumber._ops[op](this.value, n.value); + const ret = LNumber._ops[op](this.__value__, n.__value__); if (op === '/') { var is_integer = this.op('%', n).cmp(0) === 0; if (is_integer) { @@ -5339,10 +5593,10 @@ LBigInteger.prototype.sqrt = function() { var value; var minus = this.cmp(0) < 0; - if (LNumber.isNative(this.value)) { + if (LNumber.isNative(this.__value__)) { value = LNumber(Math.sqrt(minus ? -this.valueOf() : this.valueOf())); - } else if (LNumber.isBN(this.value)) { - value = minus ? this.value.neg().sqrt() : this.value.sqrt(); + } else if (LNumber.isBN(this.__value__)) { + value = minus ? this.__value__.neg().sqrt() : this.__value__.sqrt(); } if (minus) { return LComplex({ re: 0, im: value }); @@ -5358,16 +5612,28 @@ return new InputPort(read); } typecheck('InputPort', read, 'function'); + read_only(this, '__type__', text_port); + var parser; + Object.defineProperty(this, '__parser__', { + enumerable: true, + get: function() { + return parser; + }, + set: function(value) { + typecheck('InputPort::__parser__', value, 'parser'); + parser = value; + } + }); this._read = read; this._with_parser = this._with_init_parser.bind(this, async () => { if (!this.char_ready()) { const line = await this._read(); - this.__parser__ = new Parser(line, { env: this }); + parser = new Parser(line, { env: this }); } return this.__parser__; }); this.char_ready = function() { - return this.__parser__ && this.__parser__.__lexer__.peek() !== eof; + return !!this.__parser__ && this.__parser__.__lexer__.peek() !== eof; }; this._make_defaults(); } @@ -5403,7 +5669,7 @@ return this._with_parser !== null; }; InputPort.prototype.close = function() { - delete this.__parser__; + this.__parser__ = null; // make content garbage collected, we assign null, // because the value is in prototype this._with_parser = null; @@ -5426,6 +5692,7 @@ return new OutputPort(write); } typecheck('OutputPort', write, 'function'); + read_only(this, '__type__', text_port); this.write = write; } OutputPort.prototype.is_open = function() { @@ -5452,24 +5719,25 @@ return new OutputStringPort(toString); } typecheck('OutputStringPort', toString, 'function'); - this._buffer = []; + read_only(this, '__type__', text_port); + read_only(this, '__buffer__', []); this.write = (x) => { if (!LString.isString(x)) { x = toString(x); } else { x = x.valueOf(); } - this._buffer.push(x); + this.__buffer__.push(x); }; } OutputStringPort.prototype = Object.create(OutputPort.prototype); + OutputStringPort.prototype.constructor = OutputStringPort; OutputStringPort.prototype.toString = function() { - return '#<output-port <string>>'; + return '#<output-port (string)>'; }; - OutputStringPort.prototype.getString = function() { - return this._buffer.map(x => x.valueOf()).join(''); + OutputStringPort.prototype.valueOf = function() { + return this.__buffer__.map(x => x.valueOf()).join(''); }; - OutputStringPort.prototype.constructor = OutputStringPort; // ------------------------------------------------------------------------- function OutputFilePort(filename, fd) { if (typeof this !== 'undefined' && !(this instanceof OutputFilePort) || @@ -5477,26 +5745,40 @@ return new OutputFilePort(filename, fd); } typecheck('OutputFilePort', filename, 'string'); - this._filename = filename; - this._fd = fd.valueOf(); + read_only(this, '__filename__', filename); + read_only(this, '_fd', fd.valueOf(), { hidden: true }); + read_only(this, '__type__', text_port); this.write = (x) => { if (!LString.isString(x)) { x = toString(x); } else { x = x.valueOf(); } - root.fs.write(this._fd, x, function() { }); + this.fs().write(this._fd, x, function(err) { + if (err) { + throw err; + } + }); }; } OutputFilePort.prototype = Object.create(OutputPort.prototype); OutputFilePort.prototype.constructor = OutputFilePort; + OutputFilePort.prototype.fs = function() { + if (!this._fs) { + this._fs = this.internal('fs'); + } + return this._fs; + }; + OutputFilePort.prototype.internal = function(name) { + return user_env.get('**internal-env**').get(name); + }; OutputFilePort.prototype.close = function() { return new Promise((resolve, reject) => { - root.fs.close(this._fd, (err) => { + this.fs().close(this._fd, (err) => { if (err) { reject(err); } else { - this._fd = null; + read_only(this, '_fd', null, { hidden: true }); OutputPort.prototype.close.call(this); resolve(); } @@ -5504,7 +5786,7 @@ }); }; OutputFilePort.prototype.toString = function() { - return `#<output-port ${this._filename}>`; + return `#<output-port ${this.__filename__}>`; }; // ------------------------------------------------------------------------- function InputStringPort(string, env) { @@ -5521,6 +5803,7 @@ } return this.__parser__; }); + read_only(this, '__type__', text_port); this._make_defaults(); } InputStringPort.prototype.char_ready = function() { @@ -5529,7 +5812,132 @@ InputStringPort.prototype = Object.create(InputPort.prototype); InputStringPort.prototype.constructor = InputStringPort; InputStringPort.prototype.toString = function() { - return `#<input-port <string>>`; + return `#<input-port (string)>`; + }; + // ------------------------------------------------------------------------- + function InputByteVectorPort(bytevectors) { + if (typeof this !== 'undefined' && !(this instanceof InputByteVectorPort) || + typeof this === 'undefined') { + return new InputByteVectorPort(bytevectors); + } + typecheck('InputByteVectorPort', bytevectors, 'uint8array'); + read_only(this, '__vector__', bytevectors); + read_only(this, '__type__', binary_port); + var index = 0; + Object.defineProperty(this, '__index__', { + enumerable: true, + get: function() { + return index; + }, + set: function(value) { + typecheck('InputByteVectorPort::__index__', value, 'number'); + if (value instanceof LNumber) { + value = value.valueOf(); + } + if (typeof value === 'bigint') { + value = Number(value); + } + if (Math.floor(value) !== value) { + throw new Error('InputByteVectorPort::__index__ value is ' + + 'not integer'); + } + index = value; + } + }); + } + InputByteVectorPort.prototype = Object.create(InputPort.prototype); + InputByteVectorPort.prototype.constructor = InputByteVectorPort; + InputByteVectorPort.prototype.toString = function() { + return `#<input-port (bytevector)>`; + }; + InputByteVectorPort.prototype.close = function() { + read_only(this, '__vector__', nil); + ['read_u8', 'close', 'peek_u8', 'read_u8_vector'].forEach(name => { + this[name] = function() { + throw new Error('Input-binary-port: port is closed'); + }; + }); + this.char_ready = function() { + return false; + }; + }; + InputByteVectorPort.prototype.u8_ready = function() { + return true; + }; + InputByteVectorPort.prototype.peek_u8 = function() { + if (this.__index__ >= this.__vector__.length) { + return eof; + } + return this.__vector__[this.__index__]; + }; + InputByteVectorPort.prototype.skip = function() { + if (this.__index__ <= this.__vector__.length) { + ++this.__index__; + } + }; + InputByteVectorPort.prototype.read_u8 = function() { + const byte = this.peek_u8(); + this.skip(); + return byte; + }; + InputByteVectorPort.prototype.read_u8_vector = function(len) { + if (typeof len === 'undefined') { + len = this.__vector__.length; + } else if (len > this.__index__ + this.__vector__.length) { + len = this.__index__ + this.__vector__.length; + } + if (this.peek_u8() === eof) { + return eof; + } + return this.__vector__.slice(this.__index__, len); + }; + // ------------------------------------------------------------------------- + function OutputByteVectorPort() { + if (typeof this !== 'undefined' && !(this instanceof OutputByteVectorPort) || + typeof this === 'undefined') { + return new OutputByteVectorPort(); + } + read_only(this, '__type__', binary_port); + read_only(this, '_buffer', [], { hidden: true }); + this.write = function(x) { + typecheck('write', x, ['number', 'uint8array']); + if (LNumber.isNumber(x)) { + this._buffer.push(x.valueOf()); + } else { + this._buffer.push(...Array.from(x)); + } + }; + Object.defineProperty(this, '__buffer__', { + enumerable: true, + get: function() { + return Uint8Array.from(this._buffer); + } + }); + } + OutputByteVectorPort.prototype = Object.create(OutputPort.prototype); + OutputByteVectorPort.prototype.constructor = OutputByteVectorPort; + OutputByteVectorPort.prototype.close = function() { + OutputPort.prototype.close.call(this); + read_only(this, '_buffer', null, { hidden: true }); + }; + OutputByteVectorPort.prototype._close_guard = function() { + if (this._closed) { + throw new Error('output-port: binary port is closed'); + } + }; + OutputByteVectorPort.prototype.write_u8 = function(byte) { + typecheck('OutputByteVectorPort::write_u8', byte, 'number'); + this.write(byte); + }; + OutputByteVectorPort.prototype.write_u8_vector = function(vector) { + typecheck('OutputByteVectorPort::write_u8_vector', vector, 'uint8array'); + this.write(vector); + }; + OutputByteVectorPort.prototype.toString = function() { + return '#<output-port (bytevector)>'; + }; + OutputByteVectorPort.prototype.valueOf = function() { + return this.__buffer__; }; // ------------------------------------------------------------------------- function InputFilePort(content, filename) { @@ -5539,14 +5947,77 @@ } InputStringPort.call(this, content); typecheck('InputFilePort', filename, 'string'); - this.__filename__ = filename; + read_only(this, '__filename__', filename); } InputFilePort.prototype = Object.create(InputStringPort.prototype); InputFilePort.prototype.constructor = InputFilePort; InputFilePort.prototype.toString = function() { - return `#<input-port ${this.__filename__}>`; + return `#<input-port (${this.__filename__})>`; }; // ------------------------------------------------------------------------- + function InputBinaryFilePort(content, filename) { + if (typeof this !== 'undefined' && !(this instanceof InputBinaryFilePort) || + typeof this === 'undefined') { + return new InputBinaryFilePort(content, filename); + } + InputByteVectorPort.call(this, content); + typecheck('InputBinaryFilePort', filename, 'string'); + read_only(this, '__filename__', filename); + } + InputBinaryFilePort.prototype = Object.create(InputByteVectorPort.prototype); + InputBinaryFilePort.prototype.constructor = InputBinaryFilePort; + InputBinaryFilePort.prototype.toString = function() { + return `#<input-binary-port (${this.__filename__})>`; + }; + // ------------------------------------------------------------------------- + function OutputBinaryFilePort(filename, fd) { + if (typeof this !== 'undefined' && !(this instanceof OutputBinaryFilePort) || + typeof this === 'undefined') { + return new OutputBinaryFilePort(filename, fd); + } + typecheck('OutputBinaryFilePort', filename, 'string'); + read_only(this, '__filename__', filename); + read_only(this, '_fd', fd.valueOf(), { hidden: true }); + read_only(this, '__type__', binary_port); + var fs, Buffer; + this.write = function(x) { + typecheck('write', x, ['number', 'uint8array']); + var buffer; + if (!fs) { + fs = this.internal('fs'); + } + if (!Buffer) { + Buffer = this.internal('Buffer'); + } + if (LNumber.isNumber(x)) { + buffer = Buffer.from([x.valueOf()]); + } else { + buffer = Buffer.from(Array.from(x)); + } + return new Promise((resolve, reject) => { + fs.write(this._fd, buffer, function(err) { + if (err) { + reject(err); + } else { + resolve(); + } + }); + }); + }; + } + OutputBinaryFilePort.prototype = Object.create(OutputFilePort.prototype); + OutputBinaryFilePort.prototype.constructor = OutputBinaryFilePort; + OutputBinaryFilePort.prototype.write_u8 = function(byte) { + typecheck('OutputByteVectorPort::write_u8', byte, 'number'); + this.write(byte); + }; + OutputBinaryFilePort.prototype.write_u8_vector = function(vector) { + typecheck('OutputByteVectorPort::write_u8_vector', vector, 'uint8array'); + this.write(vector); + }; + // ------------------------------------------------------------------------- + const binary_port = Symbol.for('binary'); + const text_port = Symbol.for('text'); var eof = new EOF(); function EOF() {} EOF.prototype.toString = function() { @@ -5576,8 +6047,7 @@ if (is_port(stdout)) { inter.set('stdout', stdout); } - this.constant('**internal-env**', inter); - global_env.set('**interaction-environment**', this.__env__); + set_interaction_env(this.__env__, inter); } // ------------------------------------------------------------------------- Interpreter.prototype.exec = function(code, dynamic = false, env = null) { @@ -5617,7 +6087,7 @@ parent = null; } else if (typeof arguments[0] === 'string') { obj = {}; - parent = {}; + parent = null; name = arguments[0]; } } @@ -5631,6 +6101,10 @@ return get_props(this.__env__); }; // ------------------------------------------------------------------------- + Environment.prototype.fs = function() { + return this.get('**fs**'); + }; + // ------------------------------------------------------------------------- Environment.prototype.unset = function(name) { if (name instanceof LSymbol) { name = name.valueOf(); @@ -5653,7 +6127,7 @@ // ------------------------------------------------------------------------- // :: lookup function for variable doc strings // ------------------------------------------------------------------------- - Environment.prototype.doc = function(name, value = null) { + Environment.prototype.doc = function(name, value = null, dump = false) { if (name instanceof LSymbol) { name = name.__name__; } @@ -5661,6 +6135,9 @@ name = name.valueOf(); } if (value) { + if (!dump) { + value = trim_lines(value); + } this.__docs__.set(name, value); return this; } @@ -5983,7 +6460,7 @@ 'letter-unicode-regex': /\p{L}/u, 'numeral-unicode-regex': /\p{N}/u, 'space-unicode-regex': /\s/u - }); + }, undefined, 'internal'); // ------------------------------------------------------------------------- var global_env = new Environment({ nil, @@ -5992,53 +6469,52 @@ 'true': true, 'false': false, 'null': null, - 'NaN': NaN, + 'NaN': LNumber(NaN), // ------------------------------------------------------------------ - 'peek-char': doc('peek-char', function(port) { - if (port) { - typecheck('peek-char', port, ['input-port']); - } else { + 'peek-char': doc('peek-char', function(port = null) { + if (port === null) { port = internal(this, 'stdin'); } + typecheck_text_port('peek-char', port, 'input-port'); return port.peek_char(); }, `(peek-char port) Function get character from string port or EOF object if no more data in string port.`), // ------------------------------------------------------------------ - 'read-line': doc('read-line', function(port) { - if (typeof port === 'undefined') { + 'read-line': doc('read-line', function(port = null) { + if (port === null) { port = internal(this, 'stdin'); } - typecheck('read-line', port, ['input-port']); + typecheck_text_port('read-line', port, 'input-port'); return port.read_line(); }, `(read-char port) Function read next character from input port.`), // ------------------------------------------------------------------ - 'read-char': doc('read-char', function(port) { - if (typeof port === 'undefined') { + 'read-char': doc('read-char', function(port = null) { + if (port === null) { port = internal(this, 'stdin'); } - typecheck('read-char', port, ['input-port', 'input-string-port']); + typecheck_text_port('read-char', port, 'input-port'); return port.read_char(); }, `(read-char port) Function read next character from input port.`), // ------------------------------------------------------------------ - read: doc(async function read(arg) { + read: doc(async function read(arg = null) { if (LString.isString(arg)) { for await (let value of parse(arg, this)) { return value; } } var port; - if (arg) { - typecheck('read', arg, 'input-port'); - port = arg; - } else { + if (arg === null) { port = internal(this, 'stdin'); + } else { + port = arg; } + typecheck_text_port('read', port, 'input-port'); return port.read.call(this); }, `(read [string]) @@ -6119,6 +6595,8 @@ display: doc(function display(arg, port = null) { if (port === null) { port = internal(this, 'stdout'); + } else { + typecheck('display', port, 'output-port'); } const value = global_env.get('repr')(arg); port.write.call(global_env, value); @@ -6481,6 +6959,14 @@ Values are evaluated sequentialy and next value can access to previous values/names.`), // --------------------------------------------------------------------- + 'letrec*': doc( + let_macro(Symbol.for('letrec')), + `(letrec* ((a value-a) (b value-b)) body) + + Same as letrec but the order of execution of the binding is guaranteed, + so use can use recursive code as well as reference previous binding. + In LIPS both letrec and letrec* behave the same.`), + // --------------------------------------------------------------------- 'let*': doc( let_macro(Symbol.for('let*')), `(let* ((a value-a) (b value-b)) body) @@ -6600,7 +7086,7 @@ LString.isString(code.cdr.cdr.car)) { __doc__ = code.cdr.cdr.car.valueOf(); } - env.set(code.car, value, __doc__); + env.set(code.car, value, __doc__, true); }); }), `(define name expression) (define (function-name . args) body) @@ -7042,7 +7528,7 @@ function unquoted_arr(arr) { return !!arr.filter(value => { return value instanceof Pair && - LSymbol.is(value.car, 'unquote'); + LSymbol.is(value.car, /^(unquote|unquote-splicing)$/); }).length; } // ----------------------------------------------------------------- @@ -7066,7 +7552,7 @@ if (!(result instanceof Pair)) { throw new Error(`Expecting list ${type(x)} found`); } - return acc.concat(result.toArray()); + return acc.concat(result.to_array()); } acc.push(recur(x, unquote_cnt, max_unq)); return acc; @@ -7485,9 +7971,18 @@ Function return string LIPS representation of an object as string.`), // ------------------------------------------------------------------ + 'escape-regex': doc('escape-regex', function(string) { + typecheck('escape-regex', string, 'string'); + return escape_regex(string.valueOf()); + }, `(escape-regex string) + + Function return new string where all special operators used in regex, + are escaped with slash so they can be used in RegExp constructor + to match literal string`), + // ------------------------------------------------------------------ env: doc(function env(env) { env = env || this; - var names = Object.keys(env.__env__); + var names = Object.keys(env.__env__).map(LSymbol); // TODO: get symbols var result; if (names.length) { @@ -7495,13 +7990,15 @@ } else { result = nil; } - if (env.__parent__ !== undefined) { + if (env.__parent__ instanceof Environment) { return global_env.get('env')(env.__parent__).append(result); } return result; - }, `(env obj) + }, `(env) + (env obj) - Function return list values (functions and variables) inside environment.`), + Function return list of values (functions, macros and variables) + inside environment and it's parents.`), // ------------------------------------------------------------------ 'new': doc('new', function(obj, ...args) { var instance = new (unbind(obj))(...args.map(x => unbox(x))); @@ -7563,10 +8060,12 @@ Function stop JavaScript code in debugger.`), // ------------------------------------------------------------------ 'in': doc('in', function(a, b) { - if (a instanceof LSymbol || a instanceof LString) { + if (a instanceof LSymbol || + a instanceof LString || + a instanceof LNumber) { a = a.valueOf(); } - return a in b; + return a in unbox(b); }, `(in key value) Function use is in operator to check if value is in object.`), @@ -7609,12 +8108,11 @@ Function check if value is real number.`), // ------------------------------------------------------------------ - 'number?': doc( - 'number?', - LNumber.isNumber, - `(number? expression) + 'number?': doc('number?', function(x) { + return Number.isNaN(x) || LNumber.isNumber(x); + }, `(number? expression) - Function check if value is a number`), + Function check if value is a number or NaN value.`), // ------------------------------------------------------------------ 'string?': doc('string?', function(obj) { return LString.isString(obj); @@ -7687,14 +8185,14 @@ // ------------------------------------------------------------------ 'tree->array': doc( 'tree->array', - toArray('tree->array', true), + to_array('tree->array', true), `(tree->array list) Function convert LIPS list structure into JavaScript array.`), // ------------------------------------------------------------------ 'list->array': doc( 'list->array', - toArray('list->array'), + to_array('list->array'), `(list->array list) Function convert LIPS list into JavaScript array.`), @@ -8050,7 +8548,11 @@ (define add1 (curry add 1)) (define add12 (add 2)) (display (add12 3 4))`), + // ------------------------------------------------------------------ + // Numbers + // ------------------------------------------------------------------ 'gcd': doc(function gcd(...args) { + typecheck_args('lcm', args, 'number'); return args.reduce(function(result, item) { return result.gcd(item); }); @@ -8059,6 +8561,7 @@ Function return the greatest common divisor of their arguments.`), // ------------------------------------------------------------------ 'lcm': doc(function lcm(...args) { + typecheck_args('lcm', args, 'number'); // ref: https://rosettacode.org/wiki/Least_common_multiple#JavaScript var n = args.length, a = abs(args[0]); for (var i = 1; i < n; i++) { @@ -8104,6 +8607,7 @@ if (args.length === 0) { throw new Error('-: procedure require at least one argument'); } + typecheck_args('-', args, 'number'); if (args.length === 1) { return LNumber(args[0]).sub(); } @@ -8113,17 +8617,27 @@ })); } }, `(- n1 n2 ...) - (- n1) + (- n) Substract number passed as argument. If only one argument is passed it will negate the value.`), // ------------------------------------------------------------------ - '/': doc('/', reduceMathOp(function(a, b) { - return LNumber(a).div(b); - }), `(/ . numbers) + '/': doc('/', function(...args) { + if (args.length === 0) { + throw new Error('/: procedure require at least one argument'); + } + typecheck_args('/', args, 'number'); + if (args.length === 1) { + return LNumber(1).div(args[0]); + } + return args.reduce(binaryMathOp(function(a, b) { + return LNumber(a).div(b); + })); + }, `(/ n1 n2 ...) + (/ n) - Divide number passed as arguments one by one. If single argument - is passed it will return that value.`), + Divide number passed as arguments one by one. If single argument + is passed it will calculate (/ 1 n1).`), // ------------------------------------------------------------------ abs: doc('abs', singleMathOp(function(n) { return LNumber(n).abs(); @@ -8132,6 +8646,7 @@ Function create absolute value from number.`), // ------------------------------------------------------------------ truncate: doc('truncate', function(n) { + typecheck('truncate', n, 'number'); if (LNumber.isFloat(n)) { if (n instanceof LNumber) { n = n.valueOf(); @@ -8173,6 +8688,7 @@ Function substract 1 from the number and return result.`), // ------------------------------------------------------------------ '%': doc('%', function(a, b) { + typecheck_args('%', [a, b], 'number'); return LNumber(a).rem(b); }, `(% n1 n2) @@ -8180,35 +8696,40 @@ // ------------------------------------------------------------------ // Booleans '==': doc('==', function(...args) { + typecheck_args('==', args, 'number'); return seq_compare((a, b) => LNumber(a).cmp(b) === 0, args); - }, `(== x1 x2 x3 ...) + }, `(== x1 x2 ...) Function compare its numerical arguments and check if they are equal`), // ------------------------------------------------------------------ '>': doc('>', function(...args) { + typecheck_args('>', args, 'number'); return seq_compare((a, b) => LNumber(a).cmp(b) === 1, args); - }, `(> x1 x2 x3 ...) + }, `(> x1 x2 ...) Function compare its numerical arguments and check if they are monotonically increasing`), // ------------------------------------------------------------------ '<': doc('<', function(...args) { + typecheck_args('<', args, 'number'); return seq_compare((a, b) => LNumber(a).cmp(b) === -1, args); - }, `(< x1 x2 x3 ...) + }, `(< x1 x2 ...) Function compare its numerical arguments and check if they are monotonically decreasing`), // ------------------------------------------------------------------ '<=': doc(function(...args) { + typecheck_args('<=', args, 'number'); return seq_compare((a, b) => [0, -1].includes(LNumber(a).cmp(b)), args); - }, `(<= x1 x2 x3 ...) + }, `(<= x1 x2 ...) Function compare its numerical arguments and check if they are monotonically nonincreasing`), // ------------------------------------------------------------------ '>=': doc('>=', function(...args) { + typecheck_args('>=', args, 'number'); return seq_compare((a, b) => [0, 1].includes(LNumber(a).cmp(b)), args); - }, `(>= x1 x2 x3 ...) + }, `(>= x1 x2 ...) Function compare its numerical arguments and check if they are monotonically nondecreasing`), @@ -8328,8 +8849,30 @@ Function return negation of the argument.`) }, undefined, 'global'); var user_env = global_env.inherit('user-env'); - global_env.set('**interaction-environment**', user_env); - global_env.constant('**internal-env**', internal_env); + // ------------------------------------------------------------------------- + function set_interaction_env(interaction, internal) { + interaction.constant('**internal-env**', internal); + interaction.doc( + '**internal-env**', + `**internal-env** + + Constant used to hide stdin, stdout and stderr so they don't interfere + with variables with the same name. Constants are internal type + of variables that can't be redefined, defining variable with same name + will throw an error.` + ); + global_env.set('**interaction-environment**', interaction); + } + // ------------------------------------------------------------------------- + set_interaction_env(user_env, internal_env); + global_env.doc( + '**interaction-environment**', + `**interaction-environment** + + Internal dynamic, global variable used to find interpreter environment. + It's used so the read and write functions can locate **internal-env** + that contain references to stdin, stdout and stderr.` + ); // ------------------------------------------------------------------------- (function() { var map = { ceil: 'ceiling' }; @@ -8490,12 +9033,29 @@ return `Expecting ${expected}, got ${got}${postfix}`; } // ------------------------------------------------------------------------- + function typecheck_args(fn, args, expected) { + args.forEach((arg, i) => { + typecheck(fn, arg, expected, i + 1); + }); + } + // ------------------------------------------------------------------------- + function typecheck_text_port(fn, arg, type) { + typecheck(fn, arg, type); + if (arg.__type__ === binary_port) { + throw new Error(typeErrorMessage( + fn, + 'binary-port', + 'textual-port' + )); + } + } + // ------------------------------------------------------------------------- function typecheck(fn, arg, expected, position = null) { fn = fn.valueOf(); const arg_type = type(arg).toLowerCase(); var match = false; if (expected instanceof Pair) { - expected = expected.toArray(); + expected = expected.to_array(); } if (expected instanceof Array) { expected = expected.map(x => x.valueOf()); @@ -8560,7 +9120,7 @@ 'native-symbol': Symbol }; if (Number.isNaN(obj)) { - return 'NaN '; + return 'NaN'; } if (obj === nil) { return 'nil'; @@ -8577,6 +9137,9 @@ if (obj.__instance__) { obj.__instance__ = false; if (obj.__instance__) { + if (is_function(obj.toType)) { + return obj.toType(); + } return 'instance'; } } @@ -8595,9 +9158,6 @@ return obj.constructor.name.toLowerCase(); } } - if (is_function(obj) && obj[Symbol.for('promise')]) { - return 'promise'; - } return typeof obj; } // ------------------------------------------------------------------------- @@ -8836,6 +9396,15 @@ // escape promise feature #54 var __promise__ = env.get(Symbol.for('__promise__'), { throwError: false }); if (__promise__ === true && is_promise(result)) { + // fix #139 evaluate the code inside the promise that is not data. + // When promise is not quoted it happen automatically, when returing + // promise from evaluate. + result = result.then(result => { + if (result instanceof Pair && !value[__data__]) { + return evaluate(result, eval_args); + } + return result; + }); return new QuotedPromise(result); } return result; @@ -8859,8 +9428,13 @@ dynamic_scope, error: (e, code) => { if (e && e.message) { - // clean duplicated Error: added by JS - e.message = e.message.replace(/.*:\s*([^:]+:\s*)/, '$1'); + if (e.message.match(/^Error:/)) { + // clean duplicated Error: added by JS + e.message = e.message.replace(/.*:\s*([^:]+:\s*)/, '$1'); + } else { + // add missing Error + e.message = `Error: ${e.message}`; + } if (code) { // LIPS stack trace if (!(e.__code__ instanceof Array)) { @@ -9195,10 +9769,13 @@ You can also use (help name) to display help for specic function or macro and OutputPort.__class__ = 'output-port'; OutputStringPort.__class__ = 'output-string-port'; InputStringPort.__class__ = 'input-string-port'; + InputFilePort.__class__ = 'input-file-port'; + OutputFilePort.__class__ = 'output-file-port'; // types used for detect lips objects LNumber.__class__ = 'number'; LCharacter.__class__ = 'character'; LString.__class__ = 'string'; + QuotedPromise.__class__ = 'promise'; // ------------------------------------------------------------------------- var lips = { version: '{{VER}}', @@ -9236,6 +9813,10 @@ You can also use (help name) to display help for specic function or macro and OutputFilePort, InputStringPort, OutputStringPort, + InputByteVectorPort, + OutputByteVectorPort, + InputBinaryFilePort, + OutputBinaryFilePort, Formatter, Parser, diff --git a/templates/Makefile b/templates/Makefile index 64e99527..ae551e31 100755 --- a/templates/Makefile +++ b/templates/Makefile @@ -29,8 +29,9 @@ MERMAID=./node_modules/.bin/mmdc NPM=npm UGLIFY=./node_modules/.bin/uglifyjs ROLLUP=./node_modules/.bin/rollup +LIPS=./bin/lips.js -ALL: Makefile package.json .$(VERSION) assets/classDiagram.svg dist/lips.js dist/lips.min.js README.md dist/std.scm +ALL: Makefile package.json .$(VERSION) assets/classDiagram.svg dist/lips.js dist/lips.min.js README.md dist/std.min.scm dist/lips.js: src/lips.js .$(VERSION) rollup.config.js $(ROLLUP) -c @@ -45,8 +46,11 @@ dist/lips.js: src/lips.js .$(VERSION) rollup.config.js dist/lips.min.js: dist/lips.js .$(VERSION) $(UGLIFY) -o dist/lips.min.js --comments --mangle -- dist/lips.js -dist/std.scm: lib/bootstrap.scm lib/R5RS.scm lib/byte-vectors.scm lib/R7RS.scm - $(CAT) lib/bootstrap.scm lib/R5RS.scm lib/byte-vectors.scm lib/R7RS.scm > dist/std.scm +dist/std.scm: lib/bootstrap.scm lib/R5RS.scm lib/byte-vectors.scm lib/R7RS.scm lib/srfi.scm + $(CAT) lib/bootstrap.scm lib/R5RS.scm lib/byte-vectors.scm lib/R7RS.scm lib/srfi.scm > dist/std.scm + +dist/std.min.scm: dist/std.scm + $(LIPS) ./scripts/minify.scm dist/std.scm > dist/std.min.scm Makefile: templates/Makefile $(SED) -e "s/{{VER""SION}}/"$(VERSION)"/g" templates/Makefile > Makefile @@ -82,10 +86,10 @@ publish: jest-test: dist/lips.js @$(JEST) --coverage spec/*.spec.js -test: dist/lips.js dist/std.scm +test: dist/lips.js dist/std.min.scm @$(NPM) run test -test-file: dist/lips.js dist/std.scm +test-file: dist/lips.js dist/std.min.scm @$(NPM) run test -- -- -f $(FILE) test-update: dist/lips.js dist/std.scm diff --git a/templates/README.md b/templates/README.md index b89a8a79..e9c2df4b 100644 --- a/templates/README.md +++ b/templates/README.md @@ -185,6 +185,24 @@ Executables also return a S-Expression according to SRFI-176 use `lips --version * [Git Repository](https://github.com/jcubic/lips) * [Official Website](https://lips.js.org/) +## Roadmap + +### 1.0 +- [x] Full support for R5RS +- [ ] Full support for R7RS +- [ ] Continuations. +- [ ] Tail Call Optimization (TCO). +- [ ] Fully tested Numerical Tower. +- [ ] R7RS libraries (`import`/`export`/`define-library`). +- [ ] All recursive function in JS don't consume stack. +- [ ] Finish `syntax-rules` (ignore limitations of current approach). + - [ ] Objects. + - [ ] Vectors. + +### 1.1 +- [ ] Proper expansion time for both macro system. +- [ ] Fully working and tested R7RS hygienic Macros (`syntax-rules`). + ## Acknowledgments * Font used in logo is [Telegrafico](https://www.dafont.com/telegrafico.font) by [ficod](https://www.deviantart.com/ficod). * Current parser is inspired by implementation in [BiwaScheme](https://www.biwascheme.org/) by Yutaka HARA (yhara). diff --git a/tests/core.scm b/tests/core.scm index 1271009d..0f4f52a1 100644 --- a/tests/core.scm +++ b/tests/core.scm @@ -230,6 +230,29 @@ (await p) (t.is result #(10))))) +(test "core: quoted promise of object with then method" + (lambda (t) + (let ((p '>(object :then (lambda () 10)))) + (--> p (then (lambda (result) + (t.is result 10)))) + (t.is (await p) 10)))) + +(test "core: quoted promise repr" + (lambda (t) + (let ((resolve)) + (define promise '>(new Promise (lambda (r) (set! resolve r)))) + (t.is (repr promise) "#<js-promise (pending)>") + (resolve "xx") + (t.is (await promise) "xx") + (t.is (repr promise) "#<js-promise resolved (string)>")) + (let ((reject)) + (define promise '>(new Promise (lambda (_ r) (set! reject r)))) + (t.is (repr promise) "#<js-promise (pending)>") + (reject (new Error "ZONK")) + (t.is (to.throw (await promise)) true) + (t.is (repr promise) "#<js-promise (rejected)>") + (t.is (not (null? (promise.__reason__.message.match #/ZONK/))) true)))) + (test "core: regex" (lambda (t) (let* ((str "#/(\\((?:env|dir|help|apropos)[^)]*\\))/g") diff --git a/tests/formatter.scm b/tests/formatter.scm index 7303a1bc..559dbb74 100644 --- a/tests/formatter.scm +++ b/tests/formatter.scm @@ -10,13 +10,13 @@ (display "not zero") (newline)))))))) + (test "formatter: named let" (lambda (t) (t.snapshot (pretty-format '(let iter ((x 10)) (if (not (zero? x)) (iter (- x 1)))))))) - (test "formatter: let" (lambda (t) (t.snapshot (pretty-format '(let ((x 10)) @@ -24,8 +24,35 @@ (print x)))) (t.snapshot (pretty-format '(let ((x)) + 10 + 20 + "xx + yy" (print x) - (print x)))))) + (print x)))) + + (t.snapshot (pretty-format '(let ((bar (foo bar (baz))) + (foo 10)) + 10 + 20 + "xx + yy" + (foo bar) + (print0)))) + + (t.snapshot (pretty-format '(let ((bar) + (foo (baz quux)) + (foo 10)) + (foo bar) + (print0)))) + + (t.snapshot (pretty-format '(let ((foo 10) + (xxx (if (null? rest) + (current-input-port) + (car rest))) + (bar foo)) + (foo bar) + (print0)))))) (test "formatter: cond" (lambda (t) @@ -48,9 +75,9 @@ (test "formatter: define" (lambda (t) - (t.snapshot (pretty-format '(define (foo (x) (+ x x))))) + (t.snapshot (pretty-format '(define (foo x) (+ x x)))) - (t.snapshot (pretty-format '(define (foo (x) "xxx" (+ x x))))) + (t.snapshot (pretty-format '(define (foo x) "xxx" (+ x x)))) (t.snapshot (pretty-format '(define foo (lambda (x) (+ x x))))) @@ -58,6 +85,11 @@ (t.snapshot (pretty-format '(define foo (list 1 2 3)))) + (t.snapshot (pretty-format '(define (foo x) + "foo + bar" + (+ x x)))) + (t.snapshot (pretty-format '(define foo 10))))) diff --git a/tests/numbers.scm b/tests/numbers.scm index e0d6639b..4e0f89b7 100644 --- a/tests/numbers.scm +++ b/tests/numbers.scm @@ -15,10 +15,166 @@ (test "numbers: complex rational" (lambda (t) - (t.is (/ (make-rectangular 1 2) (make-rectangular 2 10)) (/ 1+2i 2+10i)))) +(test "numbers: NaN" + (lambda (t) + (t.is (= +nan.0 +nan.0) false) + (t.is (eq? +nan.0 +nan.0) false) + (t.is (eqv? +nan.0 +nan.0) true) + (t.is (equal? +nan.0 +nan.0) true) + (t.is (eq? 10 +nan.0) false) + (t.is (eq? +nan.0 10) false))) + +(test "numbers: complex NaN" + (lambda (t) + (t.is (number->string +nan.0+10i) "+nan.0+10i") + (t.is (number->string +nan.0+10.0i) "+nan.0+10.0i") + (t.is (number->string +nan.0+1/2i) "+nan.0+1/2i") + + (t.is (number->string 10+nan.0i) "10+nan.0i") + (t.is (number->string 10.0+nan.0i) "10.0+nan.0i") + (t.is (number->string 1/2+nan.0i) "1/2+nan.0i") + + (t.is (number->string -nan.0+10i) "+nan.0+10i") + (t.is (number->string -nan.0+10.0i) "+nan.0+10.0i") + (t.is (number->string -nan.0+1/2i) "+nan.0+1/2i") + + (t.is (number->string 10-nan.0i) "10+nan.0i") + (t.is (number->string 10.0-nan.0i) "10.0+nan.0i") + (t.is (number->string 1/2-nan.0i) "1/2+nan.0i"))) + +(test "numbers: operators + with NaN" + (lambda (t) + (t.is (+ +nan.0+nan.0i 10) +nan.0+nan.0i) + (t.is (+ +nan.0+nan.0i 10.0) +nan.0+nan.0i) + (t.is (+ +nan.0+nan.0i 1/2) +nan.0+nan.0i) + (t.is (+ +nan.0+nan.0i +nan.0+nan.0i) +nan.0+nan.0i) + + (t.is (+ +nan.0+nan.0i 1/2+1/2i) +nan.0+nan.0i) + (t.is (+ +nan.0+nan.0i 10+10i) +nan.0+nan.0i) + (t.is (+ +nan.0+nan.0i 10.0+10.0i) +nan.0+nan.0i) + + (t.is (+ 10+nan.0i 10) 20+nan.0i) + (t.is (+ 10.0+nan.0i 10.0) 20.0+nan.0i) + (t.is (+ 1/2+nan.0i 1/2) 1+nan.0i) + + (t.is (+ 10+nan.0i 10) 20+nan.0i) + (t.is (+ 10.0+nan.0i 10.0) 20.0+nan.0i) + (t.is (+ 1/2+nan.0i 1/2) 1+nan.0i) + + (t.is (+ +nan.0i 10) 10+nan.0i) + (t.is (+ +nan.0i 10.0) 10.0+nan.0i) + (t.is (+ +nan.0i 1/2) 1/2+nan.0i) + (t.is (+ +nan.0i 10+10i) 10+nan.0i) + + (t.is (+ +nan.0 10) +nan.0) + (t.is (+ +nan.0 10.0) +nan.0) + (t.is (+ +nan.0 1/2) +nan.0) + (t.is (+ +nan.0 10+10i) +nan.0+10i) + ;; reversed + (t.is (+ 10 +nan.0+nan.0i) +nan.0+nan.0i) + (t.is (+ 10.0 +nan.0+nan.0i) +nan.0+nan.0i) + (t.is (+ 1/2 +nan.0+nan.0i) +nan.0+nan.0i) + (t.is (+ +nan.0+nan.0i +nan.0+nan.0i) +nan.0+nan.0i) + + (t.is (+ 1/2+1/2i +nan.0+nan.0i) +nan.0+nan.0i) + (t.is (+ 10+10i +nan.0+nan.0i) +nan.0+nan.0i) + (t.is (+ 10.0+10.0i +nan.0+nan.0i) +nan.0+nan.0i) + + (t.is (+ 10 10+nan.0i) 20+nan.0i) + (t.is (+ 10.0 10.0+nan.0i) 20.0+nan.0i) + (t.is (+ 1/2 1/2+nan.0i) 1+nan.0i) + + (t.is (+ 10 10+nan.0i) 20+nan.0i) + (t.is (+ 10.0 10.0+nan.0i) 20.0+nan.0i) + (t.is (+ 1/2 1/2+nan.0i) 1+nan.0i) + + (t.is (+ 10 +nan.0i) 10+nan.0i) + (t.is (+ 10.0 +nan.0i) 10.0+nan.0i) + (t.is (+ 1/2 +nan.0i) 1/2+nan.0i) + (t.is (+ 10+10i +nan.0i) 10+nan.0i) + + (t.is (+ 10 +nan.0) +nan.0) + (t.is (+ 10.0 +nan.0) +nan.0) + (t.is (+ 1/2 +nan.0) +nan.0) + (t.is (+ 10+10i +nan.0) +nan.0+10i))) + +(test "numbers: operators + with +inf.0" + (lambda (t) + (t.is (+ +inf.0+inf.0i 10) +inf.0+inf.0i) + (t.is (+ +inf.0+inf.0i 10.0) +inf.0+inf.0i) + (t.is (+ +inf.0+inf.0i 1/2) +inf.0+inf.0i) + (t.is (+ +inf.0+inf.0i +inf.0+inf.0i) +inf.0+inf.0i) + + (t.is (+ +inf.0+inf.0i 1/2+1/2i) +inf.0+inf.0i) + (t.is (+ +inf.0+inf.0i 10+10i) +inf.0+inf.0i) + (t.is (+ +inf.0+inf.0i 10.0+10.0i) +inf.0+inf.0i) + + (t.is (+ 10+inf.0i 10) 20+inf.0i) + (t.is (+ 10.0+inf.0i 10.0) 20.0+inf.0i) + (t.is (+ 1/2+inf.0i 1/2) 1+inf.0i) + + (t.is (+ 10+inf.0i 10) 20+inf.0i) + (t.is (+ 10.0+inf.0i 10.0) 20.0+inf.0i) + (t.is (+ 1/2+inf.0i 1/2) 1+inf.0i) + + (t.is (+ +inf.0i 10) 10+inf.0i) + (t.is (+ +inf.0i 10.0) 10.0+inf.0i) + (t.is (+ +inf.0i 1/2) 1/2+inf.0i) + (t.is (+ +inf.0i 10+10i) 10+inf.0i) + + (t.is (+ +inf.0 10) +inf.0) + (t.is (+ +inf.0 10.0) +inf.0) + (t.is (+ +inf.0 1/2) +inf.0) + (t.is (+ +inf.0 10+10i) +inf.0+10i) + ;; reversed + (t.is (+ 10 +inf.0+inf.0i) +inf.0+inf.0i) + (t.is (+ 10.0 +inf.0+inf.0i) +inf.0+inf.0i) + (t.is (+ 1/2 +inf.0+inf.0i) +inf.0+inf.0i) + (t.is (+ +inf.0+inf.0i +inf.0+inf.0i) +inf.0+inf.0i) + + (t.is (+ 1/2+1/2i +inf.0+inf.0i) +inf.0+inf.0i) + (t.is (+ 10+10i +inf.0+inf.0i) +inf.0+inf.0i) + (t.is (+ 10.0+10.0i +inf.0+inf.0i) +inf.0+inf.0i) + + (t.is (+ 10 10+inf.0i) 20+inf.0i) + (t.is (+ 10.0 10.0+inf.0i) 20.0+inf.0i) + (t.is (+ 1/2 1/2+inf.0i) 1+inf.0i) + + (t.is (+ 10 10+inf.0i) 20+inf.0i) + (t.is (+ 10.0 10.0+inf.0i) 20.0+inf.0i) + (t.is (+ 1/2 1/2+inf.0i) 1+inf.0i) + + (t.is (+ 10 +inf.0i) 10+inf.0i) + (t.is (+ 10.0 +inf.0i) 10.0+inf.0i) + (t.is (+ 1/2 +inf.0i) 1/2+inf.0i) + (t.is (+ 10+10i +inf.0i) 10+inf.0i) + + (t.is (+ 10 +inf.0) +inf.0) + (t.is (+ 10.0 +inf.0) +inf.0) + (t.is (+ 1/2 +inf.0) +inf.0) + (t.is (+ 10+10i +inf.0) +inf.0+10i))) + +(test "numbers: complex infinity" + (lambda (t) + (t.is (number->string +inf.0+10i) "+inf.0+10i") + (t.is (number->string +inf.0+10.0i) "+inf.0+10.0i") + (t.is (number->string +inf.0+1/2i) "+inf.0+1/2i") + + (t.is (number->string 10+inf.0i) "10+inf.0i") + (t.is (number->string 10.0+inf.0i) "10.0+inf.0i") + (t.is (number->string 1/2+inf.0i) "1/2+inf.0i") + + (t.is (number->string -inf.0+10i) "-inf.0+10i") + (t.is (number->string -inf.0+10.0i) "-inf.0+10.0i") + (t.is (number->string -inf.0+1/2i) "-inf.0+1/2i") + + (t.is (number->string 10-inf.0i) "10-inf.0i") + (t.is (number->string 10.0-inf.0i) "10.0-inf.0i") + (t.is (number->string 1/2-inf.0i) "1/2-inf.0i"))) + (test "numbers: not numbers" (lambda (t) (t.is (. (lips.parse "0.1/0.1") 0) '0.1/0.1) @@ -56,8 +212,8 @@ (t.is (number->string (. (lips.parse "#i100") 0)) "100.0") (t.is (number->string (. (lips.parse "#i100i") 0)) "+100.0i") - (t.is (number->string (. (lips.parse "#i1/0") 0)) "Infinity") - (t.is (number->string (. (lips.parse "#i-1/0") 0)) "-Infinity") + (t.is (number->string (. (lips.parse "#i1/0") 0)) "+inf.0") + (t.is (number->string (. (lips.parse "#i-1/0") 0)) "-inf.0") (t.is #b100+100i 4+4i) (t.is (number->string 100) "100") @@ -236,7 +392,14 @@ (test "numbers: complex" (lambda (t) - (t.is (sqrt -1) +1.0i) + (t.is 10+0i 10) + (t.is 10+0i 10) + (t.is 10.0+0i 10.0) + (t.is 10+0.0i 10+0.0i) + (t.is 10.0+0.0i 10.0+0.0i) + (t.is 1/2+0i 1/2) + (t.is 1/2+0.0i 1/2+0.0i) + (t.is (sqrt -1) +1i) (t.is (sqrt 0.5) 0.7071067811865476) (t.is (sqrt -0.5) +0.7071067811865476i) (t.is (number->string 10e+10i) "+100000000000i") @@ -328,8 +491,76 @@ (t.is (+ 1/2+0.1i 1/2) 1+0.1i) (t.is (+ 1/2+0.1i 0.1) 0.6+0.1i))) +(test "numbers: operators -" + (lambda (t) + (t.is (- 1 1.0 1/10) -0.1) + (t.is (number->string (- 1/2 1/2 1.0)) "-1.0") + + (t.is (number->string (- 1 1)) "0") + (t.is (number->string (- 1.0 1)) "0.0") + (t.is (number->string (- 1 1.0)) "0.0") + + (t.is (number->string (- 1 1.1)) "-0.10000000000000009") + (t.is (number->string (- 1.1 1)) "0.10000000000000009") + + (t.is (number->string (- 1/2 1/3)) "1/6") + (t.is (number->string (- 1 1/2)) "1/2") + (t.is (number->string (- 1/2 1)) "-1/2") + + (t.is (number->string (- 1.1 1/2)) "0.6000000000000001") + (t.is (number->string (- 1/2 1.1)) "-0.6000000000000001") + + (t.is (- 0.1 +10i) 0.1-10.0i) + (t.is (- 10 +0.01i) 10-0.01i) + (t.is (- 1/10 +0.01i) 1/10-0.01i) + (t.is (- 0.01 +1/10i) 0.01-1/10i) + (t.is (- 1/10 #b100i) 1/10-4i) + (t.is (- #b100 +1/10i) 4-1/10i) + + (t.is (- 10 1) 9) + (t.is (- 10 1/2) 19/2) + (t.is (- 10 0.1) 9.9) + (t.is (- 10 10+10i) -10i) + (t.is (- 10 1/2+1/2i) 19/2-1/2i) + (t.is (- 10 0.1+0.1i) 9.9-0.1i) + + (t.is (- 10+10i 1/2) 19/2+10i) + (t.is (- 10+10i 0.1) 9.9+10.0i) + (t.is (- 10+10i 10) +10i) + + (t.is (- 0.1+0.1i 1/2) -0.4+0.1i) + (t.is (- 0.1+0.1i 0.1) +0.1i) + (t.is (- 0.1+0.1i 10) -9.9+0.1i) + + (t.is (- 1/2+1/2i 1/2) 1/2i) + (t.is (- 1/2+1/2i 0.1) 0.4+1/2i) + (t.is (- 1/2+1/2i 10) -19/2+1/2i) + + ;; mixed + (t.is (- 10+1/2i 10) +1/2i) + (t.is (- 10+1/2i 1/2) 19/2+1/2i) + (t.is (- 10+1/2i 0.1) 9.9+1/2i) + + (t.is (- 10+0.1i 10) +0.1i) + (t.is (- 10+0.1i 1/2) 19/2+0.1i) + (t.is (- 10+0.1i 0.1) 9.9+0.1i) + + (t.is (- 1/2+10i 10) -19/2+10i) + (t.is (- 1/2+10i 1/2) +10i) + (t.is (- 1/2+10i 0.1) 0.4+10.0i) + + (t.is (- 1/2+0.1i 10) -19/2+0.1i) + (t.is (- 1/2+0.1i 1/2) 0.1i) + (t.is (- 1/2+0.1i 0.1) 0.4+0.1i))) + (test "numbers: operators /" (lambda (t) + ;; single arg + (t.is (/ 10) 1/10) + (t.is (/ 10.0) 0.1) + (t.is (/ 1/10) 10) + (t.is (/ 10+10i) 1/20-1/20i) + (t.is (/ 10 10) 1) (t.is (/ 10 1/10) 100) (t.is (/ 10 2) 5) @@ -380,20 +611,76 @@ (t.is (/ 1.0 1/2+1.0i) 0.4-0.8i) (t.is (/ 1.0 1/2+1i) 0.4-0.8i))) +(test "numbers: operators *" + (lambda (t) + (t.is (* 10 10) 100) + (t.is (* 10 1/10) 1) + (t.is (* 10 2) 20) + (t.is (* 10 1/3) 10/3) + (t.is (* 10 2.0) 20.0) + + (t.is (* 2 10+10i) 20+20i) + (t.is (* 2 10+10.0i) 20+20.0i) + (t.is (* 2 10+1/10i) 20+1/5i) + + (t.is (* 2 1.0+1.0i) 2.0+2.0i) + (t.is (* 2 1.0+1i) 2.0+2.0i) + (t.is (* 2.0+1/2i) 2.0+0.5i) + + (t.is (* 2 1/10+1/10i) 1/5+1/5i) + (t.is (* 2 1/10+1i) 1/5+2i) + (t.is (* 2 1/2+1.0i) 1+2.0i) + + (t.is (* 1/2 10) 5) + (t.is (* 1/2 10.0) 5.0) + (t.is (* 1/2 1/2) 1/4) + + (t.is (* 1/2 10+10i) 5+5i) + (t.is (* 1/2 1+2.0i) 1/2+1.0i) + (t.is (* 1/2 1+1/2i) 1/2+1/4i) + + (t.is (* 1/2 10.0+10.0i) 5.0+5.0i) + (t.is (* 1/2 10.0+10i) 5.0+5i) + (t.is (* 1/2 1.0+1/2i) 0.5+1/4i) + + (t.is (* 1/2 1/20+1/20i) 1/40+1/40i) + (t.is (* 1/2 1/2+1i) 1/4+1/2i) + (t.is (* 1/2 1/2+1.0i) 1/4+0.5i) + + (t.is (* 1.0 1.0) 1.0) + (t.is (* 1.0 2) 2.0) + (t.is (* 1.0 1/10) 0.1) + + (t.is (* 1.0 1+1i) 1.0+1.0i) + (t.is (* 1.0 1+1.0i) 1.0+1.0i) + (t.is (* 1.0 1+1/2i) 1.0+0.5i) + + (t.is (* 1.0 1.0+1.0i) 1.0+1.0i) + (t.is (* 1.0 1.0+1i) 1.0+1.0i) + (t.is (* 1.0 1.0+1/2i) 1.0+0.5i) + + (t.is (* 1.0 1/2+1/2i) 0.5+0.5i) + (t.is (* 1.0 1/2+1.0i) 0.5+1.0i) + (t.is (* 1.0 1/2+1i) 0.5+1.0i) + ;; complex multiplication over conjugation + (t.is (* 10+10i 10-10i) 200) + (t.is (* 10+10.0i 10-10.0i) 200.0+0.0i) + (t.is (* 10+1/2i 10-1/2i) 401/4))) + (test "numbers: sqrt" (lambda (t) (for-each (lambda (x) - (t.is (sqrt (* x x)) x)) + (t.is (= (sqrt (* x x)) x) #t)) '(5 5+2i 1/5+1/2i 1/2 5.0 8/9)) (for-each (lambda (pair) (let ((x (car pair))) - (t.is (sqrt (* x x)) (cdr pair)))) + (t.is (= (sqrt (* x x)) (cdr pair)) #t))) '((2.0+1/2i . 2+0.5i))) (for-each (lambda (pair) (let ((x (car pair))) - (t.is (sqrt (* x x)) (cdr pair)))) + (t.is (= (sqrt (* x x)) (cdr pair)) #t))) '((2+1/2i . 2+0.5i) (2+0.5i . 2+0.5i) @@ -430,3 +717,101 @@ (t.snapshot (! 10)) (t.snapshot (--> (! 8000) (toString))))) + +(test "numbers: positive?" + (lambda (t) + (t.is (positive? 10) #t) + (t.is (positive? 1/2) #t) + (t.is (positive? 0.5) #t) + + (t.is (positive? -10) #f) + (t.is (positive? -1/2) #f) + (t.is (positive? -0.5) #f))) + +(test "numbers: negative?" + (lambda (t) + (t.is (negative? 10) #f) + (t.is (negative? 1/2) #f) + (t.is (negative? 0.5) #f) + + (t.is (negative? -10) #t) + (t.is (negative? -1/2) #t) + (t.is (negative? -0.5) #t))) + +(test "numbers: types" + (lambda (t) + (t.is (real? +nan.0) #t) + (t.is (rational? -inf.0) #f) + #;(t.is (rational? 3.5) #t) + (t.is (rational? 6/10) #t) + (t.is (rational? 6/3) #t) + (t.is (rational? 3.0) #t) + (t.is (integer? 3+0i) #t) + (t.is (integer? 3.0) #t) + (t.is (integer? 8/4) #t) + + (t.is (complex? 3+4i) #t) + (t.is (complex? 3) #t) + (t.is (real? 3) #t) + (t.is (real? -2.5+0i) #t) + (t.is (real? -2.5+0.0i) #f) + (t.is (real? #e1e10) #t) + (t.is (real? +inf.0) #t) + + (t.is (finite? 3) #t) + (t.is (finite? +inf.0) #f) + #;(t.is (finite? 3.0+inf.0i) #f) + + (t.is (infinite? 3) #f) + (t.is (infinite? +inf.0) #t) + (t.is (infinite? +nan.0) #f) + #;(t.is (infinite? 3.0+inf.0i) #t) + + (t.is (nan? +nan.0) #t) + (t.is (nan? 32) #f) + #;(t.is (nan? +nan.0+5.0i) #t) + #;(t.is (nan? 5.0+nan.0i) #t) + #;(t.is (nan? +nan.0+nan.0i) #t) + #;(t.is (nan? -nan.0+5.0i) #t) + #;(t.is (nan? 5.0-nan.0i) #t) + #;(t.is (nan? -nan.0-nan.0i) #t) + (t.is (nan? 1+2i) #f))) + +(test "numbers: zeros" + (lambda (t) + (let ((a 0) (b 0) (c 0.0) (d 0.0)) + (t.is (eq? a b) #t) + (t.is (eq? c d) #t) + (t.is (eq? a c) #f) + (t.is (= a b) #t) + (t.is (= a c) #t)))) + +(test "numbers: negative zero" + (lambda (t) + (let ((a 0) (b -0)) + (t.is (eq? a b) #t) + (t.is (eqv? a b) #t) + (t.is (equal? a b) #t) + (t.is (= a b) #t) + (t.is (number->string b) "0")) + (let ((a 0.0) (b -0.0)) + (t.is (eq? a b) #f) + (t.is (eqv? a b) #f) + (t.is (equal? a b) #f) + (t.is (= a b) #t) + (t.is (number->string b) "-0.0")))) + +(test "numbers: exact->inexact" + (lambda (t) + (t.is (exact->inexact 10) 10.0) + (t.is (exact->inexact 1/2) 0.5) + (t.is (exact->inexact 0.5) 0.5) + (t.is (exact->inexact 10+10i) 10.0+10.0i) + (t.is (exact->inexact 1/2+1/2i) 0.5+0.5i) + (t.is (exact->inexact 10.0+10.0i) 10.0+10.0i) + + (t.is (exact->inexact 10+1/2i) 10.0+0.5i) + (t.is (exact->inexact 10.0+1/2i) 10.0+0.5i) + + (t.is (exact->inexact 1/2+10i) 0.5+10.0i) + (t.is (exact->inexact 1/2+10.0i) 0.5+10.0i))) diff --git a/tests/parser.scm b/tests/parser.scm index 2501ab51..61f990aa 100644 --- a/tests/parser.scm +++ b/tests/parser.scm @@ -1,7 +1,8 @@ (set-special! "<>" 'html lips.specials.SPLICE) + (define-macro (html . args) - (let ((str (--> (list->array (map symbol->string args)) (join "+")))) - `(string-append "<" ,str "/>"))) + (let ((str (--> (list->array (map symbol->string args)) (join "+")))) + `(string-append "<" ,str "/>"))) (define parser/t1 <>(foo bar)) @@ -148,3 +149,41 @@ (match #/<title>([^<]+)<\\/title>/) 1)")) (t.is (eval (. code 0)) "hello-world"))) + + +(test "tokenizer: should create tokens for simple list" + (lambda (t) + (t.is (lips.tokenize "(foo bar baz)") + #("(" "foo" "bar" "baz" ")")))) + +(test "tokenizer: should create tokens for numbers string and regexes" + (lambda (t) + (t.is (lips.tokenize "(foo #/( \\/)/g \"bar baz\" 10 1.1 10e2 + 10+10i +inf.0+inf.0i +nan.0+nan.0i 1/2+1/2i)") + #("(" "foo" "#/( \\/)/g" "\"bar baz\"" "10" "1.1" "10e2" + "10+10i" "+inf.0+inf.0i" "+nan.0+nan.0i" "1/2+1/2i" ")")))) + +(test "tokenizer: should create token for alist" + (lambda (t) + (t.is (lips.tokenize "((foo . 10) (bar . 20) (baz . 30))") + #("(" "(" "foo" "." "10" ")" "(" "bar" "." "20" ")" "(" + "baz" "." "30" ")" ")")))) + +(test "tokenizer: should ignore comments" + (lambda (t) + (let ((code "(foo bar baz); (baz quux)")) + (t.is (lips.tokenize code) + #("(" "foo" "bar" "baz" ")"))))) + +(test "tokenizer: should handle semicolon in regexes and strings" + (lambda (t) + (let ((code "(\";()\" #/;;;/g baz); (baz quux)")) + (t.is (lips.tokenize code) + #("(" "\";()\"" "#/;;;/g" "baz" ")"))))) + +(test "tokenizer: with meta data" + (lambda (t) + (let* ((fs (require "fs")) + (code (--> (fs.promises.readFile "./tests/stubs/macro.txt") + (toString)))) + (t.snapshot (lips.tokenize code true))))) diff --git a/tests/ports.scm b/tests/ports.scm index 7f0d92d7..20220df9 100644 --- a/tests/ports.scm +++ b/tests/ports.scm @@ -1,4 +1,4 @@ -(test "ports: scheme repr (output-string)" +(test "ports: scheme repr using output-string" (lambda (t) (define (repr x . rest) (let ((port (open-output-string)) @@ -38,9 +38,14 @@ (test "ports: port repr" (lambda (t) (t.is (repr (current-input-port)) "#<input-port>") - (t.is (repr (open-input-string "xxx")) "#<input-port <string>>") - (t.is (repr (open-input-string "xxx")) "#<input-port <string>>") - (t.is (repr (open-input-file "./tests/ports.scm")) "#<input-port ./tests/ports.scm>"))) + (t.is (repr (open-input-string "xxx")) "#<input-port (string)>") + (t.is (repr (open-input-string "xxx")) "#<input-port (string)>") + (t.is (repr (open-input-file "./tests/ports.scm")) + "#<input-port (./tests/ports.scm)>") + (t.is (repr (open-binary-input-file "./tests/ports.scm")) + "#<input-binary-port (./tests/ports.scm)>") + (t.is (repr (open-input-bytevector #u8(10))) + "#<input-port (bytevector)>"))) (test "ports: syntax extensions" (lambda (t) @@ -76,7 +81,8 @@ (define f (open-input-file "./tests/ports.scm")) (read f) (close-input-port f) - (t.is (repr (open-input-file "./tests/ports.scm")) "#<input-port ./tests/ports.scm>") + (t.is (repr (open-input-file "./tests/ports.scm")) + "#<input-port (./tests/ports.scm)>") (t.is (to.throw (read f)) true))) (test "ports: with-input-from-file" @@ -110,7 +116,7 @@ (string->list (repr input))) (t.is (get-output-string port) input)))) -(test "port: write-char to output file" +(test "ports: write-char to output file" (lambda (t) (let ((filename "./tests/__x2__.scm")) (if (file-exists? filename) @@ -127,7 +133,7 @@ (delete-file filename) (t.is result input)))))) -(test "port: call-with-?-ports" +(test "ports: call-with-?-ports" (lambda (t) (let ((filename "./tests/__x3__.scm") (input '(hello world))) @@ -138,7 +144,7 @@ (delete-file filename) (t.is result input))))) -(test "port: close-output-port for output-string" +(test "ports: close-output-port for output-string" (lambda (t) (let ((input '(hello))) (let ((p (open-output-string))) @@ -149,7 +155,7 @@ (t.is (output-port-open? p) false) (t.is (get-output-string p) (repr input)))))) -(test "port: close-output-port for output-file" +(test "ports: close-output-port for output-file" (lambda (t) (let ((input '(hello))) (let ((filename "./tests/__x4__.scm")) @@ -166,7 +172,7 @@ (delete-file filename)))))) -(test "port: close-input-port for input-string" +(test "ports: close-input-port for input-string" (lambda (t) (let* ((input '(hello)) (port (open-input-string (repr input)))) @@ -176,7 +182,7 @@ (t.is (to.throw (read port)) true) (t.is (input-port-open? port) false)))) -(test "port: close-input-port for input-file" +(test "ports: close-input-port for input-file" (lambda (t) (let* ((input '(hello)) (filename "./tests/__x5__.scm")) @@ -190,8 +196,101 @@ (t.is (input-port-open? port) false) (delete-file filename))))) -(test "port: read-string for input-string" +(test "ports: read-string for input-string" (lambda (t) (let ((p (open-input-string "123456"))) (t.is (list (read-string 2 p) (read-string 2 p) (read-string 10 p)) '("12" "34" "56"))))) + +(test "ports: open-input-bytevector" + (lambda (t) + (let ((p (open-input-bytevector #u8(#x10 #x20 #xFF #xFF #xFF)))) + (t.is (binary-port? p) true) + (t.is (textual-port? p) false)))) + +(test "ports: read from open-input-bytevector" + (lambda (t) + (let ((p (open-input-bytevector #u8(#x10 #x20 #xFF #xFF #xFF)))) + (t.is (peek-u8 p) #x10) + (t.is (read-u8 p) #x10) + (t.is (peek-u8 p) #x20) + (t.is (peek-u8 p) #x20) + (t.is (peek-u8 p) #x20) + (let ((result (vector))) + (while (not (eof-object? (peek-u8 p))) + (result.push (read-u8 p))) + (t.is result #(#x20 #xFF #xFF #xFF)) + (t.is (eof-object? (peek-u8 p)) true))))) + +(test "ports: textual-port?" + (lambda (t) + (let ((filename "./tests/__x6__.scm")) + (if (file-exists? filename) + (delete-file filename)) + (let* ((closable (list (open-input-file "./tests/ports.scm") + (open-input-string "xxx") + (open-output-string) + (open-output-file filename))) + (ports (append (list (current-input-port) + (current-output-port)) + closable))) + (for-each (lambda (p) + (t.is (textual-port? p) true)) + ports) + (for-each close-port closable) + (delete-file filename))))) + +(test "ports: read binary" + (lambda (t) + (let* ((fname "./tests/stubs/test.txt") + (p (open-binary-input-file fname)) + (result (vector)) + (fs (require "fs"))) + (while (not (eof-object? (peek-u8 p))) + (result.push (string (integer->char (read-u8 p))))) + (t.is (result.join "") (--> (fs.promises.readFile fname) + (toString)))))) + +(test "ports: read bytevector" + (lambda (t) + (let ((p (open-binary-input-file "./tests/stubs/test.txt"))) + (t.is (utf8->string (read-bytevector 10 p)) + "Hello this")))) + +(test "ports: binary output port" + (lambda (t) + (let ((port (open-output-bytevector)) + (v (string->utf8 "hello"))) + (for-each (lambda (byte) + (write-u8 byte port)) + (u8vector->list v)) + (write-u8 (char->integer #\space) port) + (write-bytevector (string->utf8 "world") port) + (let ((u8 (get-output-bytevector port))) + (t.is (utf8->string u8) "hello world")) + (close-port port) + (t.is (to.throw (write-u8 (char->integer #\!) port)) + true) + (t.is (to.throw (get-output-bytevector port)) + true)))) + +(test "ports: output binary file port" + (lambda (t) + (let ((fname "./tests/__x7__.scm") + (str "hello, world!\n")) + (if (file-exists? fname) + (delete-file fname)) + (let ((port (open-binary-output-file fname))) + (call-with-port port + (lambda (p) + (write-bytevector (string->utf8 str) p))) + (t.is (to.throw (write-u8 10 port)) + true) + (t.is (with-input-from-file fname + (lambda () + (let loop ((c (read-char)) (a '())) + (if (eof-object? c) + (list->string (reverse a)) + (loop (read-char) (cons c a)))))) + str) + (delete-file fname))))) diff --git a/tests/quotation.scm b/tests/quotation.scm index 9ba0e4ef..9ad68bcb 100644 --- a/tests/quotation.scm +++ b/tests/quotation.scm @@ -327,3 +327,14 @@ (lambda (t) (t.is `(foo &(:foo ,(+ 1 2) :bar 10)) (list 'foo &(:foo 3 :bar 10))))) + +(test "quasiquote: should create list from improper list" + (lambda (t) + (t.is (let ((x '(1 2 3))) + `(foo . ,x)) + '(foo 1 2 3)))) + +(test "quasiquote: should create list with unquote-splicing and improper list" + (lambda (t) + (let ((result `((foo ,(- 10 3)) ,@(cdr '(c)) . ,(car '(cons))))) + (t.is result '((foo 7) . cons))))) diff --git a/tests/snapshots/test.js.md b/tests/snapshots/test.js.md index 1788b379..7f7e7cbd 100644 --- a/tests/snapshots/test.js.md +++ b/tests/snapshots/test.js.md @@ -8,7 +8,8 @@ Generated by [AVA](https://avajs.dev). > Snapshot 1 - `(cond ((foo 10) 10)␊ + `(cond ((foo 10)␊ + 10)␊ ((foo (bar baz))␊ (begin␊ (display "x")␊ @@ -18,7 +19,8 @@ Generated by [AVA](https://avajs.dev). > Snapshot 2 - `(cond ((foo 10) 10)␊ + `(cond ((foo 10)␊ + 10)␊ ((foo)␊ (begin␊ (display "x")␊ @@ -30,13 +32,14 @@ Generated by [AVA](https://avajs.dev). > Snapshot 1 - `(define (foo (x)␊ - (+ x x)))` + `(define (foo x)␊ + (+ x x))` > Snapshot 2 - `(define (foo (x)␊ - "xxx" (+ x x)))` + `(define (foo x)␊ + "xxx"␊ + (+ x x))` > Snapshot 3 @@ -55,6 +58,13 @@ Generated by [AVA](https://avajs.dev). > Snapshot 6 + `(define (foo x)␊ + "foo␊ + bar"␊ + (+ x x))` + +> Snapshot 7 + '(define foo 10)' ## formatter: define-syntax @@ -77,9 +87,42 @@ Generated by [AVA](https://avajs.dev). > Snapshot 2 `(let ((x))␊ + 10␊ + 20␊ + "xx␊ + yy"␊ (print x)␊ (print x))` +> Snapshot 3 + + `(let ((bar (foo bar (baz)))␊ + (foo 10))␊ + 10␊ + 20␊ + "xx␊ + yy"␊ + (foo bar)␊ + (print0))` + +> Snapshot 4 + + `(let ((bar)␊ + (foo (baz quux))␊ + (foo 10))␊ + (foo bar)␊ + (print0))` + +> Snapshot 5 + + `(let ((foo 10)␊ + (xxx (if (null? rest)␊ + (current-input-port)␊ + (car rest)))␊ + (bar foo))␊ + (foo bar)␊ + (print0))` + ## formatter: let+if+begin > Snapshot 1 @@ -148,3 +191,614 @@ Generated by [AVA](https://avajs.dev). > Snapshot 1 '<div data-foo="hello" id="foo"><button id="btn1">me</button><button id="btn2">me</button></div>' + +## tokenizer: with meta data + +> Snapshot 1 + + [ + { + col: 0, + line: 0, + offset: 0, + token: '(', + }, + { + col: 1, + line: 0, + offset: 1, + token: 'define-macro', + }, + { + col: 13, + line: 0, + offset: 13, + token: ' ', + }, + { + col: 14, + line: 0, + offset: 14, + token: '(', + }, + { + col: 15, + line: 0, + offset: 15, + token: 'defstruct', + }, + { + col: 24, + line: 0, + offset: 24, + token: ' ', + }, + { + col: 25, + line: 0, + offset: 25, + token: 'name', + }, + { + col: 29, + line: 0, + offset: 29, + token: ' ', + }, + { + col: 30, + line: 0, + offset: 30, + token: '.', + }, + { + col: 31, + line: 0, + offset: 31, + token: ' ', + }, + { + col: 32, + line: 0, + offset: 32, + token: 'fields', + }, + { + col: 38, + line: 0, + offset: 38, + token: ')', + }, + { + col: 39, + line: 0, + offset: 39, + token: `␊ + `, + }, + { + col: 0, + line: 1, + offset: 40, + token: ' ', + }, + { + col: 2, + line: 1, + offset: 42, + token: '"First Line."', + }, + { + col: 15, + line: 1, + offset: 55, + token: ' ', + }, + { + col: 16, + line: 1, + offset: 56, + token: '"word"', + }, + { + col: 22, + line: 1, + offset: 62, + token: ' ', + }, + { + col: 23, + line: 1, + offset: 63, + token: '10', + }, + { + col: 25, + line: 1, + offset: 65, + token: `␊ + `, + }, + { + col: 0, + line: 2, + offset: 66, + token: ' ', + }, + { + col: 2, + line: 2, + offset: 68, + token: '"Second Line."', + }, + { + col: 16, + line: 2, + offset: 82, + token: ' ', + }, + { + col: 20, + line: 2, + offset: 86, + token: '"word"', + }, + { + col: 26, + line: 2, + offset: 92, + token: ' ', + }, + { + col: 27, + line: 2, + offset: 93, + token: '#/regex/', + }, + { + col: 35, + line: 2, + offset: 101, + token: `␊ + `, + }, + { + col: 0, + line: 3, + offset: 102, + token: ' ', + }, + { + col: 2, + line: 3, + offset: 104, + token: '"Third Line."', + }, + { + col: 15, + line: 3, + offset: 117, + token: ' ', + }, + { + col: 20, + line: 3, + offset: 122, + token: '"word"', + }, + { + col: 26, + line: 3, + offset: 128, + token: `␊ + `, + }, + { + col: 0, + line: 4, + offset: 129, + token: ' ', + }, + { + col: 2, + line: 4, + offset: 131, + token: '10', + }, + { + col: 4, + line: 4, + offset: 133, + token: ' ', + }, + { + col: 5, + line: 4, + offset: 134, + token: '10+10i', + }, + { + col: 11, + line: 4, + offset: 140, + token: ' ', + }, + { + col: 12, + line: 4, + offset: 141, + token: '+inf.0', + }, + { + col: 18, + line: 4, + offset: 147, + token: ' ', + }, + { + col: 19, + line: 4, + offset: 148, + token: '+inf.0+inf.0i', + }, + { + col: 32, + line: 4, + offset: 161, + token: ' ', + }, + { + col: 33, + line: 4, + offset: 162, + token: '+nan.0', + }, + { + col: 39, + line: 4, + offset: 168, + token: ' ', + }, + { + col: 40, + line: 4, + offset: 169, + token: '+nan.0+nan.0i', + }, + { + col: 53, + line: 4, + offset: 182, + token: `␊ + `, + }, + { + col: 0, + line: 5, + offset: 183, + token: ' ', + }, + { + col: 2, + line: 5, + offset: 185, + token: '1/2+1/2i', + }, + { + col: 10, + line: 5, + offset: 193, + token: ' ', + }, + { + col: 11, + line: 5, + offset: 194, + token: '10.10+1/2i', + }, + { + col: 21, + line: 5, + offset: 204, + token: ' ', + }, + { + col: 22, + line: 5, + offset: 205, + token: '1/2+10.0i', + }, + { + col: 31, + line: 5, + offset: 214, + token: `␊ + `, + }, + { + col: 0, + line: 6, + offset: 215, + token: ' ', + }, + { + col: 2, + line: 6, + offset: 217, + token: '(', + }, + { + col: 3, + line: 6, + offset: 218, + token: 'let', + }, + { + col: 6, + line: 6, + offset: 221, + token: ' ', + }, + { + col: 7, + line: 6, + offset: 222, + token: '(', + }, + { + col: 8, + line: 6, + offset: 223, + token: '(', + }, + { + col: 9, + line: 6, + offset: 224, + token: 'names', + }, + { + col: 14, + line: 6, + offset: 229, + token: ' ', + }, + { + col: 15, + line: 6, + offset: 230, + token: '(', + }, + { + col: 16, + line: 6, + offset: 231, + token: 'map', + }, + { + col: 19, + line: 6, + offset: 234, + token: ' ', + }, + { + col: 20, + line: 6, + offset: 235, + token: '(', + }, + { + col: 21, + line: 6, + offset: 236, + token: 'lambda', + }, + { + col: 27, + line: 6, + offset: 242, + token: ' ', + }, + { + col: 28, + line: 6, + offset: 243, + token: '(', + }, + { + col: 29, + line: 6, + offset: 244, + token: 'symbol', + }, + { + col: 35, + line: 6, + offset: 250, + token: ')', + }, + { + col: 36, + line: 6, + offset: 251, + token: ' ', + }, + { + col: 37, + line: 6, + offset: 252, + token: '(', + }, + { + col: 38, + line: 6, + offset: 253, + token: 'gensym', + }, + { + col: 44, + line: 6, + offset: 259, + token: ')', + }, + { + col: 45, + line: 6, + offset: 260, + token: ')', + }, + { + col: 46, + line: 6, + offset: 261, + token: ' ', + }, + { + col: 47, + line: 6, + offset: 262, + token: 'fields', + }, + { + col: 53, + line: 6, + offset: 268, + token: ')', + }, + { + col: 54, + line: 6, + offset: 269, + token: ')', + }, + { + col: 55, + line: 6, + offset: 270, + token: `␊ + `, + }, + { + col: 0, + line: 7, + offset: 271, + token: ' ', + }, + { + col: 8, + line: 7, + offset: 279, + token: '(', + }, + { + col: 9, + line: 7, + offset: 280, + token: 'struct', + }, + { + col: 15, + line: 7, + offset: 286, + token: ' ', + }, + { + col: 16, + line: 7, + offset: 287, + token: '(', + }, + { + col: 17, + line: 7, + offset: 288, + token: 'gensym', + }, + { + col: 23, + line: 7, + offset: 294, + token: ')', + }, + { + col: 24, + line: 7, + offset: 295, + token: ')', + }, + { + col: 25, + line: 7, + offset: 296, + token: `␊ + `, + }, + { + col: 0, + line: 8, + offset: 297, + token: ' ', + }, + { + col: 8, + line: 8, + offset: 305, + token: '(', + }, + { + col: 9, + line: 8, + offset: 306, + token: 'field-arg', + }, + { + col: 18, + line: 8, + offset: 315, + token: ' ', + }, + { + col: 19, + line: 8, + offset: 316, + token: '(', + }, + { + col: 20, + line: 8, + offset: 317, + token: 'gensym', + }, + { + col: 26, + line: 8, + offset: 323, + token: ')', + }, + { + col: 27, + line: 8, + offset: 324, + token: ')', + }, + { + col: 28, + line: 8, + offset: 325, + token: ')', + }, + { + col: 29, + line: 8, + offset: 326, + token: `␊ + `, + }, + { + col: 0, + line: 9, + offset: 327, + token: `␊ + `, + }, + ] diff --git a/tests/snapshots/test.js.snap b/tests/snapshots/test.js.snap index 06ad58bd..e2c0151a 100644 Binary files a/tests/snapshots/test.js.snap and b/tests/snapshots/test.js.snap differ diff --git a/tests/stubs/macro.txt b/tests/stubs/macro.txt new file mode 100644 index 00000000..e9dbb056 --- /dev/null +++ b/tests/stubs/macro.txt @@ -0,0 +1,10 @@ +(define-macro (defstruct name . fields) + "First Line." "word" 10 + "Second Line." "word" #/regex/ + "Third Line." "word" + 10 10+10i +inf.0 +inf.0+inf.0i +nan.0 +nan.0+nan.0i + 1/2+1/2i 10.10+1/2i 1/2+10.0i + (let ((names (map (lambda (symbol) (gensym)) fields)) + (struct (gensym)) + (field-arg (gensym))) + diff --git a/tests/syntax.scm b/tests/syntax.scm index be357b41..973cfd66 100644 --- a/tests/syntax.scm +++ b/tests/syntax.scm @@ -937,3 +937,40 @@ (t.is (let*-values (((a b c) (values 1 2 3))) (+ a b c)) 6))) + +(test_ "syntax: nested _" + (lambda (t) + (define-syntax foo + (syntax-rules () + ((_) + (let () + (define-syntax %foo + (syntax-rules (foo bar) + ((_ (foo)) + "foo") + ((_) "bar") + ((_ x) + 'x))) + (list (%foo (foo)) + (%foo (10)) + (%foo bar) + (%foo)))))) + + (t.is (foo) '("foo" (10) bar "bar")))) + +(test_ "syntax: nesting, renaming and scope" + (lambda (t) + (let ((result 10)) + (define-syntax foo + (syntax-rules () + ((_) + (let () + (define-syntax %foo + (syntax-rules (foo bar) + ((__ (foo)) + (set! result '(foo))) + ((__ x) + (set! result 'x)))) + (%foo (foo)))))) + (foo) + (t.is result '(foo))))) diff --git a/tests/test.js b/tests/test.js index 7aaa003a..43451829 100644 --- a/tests/test.js +++ b/tests/test.js @@ -36,7 +36,7 @@ get_files().then(filenames => { })).then(async function (files) { await lips.exec(` (let-env lips.env.__parent__ - (load "./dist/std.scm") + (load "./dist/std.min.scm") (load "./tests/helpers/helpers.scm")) `); return lips.exec([` diff --git a/todo.lips b/todo.lips index 359321a7..7cf580e3 100644 --- a/todo.lips +++ b/todo.lips @@ -207,7 +207,7 @@ (data `((activeTodoCount . ,active-count) (activeTodoWord . ,(pluralize active-count "item")) (completedTodos . ,(- todo-count active-count)))) - (template (footer-template (--> data (toObject))))) + (template (footer-template (--> data (to_object))))) (--> ($ ".footer") (toggle (> todo-count 0)) (html template)))) @@ -216,7 +216,7 @@ (define (render) "render the app" (let* ((todos (get-todos)) - (data (--> (map (lambda (e) (--> e (toObject))) todos) (toArray)))) + (data (--> (map (lambda (e) (--> e (to_object))) todos) (to_array)))) (--> ($ ".todo-list") (html (todo-template data))) (--> ($ ".main") (toggle (> (length data) 0))) @@ -248,7 +248,7 @@ (let* ((routes `(("/:filter" . ,(lambda (filter) (set! selected-filter filter) (render))))) - (router (new Router (--> routes (toObject))))) + (router (new Router (--> routes (to_object))))) (--> router (init "/all")))) (init)