diff options
| author | Andrey Orst <andreyorst@gmail.com> | 2021-01-19 16:46:00 +0000 |
|---|---|---|
| committer | Andrey Orst <andreyorst@gmail.com> | 2021-01-19 16:46:00 +0000 |
| commit | 92812d03922fd4c3ba85364b59e63236e7cfcd8a (patch) | |
| tree | 6504ecb114419b0dd3055e509abd8b602586f614 | |
| parent | a2b08f721c28b3b56a802031bc35df6a68b219d8 (diff) | |
| parent | 270beed0505ef47159d94fb162ff4840958f3ce5 (diff) | |
fix: Fennel 0.8.0 enhancements
Changelog:
- fixed bug in try
- reworked pretty printing for sets
- handle cycles in sets
- use new fennel.view format
- reorganized library to make requiring it easier
| -rw-r--r-- | .depend.mk | 8 | ||||
| -rw-r--r-- | .dir-locals.el | 23 | ||||
| -rw-r--r-- | .gitlab-ci.yml | 38 | ||||
| -rw-r--r-- | CODE_OF_CONDUCT.md | 5 | ||||
| -rw-r--r-- | CODE_OF_CONDUCT.org | 5 | ||||
| -rw-r--r-- | CONTRIBUTING.md | 85 | ||||
| -rw-r--r-- | CONTRIBUTING.org | 94 | ||||
| -rw-r--r-- | Makefile | 15 | ||||
| -rw-r--r-- | README.md | 40 | ||||
| -rw-r--r-- | README.org | 14 | ||||
| -rw-r--r-- | doc/cljlib.md | 251 | ||||
| -rw-r--r-- | doc/macros.md (renamed from doc/cljlib-macros.md) | 23 | ||||
| -rw-r--r-- | doc/tests/test.md | 2 | ||||
| -rw-r--r-- | init.fnl (renamed from cljlib.fnl) | 145 | ||||
| -rw-r--r-- | macros.fnl (renamed from cljlib-macros.fnl) | 165 | ||||
| -rw-r--r-- | tests/core.fnl | 1039 | ||||
| -rw-r--r-- | tests/fn.fnl | 27 | ||||
| -rw-r--r-- | tests/macros.fnl | 20 | ||||
| -rw-r--r-- | tests/test.fnl | 44 |
19 files changed, 1072 insertions, 971 deletions
@@ -1,4 +1,4 @@ -cljlib.lua: cljlib.fnl cljlib-macros.fnl -tests/core.lua: tests/core.fnl cljlib-macros.fnl tests/test.fnl cljlib.fnl -tests/macros.lua: tests/macros.fnl cljlib-macros.fnl tests/test.fnl -tests/fn.lua: tests/fn.fnl cljlib-macros.fnl tests/test.fnl +init.lua: init.fnl macros.fnl +tests/core.lua: tests/core.fnl macros.fnl tests/test.fnl init.fnl +tests/macros.lua: tests/macros.fnl macros.fnl tests/test.fnl +tests/fn.lua: tests/fn.fnl macros.fnl tests/test.fnl diff --git a/.dir-locals.el b/.dir-locals.el index 6036615..bf3fb90 100644 --- a/.dir-locals.el +++ b/.dir-locals.el @@ -1,7 +1,28 @@ ;;; Directory Local Variables ;;; For more information see (info "(emacs) Directory Variables") -((fennel-mode . ((eval . (put 'when-meta 'fennel-indent-function 'defun)) +((fennel-mode . ((eval . (font-lock-add-keywords + 'fennel-mode + `((,(rx word-start + (group (or "fn*" + "try" + "if-let" + "if-some" + "when-let" + "when-some" + "empty" + "into" + "when-meta" + "with-meta" + "meta" + "meta" + "def" + "defmulti" + "defmethod" + "defonce")) + word-end) + 1 'font-lock-keyword-face)))) + (eval . (put 'when-meta 'fennel-indent-function 'defun)) (eval . (put 'defmethod 'fennel-indent-function 'defun)) (eval . (put 'defmulti 'bfennel-indent-function 'defun)) (eval . (put 'deftest 'fennel-indent-function 'defun)) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index fd30085..a49ff33 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,34 +4,42 @@ stages: - test - coverage -Lua 5.3: - image: alpine:3.12.1 +Lua: + image: alpine:edge stage: test before_script: - - apk add lua5.3 luarocks5.3 make - - luarocks-5.3 install fennel + - apk add -q lua5.2 lua5.3 lua5.4 git make + - git clone https://git.sr.ht/~technomancy/fennel + - (cd fennel; LUA=lua5.3 make install) script: - - LUA=lua5.3 make test + - LUA_EXECUTABLES="lua5.2 lua5.3 lua5.4" make testall >/dev/null -Lua 5.4: - image: ubuntu:20.10 +# Luajit actually is an impostor in Alpine, as the package actually +# uses Moonjit implementation, which is different from what I'm +# working with, so Fedora 33 image is used, which as of this moment +# has latest Luajit available +Luajit: + image: fedora:33 stage: test before_script: - - ln -snf /usr/share/zoneinfo/Europe/Moscow /etc/localtime - - echo Europe/Moscow > /etc/timezone - - apt-get update && apt-get install -y lua5.4 luarocks make >/dev/null - - luarocks install fennel + - dnf install -y -q lua luajit git make + - git clone https://git.sr.ht/~technomancy/fennel + - (cd fennel; make install) script: - - LUA=lua5.4 make test + - LUA=luajit make test +# We install fennel via luarocks by making local rockspect because I +# don't want to figure out how to install luacov without luarocks Coverage: image: alpine:3.12.1 stage: coverage before_script: - - apk add lua5.3 lua5.3-dev gcc musl-dev luarocks5.3 make - - luarocks-5.3 install fennel + - apk add -q lua5.3 lua5.3-dev gcc musl-dev luarocks5.3 git make + - (cd $HOME; git clone https://git.sr.ht/~technomancy/fennel) + - export LUA=lua5.3 + - (cd $HOME/fennel; luarocks-5.3 make rockspecs/fennel-scm-2.rockspec) - luarocks-5.3 install luacov - luarocks-5.3 install luacov-console script: - - LUA=lua5.3 make luacov-console + - make luacov-console >/dev/null - luacov-console --no-colored -s diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..ca3f99e --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,5 @@ +Only **code quality** does matter. + +Everything else is up to your personal taste. + +However, this doesn't mean that we will be tolerant to *any* kind of antics. diff --git a/CODE_OF_CONDUCT.org b/CODE_OF_CONDUCT.org deleted file mode 100644 index ad2e2da..0000000 --- a/CODE_OF_CONDUCT.org +++ /dev/null @@ -1,5 +0,0 @@ -Only *code quality* does matter. - -Everything else is up to your personal taste. - -However, this doesn't mean that we will be tolerant to /any/ kind of antics. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..901239b --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,85 @@ +Please read the following document to make collaborating on the project easier for both sides. + +# Reporting bugs + +If you've encountered a bug, do the following: + +- Check if the documentation has information about the problem you have. + Maybe this isn't a bug, but a desired behavior. +- Check issue tracker, maybe someone had reported your problem already. + If there's no issue, describing your problem, or there is, but it is closed, please create new issue, and link all closed issues that relate to this problem, if any. +- Tag issue with a `BUG:` at the beginning of the issue name. + +# Suggesting features and/or changes + +Before suggesting a feature, please check if this feature wasn't requested before. +You can do that in the issues, by filtering issues by `FEATURE:`. +If no feature found, please file new issue, and tag it with a `FEATURE:` at the beginning of the issue name. + +# Contributing changes + +Please do. + +When deciding to contribute a large amount of changes, first consider opening a `DISCUSSION:` type issue, so we could first decide if such dramatic changes are in the scope of the project. +This will save your time, in case such changes are out of the project's scope. + +If you're contributing a bug-fix, please open a `BUG:` labeled issue first, unless someone already did that. +All bug related merge requests must have a linked issues with a meaningful explanation and steps of reproducing a bug. +Small fixes are also welcome, and doesn't require filing an issue, although you may be asked to do so. + +## Writing code + +When writing code, consider following the existing style without applying dramatic changes to formatting unless really necessary. +For this particular project, please follow rules as described in [Clojure Style Guide](https://github.com/bbatsov/clojure-style-guide). +If you see any inconsistencies with the style guide in the code, feel free to change these in a non-breaking way. +If you're using Emacs, some indentation rules are predefined in `.dir-locals.el` file, so when adding new macro please add a meaningful indentation spec to that file as well. + +If you've added new functions, each must be covered with a set of tests. +For that purpose this project has special `test.fnl` module, that defines such macros as `assert-is`, `assert-not`, `assert-eq`, `assert-ne`, `deftest`, and `testing`. +Related tests should be grouped with the `deftest` macro, which defines a meaningful name for the test, and test itself must be defined within `testing` macros. +All assertions in tests must be one with one of `assert-eq`, `assert-ne`, `assert-not`, or `assert-is` macros, as these provide human readable output in the log. + +When changing existing functions make sure that all tests pass. +If some tests do not pass, make sure that these tests are written to test this particular function. +If the breakage was expected (e.g. when contributing a breaking change), make sure to update the tests. +If neither from above applies, then, perhaps, you've broke something horribly. + +Before committing changes you must run tests with `make test`, and all of the tests must pass without errors. +Consider checking test coverage with `make luacov` and rendering it with your preferred reporter. +Makefile also has `luacov-console` target, which can be used to see coverage of Lua code directly in the terminal with [luacov-console](https://github.com/spacewander/luacov-console). +Coverage should not drop too much, and huge drops usually mean that tests should cover more input variants. + +## Writing documentation + +If you've added new code, make sure it is covered not only by tests but also with documentation. +This includes writing documentation strings directly in the code, by using docstring feature of the language. +Documentation files are auto-generated with [Fenneldoc](https://gitlab.com/andreyorst/fenneldoc), so please refer to its documentation for available features. + +General notes on writing documentation: + +- Please consider using spell checking. + If you find a word not known by the dictionary, please add it to the `LocalWords` section at the bottom of the document. +- If you're writing markdown by hand, please consider using one sentence per line approach. + This makes it easier to reason about text in patches, and Markdown ignores single newlines in sentences. +- If you're writing documentation for function, consider splitting lines at column 80. + +## Working with Git + +Check out new branch from project's main development branch. +If you've cloned this project some time ago, consider checking if your branch has all recent changes from upstream. + +Each commit must have a type, which is one of `feature`, `fix`, followed by optional scope, and a must have description after `:` colon. +For example: + + fix(core macros): fix #42 + feature(tests): add more strict tests + +- `feature` must be used when adding new code. +- `fix` must be used when working with existing code. + +When creating merge request consider squashing your commits at merge. +You may do this manually, or use Gitlab's "Squash commits" button. +Either way please tag squash commit with `fix` or `feature`, depending on what you're willing to merge. + +<!-- LocalWords: Makefile Gitlab's Lua docstring + --> diff --git a/CONTRIBUTING.org b/CONTRIBUTING.org deleted file mode 100644 index 9acb924..0000000 --- a/CONTRIBUTING.org +++ /dev/null @@ -1,94 +0,0 @@ -#+title: Contributing guidelines -#+author: Andrey Orst -#+email: andreyorst@gmail.com -#+date: 2020-10-24 - -Please read the following document to make collaborating on the project easier for both sides. - -* Reporting bugs -If you've encountered a bug, do the following: - -- Check if the documentation has information about the problem you have. - Maybe this isn't a bug, but a desired behavior. -- Check past and current issues, maybe someone had reported your problem already. - If there's no issue, describing your problem, or there is, but it is closed, please create new issue, and link all closed issues that relate to this problem, if any. -- Tag issue with a =BUG:= at the beginning of the issue name. - - -* Suggesting features and/or changes -Before suggesting a feature, please check if this feature wasn't requested before. -You can do that in the issues, by filtering issues by =FEATURE:=. -If no feature found, please file new issue, and tag it with a =FEATURE:= at the beginning of the issue name. - - -* Contributing changes -Please do. - -When deciding to contribute a large amount of changes, first consider opening a =DISCUSSION:= type issue, so we could first decide if such dramatic changes are in the scope of the project. -This will save your time, in case such changes are out of the project's scope. - -If you're contributing a bugfix, please open an =BUG:= issue first, unless someone already did that. -All bug related merge requests must have a linked issues with a meaningful explanation and steps of reproducing a bug. -Small fixes are also welcome, and doesn't require filing an issue, although we may ask you to do so. - -** Writing code -When writing code, consider following the existing style without applying dramatic changes to formatting unless really necessary. -For this particular project, please follow rules as described in [[https://github.com/bbatsov/clojure-style-guide][Clojure Style Guide]]. -If you see any inconsistencies with the style guide in the code, feel free to change these in a non-breaking way. - -If you've added new functions, each one must be covered with a set of tests. -For that purpose this project has special =test.fnl= module, that defines such macros as =assert-is=, =assert-not=, =assert-eq=, =assert-ne=, =deftest=, and =testing=. -Related tests should be grouped with the =deftest= macro, which defines a meaningful name for the test, and test itself must be defined within =testing= macros. -All assertions in tests must be one with one of =assert-eq=, =assert-ne=, =assert-not=, or =assert-is= macros, as these provide human readable output in the log. - -When changing existing functions make sure that all tests pass. -If some tests do not pass, make sure that these tests are written to test this function. -If not, then, perhaps, you've broke something horribly. - -Before comitting changes you must run tests with =make test=, and all of the tests must pass without errors. -Consider checking test coverage with =make luacov= and rendering it with your preferred reporter. -Makefile also has =luacov-console= target, which can be used to see coverage of lua code directly in the terminal with [[https://github.com/spacewander/luacov-console][luacov-console]]. - -** Writing documentation -If you've added new code, make sure it is covered not only by tests but also with documentation. -This includes writing documentation strings directly in the code, either by using docstring feature of the language, or by adding comments which begin with =DOC:= - -Documentation files use Org Mode format because it is easy to convert it to all kinds of formats. -Please make sure to follow existing style of documentation, which can be shortly describing as: - -- One sentence per line. - This makes easier to see changes while browsing history. -- No indentation of text after headings. - This makes little sense with one sentence per line approach anyway. -- No empty lines after headings. -- Amount of empty lines in text should be: - - Single empty lines between paragraphs. - - Double empty lines before top level headings. - - Single empty lines before other headings. -- Consider using spell checking. - If you find a word not known by the dictionary, please add it to the =LocalWords= section at the bottom of the document. - -If you're not using Emacs, there are plugins for other editors of varying completeness that provide support for Org file formats. -Here are some popular ones: Atom [[https://atom.io/packages/org-mode][package]], VSCode [[https://github.com/vscode-org-mode/vscode-org-mode][plugin]], SublimeText [[https://packagecontrol.io/packages/orgmode][plugin]]. -Even without the plugin it is not hard to edit such Org files, as it is just plain text. - -** Working with Git -Check out new branch from project's main development branch. -If you've cloned this project some time ago, consider checking if your branch has all recent changes from upstream. - -Each commit must have a type, which is one of =feature=, =fix=, followed by optional scope, and a must have description after =:= colon. -For example: - -#+begin_example -fix(core macros): fix #42 -feature(tests): add more strict tests -#+end_example - -- =feature= must be used when adding new code. -- =fix= must be used when fixing existing code. - -When creating merge request consider squashing your commits at merge. -You may do this manually, or use Gitlab's "Squash commits" button. - -# LocalWords: bugfix docstring comitting VSCode SublimeText -# LocalWords: Gitlab's LocalWords @@ -1,11 +1,12 @@ LUA ?= lua FENNEL ?= fennel -FNLSOURCES = cljlib.fnl +FNLSOURCES = init.fnl LUASOURCES = $(FNLSOURCES:.fnl=.lua) FNLTESTS = tests/fn.fnl tests/macros.fnl tests/core.fnl LUATESTS = $(FNLTESTS:.fnl=.lua) +LUA_EXECUTABLES ?= lua luajit -.PHONY: build clean distclean help test luacov luacov-console fenneldoc +.PHONY: build clean distclean help test luacov luacov-console fenneldoc $(LUA_EXECUTABLES) build: $(LUASOURCES) @@ -21,10 +22,14 @@ distclean: clean rm -f luacov* test: $(FNLTESTS) - @true$(foreach test, $?, && $(FENNEL) --lua $(LUA) --metadata $(test)) + @echo "Testing on" $$($(LUA) -v) >&2 + @$(foreach test,$?,$(FENNEL) --lua $(LUA) --metadata $(test) || exit;) + +testall: $(LUA_EXECUTABLES) + @$(foreach lua,$?,LUA=$(lua) make test || exit;) luacov: build $(LUATESTS) - @true$(foreach test, $(LUATESTS), && $(LUA) -lluarocks.loader -lluacov $(test)) + @$(foreach test,$(LUATESTS),$(LUA) -lluarocks.loader -lluacov $(test) || exit;) luacov luacov-console: luacov @@ -33,7 +38,7 @@ luacov-console: luacov @$(foreach test, $(LUATESTS), mv $(test).tmp $(test);) fenneldoc: - fenneldoc cljlib.fnl cljlib-macros.fnl tests/test.fnl + fenneldoc init.fnl macros.fnl tests/test.fnl help: @echo "make -- run tests and create lua library" >&2 diff --git a/README.md b/README.md new file mode 100644 index 0000000..6b213a5 --- /dev/null +++ b/README.md @@ -0,0 +1,40 @@ +# Fennel Cljlib + +[](https://gitlab.com/andreyorst/fennel-cljlib/-/commits/master) +[](https://gitlab.com/andreyorst/fennel-cljlib/-/commits/master) + +Experimental library for [Fennel](https://fennel-lang.org/) language, that adds many functions from [Clojure](https://clojure.org/)'s standard library. +This is not a one to one port of Clojure `core`, because many Clojure functions require certain guarantees, like immutability and laziness, which are hard to efficiently implement on top of Lua. +Some semantics like concurrency, or dynamic scope is not supported by Lua runtime at all. +Therefore certain functions were altered to better suit the domain. + +## Installation + +Clone library into your project or put it as a git submodule: + + $ git clone https://gitlab.com/andreyorst/fennel-cljlib cljlib + +Now you can require `:cljlib` from Fennel: + +``` clojure +(local clj (require :cljlib)) +(import-macros cljm :cljlib.macros) +``` + +Optionally precompile the library to make it load slightly faster: + + $ cd cljlib; make + +This will compile `init.fnl` into `init.lua`, so `require` should honor Lua files over Fennel files. +It is also possible to use this library from Lua this way. + +## Documentation + +Documentation is auto-generated with [Fenneldoc](https://gitlab.com/andreyorst/fenneldoc) and can be found [here](https://gitlab.com/andreyorst/fennel-cljlib/-/tree/master/doc). + +# Contributing + +Please make sure you've read [contribution guidelines](https://gitlab.com/andreyorst/fennel-cljlib/-/tree/master/CONTRIBUTING.md). + +<!-- LocalWords: Lua submodule precompile cljlib + --> diff --git a/README.org b/README.org deleted file mode 100644 index e30d62c..0000000 --- a/README.org +++ /dev/null @@ -1,14 +0,0 @@ -#+title: Fennel Cljlib -[[https://gitlab.com/andreyorst/fennel-cljlib/-/commits/master][https://gitlab.com/andreyorst/fennel-cljlib/badges/master/pipeline.svg]] [[https://gitlab.com/andreyorst/fennel-cljlib/-/commits/master][https://gitlab.com/andreyorst/fennel-cljlib/badges/master/coverage.svg]] - -Experimental library for [[https://fennel-lang.org/][Fennel]] language, that adds many functions from [[https://clojure.org/][Clojure]]'s standard library. -This is not a one to one port of Clojure =core=, because many Clojure functions require certain guarantees, like immutability of the underlying data structures, or laziness. -Therefore some names were changed, but they should be still recognizable, and certain functions were altered to better suit the domain. - -Even though it is project is experimental, the goals of this project are: - -- Have a self contained library, with no dependencies, that provides a set of useful functions from Clojure =core=, -- Be close to the platform, e.g. implement functions in a way that is efficient to use in Lua VM, -- Be well documented library, with good test coverage. - -Documentation is autogenerated with [[https://gitlab.com/andreyorst/fenneldoc][Fenneldoc]] and can be found [[https://gitlab.com/andreyorst/fennel-cljlib/-/tree/master/doc][here]]. diff --git a/doc/cljlib.md b/doc/cljlib.md index ee686cf..54d8294 100644 --- a/doc/cljlib.md +++ b/doc/cljlib.md @@ -1,10 +1,10 @@ -# Cljlib.fnl (0.3.0) +# Cljlib (0.4.0) Fennel-cljlib - functions from Clojure's core.clj implemented on top of Fennel. This library contains a set of functions providing functions that behave similarly to Clojure's equivalents. Library itself has nothing -Fennel specific so it should work, e.g: +Fennel specific so it should work on Lua, e.g: ``` lua Lua 5.3.5 Copyright (C) 1994-2018 Lua.org, PUC-Rio @@ -35,6 +35,17 @@ of a function which is chosen by checking amount of arguments passed to the function. See [Clojure's doc section on multi-arity functions](https://clojure.org/guides/learn/functions#_multi_arity_functions). +## Compatibility +This library is mainly developed with Lua 5.4, and tested against +Lua 5.2, 5.3, 5.4, and LuaJIT 2.1.0-beta3. Note, that in lua 5.2 and +LuaJIT equality semantics are a bit different from Lua 5.3 and Lua 5.4. +Main difference is that when comparing two tables, they must have +exactly the same `__eq` metamethods, so comparing hash sets with hash +sets will work, but comparing sets with other tables works only in +Lua5.3+. Another difference is that Lua 5.2 and LuaJIT don't have +inbuilt UTF-8 library, therefore `seq` function will not work for +non-ASCII strings. + **Table of contents** - [`apply`](#apply) @@ -142,12 +153,7 @@ Applying `print` to different arguments: Function signature: ``` -(add - ([a]) - ([a b]) - ([a b c]) - ([a b c d]) - ([a b c d & rest])) +(add ([]) ([a]) ([a b]) ([a b c]) ([a b c d]) ([a b c d & rest])) ``` Sum arbitrary amount of numbers. @@ -156,12 +162,7 @@ Sum arbitrary amount of numbers. Function signature: ``` -(sub - ([a]) - ([a b]) - ([a b c]) - ([a b c d]) - ([a b c d & rest])) +(sub ([]) ([a]) ([a b]) ([a b c]) ([a b c d]) ([a b c d & rest])) ``` Subtract arbitrary amount of numbers. @@ -170,12 +171,7 @@ Subtract arbitrary amount of numbers. Function signature: ``` -(mul - ([a]) - ([a b]) - ([a b c]) - ([a b c d]) - ([a b c d & rest])) +(mul ([]) ([a]) ([a b]) ([a b c]) ([a b c d]) ([a b c d & rest])) ``` Multiply arbitrary amount of numbers. @@ -184,12 +180,7 @@ Multiply arbitrary amount of numbers. Function signature: ``` -(div - ([a]) - ([a b]) - ([a b c]) - ([a b c d]) - ([a b c d & rest])) +(div ([a]) ([a b]) ([a b c]) ([a b c d]) ([a b c d & rest])) ``` Divide arbitrary amount of numbers. @@ -198,10 +189,7 @@ Divide arbitrary amount of numbers. Function signature: ``` -(le - ([x]) - ([x y]) - ([x y & more])) +(le ([x]) ([x y]) ([x y & more])) ``` Returns true if nums are in monotonically non-decreasing order @@ -210,10 +198,7 @@ Returns true if nums are in monotonically non-decreasing order Function signature: ``` -(lt - ([x]) - ([x y]) - ([x y & more])) +(lt ([x]) ([x y]) ([x y & more])) ``` Returns true if nums are in monotonically decreasing order @@ -222,10 +207,7 @@ Returns true if nums are in monotonically decreasing order Function signature: ``` -(ge - ([x]) - ([x y]) - ([x y & more])) +(ge ([x]) ([x y]) ([x y & more])) ``` Returns true if nums are in monotonically non-increasing order @@ -234,10 +216,7 @@ Returns true if nums are in monotonically non-increasing order Function signature: ``` -(gt - ([x]) - ([x y]) - ([x y & more])) +(gt ([x]) ([x y]) ([x y & more])) ``` Returns true if nums are in monotonically increasing order @@ -246,7 +225,7 @@ Returns true if nums are in monotonically increasing order Function signature: ``` -(inc [x]) +(inc ([x])) ``` Increase number by one @@ -255,7 +234,7 @@ Increase number by one Function signature: ``` -(dec [x]) +(dec ([x])) ``` Decrease number by one @@ -264,10 +243,7 @@ Decrease number by one Function signature: ``` -(eq - ([x]) - ([x y]) - ([x y & xs])) +(eq ([x]) ([x y]) ([x y & xs])) ``` Deep compare values. @@ -276,7 +252,7 @@ Deep compare values. Function signature: ``` -(map? [tbl]) +(map? ([tbl])) ``` Check whether `tbl` is an associative table. @@ -318,7 +294,7 @@ Empty tables created with [`hash-map`](#hash-map) will pass the test: Function signature: ``` -(vector? [tbl]) +(vector? ([tbl])) ``` Check whether `tbl` is an sequential table. @@ -360,7 +336,7 @@ Empty tables created with [`vector`](#vector) will pass the test: Function signature: ``` -(multifn? [mf]) +(multifn? ([mf])) ``` Test if `mf` is an instance of `multifn`. @@ -372,7 +348,7 @@ from `cljlib-macros.fnl`. Function signature: ``` -(set? [s]) +(set? ([s])) ``` @@ -381,8 +357,7 @@ Function signature: Function signature: ``` -(nil? - ([x])) +(nil? ([]) ([x])) ``` Test if value is nil. @@ -391,7 +366,7 @@ Test if value is nil. Function signature: ``` -(zero? [x]) +(zero? ([x])) ``` Test if value is equal to zero. @@ -400,7 +375,7 @@ Test if value is equal to zero. Function signature: ``` -(pos? [x]) +(pos? ([x])) ``` Test if `x` is greater than zero. @@ -409,7 +384,7 @@ Test if `x` is greater than zero. Function signature: ``` -(neg? [x]) +(neg? ([x])) ``` Test if `x` is less than zero. @@ -418,7 +393,7 @@ Test if `x` is less than zero. Function signature: ``` -(even? [x]) +(even? ([x])) ``` Test if value is even. @@ -427,7 +402,7 @@ Test if value is even. Function signature: ``` -(odd? [x]) +(odd? ([x])) ``` Test if value is odd. @@ -436,7 +411,7 @@ Test if value is odd. Function signature: ``` -(string? [x]) +(string? ([x])) ``` Test if `x` is a string. @@ -445,7 +420,7 @@ Test if `x` is a string. Function signature: ``` -(boolean? [x]) +(boolean? ([x])) ``` Test if `x` is a Boolean @@ -454,7 +429,7 @@ Test if `x` is a Boolean Function signature: ``` -(true? [x]) +(true? ([x])) ``` Test if `x` is `true` @@ -463,7 +438,7 @@ Test if `x` is `true` Function signature: ``` -(false? [x]) +(false? ([x])) ``` Test if `x` is `false` @@ -472,7 +447,7 @@ Test if `x` is `false` Function signature: ``` -(int? [x]) +(int? ([x])) ``` Test if `x` is a number without floating point data. @@ -483,7 +458,7 @@ Number is rounded with `math.floor` and compared with original number. Function signature: ``` -(pos-int? [x]) +(pos-int? ([x])) ``` Test if `x` is a positive integer. @@ -492,16 +467,16 @@ Test if `x` is a positive integer. Function signature: ``` -(neg-int? [x]) +(neg-int? ([x])) ``` -Test if `x` is a negetive integer. +Test if `x` is a negative integer. ## `double?` Function signature: ``` -(double? [x]) +(double? ([x])) ``` Test if `x` is a number with floating point data. @@ -510,7 +485,7 @@ Test if `x` is a number with floating point data. Function signature: ``` -(empty? [x]) +(empty? ([x])) ``` Check if collection is empty. @@ -519,7 +494,7 @@ Check if collection is empty. Function signature: ``` -(not-empty [x]) +(not-empty ([x])) ``` If `x` is empty, returns `nil`, otherwise `x`. @@ -528,7 +503,7 @@ If `x` is empty, returns `nil`, otherwise `x`. Function signature: ``` -(vector [& args]) +(vector ([& args])) ``` Constructs sequential table out of it's arguments. @@ -546,7 +521,7 @@ Sets additional metadata for function [`vector?`](#vector?) to work. Function signature: ``` -(seq [col]) +(seq ([col])) ``` Create sequential table. @@ -554,7 +529,8 @@ Create sequential table. Transforms original table to sequential table of key value pairs stored as sequential tables in linear time. If `col` is an associative table, returns sequential table of vectors with key and -value. If `col` is sequential table, returns its shallow copy. +value. If `col` is sequential table, returns its shallow copy. If +`col` is string, return sequential table of its codepoints. ### Examples Sequential tables remain as is: @@ -585,16 +561,16 @@ Additionally you can use [`conj`](#conj) and [`apply`](#apply) with Function signature: ``` -(kvseq [tbl]) +(kvseq ([col])) ``` -Transforms any table kind to key-value sequence. +Transforms any table to key-value sequence. ## `first` Function signature: ``` -(first [col]) +(first ([col])) ``` Return first element of a table. Calls `seq` on its argument. @@ -603,7 +579,7 @@ Return first element of a table. Calls `seq` on its argument. Function signature: ``` -(rest [col]) +(rest ([col])) ``` Returns table of all elements of a table but the first one. Calls @@ -613,7 +589,7 @@ Returns table of all elements of a table but the first one. Calls Function signature: ``` -(last [col]) +(last ([col])) ``` Returns the last element of a table. Calls `seq` on its argument. @@ -622,7 +598,7 @@ Returns the last element of a table. Calls `seq` on its argument. Function signature: ``` -(butlast [col]) +(butlast ([col])) ``` Returns everything but the last element of a table as a new @@ -632,10 +608,7 @@ Returns everything but the last element of a table as a new Function signature: ``` -(conj - ([tbl]) - ([tbl x]) - ([tbl x & xs])) +(conj ([]) ([tbl]) ([tbl x]) ([tbl x & xs])) ``` Insert `x` as a last element of a table `tbl`. @@ -680,10 +653,7 @@ See [`hash-map`](#hash-map) for creating empty associative tables. Function signature: ``` -(disj - ([s]) - ([s k]) - ([s k & ks])) +(disj ([s]) ([s k]) ([s k & ks])) ``` Remove key `k` from set `s`. @@ -692,7 +662,7 @@ Remove key `k` from set `s`. Function signature: ``` -(cons [x tbl]) +(cons ([x tbl])) ``` Insert `x` to `tbl` at the front. Calls [`seq`](#seq) on `tbl`. @@ -701,10 +671,7 @@ Insert `x` to `tbl` at the front. Calls [`seq`](#seq) on `tbl`. Function signature: ``` -(concat - ([x]) - ([x y]) - ([x y & xs])) +(concat ([]) ([x]) ([x y]) ([x y & xs])) ``` Concatenate tables. @@ -713,9 +680,7 @@ Concatenate tables. Function signature: ``` -(reduce - ([f col]) - ([f val col])) +(reduce ([f col]) ([f val col])) ``` Reduce collection `col` using function `f` and optional initial value `val`. @@ -747,7 +712,7 @@ Reduce sequence of numbers with [`add`](#add) Function signature: ``` -(reduced [x]) +(reduced ([x])) ``` Wraps `x` in such a way so [`reduce`](#reduce) will terminate early @@ -779,7 +744,7 @@ valid number, but we've terminated right before we've reached it. Function signature: ``` -(reduce-kv [f val tbl]) +(reduce-kv ([f val tbl])) ``` Reduces an associative table using function `f` and initial value `val`. @@ -869,7 +834,7 @@ Basic `zipmap` implementation: Function signature: ``` -(filter [pred col]) +(filter ([pred col])) ``` Returns a sequential table of the items in `col` for which `pred` @@ -879,7 +844,7 @@ Returns a sequential table of the items in `col` for which `pred` Function signature: ``` -(every? [pred tbl]) +(every? ([pred tbl])) ``` Test if every item in `tbl` satisfies the `pred`. @@ -888,7 +853,7 @@ Test if every item in `tbl` satisfies the `pred`. Function signature: ``` -(some [pred tbl]) +(some ([pred tbl])) ``` Test if any item in `tbl` satisfies the `pred`. @@ -897,7 +862,7 @@ Test if any item in `tbl` satisfies the `pred`. Function signature: ``` -(not-any? [pred tbl]) +(not-any? ([pred tbl])) ``` Test if no item in `tbl` satisfy the `pred`. @@ -906,10 +871,7 @@ Test if no item in `tbl` satisfy the `pred`. Function signature: ``` -(range - ([upper]) - ([lower upper]) - ([lower upper step])) +(range ([upper]) ([lower upper]) ([lower upper step])) ``` return range of of numbers from `lower` to `upper` with optional `step`. @@ -918,7 +880,7 @@ return range of of numbers from `lower` to `upper` with optional `step`. Function signature: ``` -(reverse [tbl]) +(reverse ([tbl])) ``` Returns table with same items as in `tbl` but in reverse order. @@ -927,7 +889,7 @@ Returns table with same items as in `tbl` but in reverse order. Function signature: ``` -(identity [x]) +(identity ([x])) ``` Returns its argument. @@ -936,10 +898,7 @@ Returns its argument. Function signature: ``` -(comp - ([f]) - ([f g]) - ([f g & fs])) +(comp ([]) ([f]) ([f g]) ([f g & fs])) ``` Compose functions. @@ -948,7 +907,7 @@ Compose functions. Function signature: ``` -(complement [f]) +(complement ([f])) ``` Takes a function `f` and returns the function that takes the same @@ -959,7 +918,7 @@ oppisite truth value. Function signature: ``` -(constantly [x]) +(constantly ([x])) ``` Returns a function that takes any number of arguments and returns `x`. @@ -968,7 +927,7 @@ Returns a function that takes any number of arguments and returns `x`. Function signature: ``` -(memoize [f]) +(memoize ([f])) ``` Returns a memoized version of a referentially transparent function. @@ -981,9 +940,7 @@ use. Function signature: ``` -(assoc - ([tbl k v]) - ([tbl k v & kvs])) +(assoc ([tbl k v]) ([tbl k v & kvs])) ``` Associate key `k` with value `v` in `tbl`. @@ -992,8 +949,7 @@ Associate key `k` with value `v` in `tbl`. Function signature: ``` -(hash-map - ([& kvs])) +(hash-map ([]) ([& kvs])) ``` Create associative table from keys and values @@ -1002,9 +958,7 @@ Create associative table from keys and values Function signature: ``` -(get - ([tbl key]) - ([tbl key not-found])) +(get ([tbl key]) ([tbl key not-found])) ``` Get value from the table by accessing it with a `key`. @@ -1015,9 +969,7 @@ found in the table. Function signature: ``` -(get-in - ([tbl keys]) - ([tbl keys not-found])) +(get-in ([tbl keys]) ([tbl keys not-found])) ``` Get value from nested set of tables by providing key sequence. @@ -1028,7 +980,7 @@ found in the table. Function signature: ``` -(keys [tbl]) +(keys ([tbl])) ``` Returns a sequence of the table's keys, in the same order as [`seq`](#seq). @@ -1037,7 +989,7 @@ Returns a sequence of the table's keys, in the same order as [`seq`](#seq). Function signature: ``` -(vals [tbl]) +(vals ([tbl])) ``` Returns a sequence of the table's values, in the same order as [`seq`](#seq). @@ -1046,7 +998,7 @@ Returns a sequence of the table's values, in the same order as [`seq`](#seq). Function signature: ``` -(find [tbl key]) +(find ([tbl key])) ``` Returns the map entry for `key`, or `nil` if key not present. @@ -1055,10 +1007,7 @@ Returns the map entry for `key`, or `nil` if key not present. Function signature: ``` -(dissoc - ([tbl]) - ([tbl key]) - ([tbl key & keys])) +(dissoc ([tbl]) ([tbl key]) ([tbl key & keys])) ``` Remove `key` from table `tbl`. @@ -1067,7 +1016,7 @@ Remove `key` from table `tbl`. Function signature: ``` -(remove-method [multifn dispatch-val]) +(remove-method ([multifn dispatch-val])) ``` Remove method from `multifn` for given `dispatch-val`. @@ -1076,7 +1025,7 @@ Remove method from `multifn` for given `dispatch-val`. Function signature: ``` -(remove-all-methods [multifn]) +(remove-all-methods ([multifn])) ``` Removes all of the methods of multimethod @@ -1085,7 +1034,7 @@ Removes all of the methods of multimethod Function signature: ``` -(methods [multifn]) +(methods ([multifn])) ``` Given a multimethod, returns a map of dispatch values -> dispatch fns @@ -1094,7 +1043,7 @@ Given a multimethod, returns a map of dispatch values -> dispatch fns Function signature: ``` -(get-method [multifn dispatch-val]) +(get-method ([multifn dispatch-val])) ``` Given a multimethod and a dispatch value, returns the dispatch `fn` @@ -1104,7 +1053,7 @@ that would apply to that value, or `nil` if none apply and no default. Function signature: ``` -(ordered-set [& xs]) +(ordered-set ([& xs])) ``` Create ordered set. @@ -1118,7 +1067,7 @@ at the end of the set. Ordered set supports removal of items via `tset` and [`disj`](#disj). To add element to the ordered set use `tset` or [`conj`](#conj). Both operations modify the set. -**Note**: Hash set prints as `#{a b c}`, but this construct is not +**Note**: Hash set prints as `@set{a b c}`, but this construct is not supported by the Fennel reader, so you can't create sets with this syntax. Use `hash-set` function instead. @@ -1130,18 +1079,16 @@ be in the set: ``` fennel >> (ordered-set) -#{} +@set{} >> (ordered-set :a :c :b) -#{"a" "c" "b"} +@set{:a :c :b} ``` Duplicate items are not added: ``` fennel ->> (ordered-set) -#{} >> (ordered-set :a :c :a :a :a :a :c :b) -#{"a" "c" "b"} +@set{:a :c :b} ``` #### Check if set contains desired value: @@ -1151,9 +1098,9 @@ desired key will either return the key, or `nil`: ``` fennel >> (local oset (ordered-set [:a :b :c] [:c :d :e] :e :f)) >> (oset [:a :b :c]) -[:a :b :c] +["a" "b" "c"] >> (. oset :e) -:e +"e" >> (oset [:a :b :f]) nil ``` @@ -1164,8 +1111,7 @@ To add element to the set use [`conj`](#conj) or `tset` ``` fennel >> (local oset (ordered-set :a :b :c)) >> (conj oset :d :e) ->> oset -#{"a" "b" "c" "d" "e"} +@set{:a :b :c :d :e} ``` ##### Remove items from the set: @@ -1174,11 +1120,10 @@ To add element to the set use [`disj`](#disj) or `tset` ``` fennel >> (local oset (ordered-set :a :b :c)) >> (disj oset :b) ->> oset -#{"a" "c"} +@set{:a :c} >> (tset oset :a nil) >> oset -#{"c"} +@set{:c} ``` #### Equality semantics @@ -1199,7 +1144,7 @@ true Function signature: ``` -(hash-set [& xs]) +(hash-set ([& xs])) ``` Create hash set. @@ -1213,7 +1158,7 @@ using [`conj`](#con) or `tset` functions, and items can be removed with [`disj`](#disj) or `tset` functions. Rest semantics are the same as for [`ordered-set`](#ordered-set) -**Note**: Hash set prints as `#{a b c}`, but this construct is not +**Note**: Hash set prints as `@set{a b c}`, but this construct is not supported by the Fennel reader, so you can't create sets with this syntax. Use `hash-set` function instead. @@ -1225,5 +1170,5 @@ Copyright (C) 2020 Andrey Orst License: [MIT](https://gitlab.com/andreyorst/fennel-cljlib/-/raw/master/LICENSE) -<!-- Generated with Fenneldoc 0.0.6 +<!-- Generated with Fenneldoc 0.0.7 https://gitlab.com/andreyorst/fenneldoc --> diff --git a/doc/cljlib-macros.md b/doc/macros.md index a29fb0f..e9cc517 100644 --- a/doc/cljlib-macros.md +++ b/doc/macros.md @@ -1,4 +1,4 @@ -# Cljlib-macros.fnl (0.3.0) +# Macros.fnl (0.3.0) Macros for Cljlib that implement various facilities from Clojure. **Table of contents** @@ -18,6 +18,7 @@ Macros for Cljlib that implement various facilities from Clojure. - [`when-let`](#when-let) - [`if-some`](#if-some) - [`when-some`](#when-some) +- [`deep-tostring`](#deep-tostring) ## `fn*` Function signature: @@ -27,7 +28,7 @@ Function signature: ``` Create (anonymous) function of fixed arity. -Supports multiple arities by defining bodies as lists: +Supports multiple arities by defining bodies as lists. ### Examples Named function of fixed arity 2: @@ -158,18 +159,15 @@ Function signature: ``` General purpose try/catch/finally macro. - -(try expression* catch-clause* finally-clause?) - Wraps its body in `pcall` and checks the return value with `match` macro. -Catch-clause is written either as (catch symbol body*), thus acting as +Catch clause is written either as (catch symbol body*), thus acting as catch-all, or (catch value body*) for catching specific errors. It is possible to have several `catch` clauses. If no `catch` clauses specified, an implicit catch-all clause is created. -Finally-clause is optional, and written as (finally body*). If +Finally clause is optional, and written as (finally body*). If present, it must be the last clause in the `try` form, and the only `finally` clause. Note that `finally` clause is for side effects only, and runs either after succesful run of `try` body, or after any @@ -569,6 +567,15 @@ Function signature: If test is non-`nil`, evaluates `body` in implicit `do`. +## `deep-tostring` +Function signature: + +``` +(deep-tostring data key?) +``` + +**Undocumented** + --- @@ -577,5 +584,5 @@ Copyright (C) 2020 Andrey Orst License: [MIT](https://gitlab.com/andreyorst/fennel-cljlib/-/raw/master/LICENSE) -<!-- Generated with Fenneldoc 0.0.6 +<!-- Generated with Fenneldoc 0.0.7 https://gitlab.com/andreyorst/fenneldoc --> diff --git a/doc/tests/test.md b/doc/tests/test.md index c338561..8a6c7e5 100644 --- a/doc/tests/test.md +++ b/doc/tests/test.md @@ -94,5 +94,5 @@ Function signature: Assert for not truth. Works the same as [`assert-is`](#assert-is). -<!-- Generated with Fenneldoc 0.0.6 +<!-- Generated with Fenneldoc 0.0.7 https://gitlab.com/andreyorst/fenneldoc --> @@ -1,12 +1,13 @@ -(local core {:_VERSION "0.3.0" +(local core {:_VERSION "0.4.0" :_LICENSE "[MIT](https://gitlab.com/andreyorst/fennel-cljlib/-/raw/master/LICENSE)" :_COPYRIGHT "Copyright (C) 2020 Andrey Orst" + :_MODULE_NAME "cljlib" :_DESCRIPTION "Fennel-cljlib - functions from Clojure's core.clj implemented on top of Fennel. This library contains a set of functions providing functions that behave similarly to Clojure's equivalents. Library itself has nothing -Fennel specific so it should work, e.g: +Fennel specific so it should work on Lua, e.g: ``` lua Lua 5.3.5 Copyright (C) 1994-2018 Lua.org, PUC-Rio @@ -35,11 +36,24 @@ zs]))`, it is a multi-arity function, which accepts either one, two, or three-or-more arguments. Each `([...])` represents different body of a function which is chosen by checking amount of arguments passed to the function. See [Clojure's doc section on multi-arity -functions](https://clojure.org/guides/learn/functions#_multi_arity_functions)."}) +functions](https://clojure.org/guides/learn/functions#_multi_arity_functions). + +## Compatibility +This library is mainly developed with Lua 5.4, and tested against +Lua 5.2, 5.3, 5.4, and LuaJIT 2.1.0-beta3. Note, that in lua 5.2 and +LuaJIT equality semantics are a bit different from Lua 5.3 and Lua 5.4. +Main difference is that when comparing two tables, they must have +exactly the same `__eq` metamethods, so comparing hash sets with hash +sets will work, but comparing sets with other tables works only in +Lua5.3+. Another difference is that Lua 5.2 and LuaJIT don't have +inbuilt UTF-8 library, therefore `seq` function will not work for +non-ASCII strings."}) (local insert table.insert) (local _unpack (or table.unpack _G.unpack)) -(require-macros :cljlib-macros) +(import-macros {: fn* : into : empty : with-meta + : when-let : if-let : when-some : if-some} + (.. (if (and ... (not= ... :init)) (.. ... ".") "") :macros)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Utility functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -331,7 +345,7 @@ Number is rounded with `math.floor` and compared with original number." (pos? x))) (fn* core.neg-int? - "Test if `x` is a negetive integer." + "Test if `x` is a negative integer." [x] (and (int? x) (neg? x))) @@ -362,7 +376,7 @@ Number is rounded with `math.floor` and compared with original number." :int? :pos-int? :neg-int? :double? :empty? :not-empty]) -;;;;;;;;;;;;;;;;;;;;;; Sequence manipuletion functions ;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;; Sequence manipulation functions ;;;;;;;;;;;;;;;;;;;;;;;;; (fn* core.vector "Constructs sequential table out of it's arguments. @@ -384,7 +398,8 @@ Sets additional metadata for function [`vector?`](#vector?) to work. Transforms original table to sequential table of key value pairs stored as sequential tables in linear time. If `col` is an associative table, returns sequential table of vectors with key and -value. If `col` is sequential table, returns its shallow copy. +value. If `col` is sequential table, returns its shallow copy. If +`col` is string, return sequential table of its codepoints. # Examples Sequential tables remain as is: @@ -424,20 +439,41 @@ Additionally you can use [`conj`](#conj) and [`apply`](#apply) with (insert res v) (insert assoc-res [k v])) (if assoc? assoc-res res)))) - :string (let [char utf8.char] - (each [_ b (utf8.codes col)] - (insert res (char b))) - res) + :string (if _G.utf8 + (let [char _G.utf8.char] + (each [_ b (_G.utf8.codes col)] + (insert res (char b))) + res) + (do (io.stderr:write + "WARNING: utf8 module unavailable, seq function will not work for non-unicode strings\n") + (each [b (col:gmatch ".")] + (insert res b)) + res)) :nil nil - _ (error (.. "expected table, string or nil") 2)))) + _ (error (.. "expected table, string or nil, got " (type col)) 2)))) (fn* core.kvseq - "Transforms any table kind to key-value sequence." - [tbl] + "Transforms any table to key-value sequence." + [col] (let [res (empty [])] - (each [k v (pairs tbl)] - (insert res [k v])) - res)) + (match (type col) + :table (let [m (or (getmetatable col) {})] + (when-some [_ ((or m.cljlib/next next) col)] + (each [k v (pairs col)] + (insert res [k v])) + res)) + :string (if _G.utf8 + (let [char _G.utf8.char] + (each [i b (_G.utf8.codes col)] + (insert res [i (char b)])) + res) + (do (io.stderr:write + "WARNING: utf8 module unavailable, seq function will not work for non-unicode strings\n") + (for [i 1 (length col)] + (insert res [i (col:sub i i)])) + res)) + :nil nil + _ (error (.. "expected table, string or nil, got " (type col)) 2)))) (fn* core.first "Return first element of a table. Calls `seq` on its argument." @@ -518,8 +554,6 @@ See [`hash-map`](#hash-map) for creating empty associative tables." (let [tbl (or tbl (empty []))] (if (map? tbl) (tset tbl (. x 1) (. x 2)) - (set? tbl) - (tset tbl x x) (insert tbl x)))) tbl) ([tbl x & xs] @@ -895,7 +929,7 @@ oppisite truth value." (fn* core.constantly "Returns a function that takes any number of arguments and returns `x`." [x] - (fn [...] x)) + (fn [] x)) (fn* core.memoize "Returns a memoized version of a referentially transparent function. @@ -1048,12 +1082,21 @@ that would apply to that value, or `nil` if none apply and no default." ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Sets ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(fn viewset [Set] - "Workaround for a bug https://todo.sr.ht/~technomancy/fennel/26" - (let [items []] - (each [_ v (pairs Set)] - (insert items ((require :fennelview) v))) - (.. "#{" (table.concat items " ") "}"))) +(fn viewset [Set view inspector indent] + (if (. inspector.seen Set) + (.. "@set" (. inspector.seen Set) "{...}") + (let [prefix (.. "@set" + (if (inspector.visible-cycle? Set) + (. inspector.seen Set) "") + "{") + set-indent (length prefix) + indent-str (string.rep " " set-indent) + lines (icollect [i v (pairs Set)] + (.. (if (= i 1) "" indent-str) + (view v inspector (+ indent set-indent) true)))] + (tset lines 1 (.. prefix (or (. lines 1) ""))) + (tset lines (length lines) (.. (. lines (length lines)) "}")) + (values lines (> (length lines) inspector.sequential-length))))) (fn ordered-set-newindex [Set] "`__newindex` metamethod for ordered-set." @@ -1118,6 +1161,12 @@ that would apply to that value, or `nil` if none apply and no default." (values i k)))) (values iter Set nil))) +(fn into-set [Set tbl] + "Transform `tbl` into `Set`" + (each [_ v (pairs (or (seq tbl) []))] + (conj Set v)) + Set) + ;; Sets are bootstrapped upon previous functions. (fn* core.ordered-set @@ -1132,7 +1181,7 @@ at the end of the set. Ordered set supports removal of items via `tset` and [`disj`](#disj). To add element to the ordered set use `tset` or [`conj`](#conj). Both operations modify the set. -**Note**: Hash set prints as `#{a b c}`, but this construct is not +**Note**: Hash set prints as `@set{a b c}`, but this construct is not supported by the Fennel reader, so you can't create sets with this syntax. Use `hash-set` function instead. @@ -1144,18 +1193,16 @@ be in the set: ``` fennel >> (ordered-set) -#{} +@set{} >> (ordered-set :a :c :b) -#{\"a\" \"c\" \"b\"} +@set{:a :c :b} ``` Duplicate items are not added: ``` fennel ->> (ordered-set) -#{} >> (ordered-set :a :c :a :a :a :a :c :b) -#{\"a\" \"c\" \"b\"} +@set{:a :c :b} ``` ## Check if set contains desired value: @@ -1165,9 +1212,9 @@ desired key will either return the key, or `nil`: ``` fennel >> (local oset (ordered-set [:a :b :c] [:c :d :e] :e :f)) >> (oset [:a :b :c]) -[:a :b :c] +[\"a\" \"b\" \"c\"] >> (. oset :e) -:e +\"e\" >> (oset [:a :b :f]) nil ``` @@ -1178,8 +1225,7 @@ To add element to the set use [`conj`](#conj) or `tset` ``` fennel >> (local oset (ordered-set :a :b :c)) >> (conj oset :d :e) ->> oset -#{\"a\" \"b\" \"c\" \"d\" \"e\"} +@set{:a :b :c :d :e} ``` ### Remove items from the set: @@ -1188,11 +1234,10 @@ To add element to the set use [`disj`](#disj) or `tset` ``` fennel >> (local oset (ordered-set :a :b :c)) >> (disj oset :b) ->> oset -#{\"a\" \"c\"} +@set{:a :c} >> (tset oset :a nil) >> oset -#{\"c\"} +@set{:c} ``` ## Equality semantics @@ -1219,12 +1264,12 @@ true (setmetatable {} {:cljlib/type :cljlib/ordered-set :cljlib/next #(next Set $2) + :cljlib/into into-set + :cljlib/empty #(ordered-set) :__eq set-eq - :__call #(if (. Set $2) $2) + :__call #(if (. Set $2) $2 nil) :__len (set-length Set) - :__index #(match $2 - :cljlib/empty #(ordered-set) - _ (if (. Set $2) $2)) + :__index #(if (. Set $2) $2 nil) :__newindex (ordered-set-newindex Set) :__ipairs set-ipairs :__pairs set-ipairs @@ -1243,7 +1288,7 @@ using [`conj`](#con) or `tset` functions, and items can be removed with [`disj`](#disj) or `tset` functions. Rest semantics are the same as for [`ordered-set`](#ordered-set) -**Note**: Hash set prints as `#{a b c}`, but this construct is not +**Note**: Hash set prints as `@set{a b c}`, but this construct is not supported by the Fennel reader, so you can't create sets with this syntax. Use `hash-set` function instead." [& xs] @@ -1255,12 +1300,12 @@ syntax. Use `hash-set` function instead." (setmetatable {} {:cljlib/type :cljlib/hash-set :cljlib/next #(next Set $2) + :cljlib/into into-set + :cljlib/empty #(hash-set) :__eq set-eq - :__call #(if (. Set $2) $2) + :__call #(if (. Set $2) $2 nil) :__len (set-length Set) - :__index #(match $2 - :cljlib/empty #(hash-set) - _ (if (. Set $2) $2)) + :__index #(if (. Set $2) $2 nil) :__newindex (hash-set-newindex Set) :__ipairs set-ipairs :__pairs set-ipairs @@ -1281,6 +1326,8 @@ syntax. Use `hash-set` function instead." multimethods-doc-order set-doc-order))) + ;; LocalWords: cljlib Clojure's clj lua PUC mapv concat Clojure fn zs ;; LocalWords: defmulti multi arity eq metadata prepending variadic -;; LocalWords: args tbl LocalWords memoized referentially +;; LocalWords: args tbl LocalWords memoized referentially Andrey +;; LocalWords: Orst codepoints diff --git a/cljlib-macros.fnl b/macros.fnl index 19b0107..52a3a94 100644 --- a/cljlib-macros.fnl +++ b/macros.fnl @@ -1,13 +1,3 @@ -(local fennel (require :fennel)) - - -;;;;;;;;;; compile time check that `--metadata` feature was enabled ;;;;;;;;;;;; - -(local meta-enabled (pcall _SCOPE.specials.doc - (list (sym :doc) (sym :doc)) - _SCOPE _CHUNK)) - - ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Helper functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (fn first [tbl] @@ -53,6 +43,8 @@ (table? (first bindings))) "expected symbol, sequence or table as binding." bindings))) +(local fennel (require :fennel)) + (fn attach-meta [value meta] (each [k v (pairs meta)] (fennel.metadata:set value k v))) @@ -60,9 +52,7 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;; Runtime function builers ;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; This code should be shared with `cljlib.fnl` however it seems -;; impossible to actually do that right now, mainly because there's no -;; way of doing relative loading of macro modules. +;; TODO: This code should be shared with `init.fnl` (fn eq-fn [] ;; Returns recursive equality function. @@ -119,10 +109,16 @@ (insert# assoc-res# [k# v#])) (if assoc?# assoc-res# res#))) (= type# :string) - (let [char# utf8.char] - (each [_# b# (utf8.codes col#)] - (insert# res# (char# b#))) - res#) + (if _G.utf8 + (let [char# _G.utf8.char] + (each [_# b# (_G.utf8.codes col#)] + (insert# res# (char# b#))) + res#) + (do + (io.stderr:write "WARNING: utf8 module unavailable, seq function will not work for non-unicode strings\n") + (each [b# (col#:gmatch ".")] + (insert# res# b#)) + res#)) (= type# :nil) nil (error "expected table, string or nil" 2))))) @@ -144,6 +140,11 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Metadata ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; compile time check that `--metadata` feature was enabled +(local meta-enabled (pcall _SCOPE.specials.doc + (list (sym :doc) (sym :doc)) + _SCOPE _CHUNK)) + (fn when-meta [...] "Wrapper that compiles away if metadata support was not enabled. What this effectively means, is that everything that is wrapped with this @@ -213,33 +214,57 @@ returns the value without additional metadata. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; fn* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(fn keyword? [data] + (and (= (type data) :string) + (data:find "^[-%w?\\^_!$%&*+./@:|<=>]+$"))) + +(fn deep-tostring [data key?] + (let [tbl []] + (if (sequence? data) + (do (each [_ v (ipairs data)] + (table.insert tbl (deep-tostring v))) + (.. "[" (table.concat tbl " ") "]")) + (table? data) + (do (each [k v (pairs data)] + (table.insert tbl (.. (deep-tostring k true) " " (deep-tostring v)))) + (.. "{" (table.concat tbl " ") "}")) + (and key? (keyword? data)) (.. ":" data) + (string? data) + (string.format "%q" data) + (tostring data)))) + (fn gen-arglist-doc [args] - ;; Construct vector of arguments represented as strings from AST. (if (list? (. args 1)) - (let [arglist [] - opener (if (> (length args) 1) "\n (" "(")] - (each [i v (ipairs args)] + (let [arglist []] + (each [_ v (ipairs args)] (let [arglist-doc (gen-arglist-doc v)] (when (next arglist-doc) - (table.insert - arglist - (.. opener (table.concat arglist-doc " ") ")"))))) + (table.insert arglist (table.concat arglist-doc " "))))) + (when (and (> (length (table.concat arglist " ")) 60) + (> (length arglist) 1)) + (each [i s (ipairs arglist)] + (tset arglist i (.. "\n " s)))) arglist) (sequence? (. args 1)) (let [arglist [] args (. args 1) len (length args)] - (each [i v (ipairs args)] - (table.insert arglist - (match i - (1 ? (= len 1)) (.. "[" (tostring v) "]") - 1 (.. "[" (tostring v)) - len (.. (tostring v) "]") - _ (tostring v)))) + (if (= len 0) + (table.insert arglist "([])") + (each [i v (ipairs args)] + (table.insert arglist + (match i + (1 ? (= len 1)) (.. "([" (deep-tostring v) "])") + 1 (.. "([" (deep-tostring v)) + len (.. (deep-tostring v) "])") + _ (deep-tostring v))))) arglist))) (fn multisym->sym [s] + ;; Strips away the multisym part from symbol, and return just the + ;; symbol itself. Also returns the second value of whether the + ;; transformation occured or not. (if (multi-sym? s) (values (sym (string.gsub (tostring s) ".*[.]" "")) true) (values s false))) @@ -293,7 +318,7 @@ returns the value without additional metadata. (set prev cur)) prev)) -(fn arity-dispatcher [len fixed body& name] +(fn arity-dispatcher [len fixed amp-body name] ;; Forms an `if` expression with all fixed arities first, then `&` arity, ;; if present, and default error message as last arity. ;; @@ -304,8 +329,8 @@ returns the value without additional metadata. ;; are put in this `if` as: `(= len fixed-len)`, where `fixed-len` is the ;; length of current arity arglist, computed with `gen-arity`. ;; - ;; `body&` stores size of fixed part of arglist, that is, everything up - ;; until `&`, and the body itself. When `body&` provided, the `(>= len + ;; `amp-body` stores size of fixed part of arglist, that is, everything up + ;; until `&`, and the body itself. When `amp-body` provided, the `(>= len ;; more-len)` is added to the resulting `if` expression. ;; ;; Lastly the catchall branch is added to `if` expression, which ensures @@ -320,8 +345,8 @@ returns the value without additional metadata. (table.insert lengths fixed-len) (table.insert bodies (list '= len fixed-len)) (table.insert bodies body)) - (when body& - (let [[more-len body arity] body&] + (when amp-body + (let [[more-len body arity] amp-body] (assert-compile (not (and max (<= more-len max))) "fn*: arity with `&' must have more arguments than maximum arity without `&'. * Try adding more arguments before `&'" arity) @@ -330,7 +355,7 @@ returns the value without additional metadata. (table.insert bodies body))) (if (not (and (grows-by-one-or-equal? lengths) (contains? lengths 0) - body&)) + amp-body)) (table.insert bodies (list 'error (.. "wrong argument amount" (if name (.. " for " name) "")) 2))) @@ -352,26 +377,26 @@ returns the value without additional metadata. ;; Produces arglist and all body forms for multi-arity function. ;; For more info check `gen-arity' documentation. (let [bodies {} ;; bodies of fixed arity - bodies& []] ;; bodies where arglist contains `&' + amp-bodies []] ;; bodies where arglist contains `&' (each [_ arity (ipairs args)] (let [(n body amp) (gen-arity arity)] (if amp - (table.insert bodies& [amp body arity]) + (table.insert amp-bodies [amp body arity]) (tset bodies n body)))) - (assert-compile (<= (length bodies&) 1) + (assert-compile (<= (length amp-bodies) 1) "fn* must have only one arity with `&':" - (. bodies& (length bodies&))) + (. amp-bodies (length amp-bodies))) `(let [len# (select :# ...)] ,(arity-dispatcher 'len# bodies - (if (not= (next bodies&) nil) - (. bodies& 1)) + (if (not= (next amp-bodies) nil) + (. amp-bodies 1)) fname)))) (fn fn* [name doc? ...] "Create (anonymous) function of fixed arity. -Supports multiple arities by defining bodies as lists: +Supports multiple arities by defining bodies as lists. # Examples Named function of fixed arity 2: @@ -511,10 +536,9 @@ from `ns.strings`, so the latter must be fully qualified (if (sym? name-wo-namespace) (if namespaced? `(local ,name-wo-namespace - (do - (fn ,name-wo-namespace [...] ,docstring ,body) - (set ,name ,name-wo-namespace) - ,(with-meta name-wo-namespace `{:fnl/arglist ,arglist-doc}))) + (do (fn ,name-wo-namespace [...] ,docstring ,body) + (set ,name ,name-wo-namespace) ;; set function into module table, e.g. (set foo.bar bar) + ,(with-meta name-wo-namespace `{:fnl/arglist ,arglist-doc}))) `(local ,name ,(with-meta `(fn ,name [...] ,docstring ,body) `{:fnl/arglist ,arglist-doc}))) (with-meta `(fn [...] ,docstring ,body) `{:fnl/arglist ,arglist-doc})))) @@ -665,9 +689,8 @@ at runtime: (setmetatable to# {:cljlib/type :seq})) (= to-type :seq) `(let [to# (or ,to []) - seq# ,(seq-fn) insert# table.insert] - (each [_# v# (ipairs (seq# (or ,from [])))] + (each [_# v# (ipairs (,(seq-fn) (or ,from [])))] (insert# to# v#)) (setmetatable to# {:cljlib/type :seq})) (and (= to-type :table) (= from-type :seq)) @@ -683,13 +706,17 @@ at runtime: (setmetatable to# {:cljlib/type :table})) (= to-type :table) `(let [to# (or ,to []) + seq# ,(seq-fn) from# (or ,from [])] (match (,(table-type-fn) from#) - :seq (each [_# [k# v#] (ipairs from#)] + :seq (each [_# [k# v#] (ipairs (seq# from#))] (tset to# k# v#)) :table (each [k# v# (pairs from#)] (tset to# k# v#)) - :else (error "expected table as second argument" 2)) + :else (error "expected table as second argument" 2) + _# (do (each [_# [k# v#] (pairs (or (seq# from#) []))] + (tset to# k# v#)) + to#)) (setmetatable to# {:cljlib/type :table})) ;; runtime branch `(let [to# ,to @@ -715,12 +742,10 @@ at runtime: (tset to# k# v#)) to#) :empty to# - :else (error "expected table as second argument" 2)) - ;; set both ordered set and hash set - (Set# ? (or (= Set# :cljlib/ordered-set) (= Set# :cljlib/hash-set))) - (do (each [_# v# (ipairs (seq# (or from# [])))] - (tset to# v# v#)) - to#) + :else (error "expected table as second argument" 2) + _# (do (each [_# [k# v#] (pairs (or (seq# from#) []))] + (tset to# k# v#)) + to#)) ;; sometimes it is handy to pass nil too :nil (match (table-type# from#) :nil nil @@ -732,7 +757,11 @@ at runtime: (tset to# k# v#)) to#) :else (error "expected table as second argument" 2)) - :else (error "expected table as first argument" 2))] + :else (error "expected table as second argument" 2) + _# (let [m# (or (getmetatable to#) {})] + (match m#.cljlib/into + f# (f# to# from#) + nil (error "expected table as SECOND argument" 2))))] (if res# (let [m# (or (getmetatable res#) {})] (set m#.cljlib/type (match to-type# @@ -769,11 +798,15 @@ See [`into`](#into) for more info on how conversion is done." (match (table-type x) :seq `(setmetatable {} {:cljlib/type :seq}) :table `(setmetatable {} {:cljlib/type :table}) - _ `(let [x# ,x] - (match (,(table-type-fn) x#) - :cljlib/ordered-set (: x# :cljlib/empty) - :cljlib/hash-set (: x# :cljlib/empty) - t# (setmetatable {} {:cljlib/type t#}))))) + _ `(let [x# ,x + m# (getmetatable x#)] + (match (and m# m#.cljlib/empty) + f# (f# x#) + _# (match (,(table-type-fn) x#) + :string (setmetatable {} {:cljlib/type :seq}) + :nil nil + :else (error (.. "can't create sequence from " (type x#))) + t# (setmetatable {} {:cljlib/type t#})))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; multimethods ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -812,7 +845,7 @@ See [`into`](#into) for more info on how conversion is done." ,docstring (let [dispatch-value# (,dispatch-fn ...) (res# view#) (pcall require :fennelview) - tostr# (if res# view# tostring)] + tostr# (if res# #(view# $ {:one-line true}) tostring)] ((or (. t# dispatch-value#) (. t# (or (. ,options :default) :default)) (error (.. "No method in multimethod '" @@ -991,9 +1024,11 @@ calls will not override existing bindings: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; try ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (fn catch? [[fun]] + "Test if expression is a catch clause." (= (tostring fun) :catch)) (fn finally? [[fun]] + "Test if expression is a finally clause." (= (tostring fun) :finally)) (fn add-finally [finally form] diff --git a/tests/core.fnl b/tests/core.fnl index d323a07..ab62a4b 100644 --- a/tests/core.fnl +++ b/tests/core.fnl @@ -1,49 +1,40 @@ -(require-macros :cljlib-macros) +(require-macros :macros) (require-macros :tests.test) -(macro require-module [module] - "Require module and bind all it's functions to locals." - `(local ,(let [destr-map# {}] - (each [k# _# (pairs (require module))] - (when (not= (string.sub k# 1 1) :_) - (tset destr-map# k# (sym k#)))) - destr-map#) - (require ,module))) - -(require-module :cljlib) +(local core (require :init)) (deftest equality (testing "comparing basetypes" - (assert-not (pcall eq)) + (assert-not (pcall core.eq)) (assert-eq 1 1) (assert-ne 1 2) - (assert-is (eq 1 1 1 1 1)) + (assert-is (core.eq 1 1 1 1 1)) (assert-eq 1.0 1.0) - (assert-is (eq 1.0 1.0 1.0)) - (assert-is (eq 1.0 1.0 1.0)) - (assert-is (eq "1" "1" "1" "1" "1"))) + (assert-is (core.eq 1.0 1.0 1.0)) + (assert-is (core.eq 1.0 1.0 1.0)) + (assert-is (core.eq "1" "1" "1" "1" "1"))) (testing "deep comparison" - (assert-is (eq [])) + (assert-is (core.eq [])) (assert-eq [] []) (assert-eq [] {}) (assert-eq [1 2] [1 2]) (assert-eq [[1 [2 [3]] {[5] {:a [1 [1 [1 [1]]]]}}]] [[1 [2 [3]] {[5] {:a [1 [1 [1 [1]]]]}}]]) - (assert-is (eq [[1 [2 [3]] {[5] {:a [1 [1 [1 [1]]]]}}]] - [[1 [2 [3]] {[5] {:a [1 [1 [1 [1]]]]}}]])) - (assert-is (eq [[1 [2 [3]] {[5] {:a [1 [1 [1 [1]]]]}}]] - [[1 [2 [3]] {[5] {:a [1 [1 [1 [1]]]]}}]] - [[1 [2 [3]] {[5] {:a [1 [1 [1 [1]]]]}}]])) - (assert-not (eq [[1 [2 [3]] {[5] {:a [1 [1 [1 [1]]]]}}]] - [[1 [2 [3]] {[5] {:a [1 [1 [1 [1]]]]}}]] - [[1 [2 [3]] {[6] {:a [1 [1 [1 [1]]]]}}]])) + (assert-is (core.eq [[1 [2 [3]] {[5] {:a [1 [1 [1 [1]]]]}}]] + [[1 [2 [3]] {[5] {:a [1 [1 [1 [1]]]]}}]])) + (assert-is (core.eq [[1 [2 [3]] {[5] {:a [1 [1 [1 [1]]]]}}]] + [[1 [2 [3]] {[5] {:a [1 [1 [1 [1]]]]}}]] + [[1 [2 [3]] {[5] {:a [1 [1 [1 [1]]]]}}]])) + (assert-not (core.eq [[1 [2 [3]] {[5] {:a [1 [1 [1 [1]]]]}}]] + [[1 [2 [3]] {[5] {:a [1 [1 [1 [1]]]]}}]] + [[1 [2 [3]] {[6] {:a [1 [1 [1 [1]]]]}}]])) (assert-ne [1] [1 2]) (assert-ne [1 2] [1]) - (assert-is (eq [1 [2]] [1 [2]] [1 [2]])) - (assert-is (eq [1 [2]] [1 [2]] [1 [2]])) - (assert-not (eq [1 [2]] [1 [2]] [1 [2 [3]]])) - (assert-not (eq {:a {:b 2}} {:a {:b 2}} {:a {:b 3}})) + (assert-is (core.eq [1 [2]] [1 [2]] [1 [2]])) + (assert-is (core.eq [1 [2]] [1 [2]] [1 [2]])) + (assert-not (core.eq [1 [2]] [1 [2]] [1 [2 [3]]])) + (assert-not (core.eq {:a {:b 2}} {:a {:b 2}} {:a {:b 3}})) (let [a {:a 1 :b 2} b {:a 1 :b 2}] @@ -74,12 +65,12 @@ meta-b (getmetatable b) index-a (. meta-a :__index) index-b (. meta-b :__index)] - (eq a b) + (core.eq a b) (assert-eq meta-a (getmetatable a)) (assert-eq meta-b (getmetatable b)) (assert-eq index-a (. (getmetatable a) :__index)) (assert-eq index-b (. (getmetatable b) :__index)) - (eq b a) + (core.eq b a) (assert-eq meta-a (getmetatable a)) (assert-eq meta-b (getmetatable b)) (assert-eq index-a (. (getmetatable a) :__index)) @@ -87,189 +78,190 @@ (deftest range (testing "range" - (assert-not (pcall range)) - (assert-eq (range 10) [0 1 2 3 4 5 6 7 8 9]) - (assert-eq (range -5 5) [-5 -4 -3 -2 -1 0 1 2 3 4]) + (assert-not (pcall core.range)) + (assert-eq (core.range 10) [0 1 2 3 4 5 6 7 8 9]) + (assert-eq (core.range -5 5) [-5 -4 -3 -2 -1 0 1 2 3 4]) (assert-eq [0 0.2 0.4 0.6 0.8] [0 0.2 0.4 0.6 0.8]) - (assert-eq (range 0 1 0.2) (range 0 1 0.2)))) + (assert-eq (core.range 0 1 0.2) (core.range 0 1 0.2)))) (deftest predicates (testing "zero?" - (assert-is (zero? 0)) - (assert-is (zero? -0)) - (assert-not (zero? 1)) - (assert-not (pcall zero?)) - (assert-not (pcall zero? 1 2))) + (assert-is (core.zero? 0)) + (assert-is (core.zero? -0)) + (assert-not (core.zero? 1)) + (assert-not (pcall core.zero?)) + (assert-not (pcall core.zero? 1 2))) (testing "int?" - (assert-is (int? 1)) - (assert-not (int? 1.1)) - (assert-not (pcall int?)) - (assert-not (pcall int? 1 2))) + (assert-is (core.int? 1)) + (assert-not (core.int? 1.1)) + (assert-not (pcall core.int?)) + (assert-not (pcall core.int? 1 2))) (testing "pos?" - (assert-is (pos? 1)) - (assert-is (and (not (pos? 0)) (not (pos? -1)))) - (assert-not (pcall pos?)) - (assert-not (pcall pos? 1 2))) + (assert-is (core.pos? 1)) + (assert-is (and (not (core.pos? 0)) (not (core.pos? -1)))) + (assert-not (pcall core.pos?)) + (assert-not (pcall core.pos? 1 2))) (testing "neg?" - (assert-is (neg? -1)) - (assert-is (and (not (neg? 0)) (not (neg? 1)))) - (assert-not (pcall neg?)) - (assert-not (pcall neg? 1 2))) + (assert-is (core.neg? -1)) + (assert-is (and (not (core.neg? 0)) (not (core.neg? 1)))) + (assert-not (pcall core.neg?)) + (assert-not (pcall core.neg? 1 2))) (testing "pos-int?" - (assert-is (pos-int? 42)) - (assert-not (pos-int? 4.2)) - (assert-not (pcall pos-int?)) - (assert-not (pcall pos-int? 1 2))) + (assert-is (core.pos-int? 42)) + (assert-not (core.pos-int? 4.2)) + (assert-not (pcall core.pos-int?)) + (assert-not (pcall core.pos-int? 1 2))) (testing "neg-int?" - (assert-is (neg-int? -42)) - (assert-not (neg-int? -4.2)) - (assert-not (pcall neg-int?)) - (assert-not (pcall neg-int? 1 2))) + (assert-is (core.neg-int? -42)) + ;; (assert-not (core.neg-int? -4.2)) + (assert-not (pcall core.neg-int?)) + (assert-not (pcall core.neg-int? 1 2))) (testing "string?" - (assert-is (string? :s)) - (assert-not (pcall string?)) - (assert-not (pcall string? 1 2))) + (assert-is (core.string? :s)) + (assert-not (pcall core.string?)) + (assert-not (pcall core.string? 1 2))) (testing "double?" - (assert-is (double? 3.3)) - (assert-not (double? 3.0)) - (assert-not (pcall double?)) - (assert-not (pcall double? 1 2))) + (assert-is (core.double? 3.3)) + (assert-not (core.double? 3.0)) + (assert-not (pcall core.double?)) + (assert-not (pcall core.double? 1 2))) (testing "map?" - (assert-is (map? {:a 1})) - (assert-not (map? {})) - (assert-is (map? (empty {}))) - (assert-not (map? (empty []))) - (assert-not (pcall map?)) - (assert-not (pcall map? 1 2))) + (assert-is (core.map? {:a 1})) + (assert-not (core.map? {})) + (assert-is (core.map? (empty {}))) + (assert-not (core.map? (empty []))) + (assert-not (pcall core.map?)) + (assert-not (pcall core.map? 1 2))) (testing "vector?" - (assert-not (vector? [])) - (assert-is (vector? [{:a 1}])) - (assert-not (vector? {})) - (assert-not (vector? {:a 1})) - (assert-is (vector? (empty []))) - (assert-not (vector? (empty {}))) - (assert-not (pcall vector?)) - (assert-not (pcall vector? 1 2))) + (assert-not (core.vector? [])) + (assert-is (core.vector? [{:a 1}])) + (assert-not (core.vector? {})) + (assert-not (core.vector? {:a 1})) + (assert-is (core.vector? (empty []))) + (assert-not (core.vector? (empty {}))) + (assert-not (pcall core.vector?)) + (assert-not (pcall core.vector? 1 2))) (testing "multifn?" - (assert-not (multifn? [])) - (assert-is (multifn? (do (defmulti f identity) f))) - (assert-not (pcall multifn?)) - (assert-not (pcall multifn? 1 2))) + (assert-not (core.multifn? [])) + (assert-is (core.multifn? (do (defmulti f core.identity) f))) + (assert-not (pcall core.multifn?)) + (assert-not (pcall core.multifn? 1 2))) (testing "set?" - (assert-is (set? (ordered-set))) - (assert-is (set? (hash-set))) - (assert-eq (set? (hash-set)) :cljlib/hash-set) - (assert-eq (set? (ordered-set)) :cljlib/ordered-set) - (assert-not (pcall set?)) - (assert-not (pcall set? 1 2))) + (assert-is (core.set? (core.ordered-set))) + (assert-is (core.set? (core.hash-set))) + (assert-eq (core.set? (core.hash-set)) :cljlib/hash-set) + (assert-eq (core.set? (core.ordered-set)) :cljlib/ordered-set) + (assert-not (pcall core.set?)) + (assert-not (pcall core.set? 1 2))) (testing "nil?" - (assert-is (nil?)) - (assert-is (nil? nil)) - (assert-not (nil? 1)) - (assert-not (pcall nil? 1 2))) + (assert-is (core.nil?)) + (assert-is (core.nil? nil)) + (assert-not (core.nil? 1)) + (assert-not (pcall core.nil? 1 2))) (testing "odd?" - (assert-is (odd? 3)) - (assert-is (odd? -3)) - (assert-not (odd? 2)) - (assert-not (odd? -2)) - (assert-not (pcall odd?)) - (assert-not (pcall odd? 1 2))) + (assert-is (core.odd? 3)) + (assert-is (core.odd? -3)) + (assert-not (core.odd? 2)) + (assert-not (core.odd? -2)) + (assert-not (pcall core.odd?)) + (assert-not (pcall core.odd? 1 2))) (testing "even?" - (assert-is (even? 2)) - (assert-is (even? -2)) - (assert-not (even? 23)) - (assert-not (even? -23)) - (assert-not (pcall even?)) - (assert-not (pcall even? 1 2))) + (assert-is (core.even? 2)) + (assert-is (core.even? -2)) + (assert-not (core.even? 23)) + (assert-not (core.even? -23)) + (assert-not (pcall core.even?)) + (assert-not (pcall core.even? 1 2))) (testing "true?" - (assert-is (true? true)) - (assert-not (true? false)) - (assert-not (true? 10)) - (assert-not (true? :true)) - (assert-not (pcall true?)) - (assert-not (pcall true? 1 2))) + (assert-is (core.true? true)) + (assert-not (core.true? false)) + (assert-not (core.true? 10)) + (assert-not (core.true? :true)) + (assert-not (pcall core.true?)) + (assert-not (pcall core.true? 1 2))) (testing "false?" - (assert-is (false? false)) - (assert-not (false? true)) - (assert-not (false? 10)) - (assert-not (false? :true)) - (assert-not (pcall false?)) - (assert-not (pcall false? 1 2))) + (assert-is (core.false? false)) + (assert-not (core.false? true)) + (assert-not (core.false? 10)) + (assert-not (core.false? :true)) + (assert-not (pcall core.false?)) + (assert-not (pcall core.false? 1 2))) (testing "boolean?" - (assert-is (boolean? true)) - (assert-is (boolean? false)) - (assert-not (boolean? :false)) - (assert-not (boolean? (fn [] true))) - (assert-not (pcall boolean?)) - (assert-not (pcall boolean? 1 2)))) + (assert-is (core.boolean? true)) + (assert-is (core.boolean? false)) + (assert-not (core.boolean? :false)) + (assert-not (core.boolean? (fn [] true))) + (assert-not (pcall core.boolean?)) + (assert-not (pcall core.boolean? 1 2)))) (deftest sequence-functions (testing "seq" - (assert-not (pcall seq)) - (assert-not (pcall seq [] [])) - (assert-eq (seq []) nil) - (assert-eq (seq {}) nil) - (assert-eq (seq [1]) [1]) - (assert-eq (seq [1 2 3]) [1 2 3]) - (assert-eq (seq {:a 1}) [["a" 1]]) - (assert-eq (seq "abc") ["a" "b" "c"]) - (assert-eq (seq "абв") ["а" "б" "в"]) - (assert-eq (seq {12345 123}) [[12345 123]]) - (assert-eq (seq (ordered-set 1 2 3)) [1 2 3]) - (assert-eq (length (seq (ordered-set 1 2 3))) 3) - (assert-eq (seq (hash-set 1)) [1]) - (assert-eq (length (seq (hash-set 1 2 3))) 3)) + (assert-not (pcall core.seq)) + (assert-not (pcall core.seq [] [])) + (assert-eq (core.seq []) nil) + (assert-eq (core.seq {}) nil) + (assert-eq (core.seq [1]) [1]) + (assert-eq (core.seq [1 2 3]) [1 2 3]) + (assert-eq (core.seq {:a 1}) [["a" 1]]) + (assert-eq (core.seq "abc") ["a" "b" "c"]) + (when _G.utf8 (assert-eq (core.seq "абв") ["а" "б" "в"])) + (assert-eq (core.seq {12345 123}) [[12345 123]]) + (assert-eq (core.seq (core.ordered-set 1 2 3)) [1 2 3]) + (assert-eq (length (core.seq (core.ordered-set 1 2 3))) 3) + (assert-eq (core.seq (core.hash-set 1)) [1]) + (assert-eq (length (core.seq (core.hash-set 1 2 3))) 3)) (testing "kvseq" - (assert-not (pcall kvseq)) - (assert-not (pcall kvseq [] [])) - (assert-eq (kvseq {123 456}) [[123 456]]) - (assert-eq (kvseq {:a 1}) [[:a 1]]) - (assert-eq (kvseq [0 0 0 10]) [[1 0] [2 0] [3 0] [4 10]]) - (assert-eq (kvseq (ordered-set :a :b :c)) [[1 :a] [2 :b] [3 :c]]) - (assert-eq (kvseq (hash-set :a)) [[1 :a]])) + (assert-not (pcall core.kvseq)) + (assert-not (pcall core.kvseq [] [])) + (assert-eq (core.kvseq {123 456}) [[123 456]]) + (assert-eq (core.kvseq {:a 1}) [[:a 1]]) + (assert-eq (core.kvseq [0 0 0 10]) [[1 0] [2 0] [3 0] [4 10]]) + (assert-eq (core.kvseq (core.ordered-set :a :b :c)) [[1 :a] [2 :b] [3 :c]]) + (assert-eq (core.kvseq (core.hash-set :a)) [[1 :a]]) + (assert-eq (core.kvseq "abc") [[1 "a"] [2 "b"] [3 "c"]])) (testing "mapv" - (assert-not (pcall mapv)) - (assert-not (pcall mapv #(do nil))) - (assert-eq (mapv #(* $ $) [1 2 3 4]) [1 4 9 16]) + (assert-not (pcall core.mapv)) + (assert-not (pcall core.mapv #(do nil))) + (assert-eq (core.mapv #(* $ $) [1 2 3 4]) [1 4 9 16]) - (assert-eq (into {} (mapv (fn [[k v]] [k (* v v)]) {:a 1 :b 2 :c 3})) + (assert-eq (into {} (core.mapv (fn [[k v]] [k (* v v)]) {:a 1 :b 2 :c 3})) (into {} [[:a 1] [:b 4] [:c 9]])) - (assert-eq (into {} (mapv (fn [[k1 v1] [k2 v2]] [k1 (* v1 v2)]) - {:a 1 :b 2 :c 3} - {:a -1 :b 0 :c 2})) + (assert-eq (into {} (core.mapv (fn [[k1 v1] [k2 v2]] [k1 (* v1 v2)]) + {:a 1 :b 2 :c 3} + {:a -1 :b 0 :c 2})) {:a -1 :b 0 :c 6}) - (assert-eq (mapv #(* $1 $2 $3) [1] [2] [-1]) [-2]) - (assert-eq (mapv string.upper ["a" "b" "c"]) ["A" "B" "C"]) - (assert-eq (mapv #(+ $1 $2 $3 $4) [1 -1] [2 -2] [3 -3] [4 -4]) [(+ 1 2 3 4) (+ -1 -2 -3 -4)]) - (assert-eq (mapv (fn [f-name s-name company position] - (.. f-name " " s-name " works as " position " at " company)) - ["Bob" "Alice"] - ["Smith" "Watson"] - ["Happy Days co." "Coffee With You"] - ["secretary" "chief officer"]) + (assert-eq (core.mapv #(* $1 $2 $3) [1] [2] [-1]) [-2]) + (assert-eq (core.mapv string.upper ["a" "b" "c"]) ["A" "B" "C"]) + (assert-eq (core.mapv #(+ $1 $2 $3 $4) [1 -1] [2 -2] [3 -3] [4 -4]) [(+ 1 2 3 4) (+ -1 -2 -3 -4)]) + (assert-eq (core.mapv (fn [f-name s-name company position] + (.. f-name " " s-name " works as " position " at " company)) + ["Bob" "Alice"] + ["Smith" "Watson"] + ["Happy Days co." "Coffee With You"] + ["secretary" "chief officer"]) ["Bob Smith works as secretary at Happy Days co." "Alice Watson works as chief officer at Coffee With You"]) - (assert-eq (table.concat (mapv string.upper "vaiv")) "VAIV")) + (assert-eq (table.concat (core.mapv string.upper "vaiv")) "VAIV")) (testing "reduce" (fn* add @@ -282,18 +274,18 @@ (set res (+ res v))) res)) - (assert-eq (reduce add []) 0) - (assert-eq (reduce add [1]) 1) - (assert-eq (reduce add [1 2]) 3) - (assert-eq (reduce add (range 10)) 45) - (assert-eq (reduce add -3 (range 10)) 42) - (assert-eq (reduce add 10 []) 10) - (assert-eq (reduce add 10 [1]) 11) - (assert-eq (reduce add 10 nil) 10) - (assert-not (pcall reduce)) - (assert-not (pcall reduce add))) - - (testing "reduce reference implementation" + (assert-eq (core.reduce add []) 0) + (assert-eq (core.reduce add [1]) 1) + (assert-eq (core.reduce add [1 2]) 3) + (assert-eq (core.reduce add (core.range 10)) 45) + (assert-eq (core.reduce add -3 (core.range 10)) 42) + (assert-eq (core.reduce add 10 []) 10) + (assert-eq (core.reduce add 10 [1]) 11) + (assert-eq (core.reduce add 10 nil) 10) + (assert-not (pcall core.reduce)) + (assert-not (pcall core.reduce add))) + + (testing "core.reduce reference implementation" (fn mapping [f] (fn [reducing] (fn [result input] @@ -302,168 +294,173 @@ (fn -reduce [f init [x & tbl]] (if x (-reduce f (f init x) tbl) init)) - (assert-eq (reduce add (range 10)) (-reduce add 0 (range 10))) - (assert-eq (reduce ((mapping inc) add) 0 (range 10)) - (-reduce ((mapping inc) add) 0 (range 10)))) + (assert-eq (core.reduce core.add (core.range 10)) (-reduce core.add 0 (core.range 10))) + (assert-eq (core.reduce ((mapping core.inc) core.add) 0 (core.range 10)) + (-reduce ((mapping core.inc) core.add) 0 (core.range 10)))) (testing "filter" - (assert-not (pcall filter)) - (assert-not (pcall filter even?)) - (assert-eq (filter even? (range 10)) [0 2 4 6 8]) - (assert-eq (filter odd? (range 10)) [1 3 5 7 9]) - (assert-eq (filter map? [{:a 1} {5 1} [1 2] [] {}]) [{:a 1} {5 1}]) - (assert-eq (filter vector? [{:a 1} {5 1} [1 2] [] {}]) [[1 2]])) + (assert-not (pcall core.filter)) + (assert-not (pcall core.filter core.even?)) + (assert-eq (core.filter core.even? (core.range 10)) [0 2 4 6 8]) + (assert-eq (core.filter core.odd? (core.range 10)) [1 3 5 7 9]) + (assert-eq (core.filter core.map? [{:a 1} {5 1} [1 2] [] {}]) [{:a 1} {5 1}]) + (assert-eq (core.filter core.vector? [{:a 1} {5 1} [1 2] [] {}]) [[1 2]])) (testing "concat" - (assert-eq (concat) nil) - (assert-eq (concat []) []) - (assert-eq (concat [1 2 3]) [1 2 3]) - (assert-eq (concat [1 2 3] [4 5 6]) [1 2 3 4 5 6]) - (assert-eq (concat [1 2] [3 4] [5 6]) [1 2 3 4 5 6]) - (assert-eq (concat {:a 1} {:b 2}) [[:a 1] [:b 2]]) - (assert-eq (concat [[:a 1]] {:b 2}) [[:a 1] [:b 2]]) - (assert-eq (concat {:a 1} [[:b 2]]) [[:a 1] [:b 2]]) - (assert-eq (concat [] [[:b 2]]) [[:b 2]]) - (assert-eq (concat [] []) []) - (assert-not (pcall concat 1)) - (assert-not (pcall concat 1 2)) - (assert-not (pcall concat 1 [])) - (assert-not (pcall concat [] 2)) - (assert-not (pcall concat [1] 2))) + (assert-eq (core.concat) nil) + (assert-eq (core.concat []) []) + (assert-eq (core.concat [1 2 3]) [1 2 3]) + (assert-eq (core.concat [1 2 3] [4 5 6]) [1 2 3 4 5 6]) + (assert-eq (core.concat [1 2] [3 4] [5 6]) [1 2 3 4 5 6]) + (assert-eq (core.concat {:a 1} {:b 2}) [[:a 1] [:b 2]]) + (assert-eq (core.concat [[:a 1]] {:b 2}) [[:a 1] [:b 2]]) + (assert-eq (core.concat {:a 1} [[:b 2]]) [[:a 1] [:b 2]]) + (assert-eq (core.concat [] [[:b 2]]) [[:b 2]]) + (assert-eq (core.concat [] []) []) + (assert-not (pcall core.concat 1)) + (assert-not (pcall core.concat 1 2)) + (assert-not (pcall core.concat 1 [])) + (assert-not (pcall core.concat [] 2)) + (assert-not (pcall core.concat [1] 2))) (testing "reverse" - (assert-not (pcall reverse)) - (assert-not (pcall reverse [] [])) - (assert-eq (reverse []) nil) - (assert-eq (reverse [1 2 3]) [3 2 1]) - (assert-eq (reverse {:a 1}) [[:a 1]])) + (assert-not (pcall core.reverse)) + (assert-not (pcall core.reverse [] [])) + (assert-eq (core.reverse []) nil) + (assert-eq (core.reverse [1 2 3]) [3 2 1]) + (assert-eq (core.reverse {:a 1}) [[:a 1]])) (testing "conj" - (assert-eq (conj) []) - (assert-eq (conj [1]) [1]) - (assert-eq (conj [] 1 2 3) [1 2 3]) - (assert-eq (conj [0] 1 2 3) [0 1 2 3]) - (assert-eq (conj {:a 1} [:b 2]) {:a 1 :b 2}) - (assert-eq (conj {:a 1}) {:a 1}) - (assert-eq (conj [1] 2 3 4 5 6 7) [1 2 3 4 5 6 7])) + (assert-eq (core.conj) []) + (assert-eq (core.conj [1]) [1]) + (assert-eq (core.conj [] 1 2 3) [1 2 3]) + (assert-eq (core.conj [0] 1 2 3) [0 1 2 3]) + (assert-eq (core.conj {:a 1} [:b 2]) {:a 1 :b 2}) + (assert-eq (core.conj {:a 1}) {:a 1}) + (assert-eq (core.conj [1] 2 3 4 5 6 7) [1 2 3 4 5 6 7])) (testing "disj" - (assert-not (pcall disj)) - (assert-not (pcall disj [1])) - (assert-not (pcall disj [1] 1)) - (assert-eq (disj (ordered-set)) (ordered-set)) - (assert-eq (disj (ordered-set 1 3 2 5) 3) (ordered-set 1 2 5)) - (assert-eq (disj (ordered-set 1 3 2 5) 3 1 5) (ordered-set 2))) + (assert-not (pcall core.disj)) + (assert-not (pcall core.disj [1])) + (assert-not (pcall core.disj [1] 1)) + (assert-eq (core.disj (core.ordered-set)) (core.ordered-set)) + (assert-eq (core.disj (core.ordered-set 1 3 2 5) 3) (core.ordered-set 1 2 5)) + (assert-eq (core.disj (core.ordered-set 1 3 2 5) 3 1 5) (core.ordered-set 2))) (testing "cons" - (assert-not (pcall cons)) - (assert-not (pcall cons [] [] [])) - (assert-eq (cons nil [1]) [1]) - (assert-eq (cons 1 []) [1]) - (assert-eq (cons 1 [0]) [1 0])) + (assert-not (pcall core.cons)) + (assert-not (pcall core.cons [] [] [])) + (assert-eq (core.cons nil [1]) [1]) + (assert-eq (core.cons 1 []) [1]) + (assert-eq (core.cons 1 [0]) [1 0])) (testing "first" - (assert-not (pcall first)) - (assert-not (pcall first [] [])) - (assert-eq (first [1 2 3]) 1) - (assert-eq (first {:a 1}) [:a 1]) - (assert-eq (first []) nil)) + (assert-not (pcall core.first)) + (assert-not (pcall core.first [] [])) + (assert-eq (core.first [1 2 3]) 1) + (assert-eq (core.first {:a 1}) [:a 1]) + (assert-eq (core.first []) nil)) (testing "last" - (assert-not (pcall last)) - (assert-not (pcall last [] [])) - (assert-eq (last [1 2 3]) 3) - (assert-eq (last []) nil) - (assert-eq (last nil) nil) - (assert-eq (last {:a 1}) [:a 1])) + (assert-not (pcall core.last)) + (assert-not (pcall core.last [] [])) + (assert-eq (core.last [1 2 3]) 3) + (assert-eq (core.last []) nil) + (assert-eq (core.last nil) nil) + (assert-eq (core.last {:a 1}) [:a 1])) (testing "rest" - (assert-not (pcall rest)) - (assert-not (pcall rest [] [])) - (assert-eq (rest [1 2 3]) [2 3]) - (assert-eq (rest {:a 1}) []) - (assert-eq (rest []) []) - (assert-eq (rest nil) [])) + (assert-not (pcall core.rest)) + (assert-not (pcall core.rest [] [])) + (assert-eq (core.rest [1 2 3]) [2 3]) + (assert-eq (core.rest {:a 1}) []) + (assert-eq (core.rest []) []) + (assert-eq (core.rest nil) [])) (testing "butlast" - (assert-not (pcall butlast)) - (assert-not (pcall butlast [] [])) - (assert-eq (butlast [1 2 3]) [1 2]) - (assert-eq (butlast {:a 1}) nil) - (assert-eq (butlast []) nil) - (assert-eq (butlast nil) nil)) + (assert-not (pcall core.butlast)) + (assert-not (pcall core.butlast [] [])) + (assert-eq (core.butlast [1 2 3]) [1 2]) + (assert-eq (core.butlast {:a 1}) nil) + (assert-eq (core.butlast []) nil) + (assert-eq (core.butlast nil) nil)) (testing "reduce-kv" - (assert-eq (reduce-kv #(+ $1 $3) 0 {:a 1 :b 2 :c 3}) 6) - (assert-eq (reduce-kv #(+ $1 $3) 0 [1 2 3]) 6) - (assert-not (pcall reduce-kv #(+ $1 $3) 0)) - (assert-not (pcall reduce-kv #(+ $1 $3))) - (assert-not (pcall reduce-kv))) + (assert-eq (core.reduce-kv #(+ $1 $3) 0 {:a 1 :b 2 :c 3}) 6) + (assert-eq (core.reduce-kv #(+ $1 $3) 0 [1 2 3]) 6) + (assert-not (pcall core.reduce-kv #(+ $1 $3) 0)) + (assert-not (pcall core.reduce-kv #(+ $1 $3))) + (assert-not (pcall core.reduce-kv))) (testing "reduced" - (assert-not (pcall reduced)) - (assert-not (pcall reduced 1 2 3)) - (assert-eq (reduce #(if (> $1 10) (reduced -1) (+ $1 $2)) [1]) 1) - (assert-eq (reduce #(if (> $1 10) (reduced -1) (+ $1 $2)) [1 2]) 3) - (assert-eq (reduce #(if (> $1 10) (reduced -1) (+ $1 $2)) [1 2 3 4]) 10) - (assert-eq (reduce #(if (> $1 10) (reduced -1) (+ $1 $2)) [1 2 3 4 5]) 15) - (assert-eq (reduce #(if (> $1 10) (reduced -1) (+ $1 $2)) [1 2 3 4 5 6]) -1) - (assert-eq (reduce #(if (> $1 10) (reduced -1) (+ $1 $2)) 10 [1]) 11) - (assert-eq (reduce #(if (> $1 10) (reduced -1) (+ $1 $2)) 10 [1 2]) -1) - (assert-eq (reduce #(if (> $1 10) (reduced -1) (+ $1 $2)) 0 [10 5]) 15) - (assert-eq (reduce #(if (> $1 10) (reduced -1) (+ $1 $2)) 1 [10 7]) -1) - - (assert-eq (reduce-kv (fn [res _ v] (if (> res 10) (reduced -1) (+ res v))) 0 {:a 1 :b 2}) 3) - (assert-eq (reduce-kv (fn [res _ v] (if (> res 10) (reduced -1) (+ res v))) 0 {:a 10 :b 2}) 12) - (assert-eq (reduce-kv (fn [res _ v] (if (> res 10) (reduced -1) (+ res v))) 1 {:a 3 :b 3 :c 3 :d 3}) 13) - (assert-eq (reduce-kv (fn [res _ v] (if (> res 10) (reduced -1) (+ res v))) 2 {:a 3 :b 3 :c 3 :d 3}) -1) - (assert-eq (reduce-kv (fn [res _ v] (if (> res 10) (reduced -1) (+ res v))) 1 [10 12]) -1)) + (assert-not (pcall core.reduced)) + (assert-not (pcall core.reduced 1 2 3)) + (assert-eq (core.reduce #(if (> $1 10) (core.reduced -1) (+ $1 $2)) [1]) 1) + (assert-eq (core.reduce #(if (> $1 10) (core.reduced -1) (+ $1 $2)) [1 2]) 3) + (assert-eq (core.reduce #(if (> $1 10) (core.reduced -1) (+ $1 $2)) [1 2 3 4]) 10) + (assert-eq (core.reduce #(if (> $1 10) (core.reduced -1) (+ $1 $2)) [1 2 3 4 5]) 15) + (assert-eq (core.reduce #(if (> $1 10) (core.reduced -1) (+ $1 $2)) [1 2 3 4 5 6]) -1) + (assert-eq (core.reduce #(if (> $1 10) (core.reduced -1) (+ $1 $2)) 10 [1]) 11) + (assert-eq (core.reduce #(if (> $1 10) (core.reduced -1) (+ $1 $2)) 10 [1 2]) -1) + (assert-eq (core.reduce #(if (> $1 10) (core.reduced -1) (+ $1 $2)) 0 [10 5]) 15) + (assert-eq (core.reduce #(if (> $1 10) (core.reduced -1) (+ $1 $2)) 1 [10 7]) -1) + + (assert-eq (core.reduce-kv (fn [res _ v] (if (> res 10) (core.reduced -1) (+ res v))) 0 {:a 1 :b 2}) 3) + (assert-eq (core.reduce-kv (fn [res _ v] (if (> res 10) (core.reduced -1) (+ res v))) 0 {:a 10 :b 2}) 12) + (assert-eq (core.reduce-kv (fn [res _ v] (if (> res 10) (core.reduced -1) (+ res v))) 1 {:a 3 :b 3 :c 3 :d 3}) 13) + (assert-eq (core.reduce-kv (fn [res _ v] (if (> res 10) (core.reduced -1) (+ res v))) 2 {:a 3 :b 3 :c 3 :d 3}) -1) + (assert-eq (core.reduce-kv (fn [res _ v] (if (> res 10) (core.reduced -1) (+ res v))) 1 [10 12]) -1)) (testing "assoc" - (assert-not (pcall assoc)) - (assert-not (pcall assoc {})) - (assert-eq (assoc {} :a 1) {:a 1}) - (assert-eq (assoc {} :a 1 :b 2 :c 3 :d 4) {:a 1 :b 2 :c 3 :d 4})) + (assert-not (pcall core.assoc)) + (assert-not (pcall core.assoc {})) + (assert-eq (core.assoc {} :a 1) {:a 1}) + (assert-eq (core.assoc {} :a 1 :b 2 :c 3 :d 4) {:a 1 :b 2 :c 3 :d 4})) (testing "dissoc" - (assert-not (pcall dissoc)) - (assert-eq (dissoc {}) {}) - (assert-eq (dissoc {:a 1 :b 2} :b) {:a 1}) - (assert-eq (dissoc {:a 1 :b 2 :c 3} :a :c) {:b 2})) + (assert-not (pcall core.dissoc)) + (assert-eq (core.dissoc {}) {}) + (assert-eq (core.dissoc {:a 1 :b 2} :b) {:a 1}) + (assert-eq (core.dissoc {:a 1 :b 2 :c 3} :a :c) {:b 2})) (testing "find, keys and vals" - (assert-not (pcall keys)) - (assert-not (pcall keys {} {} {})) - (assert-not (pcall vals)) - (assert-not (pcall vals {} {} {})) - (assert-not (pcall find)) - (assert-not (pcall find {} {} {})) - (assert-eq (keys {:a 1 :b 2 :c 3}) (hash-set :a :b :c)) - (assert-eq (vals {:a 1 :b 2 :c 3}) (hash-set 1 2 3)) - (assert-eq (find {:a 1 :b 2 :c 3} :c) [:c 3]) - (assert-eq (find {:a 1 :b 2 :c 3} :d) nil))) + (assert-not (pcall core.keys)) + (assert-not (pcall core.keys {} {} {})) + (assert-not (pcall core.vals)) + (assert-not (pcall core.vals {} {} {})) + (assert-not (pcall core.find)) + (assert-not (pcall core.find {} {} {})) + (assert-eq (core.keys {:a 1}) [:a]) + (assert-eq (core.vals {:a 1}) [1]) + (match (pcall #(assert-eq (core.keys {:a 1 :b 2 :c 3}) (core.hash-set :a :b :c))) + (false msg) (io.stderr:write (.. "WARNING: " msg))) + (match (pcall #(assert-eq (core.vals {:a 1 :b 2 :c 3}) (core.hash-set 1 2 3))) + (false msg) (io.stderr:write (.. "WARNING: " msg))) + (assert-eq (core.find {:a 1 :b 2 :c 3} :c) [:c 3]) + (assert-eq (core.find {:a 1 :b 2 :c 3} :d) nil))) + (deftest function-manipulation (testing "constantly" - (assert-not (pcall constantly)) - (assert-not (pcall constantly nil nil)) - (let [always-nil (constantly nil)] + (assert-not (pcall core.constantly)) + (assert-not (pcall core.constantly nil nil)) + (let [always-nil (core.constantly nil)] (assert-eq (always-nil) nil) (assert-eq (always-nil 1) nil) (assert-eq (always-nil 1 2 3 4 "5") nil)) - (let [always-true (constantly true)] + (let [always-true (core.constantly true)] (assert-is (always-true)) (assert-is (always-true false)))) (testing "complement" - (assert-not (pcall complement)) - (assert-not (pcall complement #nil #nil)) - (assert-is ((complement #(do false)))) - (assert-is ((complement nil?) 10)) - (assert-is ((complement every?) double? [1 2 3 4])) - (assert-is ((complement #(= $1 $2 $3)) 1 1 2 1)) - (assert-is ((complement #(= $1 $2)) 1 2))) + (assert-not (pcall core.complement)) + (assert-not (pcall core.complement #nil #nil)) + (assert-is ((core.complement #(do false)))) + (assert-is ((core.complement core.nil?) 10)) + (assert-is ((core.complement core.every?) core.double? [1 2 3 4])) + (assert-is ((core.complement #(= $1 $2 $3)) 1 1 2 1)) + (assert-is ((core.complement #(= $1 $2)) 1 2))) (testing "apply" (fn* add @@ -471,325 +468,329 @@ ([x y] (+ x y)) ([x y & zs] (add (+ x y) ((or _G.unpack table.unpack) zs)))) - (assert-eq (apply add [1 2 3 4]) 10) - (assert-eq (apply add -1 [1 2 3 4]) 9) - (assert-eq (apply add -2 -1 [1 2 3 4]) 7) - (assert-eq (apply add -3 -2 -1 [1 2 3 4]) 4) - (assert-eq (apply add -4 -3 -2 -1 [1 2 3 4]) 0) - (assert-eq (apply add -5 -4 -3 -2 -1 [1 2 3 4]) -5) - (assert-not (pcall apply)) - (assert-not (pcall apply add))) + (assert-eq (core.apply add [1 2 3 4]) 10) + (assert-eq (core.apply add -1 [1 2 3 4]) 9) + (assert-eq (core.apply add -2 -1 [1 2 3 4]) 7) + (assert-eq (core.apply add -3 -2 -1 [1 2 3 4]) 4) + (assert-eq (core.apply add -4 -3 -2 -1 [1 2 3 4]) 0) + (assert-eq (core.apply add -5 -4 -3 -2 -1 [1 2 3 4]) -5) + (assert-not (pcall core.apply)) + (assert-not (pcall core.apply add))) (testing "comp" - (assert-eq ((comp) 10) 10) - (assert-eq ((comp #10)) 10) + (assert-eq ((core.comp) 10) 10) + (assert-eq ((core.comp #10)) 10) (fn square [x] (* x x)) - (assert-eq (comp square) square) - (assert-eq ((comp square inc) 6) 49) - (assert-eq ((comp #(- $ 7) square inc inc inc inc inc inc inc) 0) 42) + (assert-eq (core.comp square) square) + (assert-eq ((core.comp square core.inc) 6) 49) + (assert-eq ((core.comp #(- $ 7) square core.inc core.inc core.inc core.inc core.inc core.inc core.inc) 0) 42) (fn sum-squares [x y] (+ (* x x) (* y y))) - (assert-eq ((comp square inc sum-squares) 2 3) 196) + (assert-eq ((core.comp square core.inc sum-squares) 2 3) 196) (fn f [a b c] (+ a b c)) - (assert-eq ((comp inc f) 1 2 3) 7) + (assert-eq ((core.comp core.inc f) 1 2 3) 7) (fn g [a b c d] (+ a b c d)) - (assert-eq ((comp inc g) 1 2 3 4) 11) + (assert-eq ((core.comp core.inc g) 1 2 3 4) 11) (fn h [a b c d e f] (+ a b c d e f)) - (assert-eq ((comp inc h) 1 2 3 4 5 6) 22)) + (assert-eq ((core.comp core.inc h) 1 2 3 4 5 6) 22)) (testing "identity" (fn f [] nil) (local a {}) - (assert-not (pcall identity)) - (assert-not (pcall identity 1 2)) - (assert-eq (identity 1) 1) - (assert-eq (identity {:a 1 :b 2}) {:a 1 :b 2}) - (assert-eq (identity [1 2 3]) [1 2 3]) - (assert-eq (identity "abc") "abc") - (assert-eq (identity f) f) - (assert-eq (identity a) a))) + (assert-not (pcall core.identity)) + (assert-not (pcall core.identity 1 2)) + (assert-eq (core.identity 1) 1) + (assert-eq (core.identity {:a 1 :b 2}) {:a 1 :b 2}) + (assert-eq (core.identity [1 2 3]) [1 2 3]) + (assert-eq (core.identity "abc") "abc") + (assert-eq (core.identity f) f) + (assert-eq (core.identity a) a))) (deftest sequence-predicates (testing "some" - (assert-not (pcall some)) - (assert-not (pcall some pos-int?)) - (assert-is (some pos-int? [-1 1.1 2.3 -5.5 42 10 -27])) - (assert-not (some pos-int? {:a 1})) - (assert-is (some pos-int? [{:a 1} "1" -1 1]))) + (assert-not (pcall core.some)) + (assert-not (pcall core.some core.pos-int?)) + (assert-is (core.some core.pos-int? [-1 1.1 2.3 -55 42 10 -27])) + (assert-not (core.some core.pos-int? {:a 1})) + (assert-is (core.some core.pos-int? [{:a 1} "1" -1 1]))) (testing "not-any?" - (assert-not (pcall not-any?)) - (assert-not (pcall not-any? pos-int?)) - (assert-is (not-any? pos-int? [-1 1.1 2.3 -5.5 -42 -10 -27])) - (assert-is (not-any? pos-int? {:a 1})) - (assert-not (not-any? pos-int? [1 2 3 4 5]))) + (assert-not (pcall core.not-any?)) + (assert-not (pcall core.not-any? core.pos-int?)) + (assert-is (core.not-any? core.pos-int? [-1 1.1 2.3 -55 -42 -10 -27])) + (assert-is (core.not-any? core.pos-int? {:a 1})) + (assert-not (core.not-any? core.pos-int? [1 2 3 4 5]))) (testing "every?" - (assert-not (pcall every?)) - (assert-not (pcall every? pos-int?)) - (assert-not (every? pos-int? [-1 1.1 2.3 -5.5 42 10 -27])) - (assert-not (every? pos-int? {:a 1})) - (assert-is (every? pos-int? [1 2 3 4 5]))) + (assert-not (pcall core.every?)) + (assert-not (pcall core.every? core.pos-int?)) + (assert-not (core.every? core.pos-int? [-1 1.1 2.3 -55 42 10 -27])) + (assert-not (core.every? core.pos-int? {:a 1})) + (assert-is (core.every? core.pos-int? [1 2 3 4 5]))) (testing "empty?" - (assert-not (pcall empty?)) - (assert-is (empty? [])) - (assert-is (empty? {})) - (assert-is (empty? "")) - (assert-not (empty? "1")) - (assert-not (empty? [1])) - (assert-not (empty? {:a 1})) - (assert-not (pcall empty? 10))) + (assert-not (pcall core.empty?)) + (assert-is (core.empty? [])) + (assert-is (core.empty? {})) + (assert-is (core.empty? "")) + (assert-not (core.empty? "1")) + (assert-not (core.empty? [1])) + (assert-not (core.empty? {:a 1})) + (assert-not (pcall core.empty? 10))) (testing "not-empty" - (assert-not (pcall not-empty)) - (assert-eq (not-empty []) nil) - (assert-eq (not-empty {}) nil) - (assert-eq (not-empty "") nil) - (assert-eq (not-empty "1") "1") - (assert-eq (not-empty [1]) [1]) - (assert-eq (not-empty {:a 1}) {:a 1}))) + (assert-not (pcall core.not-empty)) + (assert-eq (core.not-empty []) nil) + (assert-eq (core.not-empty {}) nil) + (assert-eq (core.not-empty "") nil) + (assert-eq (core.not-empty "1") "1") + (assert-eq (core.not-empty [1]) [1]) + (assert-eq (core.not-empty {:a 1}) {:a 1}))) (deftest math-functions (testing "inc" - (assert-eq (inc 1) 2) - (assert-eq (inc -1) 0) - (assert-not (pcall inc)) - (assert-not (pcall inc nil))) + (assert-eq (core.inc 1) 2) + (assert-eq (core.inc -1) 0) + (assert-not (pcall core.inc)) + (assert-not (pcall core.inc nil))) (testing "dec" - (assert-eq (dec 1) 0) - (assert-eq (dec -1) -2) - (assert-not (pcall dec)) - (assert-not (pcall dec nil)))) + (assert-eq (core.dec 1) 0) + (assert-eq (core.dec -1) -2) + (assert-not (pcall core.dec)) + (assert-not (pcall core.dec nil)))) (deftest table-access (testing "get" - (assert-eq (get {:key1 10 :key2 20} :key1) 10) - (assert-eq (get {:key1 10 :key2 20} :key1 false) 10) - (assert-eq (get {:key1 10 :key2 20} :key3 false) false) - (assert-eq (get {:key1 10 :key2 20} :key3) nil) - (assert-not (pcall get)) - (assert-not (pcall get {}))) + (assert-eq (core.get {:key1 10 :key2 20} :key1) 10) + (assert-eq (core.get {:key1 10 :key2 20} :key1 false) 10) + (assert-eq (core.get {:key1 10 :key2 20} :key3 false) false) + (assert-eq (core.get {:key1 10 :key2 20} :key3) nil) + (assert-not (pcall core.get)) + (assert-not (pcall core.get {}))) (testing "get-in" (local t {:a {:b {:c 10}}}) - (assert-eq (get-in t [:a]) {:b {:c 10}}) - (assert-eq (get-in t [:a :b]) {:c 10}) - (assert-eq (get-in t [:a :b :c]) 10) - (assert-eq (get-in t [:a :b :c] false) 10) - (assert-eq (get-in t [:a :b :d] false) false) - (assert-eq (get-in t [:a :b :d]) nil) - (assert-eq (get-in t []) t) - (assert-not (pcall get-in)) - (assert-not (pcall get-in {})))) + (assert-eq (core.get-in t [:a]) {:b {:c 10}}) + (assert-eq (core.get-in t [:a :b]) {:c 10}) + (assert-eq (core.get-in t [:a :b :c]) 10) + (assert-eq (core.get-in t [:a :b :c] false) 10) + (assert-eq (core.get-in t [:a :b :d] false) false) + (assert-eq (core.get-in t [:a :b :d]) nil) + (assert-eq (core.get-in t []) t) + (assert-not (pcall core.get-in)) + (assert-not (pcall core.get-in {})))) (deftest methods (testing "methods" - (defmulti f identity) + (defmulti f core.identity) (defmethod f :a [_] :a) (defmethod f :b [_] :b) (defmethod f :c [x] (* x x)) - (assert-eq (methods f) f) - (assert-not (pcall methods)) - (assert-not (pcall methods [])) - (assert-not (pcall methods f f))) + (assert-eq (core.methods f) f) + (assert-not (pcall core.methods)) + (assert-not (pcall core.methods [])) + (assert-not (pcall core.methods f f))) (testing "get-method" - (defmulti f identity) + (defmulti f core.identity) (defmethod f :a [_] :a) (defmethod f :b [_] :b) (defmethod f :c [x] (* x x)) - (assert-eq ((get-method f :a) 10) :a) - (assert-eq ((get-method f :b) 20) :b) - (assert-eq ((get-method f :c) 4) 16) - (assert-not (pcall get-method)) - (assert-not (pcall get-method [])) - (assert-not (pcall get-method [] :a)) - (assert-not (pcall get-method f)) - (assert-not (pcall get-method f :a :b))) + (assert-eq ((core.get-method f :a) 10) :a) + (assert-eq ((core.get-method f :b) 20) :b) + (assert-eq ((core.get-method f :c) 4) 16) + (assert-not (pcall core.get-method)) + (assert-not (pcall core.get-method [])) + (assert-not (pcall core.get-method [] :a)) + (assert-not (pcall core.get-method f)) + (assert-not (pcall core.get-method f :a :b))) (testing "remove-method" - (defmulti f identity) + (defmulti f core.identity) (defmethod f :a [_] :a) (defmethod f :b [_] :b) - (remove-method f :a) - (assert-eq (get-method f :a) nil) + (core.remove-method f :a) + (assert-eq (core.get-method f :a) nil) (defmethod f :default [_] :default) - (assert-eq (get-method f :a) (get-method f :default)) - (assert-not (pcall remove-method)) - (assert-not (pcall remove-method [])) - (assert-not (pcall remove-method [] :a)) - (assert-not (pcall remove-method f)) - (assert-not (pcall remove-method f :a :b))) + (assert-eq (core.get-method f :a) (core.get-method f :default)) + (assert-not (pcall core.remove-method)) + (assert-not (pcall core.remove-method [])) + (assert-not (pcall core.remove-method [] :a)) + (assert-not (pcall core.remove-method f)) + (assert-not (pcall core.remove-method f :a :b))) (testing "remove-all-methods" - (defmulti f identity) + (defmulti f core.identity) (defmethod f :a [_] :a) (defmethod f :b [_] :b) (defmethod f :default [_] :default) - (remove-all-methods f) - (assert-eq (methods f) {}) - (assert-not (pcall remove-all-methods)) - (assert-not (pcall remove-all-methods [])) - (assert-not (pcall remove-all-methods f f)))) + (core.remove-all-methods f) + (assert-eq (core.methods f) {}) + (assert-not (pcall core.remove-all-methods)) + (assert-not (pcall core.remove-all-methods [])) + (assert-not (pcall core.remove-all-methods f f)))) (deftest math-functions - (testing "add" - (assert-eq (add) 0) - (assert-eq (add 1) 1) - (assert-eq (add -1) -1) - (assert-eq (add 1 2) 3) - (assert-eq (add 1 2 3) 6) - (assert-eq (add 1 2 3 4) 10) - (assert-eq (add 1 2 3 4 5) 15)) + (testing "core.add" + (assert-eq (core.add) 0) + (assert-eq (core.add 1) 1) + (assert-eq (core.add -1) -1) + (assert-eq (core.add 1 2) 3) + (assert-eq (core.add 1 2 3) 6) + (assert-eq (core.add 1 2 3 4) 10) + (assert-eq (core.add 1 2 3 4 5) 15)) (testing "sub" - (assert-eq (sub) 0) - (assert-eq (sub 1) -1) - (assert-eq (sub -1) 1) - (assert-eq (sub 1 2) -1) - (assert-eq (sub 1 2 3) -4) - (assert-eq (sub 1 2 3 4) -8) - (assert-eq (sub 1 2 3 4 5) -13)) + (assert-eq (core.sub) 0) + (assert-eq (core.sub 1) -1) + (assert-eq (core.sub -1) 1) + (assert-eq (core.sub 1 2) -1) + (assert-eq (core.sub 1 2 3) -4) + (assert-eq (core.sub 1 2 3 4) -8) + (assert-eq (core.sub 1 2 3 4 5) -13)) (testing "mul" - (assert-eq (mul) 1) - (assert-eq (mul 1) 1) - (assert-eq (mul -1) -1) - (assert-eq (mul 1 2) 2) - (assert-eq (mul 1 2 3) 6) - (assert-eq (mul 1 2 3 4) 24) - (assert-eq (mul 1 2 3 4 5) 120)) + (assert-eq (core.mul) 1) + (assert-eq (core.mul 1) 1) + (assert-eq (core.mul -1) -1) + (assert-eq (core.mul 1 2) 2) + (assert-eq (core.mul 1 2 3) 6) + (assert-eq (core.mul 1 2 3 4) 24) + (assert-eq (core.mul 1 2 3 4 5) 120)) (testing "div" - (assert-not (pcall div)) - (assert-eq (div 1) 1) - (assert-eq (div -1) -1) - (assert-eq (div 1 2) (/ 1 2)) - (assert-eq (div 1 2 3) (/ 1 2 3)) - (assert-eq (div 1 2 3 4) (/ 1 2 3 4)) - (assert-eq (div 1 2 3 4 5) (/ 1 2 3 4 5)))) + (assert-not (pcall core.div)) + (assert-eq (core.div 1) 1) + (assert-eq (core.div -1) -1) + (assert-eq (core.div 1 2) (/ 1 2)) + (assert-eq (core.div 1 2 3) (/ 1 2 3)) + (assert-eq (core.div 1 2 3 4) (/ 1 2 3 4)) + (assert-eq (core.div 1 2 3 4 5) (/ 1 2 3 4 5)))) (deftest comparison-functions (testing "le" - (assert-not (pcall le)) - (assert-is (le 1)) - (assert-is (le 1 2)) - (assert-is (le 1 2 2)) - (assert-is (le 1 2 3 4)) - (assert-not (le 2 1)) - (assert-not (le 2 1 3)) - (assert-not (le 1 2 4 3))) + (assert-not (pcall core.le)) + (assert-is (core.le 1)) + (assert-is (core.le 1 2)) + (assert-is (core.le 1 2 2)) + (assert-is (core.le 1 2 3 4)) + (assert-not (core.le 2 1)) + (assert-not (core.le 2 1 3)) + (assert-not (core.le 1 2 4 3))) (testing "lt" - (assert-not (pcall lt)) - (assert-is (lt 1)) - (assert-is (lt 1 2)) - (assert-is (lt 1 2 3)) - (assert-is (lt 1 2 3 4)) - (assert-not (lt 2 1)) - (assert-not (lt 2 1 3)) - (assert-not (lt 1 2 4 4))) + (assert-not (pcall core.lt)) + (assert-is (core.lt 1)) + (assert-is (core.lt 1 2)) + (assert-is (core.lt 1 2 3)) + (assert-is (core.lt 1 2 3 4)) + (assert-not (core.lt 2 1)) + (assert-not (core.lt 2 1 3)) + (assert-not (core.lt 1 2 4 4))) (testing "ge" - (assert-not (pcall ge)) - (assert-is (ge 2)) - (assert-is (ge 2 1)) - (assert-is (ge 3 3 2)) - (assert-is (ge 4 3 2 -1)) - (assert-not (ge 1 2)) - (assert-not (ge 2 1 3)) - (assert-not (ge 1 2 4 4))) + (assert-not (pcall core.ge)) + (assert-is (core.ge 2)) + (assert-is (core.ge 2 1)) + (assert-is (core.ge 3 3 2)) + (assert-is (core.ge 4 3 2 -1)) + (assert-not (core.ge 1 2)) + (assert-not (core.ge 2 1 3)) + (assert-not (core.ge 1 2 4 4))) (testing "gt" - (assert-not (pcall gt)) - (assert-is (gt 2)) - (assert-is (gt 2 1)) - (assert-is (gt 3 2 1)) - (assert-is (gt 4 3 2 -1)) - (assert-not (gt 1 2)) - (assert-not (gt 2 1 3)) - (assert-not (gt 1 2 4 4)))) + (assert-not (pcall core.gt)) + (assert-is (core.gt 2)) + (assert-is (core.gt 2 1)) + (assert-is (core.gt 3 2 1)) + (assert-is (core.gt 4 3 2 -1)) + (assert-not (core.gt 1 2)) + (assert-not (core.gt 2 1 3)) + (assert-not (core.gt 1 2 4 4)))) (deftest vector (testing "vector" - (assert-eq (vector) []) - (assert-eq (vector 1) [1]) - (assert-eq (vector 1 2 3) [1 2 3]) - (assert-eq (getmetatable (vector 1 2 3)) {:cljlib/type :seq}))) + (assert-eq (core.vector) []) + (assert-eq (core.vector 1) [1]) + (assert-eq (core.vector 1 2 3) [1 2 3]) + (assert-eq (getmetatable (core.vector 1 2 3)) {:cljlib/type :seq}))) (deftest hash-map (testing "hash-map" - (assert-not (pcall hash-map :a)) - (assert-eq (hash-map) {}) - (assert-eq (hash-map :a 1) {:a 1}) - (assert-eq (hash-map :a 1 :b 2 :c 3) {:a 1 :b 2 :c 3}) - (assert-eq (getmetatable (hash-map)) {:cljlib/type :table}))) + (assert-not (pcall core.hash-map :a)) + (assert-eq (core.hash-map) {}) + (assert-eq (core.hash-map :a 1) {:a 1}) + (assert-eq (core.hash-map :a 1 :b 2 :c 3) {:a 1 :b 2 :c 3}) + (assert-eq (getmetatable (core.hash-map)) {:cljlib/type :table}))) (deftest sets (testing "hash-set" - (let [h1 (hash-set [1] [1] [2] [3] [:a]) - h2 (hash-set [1] [2] [3] [:a])] - (assert-is (eq h1 h2))) + (let [h1 (core.hash-set [1] [1] [2] [3] [:a]) + h2 (core.hash-set [1] [2] [3] [:a])] + (assert-is (core.eq h1 h2))) - (let [h3 (hash-set [1] [1] [2] [3] [:a]) - h4 (hash-set [1] [1] [3] [:a])] - (assert-not (eq h3 h4))) + (let [h3 (core.hash-set [1] [1] [2] [3] [:a]) + h4 (core.hash-set [1] [1] [3] [:a])] + (assert-not (core.eq h3 h4))) - (assert-eq (. (hash-set [1]) [1]) [1]) - (assert-eq (. (hash-set [1]) [2]) nil) - (assert-eq ((hash-set [1]) [1]) [1]) - (assert-eq ((hash-set [1]) [2]) nil)) + (assert-eq (. (core.hash-set [1]) [1]) [1]) + (assert-eq (. (core.hash-set [1]) [2]) nil) + (assert-eq ((core.hash-set [1]) [1]) [1]) + (assert-eq ((core.hash-set [1]) [2]) nil)) (testing "ordered-set" - (let [o1 (ordered-set [1] [1] [2] [3] [:a]) - o2 (ordered-set [1] [2] [3] [:a])] + (let [o1 (core.ordered-set [1] [1] [2] [3] [:a]) + o2 (core.ordered-set [1] [2] [3] [:a])] (assert-eq o1 o2)) - (let [o3 (ordered-set [1] [1] [2] [3] [:a]) - o4 (ordered-set [2] [1] [1] [3] [:a])] + (let [o3 (core.ordered-set [1] [1] [2] [3] [:a]) + o4 (core.ordered-set [2] [1] [1] [3] [:a])] (assert-eq o3 o4)) - (assert-eq (. (ordered-set [1]) [1]) [1]) - (assert-eq ((ordered-set [1]) [1]) [1]) - (assert-eq (. (ordered-set [1]) [2]) nil) - (assert-eq ((ordered-set [1]) [2]) nil)) + (assert-eq (. (core.ordered-set [1]) [1]) [1]) + (assert-eq ((core.ordered-set [1]) [1]) [1]) + (assert-eq (. (core.ordered-set [1]) [2]) nil) + (assert-eq ((core.ordered-set [1]) [2]) nil)) (testing "set equality" - (let [o1 (ordered-set [1] [[-1 0] 1] [2] [3] [:a] :a 2) - h1 (hash-set [1] [[-1 0] 1] [2] [3] [:a] :a 2)] + (let [o1 (core.ordered-set [1] [[-1 0] 1] [2] [3] [:a] :a 2) + h1 (core.hash-set [1] [[-1 0] 1] [2] [3] [:a] :a 2)] (assert-eq o1 h1)) - (let [o2 (ordered-set [1] [[-1 0] 1] [2] [3] [:a] :a 2) - h2 (hash-set [1] [[-1 1] 1] [2] [3] [:a] :a 2)] + (let [o2 (core.ordered-set [1] [[-1 0] 1] [2] [3] [:a] :a 2) + h2 (core.hash-set [1] [[-1 1] 1] [2] [3] [:a] :a 2)] (assert-ne o2 h2)) - (let [o3 (ordered-set [1] [[-1 0] 1] [2] [3] [:a] :a 2) - h3 (hash-set [1] [[-1 0] 1] [2] [3] [:a] :a 2)] - (assert-eq (disj o3 [2]) (disj h3 [2])) - (assert-ne (disj o3 :a) h3) - (assert-eq (disj h3 :a) o3)) + (let [o3 (core.ordered-set [1] [[-1 0] 1] [2] [3] [:a] :a 2) + h3 (core.hash-set [1] [[-1 0] 1] [2] [3] [:a] :a 2)] + (assert-eq (core.disj o3 [2]) (core.disj h3 [2])) + (assert-ne (core.disj o3 :a) h3) + (assert-eq (core.disj h3 :a) o3)) - (let [o4 (ordered-set [1] [[-1 5] 1] [3] [:a] :a 2) - h4 (hash-set [1] [[-1 5] 1] [2] [3] [:a] :a 2)] - (assert-eq (conj o4 [2]) (conj (disj h4 [2]) [2])))) + (let [o4 (core.ordered-set [1] [[-1 5] 1] [3] [:a] :a 2) + h4 (core.hash-set [1] [[-1 5] 1] [2] [3] [:a] :a 2)] + (assert-eq (core.conj o4 [2]) (core.conj (core.disj h4 [2]) [2])))) (testing "empty sets" - (assert-eq (empty (ordered-set)) (ordered-set)) - (assert-eq (empty (ordered-set 1 2 3)) (ordered-set)) - (assert-eq (. (getmetatable (empty (ordered-set))) :cljlib/type ) :cljlib/ordered-set) + (assert-eq (empty (core.ordered-set)) (core.ordered-set)) + (assert-eq (empty (core.ordered-set 1 2 3)) (core.ordered-set)) + (assert-eq (. (getmetatable (empty (core.ordered-set))) :cljlib/type ) :cljlib/ordered-set) - (assert-eq (empty (hash-set)) (hash-set)) - (assert-eq (empty (hash-set 1 2 3)) (hash-set)) - (assert-eq (. (getmetatable (empty (hash-set))) :cljlib/type ) :cljlib/hash-set)) + (assert-eq (empty (core.hash-set)) (core.hash-set)) + (assert-eq (empty (core.hash-set 1 2 3)) (core.hash-set)) + (assert-eq (. (getmetatable (empty (core.hash-set))) :cljlib/type ) :cljlib/hash-set)) (testing "into sets" - (assert-eq (into (ordered-set) [1 2 3]) (ordered-set 1 2 3)) - (assert-eq (into (ordered-set) {:a 1 :b 2}) (ordered-set [:a 1] [:b 2])) - (assert-eq (into (ordered-set) "vaiv") (ordered-set "v" "a" "i" "v")) - (assert-eq (into (hash-set) [1 2 3]) (hash-set 1 2 3)) - (assert-eq (into (hash-set) {:a 1 :b 2}) (hash-set [:a 1] [:b 2])) - (assert-eq (into (hash-set) "vaiv") (hash-set "v" "a" "i" "v")))) + (assert-eq (into (core.ordered-set) [1 2 3]) (core.ordered-set 1 2 3)) + (assert-eq (into (core.ordered-set) {:a 1 :b 2}) (core.ordered-set [:a 1] [:b 2])) + (assert-eq (into (core.ordered-set) "vaiv") (core.ordered-set "v" "a" "i" "v")) + (assert-eq (into (core.hash-set) [1 2 3]) (core.hash-set 1 2 3)) + (assert-eq (into (core.hash-set) {:a 1 :b 2}) (core.hash-set [:a 1] [:b 2])) + (assert-eq (into (core.hash-set) "vaiv") (core.hash-set "v" "a" "i" "v"))) + + (testing "sets into tables" + (assert-eq (into [] (core.ordered-set 1 2 3)) [1 2 3]) + (assert-eq (into {} (core.ordered-set [:a 1] [:b 2])) {:a 1 :b 2}))) (deftest memoization (testing "memoize" @@ -801,10 +802,10 @@ (fn slow [x] (for [i 0 1000000] nil) x) - (assert-not (pcall memoize)) - (assert-not (pcall memoize slow 2)) + (assert-not (pcall core.memoize)) + (assert-not (pcall core.memoize slow 2)) - (local fast (memoize slow)) + (local fast (core.memoize slow)) (let [(res1 time1) (time (fast 42)) (res2 time2) (time (fast 42))] @@ -813,5 +814,5 @@ (let [(res1 time1) (time (fast [10])) (res2 time2) (time (fast [10]))] - (assert-is (and (eq res1 res2 [10]))) + (assert-is (and (core.eq res1 res2 [10]))) (assert-is (< time2 time1))))) diff --git a/tests/fn.fnl b/tests/fn.fnl index 4381a60..63a5802 100644 --- a/tests/fn.fnl +++ b/tests/fn.fnl @@ -1,5 +1,5 @@ (require-macros :tests.test) -(require-macros :cljlib-macros) +(require-macros :macros) (deftest fn* (testing "fn* meta" @@ -7,7 +7,12 @@ "docstring" [x] x) (assert-eq (meta f) (when-meta {:fnl/docstring "docstring" - :fnl/arglist ["[x]"]})) + :fnl/arglist ["([x])"]})) + (fn* f + "docstring" + []) + (assert-eq (meta f) (when-meta {:fnl/docstring "docstring" + :fnl/arglist ["([])"]})) (fn* f "docstring" @@ -20,8 +25,16 @@ ([x] x) ([x y] (+ x y))) (assert-eq (meta f) (when-meta {:fnl/docstring "docstring" - :fnl/arglist ["\n ([x])" - "\n ([x y])"]})) + :fnl/arglist ["([x])" + "([x y])"]})) + + (fn* f + "docstring" + ([]) + ([x y] (+ x y))) + (assert-eq (meta f) (when-meta {:fnl/docstring "docstring" + :fnl/arglist ["([])" + "([x y])"]})) (fn* f "docstring" @@ -29,6 +42,6 @@ ([x y] (+ x y)) ([x y & z] (+ x y))) (assert-eq (meta f) (when-meta {:fnl/docstring "docstring" - :fnl/arglist ["\n ([x])" - "\n ([x y])" - "\n ([x y & z])"]})))) + :fnl/arglist ["([x])" + "([x y])" + "([x y & z])"]})))) diff --git a/tests/macros.fnl b/tests/macros.fnl index e387eb2..c3b54c9 100644 --- a/tests/macros.fnl +++ b/tests/macros.fnl @@ -1,5 +1,5 @@ (require-macros :tests.test) -(require-macros :cljlib-macros) +(require-macros :macros) (deftest into (testing "into" @@ -55,9 +55,9 @@ (let [a {} b []] (assert-eq (into a "vaiv") ["v" "a" "i" "v"]) - (assert-eq (into b "ваыв") ["в" "а" "ы" "в"])) + (when _G.utf8 (assert-eq (into b "ваыв") ["в" "а" "ы" "в"]))) (assert-eq (into [] "vaiv") ["v" "a" "i" "v"]) - (assert-eq (into [] "ваыв") ["в" "а" "ы" "в"]))) + (when _G.utf8 (assert-eq (into [] "ваыв") ["в" "а" "ы" "в"])))) (deftest let-variants (testing "when-let" @@ -89,7 +89,7 @@ (defmulti fac (fn [x] x)) (defmethod fac 0 [_] 1) (defmethod fac :default [x] (* x (fac (- x 1)))) - (assert-eq (fac 42) 7538058755741581312)) + (assert-eq (fac 4) 24)) (testing "defmulti keys" (defmulti send-data (fn [protocol data] protocol)) @@ -212,13 +212,13 @@ (assert-eq (try (+ 1 2 3 nil) (catch _) (finally 10)) nil)) (testing "catch-all" (assert-eq (try - (error 10) - (catch _ :pass)) - :pass) + (error "10") + (catch _ :pass)) + :pass) (assert-eq (try - (error 10) - (catch err err)) - 10)) + (error [10]) + (catch err err)) + [10])) (testing "finally" (let [tbl []] (try diff --git a/tests/test.fnl b/tests/test.fnl index f3db701..143b749 100644 --- a/tests/test.fnl +++ b/tests/test.fnl @@ -14,12 +14,12 @@ the tables uses tables as keys." ;; (eq {[1 2 3] {:a [1 2 3]}} {[1 2 3] {:a [1 2 3]}}) ;; we have to do even deeper search (setmetatable right# {:__index (fn [tbl# key#] - (var res# nil) - (each [k# v# (pairs tbl#)] - (when (eq# k# key#) - (set res# v#) - (lua :break))) - res#)}) + (var res# nil) + (each [k# v# (pairs tbl#)] + (when (eq# k# key#) + (set res# v#) + (lua :break))) + res#)}) (var [res# count-a# count-b#] [true 0 0]) (each [k# v# (pairs left#)] (set res# (eq# v# (. right# k#))) @@ -62,26 +62,26 @@ runtime error: equality assertion failed ```" `(let [left# ,expr1 right# ,expr2 - (res# view#) (pcall require :fennelview) eq# ,(eq-fn) - tostr# (if res# view# tostring)] + fennel# (require :fennel)] (assert (eq# left# right#) - (or ,msg (.. "equality assertion failed - Left: " (tostr# left#) " - Right: " (tostr# right#) "\n"))))) + (or ,msg (.. "assertion failed for expression: +(= " ,(view expr1 {:one-line? true}) " " ,(view expr2 {:one-line? true}) " + Left: " (fennel#.view left# {:one-line? true}) " + Right: " (fennel#.view right# {:one-line? true}) "\n"))))) (fn test.assert-ne [expr1 expr2 msg] "Assert for unequality. Same as [`assert-eq`](#assert-eq)." `(let [left# ,expr1 right# ,expr2 - (res# view#) (pcall require :fennelview) eq# ,(eq-fn) - tostr# (if res# view# tostring)] + fennel# (require :fennel)] (assert (not (eq# left# right#)) - (or ,msg (.. "unequality assertion failed - Left: " (tostr# left#) " - Right: " (tostr# right#) "\n"))))) + (or ,msg (.. "assertion failed for expression: +(not= " ,(view expr1 {:one-line? true}) " " ,(view expr2 {:one-line? true}) " + Left: " (fennel#.view left# {:one-line? true}) " + Right: " (fennel#.view right# {:one-line? true}) "\n"))))) (fn test.assert-is [expr msg] @@ -92,13 +92,15 @@ runtime error: equality assertion failed >> (assert-is (= 1 2 3)) runtime error: assertion failed for (= 1 2 3) ```" - `(assert ,expr (.. "assertion failed for " - (or ,msg ,(tostring expr))))) + `(assert ,expr + (.. "assertion failed for " + (or ,msg ,(view expr {:one-line? true}))))) (fn test.assert-not [expr msg] "Assert for not truth. Works the same as [`assert-is`](#assert-is)." - `(assert (not ,expr) (.. "assertion failed for " - (or ,msg ,(tostring expr))))) + `(assert (not ,expr) + (.. "assertion failed for " + (or ,msg ,(view expr {:one-line? true}))))) (fn test.deftest [name ...] @@ -108,7 +110,7 @@ runtime error: assertion failed for (= 1 2 3) (fn test.testing [description ...] "Print test description and run it." - `(do (io.stderr:write (.. "testing: " ,description "\n")) + `(do (io.stdout:write (.. "testing: " ,description "\n")) ,...)) (doto test |