├── .circleci
└── config.yml
├── .gitattributes
├── .gitignore
├── DEVELOPER.md
├── LIBRARIES.md
├── LICENSE
├── README.md
├── all-tests.sh
├── build-all.sh
├── build-arm.sh
├── build.sh
├── core
├── array_map.go
├── array_vector.go
├── buffer.go
├── buffered_reader.go
├── channel.go
├── code.go
├── common.go
├── data.go
├── data
│ ├── better_cond.joke
│ ├── core.joke
│ ├── hiccup.joke
│ ├── linter_all.joke
│ ├── linter_clj.joke
│ ├── linter_cljs.joke
│ ├── linter_cljx.joke
│ ├── linter_joker.joke
│ ├── pprint.joke
│ ├── repl.joke
│ ├── set.joke
│ ├── template.joke
│ ├── test.joke
│ ├── tools_cli.joke
│ └── walk.joke
├── deps.go
├── environment.go
├── environment_fast_init.go
├── environment_slow_init.go
├── eval.go
├── expr.go
├── file.go
├── format.go
├── gen
│ └── gen_types.go
├── gen_code
│ └── gen_code.go
├── gen_go
│ ├── gen_go.go
│ ├── sorter.go
│ └── unsafe_stuff.go
├── hash_map.go
├── intern.go
├── intern_slow_init.go
├── io_reader.go
├── io_writer.go
├── line_runereader.go
├── list.go
├── map.go
├── ns.go
├── numbers.go
├── object.go
├── object_slow_init.go
├── pack.go
├── parse.go
├── parse_slow_init.go
├── procs.go
├── procs_slow_init.go
├── read.go
├── reader.go
├── rune_window.go
├── seq.go
├── set.go
├── spew_disabled.go
├── spew_enabled.go
├── stringable.go
├── types_assert_gen.go
├── types_info_gen.go
└── vector.go
├── docs
├── dash.sh
├── dash
│ └── dashing.json
├── generate-docs.joke
├── generate-xml.joke
├── index.html
├── joker.base64.html
├── joker.better-cond.html
├── joker.bolt.html
├── joker.core.html
├── joker.crypto.html
├── joker.csv.html
├── joker.filepath.html
├── joker.git.html
├── joker.hex.html
├── joker.hiccup.html
├── joker.html.html
├── joker.http.html
├── joker.io.html
├── joker.json.html
├── joker.markdown.html
├── joker.math.html
├── joker.os.html
├── joker.pprint.html
├── joker.repl.html
├── joker.runtime.html
├── joker.set.html
├── joker.strconv.html
├── joker.string.html
├── joker.template.html
├── joker.test.html
├── joker.tgz
├── joker.time.html
├── joker.tools.cli.html
├── joker.url.html
├── joker.uuid.html
├── joker.walk.html
├── joker.xml
├── joker.yaml.html
├── joker32.png
├── main.css
├── main.js
├── misc
│ ├── bigfloat.md
│ └── lib-loader.md
└── templates
│ ├── index.html
│ ├── link-item.html
│ ├── main.js
│ ├── ns-summary.html
│ ├── ns.html
│ ├── special-form.html
│ ├── type-summary.html
│ ├── usage-with-types.html
│ ├── usage.html
│ ├── var.html
│ └── xml.html
├── epl-v10.html
├── eval-tests.sh
├── exiters.go
├── exiters_plan9.go
├── exiters_windows.go
├── flag-tests.sh
├── formatter-tests.sh
├── go.mod
├── go.sum
├── linter-tests.sh
├── main.go
├── release.joke
├── repl.go
├── repl_plan9.go
├── run.sh
├── shadow.sh
├── std
├── addmeta.tmpl
├── arity.tmpl
├── base64.joke
├── base64
│ ├── a_base64.go
│ ├── a_base64_slow_init.go
│ └── base64_native.go
├── bolt.joke
├── bolt
│ ├── a_bolt.go
│ ├── a_bolt_slow_init.go
│ └── bolt_native.go
├── crypto.joke
├── crypto
│ ├── a_crypto.go
│ ├── a_crypto_slow_init.go
│ └── crypto_native.go
├── csv.joke
├── csv
│ ├── a_csv.go
│ ├── a_csv_slow_init.go
│ └── csv_native.go
├── filepath.joke
├── filepath
│ ├── a_filepath.go
│ ├── a_filepath_slow_init.go
│ └── filepath_native.go
├── fn.tmpl
├── generate-std.joke
├── git.joke
├── git
│ ├── a_git.go
│ ├── a_git_slow_init.go
│ └── git_native.go
├── hex.joke
├── hex
│ ├── a_hex.go
│ └── a_hex_slow_init.go
├── html.joke
├── html
│ ├── a_html.go
│ ├── a_html_fast_init.go
│ └── a_html_slow_init.go
├── http.joke
├── http
│ ├── a_http.go
│ ├── a_http_slow_init.go
│ └── http_native.go
├── intern.tmpl
├── io.joke
├── io
│ ├── a_io.go
│ ├── a_io_slow_init.go
│ └── io_native.go
├── json.joke
├── json
│ ├── a_json.go
│ ├── a_json_slow_init.go
│ └── json_native.go
├── markdown.joke
├── markdown
│ ├── a_markdown.go
│ ├── a_markdown_slow_init.go
│ └── markdown_native.go
├── math.joke
├── math
│ ├── a_math.go
│ ├── a_math_slow_init.go
│ └── math_native.go
├── os.joke
├── os
│ ├── a_os.go
│ ├── a_os_slow_init.go
│ ├── os_native.go
│ ├── sh.go
│ └── sh_plan9.go
├── package-fast.tmpl
├── package-slow.tmpl
├── package.tmpl
├── runtime.joke
├── runtime
│ ├── a_runtime.go
│ └── a_runtime_slow_init.go
├── strconv.joke
├── strconv
│ ├── a_strconv.go
│ └── a_strconv_slow_init.go
├── string.joke
├── string
│ ├── a_string.go
│ ├── a_string_fast_init.go
│ ├── a_string_slow_init.go
│ └── string_native.go
├── time.joke
├── time
│ ├── a_time.go
│ ├── a_time_slow_init.go
│ └── time_native.go
├── url.joke
├── url
│ ├── a_url.go
│ ├── a_url_slow_init.go
│ └── url_native.go
├── uuid.joke
├── uuid
│ ├── a_uuid.go
│ ├── a_uuid_slow_init.go
│ └── uuid_native.go
├── yaml.joke
└── yaml
│ ├── a_yaml.go
│ ├── a_yaml_slow_init.go
│ └── yaml_native.go
├── test-format.sh
├── test-linter.sh
├── tests
├── 1.clj
├── eval
│ ├── atoms.joke
│ ├── better-cond-test.joke
│ ├── bolt.joke
│ ├── classpath
│ │ ├── a
│ │ │ └── b
│ │ │ │ └── c.joke
│ │ ├── b
│ │ │ └── c.joke
│ │ ├── d
│ │ │ └── e
│ │ │ │ └── f.joke
│ │ ├── g
│ │ │ └── h
│ │ │ │ └── i.joke
│ │ ├── input.joke
│ │ ├── stdout.txt
│ │ └── x
│ │ │ └── y
│ │ │ ├── q
│ │ │ └── r
│ │ │ │ └── s.joke
│ │ │ └── z.joke
│ ├── clojure_walk.joke
│ ├── control.joke
│ ├── core.joke
│ ├── corelibs
│ │ ├── input.joke
│ │ └── stdout.txt
│ ├── crypto-test.joke
│ ├── csv.joke
│ ├── deps-test.joke
│ ├── deps.joke
│ ├── format.joke
│ ├── hash.joke
│ ├── hiccup.joke
│ ├── json.joke
│ ├── large-forked-stdout
│ │ ├── input.joke
│ │ ├── lots-of-stderr.joke
│ │ ├── stderr.txt
│ │ └── stdout.txt
│ ├── load-file
│ │ ├── input.joke
│ │ ├── parse-error.joke
│ │ └── stdout.txt
│ ├── macro-test.joke
│ ├── map-test.joke
│ ├── markdown.joke
│ ├── math.joke
│ ├── multi-methods
│ │ ├── input.joke
│ │ └── stdout.txt
│ ├── multimethods.joke
│ ├── numbers.joke
│ ├── os.joke
│ ├── printer.joke
│ ├── read-line
│ │ ├── input.joke
│ │ ├── lines.txt
│ │ ├── stdin.txt
│ │ └── stdout.txt
│ ├── reader-conditionals.joke
│ ├── reader.joke
│ ├── stdin-pipe
│ │ ├── input.joke
│ │ ├── stdin.txt
│ │ └── stdout.txt
│ ├── string.joke
│ ├── tools_cli.joke
│ ├── types.joke
│ └── url-test.joke
├── flags
│ ├── config
│ │ └── .joker
│ ├── input-warning.clj
│ ├── input.clj
│ ├── input.cljs
│ ├── input.edn
│ ├── input.joke
│ ├── macro.clj
│ └── script-flags.joke
├── formatter
│ └── main
│ │ ├── input.clj
│ │ └── output.clj
├── lib
│ └── test-local
│ │ └── lib.joke
├── lib1.joke
├── lib2.joke
├── lib3.joke
├── linter
│ ├── anonymous-fn
│ │ ├── input.clj
│ │ └── output.txt
│ ├── case
│ │ ├── input.clj
│ │ └── output.txt
│ ├── classnames
│ │ ├── input.clj
│ │ └── output.txt
│ ├── cljs-interop
│ │ ├── input.cljs
│ │ └── output.txt
│ ├── cond
│ │ ├── input.clj
│ │ └── output.txt
│ ├── conditionals-clj-1
│ │ ├── input.clj
│ │ └── output.txt
│ ├── conditionals-clj-2
│ │ ├── input.clj
│ │ └── output.txt
│ ├── conditionals-clj-3
│ │ ├── input.clj
│ │ └── output.txt
│ ├── conditionals-cljs
│ │ ├── input.cljs
│ │ └── output.txt
│ ├── condp
│ │ ├── input.clj
│ │ └── output.txt
│ ├── constr-call-cljs
│ │ ├── input.cljs
│ │ └── output.txt
│ ├── def
│ │ ├── input.clj
│ │ └── output.txt
│ ├── defmethod
│ │ ├── input.clj
│ │ └── output.txt
│ ├── defn-0
│ │ ├── input.clj
│ │ └── output.txt
│ ├── defn-1
│ │ ├── input.clj
│ │ └── output.txt
│ ├── defn-2
│ │ ├── input.clj
│ │ └── output.txt
│ ├── defn-3
│ │ ├── input.clj
│ │ └── output.txt
│ ├── defprotocol
│ │ ├── .joker
│ │ ├── input.clj
│ │ └── output.txt
│ ├── defrecord
│ │ ├── input.clj
│ │ └── output.txt
│ ├── deftest
│ │ ├── input.clj
│ │ └── output.txt
│ ├── do
│ │ ├── input.clj
│ │ └── output.txt
│ ├── doseq
│ │ ├── input.clj
│ │ └── output.txt
│ ├── duplicate-def
│ │ ├── input.clj
│ │ └── output.txt
│ ├── exclude-list
│ │ ├── input.clj
│ │ └── output.txt
│ ├── extend-protocol
│ │ ├── input.clj
│ │ └── output.txt
│ ├── extend-type-cljs
│ │ ├── input.cljs
│ │ └── output.txt
│ ├── extend-type
│ │ ├── input.clj
│ │ └── output.txt
│ ├── fn-0
│ │ ├── input.clj
│ │ └── output.txt
│ ├── fn-1
│ │ ├── input.clj
│ │ └── output.txt
│ ├── fn-2
│ │ ├── input.clj
│ │ └── output.txt
│ ├── fn-3
│ │ ├── input.clj
│ │ └── output.txt
│ ├── fn-unused-parameters
│ │ ├── .joker
│ │ ├── input.clj
│ │ └── output.txt
│ ├── fn-with-empty-body
│ │ ├── input.clj
│ │ └── output.txt
│ ├── for-1
│ │ ├── input.clj
│ │ └── output.txt
│ ├── for-2
│ │ ├── input.clj
│ │ └── output.txt
│ ├── for-3
│ │ ├── input.clj
│ │ └── output.txt
│ ├── function-call-cljs
│ │ ├── input.cljs
│ │ └── output.txt
│ ├── function-call
│ │ ├── input.clj
│ │ └── output.txt
│ ├── if-let-1
│ │ ├── input.clj
│ │ └── output.txt
│ ├── if-let-2
│ │ ├── input.clj
│ │ └── output.txt
│ ├── if-let-3
│ │ ├── input.clj
│ │ └── output.txt
│ ├── if
│ │ ├── .joker
│ │ ├── input.clj
│ │ └── output.txt
│ ├── inline-def
│ │ ├── input.clj
│ │ └── output.txt
│ ├── learned-macros
│ │ ├── .jokerd
│ │ │ └── linter.clj
│ │ ├── input.clj
│ │ └── output.txt
│ ├── let-1
│ │ ├── input.clj
│ │ └── output.txt
│ ├── let
│ │ ├── input.clj
│ │ └── output.txt
│ ├── letfn
│ │ ├── input.clj
│ │ └── output.txt
│ ├── linter-files
│ │ ├── .joker
│ │ ├── .jokerd
│ │ │ └── linter.clj
│ │ ├── input.clj
│ │ └── output.txt
│ ├── macro-call-1
│ │ ├── input.clj
│ │ └── output.txt
│ ├── macro-call
│ │ ├── input.clj
│ │ └── output.txt
│ ├── merge
│ │ ├── input.clj
│ │ └── output.txt
│ ├── namespaced-maps
│ │ ├── input.clj
│ │ └── output.txt
│ ├── ns-1
│ │ ├── input.clj
│ │ └── output.txt
│ ├── ns-10
│ │ ├── input.clj
│ │ └── output.txt
│ ├── ns-2
│ │ ├── input.clj
│ │ └── output.txt
│ ├── ns-3
│ │ ├── input.clj
│ │ └── output.txt
│ ├── ns-4
│ │ ├── input.clj
│ │ └── output.txt
│ ├── ns-5
│ │ ├── input.clj
│ │ └── output.txt
│ ├── ns-6
│ │ ├── input.clj
│ │ └── output.txt
│ ├── ns-7
│ │ ├── input.clj
│ │ └── output.txt
│ ├── ns-8
│ │ ├── input.clj
│ │ └── output.txt
│ ├── ns-9
│ │ ├── input.clj
│ │ └── output.txt
│ ├── ns-cljs-1
│ │ ├── input.cljs
│ │ └── output.txt
│ ├── ns-cljs-2
│ │ ├── .joker
│ │ ├── input.cljs
│ │ └── output.txt
│ ├── ns-cljs-3
│ │ ├── input.cljs
│ │ └── output.txt
│ ├── ns-cljs-4
│ │ ├── input.cljs
│ │ └── output.txt
│ ├── ns-cljs-5
│ │ ├── input.cljs
│ │ └── output.txt
│ ├── proxy
│ │ ├── input.clj
│ │ └── output.txt
│ ├── reader
│ │ ├── input.clj
│ │ └── output.txt
│ ├── recur
│ │ ├── input.clj
│ │ └── output.txt
│ ├── redundant-do
│ │ ├── input.clj
│ │ └── output.txt
│ ├── regex
│ │ ├── input.clj
│ │ └── output.txt
│ ├── reify
│ │ ├── input.clj
│ │ └── output.txt
│ ├── symbol-resolution-1
│ │ ├── .joker
│ │ ├── input.clj
│ │ └── output.txt
│ ├── symbol-resolution-2
│ │ ├── input.clj
│ │ └── output.txt
│ ├── symbol-resolution-cljs
│ │ ├── input.cljs
│ │ └── output.txt
│ ├── symbol-resolution
│ │ ├── input.clj
│ │ └── output.txt
│ ├── tagged-literals
│ │ ├── .joker
│ │ ├── input.clj
│ │ └── output.txt
│ ├── threading-macros-1
│ │ ├── .joker
│ │ ├── input.clj
│ │ └── output.txt
│ ├── threading-macros
│ │ ├── input.clj
│ │ └── output.txt
│ ├── try
│ │ ├── input.clj
│ │ └── output.txt
│ ├── types-1
│ │ ├── input.clj
│ │ └── output.txt
│ ├── types-2
│ │ ├── input.clj
│ │ └── output.txt
│ ├── types-3
│ │ ├── input.clj
│ │ └── output.txt
│ ├── types-4
│ │ ├── input.clj
│ │ └── output.txt
│ ├── types-cljs
│ │ ├── input.cljs
│ │ └── output.txt
│ ├── unused-as
│ │ ├── .joker
│ │ ├── input.clj
│ │ └── output.txt
│ ├── unused-bindings
│ │ ├── input.clj
│ │ └── output.txt
│ ├── unused-keys
│ │ ├── .joker
│ │ ├── input.clj
│ │ └── output.txt
│ ├── unused-ns
│ │ ├── .joker
│ │ ├── input.clj
│ │ └── output.txt
│ ├── unused-vars-1
│ │ ├── input.clj
│ │ └── output.txt
│ ├── unused-vars
│ │ ├── input.clj
│ │ └── output.txt
│ ├── valid-indent
│ │ ├── input.clj
│ │ └── output.txt
│ └── when
│ │ ├── input.clj
│ │ └── output.txt
├── main.clj
├── run-eval-tests.joke
├── run-flag-tests.joke
├── run-tests.joke
└── test-helper.joke
└── tools
├── cljs-macros.joke
├── gen-defns.clj
├── gen-defns.cljs
└── sum256dir
├── .gitignore
└── main.go
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | jobs:
3 | build:
4 | docker:
5 | - image: cimg/go:1.23
6 | working_directory: /home/circleci/go/src/github.com/candid82/joker
7 | steps:
8 | - checkout
9 | - run:
10 | name: go get liner
11 | command: go get -d -v github.com/candid82/liner
12 | - run:
13 | name: go get profile
14 | command: go get -d -v github.com/pkg/profile
15 | - run:
16 | name: go get yaml
17 | command: go get -d -v gopkg.in/yaml.v2
18 | - run:
19 | name: go generate
20 | command: go generate -v ./...
21 | - run:
22 | name: go build
23 | command: go build -v github.com/candid82/joker
24 | - run:
25 | name: linter tests
26 | command: ./linter-tests.sh
27 | - run:
28 | name: flag tests
29 | command: ./flag-tests.sh
30 | - run:
31 | name: eval tests
32 | command: ./eval-tests.sh
33 | - run:
34 | name: formatter tests
35 | command: ./formatter-tests.sh
36 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Set the default behavior.
2 | * text eol=lf
3 |
4 | # DOS line endings on .bat files.
5 | *.bat text=auto
6 |
7 | *.tgz binary
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | joker
2 | .vscode
3 | .idea
4 | core/a_*.go
5 | *.exe
6 | *~
7 | *.zip
8 | *.docset
9 | .DS_Store
10 | docs/dash/*.html
11 | docs/dash/*.css
12 | docs/dash/*.js
13 |
--------------------------------------------------------------------------------
/all-tests.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | fail=0
4 |
5 | for test_script in *-tests.sh
6 | do
7 | if [ $test_script != "all-tests.sh" ]; then
8 | echo >&2 "RUNNING $test_script"
9 | ./$test_script
10 | if [[ $? != 0 ]]; then
11 | echo ${test_script//.sh/} failed.
12 | fail=1
13 | fi
14 | fi
15 | done
16 |
17 | if [[ $fail == 0 ]]; then
18 | echo >&2 "All tests passed."
19 | fi
20 |
21 | exit $fail
22 |
--------------------------------------------------------------------------------
/build-all.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -eu
3 |
4 | export GOARCH=amd64
5 | export GOOS=
6 |
7 | for GOOS in darwin linux windows freebsd netbsd openbsd; do
8 | if ! go build; then
9 | echo \
10 | error: \
11 | "building for GOARCH=$GOARCH GOOS=$GOOS failed" \
12 | >/dev/stderr \
13 | ;
14 | continue
15 | fi
16 |
17 | case "$GOOS" in
18 | darwin) os=mac ;;
19 | windows) os=win ;;
20 | *) os=$GOOS ;;
21 | esac
22 | [[ $GOOS = windows ]] && executable=joker.exe || executable=joker
23 |
24 | zip -9 joker-"$os"-"$GOARCH".zip "$executable"
25 | done
26 |
--------------------------------------------------------------------------------
/build-arm.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | GOOS=linux GOARCH=386 go generate ./...
4 | GOOS=linux GOARCH=arm go build
5 |
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | go generate ./... && go vet ./... && go build
4 |
--------------------------------------------------------------------------------
/core/buffer.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "bytes"
5 | "unsafe"
6 | )
7 |
8 | type (
9 | Buffer struct {
10 | *bytes.Buffer
11 | hash uint32
12 | }
13 | )
14 |
15 | func MakeBuffer(b *bytes.Buffer) *Buffer {
16 | res := &Buffer{b, 0}
17 | res.hash = HashPtr(uintptr(unsafe.Pointer(res)))
18 | return res
19 | }
20 |
21 | func (b *Buffer) ToString(escape bool) string {
22 | return b.String()
23 | }
24 |
25 | func (b *Buffer) Equals(other interface{}) bool {
26 | return b == other
27 | }
28 |
29 | func (b *Buffer) GetInfo() *ObjectInfo {
30 | return nil
31 | }
32 |
33 | func (b *Buffer) GetType() *Type {
34 | return TYPE.Buffer
35 | }
36 |
37 | func (b *Buffer) Hash() uint32 {
38 | return b.hash
39 | }
40 |
41 | func (b *Buffer) WithInfo(info *ObjectInfo) Object {
42 | return b
43 | }
44 |
--------------------------------------------------------------------------------
/core/buffered_reader.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "bufio"
5 | "io"
6 | "unsafe"
7 | )
8 |
9 | type (
10 | BufferedReader struct {
11 | *bufio.Reader
12 | hash uint32
13 | }
14 | )
15 |
16 | func MakeBufferedReader(rd io.Reader) *BufferedReader {
17 | res := &BufferedReader{bufio.NewReader(rd), 0}
18 | res.hash = HashPtr(uintptr(unsafe.Pointer(res)))
19 | return res
20 | }
21 |
22 | func (br *BufferedReader) ToString(escape bool) string {
23 | return "#object[BufferedReader]"
24 | }
25 |
26 | func (br *BufferedReader) Equals(other interface{}) bool {
27 | return br == other
28 | }
29 |
30 | func (br *BufferedReader) GetInfo() *ObjectInfo {
31 | return nil
32 | }
33 |
34 | func (br *BufferedReader) GetType() *Type {
35 | return TYPE.BufferedReader
36 | }
37 |
38 | func (br *BufferedReader) Hash() uint32 {
39 | return br.hash
40 | }
41 |
42 | func (br *BufferedReader) WithInfo(info *ObjectInfo) Object {
43 | return br
44 | }
45 |
--------------------------------------------------------------------------------
/core/channel.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "unsafe"
5 | )
6 |
7 | type (
8 | FutureResult struct {
9 | value Object
10 | err Error
11 | }
12 | Channel struct {
13 | ch chan FutureResult
14 | isClosed bool
15 | hash uint32
16 | }
17 | )
18 |
19 | func MakeFutureResult(value Object, err Error) FutureResult {
20 | return FutureResult{value: value, err: err}
21 | }
22 |
23 | func (ch *Channel) ToString(escape bool) string {
24 | return "#object[Channel]"
25 | }
26 |
27 | func (ch *Channel) Equals(other interface{}) bool {
28 | return ch == other
29 | }
30 |
31 | func (ch *Channel) GetInfo() *ObjectInfo {
32 | return nil
33 | }
34 |
35 | func (ch *Channel) GetType() *Type {
36 | return TYPE.Channel
37 | }
38 |
39 | func (ch *Channel) Hash() uint32 {
40 | return ch.hash
41 | }
42 |
43 | func (ch *Channel) WithInfo(info *ObjectInfo) Object {
44 | return ch
45 | }
46 |
47 | func MakeChannel(ch chan FutureResult) *Channel {
48 | res := &Channel{ch: ch, hash: 0}
49 | res.hash = HashPtr(uintptr(unsafe.Pointer(res)))
50 | return res
51 | }
52 |
53 | func ExtractChannel(args []Object, index int) *Channel {
54 | return EnsureArgIsChannel(args, index)
55 | }
56 |
57 | func (ch *Channel) Close() {
58 | if !ch.isClosed {
59 | close(ch.ch)
60 | ch.isClosed = true
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/core/data.go:
--------------------------------------------------------------------------------
1 | //go:build !gen_code
2 | // +build !gen_code
3 |
4 | package core
5 |
6 | var haveSetCoreNamespaces bool
7 |
8 | func ProcessCoreData() {
9 | // Let MaybeLazy() handle initialization.
10 | if !haveSetCoreNamespaces {
11 | setCoreNamespaces()
12 | haveSetCoreNamespaces = true
13 | }
14 | }
15 |
16 | func ProcessReplData() {
17 | // Let MaybeLazy() handle initialization.
18 | }
19 |
20 | func ProcessLinterData(dialect Dialect) {
21 | if dialect == EDN {
22 | markJokerNamespacesAsUsed()
23 | return
24 | }
25 | processData(linter_allData)
26 | if dialect == JOKER {
27 | markJokerNamespacesAsUsed()
28 | processData(linter_jokerData)
29 | return
30 | }
31 | processData(linter_cljxData)
32 | switch dialect {
33 | case CLJ:
34 | processData(linter_cljData)
35 | case CLJS:
36 | processData(linter_cljsData)
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/core/data/linter_all.joke:
--------------------------------------------------------------------------------
1 | ;; Additional restriction on arities where it makes sense
2 |
3 | (def __=__ =)
4 | (defn =
5 | ^Boolean [x y & more]
6 | (apply __=__ x y more))
7 |
8 | (def __not=__ not=)
9 | (defn not=
10 | ^Boolean [x y & more]
11 | (apply __not=__ x y more))
12 |
13 | (def __<__ <)
14 | (defn <
15 | ^Boolean [^Number x ^Number y & more]
16 | (apply __<__ x y more))
17 |
18 | (def __>__ >)
19 | (defn >
20 | ^Boolean [^Number x ^Number y & more]
21 | (apply __>__ x y more))
22 |
23 | (def __<=__ <=)
24 | (defn <=
25 | ^Boolean [^Number x ^Number y & more]
26 | (apply __<=__ x y more))
27 |
28 | (def __>=__ >=)
29 | (defn >=
30 | ^Boolean [^Number x ^Number y & more]
31 | (apply __>=__ x y more))
32 |
33 | (def __==__ ==)
34 | (defn ==
35 | ^Boolean [^Number x ^Number y & more]
36 | (apply __==__ x y more))
37 |
38 | (def __merge__ merge)
39 | (defn merge
40 | ^Map [^Map m1 & more]
41 | (apply __merge__ m1 more))
42 |
43 | (def __merge-with__ merge-with)
44 | (defn merge-with
45 | ^Map [^Callable f ^Map m1 & more]
46 | (apply __merge-with__ f m1 more))
47 |
48 | ;; Redefine when and when-not with additional checks
49 |
50 | (defmacro when
51 | "Evaluates test. If logical true, evaluates body in an implicit do."
52 | {:added "1.0"}
53 | [test & body]
54 | (let [c (count body)
55 | b (if (> c 1)
56 | (cons 'do body)
57 | (first body))]
58 | (when *linter-mode*
59 | (when (zero? c)
60 | (println-linter__ (ex-info "when form with empty body" {:form &form :_prefix "Parse warning"}))))
61 | (list 'if test b nil)))
62 |
63 | (defmacro when-not
64 | "Evaluates test. If logical false, evaluates body in an implicit do."
65 | {:added "1.0"}
66 | [test & body]
67 | (let [c (count body)
68 | b (if (> c 1)
69 | (cons 'do body)
70 | (first body))]
71 | (when *linter-mode*
72 | (when (zero? c)
73 | (println-linter__ (ex-info "when-not form with empty body" {:form &form :_prefix "Parse warning"}))))
74 | (list 'if test nil b)))
75 |
--------------------------------------------------------------------------------
/core/data/linter_joker.joke:
--------------------------------------------------------------------------------
1 | (def *known-macros*
2 | (merge {'joker.test/deftest nil 'joker.test/is nil 'joker.test/are nil}
3 | (:known-macros joker.core/*linter-config*)))
4 |
--------------------------------------------------------------------------------
/core/data/pprint.joke:
--------------------------------------------------------------------------------
1 | (ns joker.pprint
2 | "Pretty printing utilities. Based on Clojure implementation."
3 | {:added "1.0"})
4 |
5 | (defn print-table
6 | "Prints a collection of maps in a textual table. Prints table headings
7 | ks, and then a line of output for each row, corresponding to the keys
8 | in ks. If ks are not specified, use the keys of the first item in rows."
9 | {:added "1.0"}
10 | ([ks rows]
11 | (when (seq rows)
12 | (let [widths (map
13 | (fn [k]
14 | (apply max (count (str k)) (map #(count (str (get % k))) rows)))
15 | ks)
16 | spacers (map #(apply str (repeat % "-")) widths)
17 | fmts (map #(str "%" % "s") widths)
18 | fmt-row (fn [leader divider trailer row]
19 | (str leader
20 | (apply str (interpose divider
21 | (for [[col fmt] (map vector (map #(get row %) ks) fmts)]
22 | (format fmt (str col)))))
23 | trailer))]
24 | (println)
25 | (println (fmt-row "| " " | " " |" (zipmap ks ks)))
26 | (println (fmt-row "|-" "-+-" "-|" (zipmap ks spacers)))
27 | (doseq [row rows]
28 | (println (fmt-row "| " " | " " |" row))))))
29 | ([rows] (print-table (keys (first rows)) rows)))
30 |
--------------------------------------------------------------------------------
/core/data/template.joke:
--------------------------------------------------------------------------------
1 | ; Copyright (c) Rich Hickey. All rights reserved.
2 | ; The use and distribution terms for this software are covered by the
3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
4 | ; which can be found in the file epl-v10.html at the root of this distribution.
5 | ; By using this software in any fashion, you are agreeing to be bound by
6 | ; the terms of this license.
7 | ; You must not remove this notice, or any other, from this software.
8 |
9 | ;;; template.clj - anonymous functions that pre-evaluate sub-expressions
10 |
11 | ;; By Stuart Sierra
12 | ;; June 23, 2009
13 |
14 | ;; CHANGE LOG
15 | ;;
16 | ;; June 23, 2009: complete rewrite, eliminated _1,_2,... argument
17 | ;; syntax
18 | ;;
19 | ;; January 20, 2009: added "template?" and checks for valid template
20 | ;; expressions.
21 | ;;
22 | ;; December 15, 2008: first version
23 |
24 |
25 | (ns ^{:doc "Macros that expand to repeated copies of a template expression."
26 | :author "Stuart Sierra"
27 | :added "1.0"}
28 | joker.template
29 | (:require [joker.walk :as walk]))
30 |
31 | (defn apply-template
32 | "For use in macros. argv is an argument list, as in defn. expr is
33 | a quoted expression using the symbols in argv. values is a sequence
34 | of values to be used for the arguments.
35 |
36 | apply-template will recursively replace argument symbols in expr
37 | with their corresponding values, returning a modified expr.
38 |
39 | Example: (apply-template '[x] '(+ x x) '[2])
40 | ;=> (+ 2 2)"
41 | {:added "1.0"}
42 | [argv expr values]
43 | (assert (vector? argv))
44 | (assert (every? symbol? argv))
45 | (walk/postwalk-replace (zipmap argv values) expr))
46 |
47 | (defmacro do-template
48 | "Repeatedly copies expr (in a do block) for each group of arguments
49 | in values. values are automatically partitioned by the number of
50 | arguments in argv, an argument vector as in defn.
51 |
52 | Example: (macroexpand '(do-template [x y] (+ y x) 2 4 3 5))
53 | ;=> (do (+ 4 2) (+ 5 3))"
54 | {:added "1.0"}
55 | [argv expr & values]
56 | (let [c (count argv)]
57 | `(do ~@(map (fn [a] (apply-template argv expr a))
58 | (partition c values)))))
59 |
--------------------------------------------------------------------------------
/core/deps.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "fmt"
5 | "io"
6 | "net/http"
7 | "os"
8 | "path/filepath"
9 | "regexp"
10 | "strings"
11 | )
12 |
13 | func externalHttpSourceToPath(lib string, url string) (path string) {
14 | home := HomeDir()
15 | localBase := filepath.Join(home, ".jokerd", "deps", strings.SplitN(url, "//", 2)[1])
16 | libBase := filepath.Join(strings.Split(lib, ".")...) + ".joke"
17 | libPath := filepath.Join(localBase, libBase)
18 | libPathDir := filepath.Dir(libPath)
19 |
20 | if _, err := os.Stat(libPathDir); os.IsNotExist(err) {
21 | os.MkdirAll(libPathDir, 0777)
22 | }
23 |
24 | if _, err := os.Stat(libPath); os.IsNotExist(err) {
25 | if !strings.HasSuffix(url, ".joke") {
26 | url = url + libBase
27 | }
28 | resp, err := http.Get(url)
29 | PanicOnErr(err)
30 | defer resp.Body.Close()
31 |
32 | if resp.StatusCode != http.StatusOK {
33 | panic(RT.NewError(fmt.Sprintf("Unable to retrieve: %s\nServer response: %d", url, resp.StatusCode)))
34 | }
35 |
36 | out, err := os.Create(libPath)
37 | defer out.Close()
38 | PanicOnErr(err)
39 |
40 | _, err = io.Copy(out, resp.Body)
41 | PanicOnErr(err)
42 | }
43 |
44 | return libPath
45 | }
46 |
47 | func externalSourceToPath(lib string, url string) (path string) {
48 | httpPath, _ := regexp.MatchString("http://|https://", url)
49 | if httpPath {
50 | return externalHttpSourceToPath(lib, url)
51 | } else {
52 | return filepath.Join(append([]string{url}, strings.Split(lib, ".")...)...) + ".joke"
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/core/environment_fast_init.go:
--------------------------------------------------------------------------------
1 | //go:build !gen_code
2 | // +build !gen_code
3 |
4 | package core
5 |
6 | func (env *Env) ReferCoreToUser() {
7 | // Nothing need be done; it's already "baked in" in the fast-startup version.
8 | }
9 |
--------------------------------------------------------------------------------
/core/environment_slow_init.go:
--------------------------------------------------------------------------------
1 | //go:build gen_code
2 | // +build gen_code
3 |
4 | package core
5 |
6 | /*
7 | Called by parse_init.go in an outer var block, this runs before any
8 |
9 | func init() as well as before func main(). InitEnv() and others are
10 | called at runtime to set some of these Values based on the current
11 | invocation.
12 | */
13 | func NewEnv() *Env {
14 | features := EmptySet()
15 | features.Add(MakeKeyword("default"))
16 | features.Add(MakeKeyword("joker"))
17 | res := &Env{
18 | Namespaces: make(map[*string]*Namespace),
19 | Features: features,
20 | }
21 | res.CoreNamespace = res.EnsureSymbolIsNamespace(SYMBOLS.joker_core)
22 | res.CoreNamespace.meta = MakeMeta(nil, "Core library of Joker.", "1.0")
23 | res.NS_VAR = res.CoreNamespace.Intern(MakeSymbol("ns"))
24 | res.IN_NS_VAR = res.CoreNamespace.Intern(MakeSymbol("in-ns"))
25 | res.ns = res.CoreNamespace.Intern(MakeSymbol("*ns*"))
26 | res.stdin = res.CoreNamespace.Intern(MakeSymbol("*in*"))
27 | res.stdout = res.CoreNamespace.Intern(MakeSymbol("*out*"))
28 | res.stderr = res.CoreNamespace.Intern(MakeSymbol("*err*"))
29 | res.file = res.CoreNamespace.Intern(MakeSymbol("*file*"))
30 | res.MainFile = res.CoreNamespace.Intern(MakeSymbol("*main-file*"))
31 | res.version = res.CoreNamespace.InternVar("*joker-version*", versionMap(),
32 | MakeMeta(nil, `The version info for Clojure core, as a map containing :major :minor
33 | :incremental and :qualifier keys. Feature releases may increment
34 | :minor and/or :major, bugfix releases will increment :incremental.`, "1.0"))
35 | res.args = res.CoreNamespace.Intern(MakeSymbol("*command-line-args*"))
36 | res.classPath = res.CoreNamespace.Intern(MakeSymbol("*classpath*"))
37 | res.classPath.Value = NIL
38 | res.classPath.isPrivate = true
39 | res.printReadably = res.CoreNamespace.Intern(MakeSymbol("*print-readably*"))
40 | res.printReadably.Value = Boolean{B: true}
41 | res.CoreNamespace.InternVar("*repl*", Boolean{B: false},
42 | MakeMeta(nil, "true if Joker is running in repl mode", "1.5"))
43 | res.CoreNamespace.InternVar("*linter-mode*", Boolean{B: LINTER_MODE},
44 | MakeMeta(nil, "true if Joker is running in linter mode", "1.0"))
45 | res.CoreNamespace.InternVar("*linter-config*", EmptyArrayMap(),
46 | MakeMeta(nil, "Map of configuration key/value pairs for linter mode", "1.0"))
47 | res.libs = res.CoreNamespace.Intern(MakeSymbol("*loaded-libs*"))
48 | res.libs.Value = EmptySet()
49 | res.libs.isPrivate = true
50 | return res
51 | }
52 |
53 | func (env *Env) ReferCoreToUser() {
54 | env.FindNamespace(MakeSymbol("user")).ReferAll(env.CoreNamespace)
55 | }
56 |
--------------------------------------------------------------------------------
/core/file.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "os"
5 | "unsafe"
6 | )
7 |
8 | type (
9 | File struct {
10 | *os.File
11 | }
12 | )
13 |
14 | func (f *File) ToString(escape bool) string {
15 | return "#object[File]"
16 | }
17 |
18 | func (f *File) Equals(other interface{}) bool {
19 | return f == other
20 | }
21 |
22 | func (f *File) GetInfo() *ObjectInfo {
23 | return nil
24 | }
25 |
26 | func (f *File) GetType() *Type {
27 | return TYPE.File
28 | }
29 |
30 | func (f *File) Hash() uint32 {
31 | return HashPtr(uintptr(unsafe.Pointer(f)))
32 | }
33 |
34 | func (f *File) WithInfo(info *ObjectInfo) Object {
35 | return f
36 | }
37 |
38 | // To satisfy Named interface
39 | func (f *File) Namespace() string {
40 | return ""
41 | }
42 |
43 | func MakeFile(f *os.File) *File {
44 | return &File{f}
45 | }
46 |
47 | func ExtractFile(args []Object, index int) *File {
48 | return EnsureArgIsFile(args, index)
49 | }
50 |
--------------------------------------------------------------------------------
/core/gen_go/unsafe_stuff.go:
--------------------------------------------------------------------------------
1 | package gen_go
2 |
3 | // This module currently is needed only to give gen_code access to
4 | // private fields in Joker's core-package types.
5 | //
6 | // Since Joker's core package isn't really designed to be imported by
7 | // any component outside of Joker itself, it's possible that making
8 | // all (pertinent) fields public could be a straightforward way to
9 | // eliminate the need for this module.
10 |
11 | // NOTE: This code comes from github.com/jcburley/go-spew (originally
12 | // davecgh/go-spew):
13 |
14 | import (
15 | "reflect"
16 | "unsafe"
17 | )
18 |
19 | const flagPrivate = 0x20
20 |
21 | var flagValOffset = func() uintptr {
22 | field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag")
23 | if !ok {
24 | panic("reflect.Value has no flag field")
25 | }
26 | return field.Offset
27 | }()
28 |
29 | type flag uintptr
30 |
31 | func flagField(v *reflect.Value) *flag {
32 | return (*flag)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + flagValOffset))
33 | }
34 |
35 | func UnsafeReflectValue(v reflect.Value) reflect.Value {
36 | if !v.IsValid() || (v.CanInterface() && v.CanAddr()) {
37 | return v
38 | }
39 | flagFieldPtr := flagField(&v)
40 | *flagFieldPtr &^= flagPrivate
41 | return v
42 | }
43 |
--------------------------------------------------------------------------------
/core/intern.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | type (
4 | StringPool map[string]*string
5 | )
6 |
7 | func (p StringPool) Intern(s string) *string {
8 | ss, exists := p[s]
9 | if exists {
10 | return ss
11 | }
12 | p[s] = &s
13 | return &s
14 | }
15 |
--------------------------------------------------------------------------------
/core/intern_slow_init.go:
--------------------------------------------------------------------------------
1 | //go:build gen_code
2 | // +build gen_code
3 |
4 | package core
5 |
6 | var STRINGS StringPool = StringPool{}
7 |
--------------------------------------------------------------------------------
/core/io_reader.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "io"
5 | "unsafe"
6 | )
7 |
8 | type (
9 | IOReader struct {
10 | io.Reader
11 | hash uint32
12 | }
13 | )
14 |
15 | func MakeIOReader(r io.Reader) *IOReader {
16 | res := &IOReader{r, 0}
17 | res.hash = HashPtr(uintptr(unsafe.Pointer(res)))
18 | return res
19 | }
20 |
21 | func (ior *IOReader) ToString(escape bool) string {
22 | return "#object[IOReader]"
23 | }
24 |
25 | func (ior *IOReader) Equals(other interface{}) bool {
26 | return ior == other
27 | }
28 |
29 | func (ior *IOReader) GetInfo() *ObjectInfo {
30 | return nil
31 | }
32 |
33 | func (ior *IOReader) GetType() *Type {
34 | return TYPE.IOReader
35 | }
36 |
37 | func (ior *IOReader) Hash() uint32 {
38 | return ior.hash
39 | }
40 |
41 | func (ior *IOReader) WithInfo(info *ObjectInfo) Object {
42 | return ior
43 | }
44 |
45 | func (ior *IOReader) Close() error {
46 | if c, ok := ior.Reader.(io.Closer); ok {
47 | return c.Close()
48 | } else {
49 | return RT.NewError("Object is not closable: " + ior.ToString(false))
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/core/io_writer.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "io"
5 | "unsafe"
6 | )
7 |
8 | type (
9 | IOWriter struct {
10 | io.Writer
11 | hash uint32
12 | }
13 | )
14 |
15 | func MakeIOWriter(w io.Writer) *IOWriter {
16 | res := &IOWriter{w, 0}
17 | res.hash = HashPtr(uintptr(unsafe.Pointer(res)))
18 | return res
19 | }
20 |
21 | func (iow *IOWriter) ToString(escape bool) string {
22 | return "#object[IOWriter]"
23 | }
24 |
25 | func (iow *IOWriter) Equals(other interface{}) bool {
26 | return iow == other
27 | }
28 |
29 | func (iow *IOWriter) GetInfo() *ObjectInfo {
30 | return nil
31 | }
32 |
33 | func (iow *IOWriter) GetType() *Type {
34 | return TYPE.IOWriter
35 | }
36 |
37 | func (iow *IOWriter) Hash() uint32 {
38 | return iow.hash
39 | }
40 |
41 | func (iow *IOWriter) WithInfo(info *ObjectInfo) Object {
42 | return iow
43 | }
44 |
45 | func (iow *IOWriter) Close() error {
46 | if c, ok := iow.Writer.(io.Closer); ok {
47 | return c.Close()
48 | } else {
49 | return RT.NewError("Object is not closable: " + iow.ToString(false))
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/core/line_runereader.go:
--------------------------------------------------------------------------------
1 | //go:build !plan9
2 | // +build !plan9
3 |
4 | package core
5 |
6 | import (
7 | "io"
8 | "strings"
9 | "unicode/utf8"
10 |
11 | "github.com/candid82/liner"
12 | )
13 |
14 | type (
15 | LineRuneReader struct {
16 | rl *liner.State
17 | buffer []rune
18 | i int
19 | Prompt string
20 | }
21 | )
22 |
23 | func NewLineRuneReader(rl *liner.State) *LineRuneReader {
24 | return &LineRuneReader{rl: rl}
25 | }
26 |
27 | func (lrr *LineRuneReader) ReadRune() (rune, int, error) {
28 | if lrr.buffer != nil && lrr.i < len(lrr.buffer) {
29 | r := lrr.buffer[lrr.i]
30 | lrr.i++
31 | return r, utf8.RuneLen(r), nil
32 | }
33 | line, err := lrr.rl.Prompt(lrr.Prompt)
34 | if err != nil {
35 | return EOF, 0, io.EOF
36 | }
37 | if strings.TrimSpace(line) != "" {
38 | lrr.rl.AppendHistory(line)
39 | }
40 | lrr.buffer = make([]rune, 0, len(line)+1)
41 | for _, r := range line {
42 | lrr.buffer = append(lrr.buffer, r)
43 | }
44 | lrr.buffer = append(lrr.buffer, '\n')
45 | lrr.i = 1
46 | return lrr.buffer[0], utf8.RuneLen(lrr.buffer[0]), nil
47 | }
48 |
--------------------------------------------------------------------------------
/core/reader.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | import (
4 | "io"
5 | )
6 |
7 | type (
8 | Reader struct {
9 | runeReader io.RuneReader
10 | rw *RuneWindow
11 | line int
12 | prevLineLength int
13 | column int
14 | isEof bool
15 | rewind int
16 | filename *string
17 | }
18 | )
19 |
20 | func NewReader(runeReader io.RuneReader, filename string) *Reader {
21 | return &Reader{
22 | line: 1,
23 | runeReader: runeReader,
24 | rw: &RuneWindow{},
25 | rewind: -1,
26 | filename: STRINGS.Intern(filename),
27 | }
28 | }
29 |
30 | func (reader *Reader) Get() rune {
31 | if reader.isEof {
32 | return EOF
33 | }
34 | if reader.rewind > -1 {
35 | r := top(reader.rw, reader.rewind)
36 | reader.rewind--
37 | if r == '\n' {
38 | reader.line++
39 | reader.prevLineLength = reader.column
40 | reader.column = 0
41 | } else {
42 | reader.column++
43 | }
44 | return r
45 | }
46 | r, _, err := reader.runeReader.ReadRune()
47 | switch {
48 | case err == io.EOF:
49 | reader.isEof = true
50 | return EOF
51 | case err != nil:
52 | panic(err)
53 | case r == '\n':
54 | reader.line++
55 | reader.prevLineLength = reader.column
56 | reader.column = 0
57 | add(reader.rw, r)
58 | return r
59 | default:
60 | reader.column++
61 | add(reader.rw, r)
62 | return r
63 | }
64 | }
65 |
66 | func (reader *Reader) Unget() {
67 | if reader.isEof {
68 | return
69 | }
70 | reader.rewind++
71 | if reader.column == 0 {
72 | reader.line--
73 | reader.column = reader.prevLineLength
74 | } else {
75 | reader.column--
76 | }
77 | }
78 |
79 | func (reader *Reader) Peek() rune {
80 | if reader.isEof {
81 | return EOF
82 | }
83 | r := reader.Get()
84 | reader.Unget()
85 | return r
86 | }
87 |
--------------------------------------------------------------------------------
/core/rune_window.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | type (
4 | RuneWindow struct {
5 | arr [5]rune
6 | start int // points to an element before the first one
7 | end int // point to the last element
8 | }
9 | )
10 |
11 | func add(rw *RuneWindow, r rune) {
12 | rw.end++
13 | if rw.end == len(rw.arr) {
14 | rw.end = 0
15 | }
16 | rw.arr[rw.end] = r
17 | if rw.end == rw.start {
18 | rw.start++
19 | if rw.start == len(rw.arr) {
20 | rw.start = 0
21 | }
22 | }
23 | }
24 |
25 | func size(rw *RuneWindow) int {
26 | if rw.end >= rw.start {
27 | return rw.end - rw.start
28 | }
29 | return len(rw.arr) - (rw.start - rw.end)
30 | }
31 |
32 | func top(rw *RuneWindow, i int) rune {
33 | if i >= size(rw) {
34 | panic("RuneWindow: index out of range")
35 | }
36 | index := rw.end - i
37 | if index < 0 {
38 | index += len(rw.arr)
39 | }
40 | return rw.arr[index]
41 | }
42 |
--------------------------------------------------------------------------------
/core/spew_disabled.go:
--------------------------------------------------------------------------------
1 | //go:build !go_spew
2 | // +build !go_spew
3 |
4 | package core
5 |
6 | var procGoSpew = func(args []Object) (res Object) {
7 | return MakeBoolean(false)
8 | }
9 |
--------------------------------------------------------------------------------
/core/spew_enabled.go:
--------------------------------------------------------------------------------
1 | //go:build go_spew
2 | // +build go_spew
3 |
4 | package core
5 |
6 | import (
7 | "fmt"
8 | "github.com/jcburley/go-spew/spew"
9 | )
10 |
11 | var procGoSpew = func(args []Object) (res Object) {
12 | res = MakeBoolean(false)
13 | CheckArity(args, 1, 2)
14 | defer func() {
15 | if r := recover(); r != nil {
16 | fmt.Fprintf(Stderr, "Error: %v\n", r)
17 | }
18 | }()
19 | scs := spew.NewDefaultConfig()
20 | if len(args) > 1 {
21 | m := ExtractMap(args, 1)
22 | if yes, k := m.Get(MakeKeyword("Indent")); yes {
23 | scs.Indent = k.(Native).Native().(string)
24 | }
25 | if yes, k := m.Get(MakeKeyword("MaxDepth")); yes {
26 | scs.MaxDepth = k.(Native).Native().(int)
27 | }
28 | if yes, k := m.Get(MakeKeyword("DisableMethods")); yes {
29 | scs.DisableMethods = k.(Native).Native().(bool)
30 | }
31 | if yes, k := m.Get(MakeKeyword("DisablePointerMethods")); yes {
32 | scs.DisablePointerMethods = k.(Native).Native().(bool)
33 | }
34 | if yes, k := m.Get(MakeKeyword("DisablePointerAddresses")); yes {
35 | scs.DisablePointerAddresses = k.(Native).Native().(bool)
36 | }
37 | if yes, k := m.Get(MakeKeyword("DisableCapacities")); yes {
38 | scs.DisableCapacities = k.(Native).Native().(bool)
39 | }
40 | if yes, k := m.Get(MakeKeyword("ContinueOnMethod")); yes {
41 | scs.ContinueOnMethod = k.(Native).Native().(bool)
42 | }
43 | if yes, k := m.Get(MakeKeyword("SortKeys")); yes {
44 | scs.SortKeys = k.(Native).Native().(bool)
45 | }
46 | if yes, k := m.Get(MakeKeyword("SpewKeys")); yes {
47 | scs.SpewKeys = k.(Native).Native().(bool)
48 | }
49 | if yes, k := m.Get(MakeKeyword("NoDuplicates")); yes {
50 | scs.NoDuplicates = k.(Native).Native().(bool)
51 | }
52 | if yes, k := m.Get(MakeKeyword("UseOrdinals")); yes {
53 | scs.UseOrdinals = k.(Native).Native().(bool)
54 | }
55 | }
56 | scs.Fdump(Stderr, args[0])
57 | return MakeBoolean(true)
58 | }
59 |
--------------------------------------------------------------------------------
/core/stringable.go:
--------------------------------------------------------------------------------
1 | package core
2 |
3 | func EnsureObjectIsStringable(obj Object, pattern string) String {
4 | switch c := obj.(type) {
5 | case String:
6 | return c
7 | case Char:
8 | return String{S: string(c.Ch)}
9 | default:
10 | panic(FailObject(c, "Stringable", pattern))
11 | }
12 | }
13 |
14 | func EnsureArgIsStringable(args []Object, index int) String {
15 | switch c := args[index].(type) {
16 | case String:
17 | return c
18 | case Char:
19 | return String{S: string(c.Ch)}
20 | default:
21 | panic(FailArg(c, "Stringable", index))
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/docs/dash.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | rm -f ./joker.xml
4 | ../joker generate-xml.joke || exit
5 |
6 | pushd dash
7 | rm -f ./*.html
8 | rm -f ./*.css
9 | rm -f ./*.js
10 | rm -rf joker.docset
11 | cp ../*.html ./
12 | cp ../*.css ./
13 | cp ../*.js ./
14 | dashing build joker
15 | tar --exclude='.DS_Store' -cvzf ../joker.tgz joker.docset
16 | popd
17 |
--------------------------------------------------------------------------------
/docs/dash/dashing.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Joker",
3 | "package": "joker",
4 | "index": "index.html",
5 | "selectors": {
6 | "h3.ns": "Namespace",
7 | "h3.type": "Type",
8 | "h3.Function": "Function",
9 | "h3.Macro": "Macro",
10 | "h3.Variable": "Variable",
11 | "h3.Constant": "Constant"
12 | },
13 | "icon32x32": "../joker32.png",
14 | "allowJS": true,
15 | "ExternalURL": "https://candid82.github.io/joker",
16 | "ignore": ["{name}"]
17 | }
18 |
--------------------------------------------------------------------------------
/docs/generate-xml.joke:
--------------------------------------------------------------------------------
1 | (require '[joker.string :as s])
2 |
3 | (def xml-template
4 | (slurp "templates/xml.html"))
5 |
6 | (spit "joker.xml" (s/replace xml-template "{version}" (joker-version)))
7 |
--------------------------------------------------------------------------------
/docs/joker.base64.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
Namespace: joker.base64
8 |
v1.0
9 |
Contents
10 |
27 |
Summary
28 |
Implements base64 encoding as specified by RFC 4648.
29 |
Index
30 |
39 |
Constants
40 | Constants are variables with
:const true in their metadata. Joker currently does not recognize them as special; as such, it allows redefining them or their values.
41 |
44 |
Variables
45 |
48 |
Functions, Macros, and Special Forms
49 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/docs/joker.hex.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
Namespace: joker.hex
8 |
v1.0
9 |
Contents
10 |
27 |
Summary
28 |
Implements hexadecimal encoding and decoding.
29 |
Index
30 |
39 |
Constants
40 | Constants are variables with
:const true in their metadata. Joker currently does not recognize them as special; as such, it allows redefining them or their values.
41 |
44 |
Variables
45 |
48 |
Functions, Macros, and Special Forms
49 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/docs/joker.html.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
Namespace: joker.html
8 |
v1.0
9 |
Contents
10 |
27 |
Summary
28 |
Provides functions for escaping and unescaping HTML text.
29 |
Index
30 |
39 |
Constants
40 | Constants are variables with
:const true in their metadata. Joker currently does not recognize them as special; as such, it allows redefining them or their values.
41 |
44 |
Variables
45 |
48 |
Functions, Macros, and Special Forms
49 |
50 |
51 | escape
52 | Function
53 | v1.0
54 | (escape s)
55 |
56 | Escapes special characters like < to become <. It escapes only five such characters: <, >, &, ' and ".
57 |
58 |
59 |
60 |
61 | unescape
62 | Function
63 | v1.0
64 | (unescape s)
65 |
66 | Unescapes entities like < to become <.
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/docs/joker.markdown.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
Namespace: joker.markdown
8 |
v1.0
9 |
Contents
10 |
27 |
Summary
28 |
Implements GitHub Flavored Markdown rendering.
29 |
Index
30 |
36 |
Constants
37 | Constants are variables with
:const true in their metadata. Joker currently does not recognize them as special; as such, it allows redefining them or their values.
38 |
41 |
Variables
42 |
45 |
Functions, Macros, and Special Forms
46 |
47 |
48 | convert-string
49 | Function
50 | v1.0
51 | (convert-string s)
52 | (convert-string s opts)
53 |
54 | Returns the HTML rendering of Markdown string s.
55 | opts is an optional map of boolean rendering options (all default to true)
56 |
57 | :with-hard-wraps? - Render newlines as <br>.
58 | :with-xhtml? - Render as XHTML.
59 | :with-unsafe? - When false, all raw html will be omitted from the output. When true html is passed through unchanged.
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/docs/joker.pprint.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
Namespace: joker.pprint
8 |
v1.0
9 |
Contents
10 |
27 |
Summary
28 |
Pretty printing utilities. Based on Clojure implementation.
29 |
Index
30 |
36 |
Constants
37 | Constants are variables with
:const true in their metadata. Joker currently does not recognize them as special; as such, it allows redefining them or their values.
38 |
41 |
Variables
42 |
45 |
Functions, Macros, and Special Forms
46 |
47 |
48 | print-table
49 | Function
50 | v1.0
51 | (print-table ks rows)
52 | (print-table rows)
53 |
54 | Prints a collection of maps in a textual table. Prints table headings
55 | ks, and then a line of output for each row, corresponding to the keys
56 | in ks. If ks are not specified, use the keys of the first item in rows.
57 | source
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/docs/joker.tgz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/candid82/joker/1eed1c02c38ef1373640c42af1423808826820cc/docs/joker.tgz
--------------------------------------------------------------------------------
/docs/joker.uuid.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
Namespace: joker.uuid
8 |
v1.0
9 |
Contents
10 |
27 |
Summary
28 |
Generates UUIDs.
29 |
Index
30 |
31 |
32 | new
33 |
34 |
35 |
36 |
Constants
37 | Constants are variables with
:const true in their metadata. Joker currently does not recognize them as special; as such, it allows redefining them or their values.
38 |
41 |
Variables
42 |
45 |
Functions, Macros, and Special Forms
46 |
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/docs/joker.xml:
--------------------------------------------------------------------------------
1 |
2 | 0.17.0
3 | https://github.com/candid82/joker/raw/master/docs/joker.tgz
4 |
5 |
--------------------------------------------------------------------------------
/docs/joker.yaml.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
Namespace: joker.yaml
8 |
v1.0
9 |
Contents
10 |
27 |
Summary
28 |
Implements encoding and decoding of YAML.
29 |
Index
30 |
39 |
Constants
40 | Constants are variables with
:const true in their metadata. Joker currently does not recognize them as special; as such, it allows redefining them or their values.
41 |
44 |
Variables
45 |
48 |
Functions, Macros, and Special Forms
49 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/docs/joker32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/candid82/joker/1eed1c02c38ef1373640c42af1423808826820cc/docs/joker32.png
--------------------------------------------------------------------------------
/docs/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
Joker Standard Namespaces and Types
8 |
12 |
Indexes of Joker Standard Namespaces and Types
13 |
14 |
15 | {index-of-special-forms}
16 |
17 |
18 |
19 | {index-of-namespaces}
20 |
21 |
22 |
23 | {index-of-types}
24 |
25 |
26 |
27 | {special-forms}
28 |
29 |
Joker Standard Namespaces
30 |
33 |
Joker Standard Types
34 |
Note: These types are "omnipresent", in that they're not members of any particular namespace, but are available for resolution regardless of the current value of *ns* (the current namespace).
35 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/docs/templates/link-item.html:
--------------------------------------------------------------------------------
1 |
2 | {escaped-name}
3 |
4 |
--------------------------------------------------------------------------------
/docs/templates/ns-summary.html:
--------------------------------------------------------------------------------
1 |
2 | {name}
3 | v{added}
4 | {docstring}
5 | details
6 |
7 |
--------------------------------------------------------------------------------
/docs/templates/ns.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
Namespace: {name}
8 |
v{added}
9 |
Contents
10 |
27 |
Summary
28 |
{docstring}
29 |
Index
30 |
33 |
Constants
34 | Constants are variables with
:const true in their metadata. Joker currently does not recognize them as special; as such, it allows redefining them or their values.
35 |
38 |
Variables
39 |
42 |
Functions, Macros, and Special Forms
43 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/docs/templates/special-form.html:
--------------------------------------------------------------------------------
1 |
2 | {name}
3 | {usage}
4 | {docstring}
5 |
6 |
--------------------------------------------------------------------------------
/docs/templates/type-summary.html:
--------------------------------------------------------------------------------
1 |
2 | {name}
3 | v{added}
4 | {docstring}
5 |
6 |
--------------------------------------------------------------------------------
/docs/templates/usage-with-types.html:
--------------------------------------------------------------------------------
1 | {usage}
{usage-with-types}
2 |
--------------------------------------------------------------------------------
/docs/templates/usage.html:
--------------------------------------------------------------------------------
1 | {usage}
2 |
--------------------------------------------------------------------------------
/docs/templates/var.html:
--------------------------------------------------------------------------------
1 |
2 | {name}
3 | {type}
4 | v{added}
5 | {usage}
6 | {docstring}
7 | {source}
8 | {show-types}
9 |
10 |
--------------------------------------------------------------------------------
/docs/templates/xml.html:
--------------------------------------------------------------------------------
1 |
2 | {version}
3 | https://github.com/candid82/joker/raw/master/docs/joker.tgz
4 |
5 |
--------------------------------------------------------------------------------
/eval-tests.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ./joker tests/run-eval-tests.joke "$@"
4 |
--------------------------------------------------------------------------------
/exiters.go:
--------------------------------------------------------------------------------
1 | //go:build !windows && !plan9
2 | // +build !windows,!plan9
3 |
4 | package main
5 |
6 | const EXITERS = "EOF (Ctrl-D), or SIGINT (Ctrl-C)"
7 |
--------------------------------------------------------------------------------
/exiters_plan9.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | const EXITERS = "EOF (Ctrl-D), or 'Interrupt' note (Ctrl-C)"
4 |
--------------------------------------------------------------------------------
/exiters_windows.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | const EXITERS = "EOF (Ctrl-Z), or Ctrl-C"
4 |
--------------------------------------------------------------------------------
/flag-tests.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ./joker tests/run-flag-tests.joke
4 |
--------------------------------------------------------------------------------
/formatter-tests.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ./joker tests/run-tests.joke --format tests/formatter out output.clj
4 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/candid82/joker
2 |
3 | go 1.23.0
4 |
5 | toolchain go1.24.1
6 |
7 | require (
8 | github.com/candid82/liner v1.4.0
9 | github.com/go-git/go-git/v5 v5.13.0
10 | github.com/jcburley/go-spew v1.3.0
11 | github.com/pkg/profile v1.2.1
12 | github.com/yuin/goldmark v1.4.13
13 | go.etcd.io/bbolt v1.3.7
14 | gopkg.in/yaml.v2 v2.4.0
15 | )
16 |
17 | require (
18 | dario.cat/mergo v1.0.0 // indirect
19 | github.com/Microsoft/go-winio v0.6.1 // indirect
20 | github.com/ProtonMail/go-crypto v1.1.3 // indirect
21 | github.com/cloudflare/circl v1.3.7 // indirect
22 | github.com/cyphar/filepath-securejoin v0.2.5 // indirect
23 | github.com/emirpasic/gods v1.18.1 // indirect
24 | github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
25 | github.com/go-git/go-billy/v5 v5.6.0 // indirect
26 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
27 | github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
28 | github.com/kevinburke/ssh_config v1.2.0 // indirect
29 | github.com/mattn/go-runewidth v0.0.3 // indirect
30 | github.com/pjbgf/sha1cd v0.3.0 // indirect
31 | github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
32 | github.com/skeema/knownhosts v1.3.0 // indirect
33 | github.com/xanzy/ssh-agent v0.3.3 // indirect
34 | golang.org/x/crypto v0.36.0 // indirect
35 | golang.org/x/mod v0.17.0 // indirect
36 | golang.org/x/net v0.38.0 // indirect
37 | golang.org/x/sync v0.10.0 // indirect
38 | golang.org/x/sys v0.31.0 // indirect
39 | golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
40 | gopkg.in/warnings.v0 v0.1.2 // indirect
41 | )
42 |
--------------------------------------------------------------------------------
/linter-tests.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ./joker tests/run-tests.joke --lint tests/linter err output.txt
4 |
--------------------------------------------------------------------------------
/repl_plan9.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "bufio"
5 | "fmt"
6 | "io"
7 |
8 | . "github.com/candid82/joker/core"
9 | )
10 |
11 | func repl(phase Phase) {
12 | ProcessReplData()
13 | GLOBAL_ENV.FindNamespace(MakeSymbol("user")).ReferAll(GLOBAL_ENV.FindNamespace(MakeSymbol("joker.repl")))
14 | fmt.Printf("Welcome to joker %s. Use '(exit)', %s to exit.\n", VERSION, EXITERS)
15 | parseContext := &ParseContext{GlobalEnv: GLOBAL_ENV}
16 | replContext := NewReplContext(parseContext.GlobalEnv)
17 |
18 | var runeReader io.RuneReader
19 | runeReader = bufio.NewReader(Stdin)
20 | reader := NewReader(runeReader, "")
21 |
22 | for {
23 | print(GLOBAL_ENV.CurrentNamespace().Name.ToString(false) + "=> ")
24 | if processReplCommand(reader, phase, parseContext, replContext) {
25 | return
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/run.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | build() {
4 | go clean
5 | rm -f core/a_*.go # In case switching from a gen-code branch or similar (any existing files might break the build here)
6 | go generate ./...
7 | (cd core; go fmt a_*.go > /dev/null)
8 | go vet ./...
9 | go build
10 | }
11 |
12 | set -e # Exit on error.
13 |
14 | build
15 |
16 | if [ "$1" == "-v" ]; then
17 | ./joker -e '(print "\nLibraries available in this build:\n ") (loaded-libs) (println)'
18 | fi
19 |
20 | SUM256="$(go run tools/sum256dir/main.go std)"
21 | OUT="$(cd std; ../joker generate-std.joke 2>&1 | grep -v 'WARNING:.*already refers' | grep '.')" || : # grep returns non-zero if no lines match
22 | if [ -n "$OUT" ]; then
23 | echo "$OUT"
24 | echo >&2 "Unable to generate fresh library files; exiting."
25 | exit 2
26 | fi
27 | (cd std; go fmt ./... > /dev/null)
28 | NEW_SUM256="$(go run tools/sum256dir/main.go std)"
29 |
30 | if [ "$SUM256" != "$NEW_SUM256" ]; then
31 | echo 'std has changed, rebuilding...'
32 | build
33 | fi
34 |
35 | if [ "$1" != "--build-only" ]; then
36 | ./joker "$@"
37 | fi
38 |
--------------------------------------------------------------------------------
/shadow.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Check for shadowed variables.
4 |
5 | if which shadow >/dev/null 2>/dev/null; then
6 | # Install via: go install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow
7 | SHADOW="-vettool=$(which shadow)"
8 | elif $(go tool vet nonexistent.go 2>&1 | grep -q -v unsupported); then
9 | SHADOW="-shadow=true"
10 | fi
11 |
12 | if [ -n "$SHADOW" ]; then
13 | go vet "$SHADOW" ./...
14 | else
15 | echo >&2 "Not performing shadowed-variables check; consider installing shadow tool via:"
16 | echo >&2 " go install golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow"
17 | echo >&2 "and rerunning this script."
18 | exit 99
19 | fi
20 |
--------------------------------------------------------------------------------
/std/addmeta.tmpl:
--------------------------------------------------------------------------------
1 | .Plus(MakeKeyword("{key}"), {value})
2 |
--------------------------------------------------------------------------------
/std/arity.tmpl:
--------------------------------------------------------------------------------
1 | case {arity}:
2 | {arityCheck}
3 | {args}
4 | {goExpr}
5 | {return}
6 |
--------------------------------------------------------------------------------
/std/base64.joke:
--------------------------------------------------------------------------------
1 | (ns ^{:go-imports []
2 | :doc "Implements base64 encoding as specified by RFC 4648."}
3 | base64)
4 |
5 | (defn ^String decode-string
6 | "Returns the bytes represented by the base64 string s."
7 | {:added "1.0"
8 | :go "decodeString(s)"}
9 | [^String s])
10 |
11 | (defn ^String encode-string
12 | "Returns the base64 encoding of s."
13 | {:added "1.0"
14 | :go "encodeString(s)"}
15 | [^String s])
16 |
--------------------------------------------------------------------------------
/std/base64/a_base64.go:
--------------------------------------------------------------------------------
1 | // This file is generated by generate-std.joke script. Do not edit manually!
2 |
3 | package base64
4 |
5 | import (
6 | . "github.com/candid82/joker/core"
7 | )
8 |
9 | var __decode_string__P ProcFn = __decode_string_
10 | var decode_string_ Proc = Proc{Fn: __decode_string__P, Name: "decode_string_", Package: "std/base64"}
11 |
12 | func __decode_string_(_args []Object) Object {
13 | _c := len(_args)
14 | switch {
15 | case _c == 1:
16 | s := ExtractString(_args, 0)
17 | _res := decodeString(s)
18 | return MakeString(_res)
19 |
20 | default:
21 | PanicArity(_c)
22 | }
23 | return NIL
24 | }
25 |
26 | var __encode_string__P ProcFn = __encode_string_
27 | var encode_string_ Proc = Proc{Fn: __encode_string__P, Name: "encode_string_", Package: "std/base64"}
28 |
29 | func __encode_string_(_args []Object) Object {
30 | _c := len(_args)
31 | switch {
32 | case _c == 1:
33 | s := ExtractString(_args, 0)
34 | _res := encodeString(s)
35 | return MakeString(_res)
36 |
37 | default:
38 | PanicArity(_c)
39 | }
40 | return NIL
41 | }
42 |
43 | func Init() {
44 |
45 | InternsOrThunks()
46 | }
47 |
48 | var base64Namespace = GLOBAL_ENV.EnsureSymbolIsLib(MakeSymbol("joker.base64"))
49 |
50 | func init() {
51 | base64Namespace.Lazy = Init
52 | }
53 |
--------------------------------------------------------------------------------
/std/base64/a_base64_slow_init.go:
--------------------------------------------------------------------------------
1 | // This file is generated by generate-std.joke script. Do not edit manually!
2 |
3 | package base64
4 |
5 | import (
6 | "fmt"
7 | . "github.com/candid82/joker/core"
8 | "os"
9 | )
10 |
11 | func InternsOrThunks() {
12 | if VerbosityLevel > 0 {
13 | fmt.Fprintln(os.Stderr, "Lazily running slow version of base64.InternsOrThunks().")
14 | }
15 | base64Namespace.ResetMeta(MakeMeta(nil, `Implements base64 encoding as specified by RFC 4648.`, "1.0"))
16 |
17 | base64Namespace.InternVar("decode-string", decode_string_,
18 | MakeMeta(
19 | NewListFrom(NewVectorFrom(MakeSymbol("s"))),
20 | `Returns the bytes represented by the base64 string s.`, "1.0").Plus(MakeKeyword("tag"), String{S: "String"}))
21 |
22 | base64Namespace.InternVar("encode-string", encode_string_,
23 | MakeMeta(
24 | NewListFrom(NewVectorFrom(MakeSymbol("s"))),
25 | `Returns the base64 encoding of s.`, "1.0").Plus(MakeKeyword("tag"), String{S: "String"}))
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/std/base64/base64_native.go:
--------------------------------------------------------------------------------
1 | package base64
2 |
3 | import (
4 | "encoding/base64"
5 |
6 | . "github.com/candid82/joker/core"
7 | )
8 |
9 | func decodeString(s string) string {
10 | decoded, err := base64.StdEncoding.DecodeString(s)
11 | if err != nil {
12 | panic(RT.NewError("Invalid base64 string: " + err.Error()))
13 | }
14 | return string(decoded)
15 | }
16 |
17 | func encodeString(s string) string {
18 | return base64.StdEncoding.EncodeToString([]byte(s))
19 | }
20 |
--------------------------------------------------------------------------------
/std/crypto.joke:
--------------------------------------------------------------------------------
1 | (ns ^{:go-imports ["crypto/sha256" "crypto/sha512" "crypto/md5" "crypto/sha1"]
2 | :doc "Implements common cryptographic and hash functions."}
3 | crypto)
4 |
5 | (defn ^String hmac
6 | "Returns HMAC signature for message and key using specified algorithm.
7 | Algorithm is one of the following: :sha1, :sha224, :sha256, :sha384, :sha512."
8 | {:added "1.0"
9 | :go "hmacSum(algorithm, message, key)"}
10 | [^Keyword algorithm ^String message ^String key])
11 |
12 | (defn ^String sha256
13 | "Returns the SHA256 checksum of the data."
14 | {:added "1.0"
15 | :go "! t := sha256.Sum256([]byte(data)); _res := string(t[:])"}
16 | [^String data])
17 |
18 | (defn ^String sha224
19 | "Returns the SHA224 checksum of the data."
20 | {:added "1.0"
21 | :go "! t := sha256.Sum224([]byte(data)); _res := string(t[:])"}
22 | [^String data])
23 |
24 | (defn ^String sha384
25 | "Returns the SHA384 checksum of the data."
26 | {:added "1.0"
27 | :go "! t := sha512.Sum384([]byte(data)); _res := string(t[:])"}
28 | [^String data])
29 |
30 | (defn ^String sha512
31 | "Returns the SHA512 checksum of the data."
32 | {:added "1.0"
33 | :go "! t := sha512.Sum512([]byte(data)); _res := string(t[:])"}
34 | [^String data])
35 |
36 | (defn ^String sha512-224
37 | "Returns the SHA512/224 checksum of the data."
38 | {:added "1.0"
39 | :go "! t := sha512.Sum512_224([]byte(data)); _res := string(t[:])"}
40 | [^String data])
41 |
42 | (defn ^String sha512-256
43 | "Returns the SHA512/256 checksum of the data."
44 | {:added "1.0"
45 | :go "! t := sha512.Sum512_256([]byte(data)); _res := string(t[:])"}
46 | [^String data])
47 |
48 | (defn ^String md5
49 | "Returns the MD5 checksum of the data."
50 | {:added "1.0"
51 | :go "! t := md5.Sum([]byte(data)); _res := string(t[:])"}
52 | [^String data])
53 |
54 | (defn ^String sha1
55 | "Returns the SHA1 checksum of the data."
56 | {:added "1.0"
57 | :go "! t := sha1.Sum([]byte(data)); _res := string(t[:])"}
58 | [^String data])
59 |
--------------------------------------------------------------------------------
/std/crypto/crypto_native.go:
--------------------------------------------------------------------------------
1 | package crypto
2 |
3 | import (
4 | "crypto/hmac"
5 | "crypto/sha1"
6 | "crypto/sha256"
7 | "crypto/sha512"
8 | "hash"
9 |
10 | . "github.com/candid82/joker/core"
11 | )
12 |
13 | func hmacSum(algorithm, message, key string) string {
14 | var h func() hash.Hash
15 | switch algorithm {
16 | case ":sha1":
17 | h = sha1.New
18 | case ":sha224":
19 | h = sha256.New224
20 | case ":sha256":
21 | h = sha256.New
22 | case ":sha384":
23 | h = sha512.New384
24 | case ":sha512":
25 | h = sha512.New
26 | default:
27 | panic(RT.NewError("Unsupported algorithm " + algorithm +
28 | ". Supported algorithms are: :sha1, :sha224, :sha256, :sha384, :sha512"))
29 | }
30 | mac := hmac.New(h, []byte(key))
31 | mac.Write([]byte(message))
32 | return string(mac.Sum(nil))
33 | }
34 |
--------------------------------------------------------------------------------
/std/csv/a_csv.go:
--------------------------------------------------------------------------------
1 | // This file is generated by generate-std.joke script. Do not edit manually!
2 |
3 | package csv
4 |
5 | import (
6 | . "github.com/candid82/joker/core"
7 | )
8 |
9 | var __csv_seq__P ProcFn = __csv_seq_
10 | var csv_seq_ Proc = Proc{Fn: __csv_seq__P, Name: "csv_seq_", Package: "std/csv"}
11 |
12 | func __csv_seq_(_args []Object) Object {
13 | _c := len(_args)
14 | switch {
15 | case _c == 1:
16 | rdr := ExtractObject(_args, 0)
17 | _res := csvSeqOpts(rdr, EmptyArrayMap())
18 | return _res
19 |
20 | case _c == 2:
21 | rdr := ExtractObject(_args, 0)
22 | opts := ExtractMap(_args, 1)
23 | _res := csvSeqOpts(rdr, opts)
24 | return _res
25 |
26 | default:
27 | PanicArity(_c)
28 | }
29 | return NIL
30 | }
31 |
32 | var __write__P ProcFn = __write_
33 | var write_ Proc = Proc{Fn: __write__P, Name: "write_", Package: "std/csv"}
34 |
35 | func __write_(_args []Object) Object {
36 | _c := len(_args)
37 | switch {
38 | case _c == 2:
39 | f := ExtractIOWriter(_args, 0)
40 | data := ExtractSeqable(_args, 1)
41 | _res := write(f, data, EmptyArrayMap())
42 | return _res
43 |
44 | case _c == 3:
45 | f := ExtractIOWriter(_args, 0)
46 | data := ExtractSeqable(_args, 1)
47 | opts := ExtractMap(_args, 2)
48 | _res := write(f, data, opts)
49 | return _res
50 |
51 | default:
52 | PanicArity(_c)
53 | }
54 | return NIL
55 | }
56 |
57 | var __write_string__P ProcFn = __write_string_
58 | var write_string_ Proc = Proc{Fn: __write_string__P, Name: "write_string_", Package: "std/csv"}
59 |
60 | func __write_string_(_args []Object) Object {
61 | _c := len(_args)
62 | switch {
63 | case _c == 1:
64 | data := ExtractSeqable(_args, 0)
65 | _res := writeString(data, EmptyArrayMap())
66 | return MakeString(_res)
67 |
68 | case _c == 2:
69 | data := ExtractSeqable(_args, 0)
70 | opts := ExtractMap(_args, 1)
71 | _res := writeString(data, opts)
72 | return MakeString(_res)
73 |
74 | default:
75 | PanicArity(_c)
76 | }
77 | return NIL
78 | }
79 |
80 | func Init() {
81 |
82 | InternsOrThunks()
83 | }
84 |
85 | var csvNamespace = GLOBAL_ENV.EnsureSymbolIsLib(MakeSymbol("joker.csv"))
86 |
87 | func init() {
88 | csvNamespace.Lazy = Init
89 | }
90 |
--------------------------------------------------------------------------------
/std/filepath/filepath_native.go:
--------------------------------------------------------------------------------
1 | package filepath
2 |
3 | import (
4 | "os"
5 | "path/filepath"
6 |
7 | . "github.com/candid82/joker/core"
8 | )
9 |
10 | func fileSeq(root string) *ArrayVector {
11 | res := EmptyArrayVector()
12 | filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
13 | PanicOnErr(err)
14 | m := FileInfoMap(path, info)
15 | res.Append(m)
16 | return nil
17 | })
18 | return res
19 | }
20 |
--------------------------------------------------------------------------------
/std/fn.tmpl:
--------------------------------------------------------------------------------
1 | var __{goName}_P ProcFn = __{goName}
2 | var {goName} Proc = Proc{Fn: __{goName}_P, Name: "{goName}", Package: "std/{pkg}"}
3 |
4 | func __{goName}(_args []Object) Object {
5 | _c := len(_args)
6 | switch {
7 | {arities}
8 | default:
9 | PanicArity(_c)
10 | }
11 | return NIL
12 | }
13 |
--------------------------------------------------------------------------------
/std/hex.joke:
--------------------------------------------------------------------------------
1 | (ns ^{:go-imports ["encoding/hex"]
2 | :doc "Implements hexadecimal encoding and decoding."}
3 | hex)
4 |
5 | (defn ^String decode-string
6 | "Returns the bytes represented by the hexadecimal string s."
7 | {:added "1.0"
8 | :go "! t, err := hex.DecodeString(s); PanicOnErr(err); _res := string(t)"}
9 | [^String s])
10 |
11 | (defn ^String encode-string
12 | "Returns the hexadecimal encoding of s."
13 | {:added "1.0"
14 | :go "hex.EncodeToString([]byte(s))"}
15 | [^String s])
16 |
--------------------------------------------------------------------------------
/std/hex/a_hex.go:
--------------------------------------------------------------------------------
1 | // This file is generated by generate-std.joke script. Do not edit manually!
2 |
3 | package hex
4 |
5 | import (
6 | "encoding/hex"
7 | . "github.com/candid82/joker/core"
8 | )
9 |
10 | var __decode_string__P ProcFn = __decode_string_
11 | var decode_string_ Proc = Proc{Fn: __decode_string__P, Name: "decode_string_", Package: "std/hex"}
12 |
13 | func __decode_string_(_args []Object) Object {
14 | _c := len(_args)
15 | switch {
16 | case _c == 1:
17 | s := ExtractString(_args, 0)
18 | t, err := hex.DecodeString(s)
19 | PanicOnErr(err)
20 | _res := string(t)
21 | return MakeString(_res)
22 |
23 | default:
24 | PanicArity(_c)
25 | }
26 | return NIL
27 | }
28 |
29 | var __encode_string__P ProcFn = __encode_string_
30 | var encode_string_ Proc = Proc{Fn: __encode_string__P, Name: "encode_string_", Package: "std/hex"}
31 |
32 | func __encode_string_(_args []Object) Object {
33 | _c := len(_args)
34 | switch {
35 | case _c == 1:
36 | s := ExtractString(_args, 0)
37 | _res := hex.EncodeToString([]byte(s))
38 | return MakeString(_res)
39 |
40 | default:
41 | PanicArity(_c)
42 | }
43 | return NIL
44 | }
45 |
46 | func Init() {
47 |
48 | InternsOrThunks()
49 | }
50 |
51 | var hexNamespace = GLOBAL_ENV.EnsureSymbolIsLib(MakeSymbol("joker.hex"))
52 |
53 | func init() {
54 | hexNamespace.Lazy = Init
55 | }
56 |
--------------------------------------------------------------------------------
/std/hex/a_hex_slow_init.go:
--------------------------------------------------------------------------------
1 | // This file is generated by generate-std.joke script. Do not edit manually!
2 |
3 | package hex
4 |
5 | import (
6 | "fmt"
7 | . "github.com/candid82/joker/core"
8 | "os"
9 | )
10 |
11 | func InternsOrThunks() {
12 | if VerbosityLevel > 0 {
13 | fmt.Fprintln(os.Stderr, "Lazily running slow version of hex.InternsOrThunks().")
14 | }
15 | hexNamespace.ResetMeta(MakeMeta(nil, `Implements hexadecimal encoding and decoding.`, "1.0"))
16 |
17 | hexNamespace.InternVar("decode-string", decode_string_,
18 | MakeMeta(
19 | NewListFrom(NewVectorFrom(MakeSymbol("s"))),
20 | `Returns the bytes represented by the hexadecimal string s.`, "1.0").Plus(MakeKeyword("tag"), String{S: "String"}))
21 |
22 | hexNamespace.InternVar("encode-string", encode_string_,
23 | MakeMeta(
24 | NewListFrom(NewVectorFrom(MakeSymbol("s"))),
25 | `Returns the hexadecimal encoding of s.`, "1.0").Plus(MakeKeyword("tag"), String{S: "String"}))
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/std/html.joke:
--------------------------------------------------------------------------------
1 | (ns ^{:go-imports ["html"]
2 | :doc "Provides functions for escaping and unescaping HTML text."}
3 | html)
4 |
5 | (defn ^String escape
6 | "Escapes special characters like < to become <. It escapes only five such characters: <, >, &, ' and \"."
7 | {:added "1.0"
8 | :go "html.EscapeString(s)"}
9 | [^String s])
10 |
11 | (defn ^String unescape
12 | "Unescapes entities like < to become <."
13 | {:added "1.0"
14 | :go "html.UnescapeString(s)"}
15 | [^String s])
16 |
--------------------------------------------------------------------------------
/std/html/a_html.go:
--------------------------------------------------------------------------------
1 | // This file is generated by generate-std.joke script. Do not edit manually!
2 |
3 | package html
4 |
5 | import (
6 | . "github.com/candid82/joker/core"
7 | "html"
8 | )
9 |
10 | var __escape__P ProcFn = __escape_
11 | var escape_ Proc = Proc{Fn: __escape__P, Name: "escape_", Package: "std/html"}
12 |
13 | func __escape_(_args []Object) Object {
14 | _c := len(_args)
15 | switch {
16 | case _c == 1:
17 | s := ExtractString(_args, 0)
18 | _res := html.EscapeString(s)
19 | return MakeString(_res)
20 |
21 | default:
22 | PanicArity(_c)
23 | }
24 | return NIL
25 | }
26 |
27 | var __unescape__P ProcFn = __unescape_
28 | var unescape_ Proc = Proc{Fn: __unescape__P, Name: "unescape_", Package: "std/html"}
29 |
30 | func __unescape_(_args []Object) Object {
31 | _c := len(_args)
32 | switch {
33 | case _c == 1:
34 | s := ExtractString(_args, 0)
35 | _res := html.UnescapeString(s)
36 | return MakeString(_res)
37 |
38 | default:
39 | PanicArity(_c)
40 | }
41 | return NIL
42 | }
43 |
44 | func Init() {
45 |
46 | InternsOrThunks()
47 | }
48 |
49 | var htmlNamespace = GLOBAL_ENV.EnsureSymbolIsLib(MakeSymbol("joker.html"))
50 |
51 | func init() {
52 | htmlNamespace.Lazy = Init
53 | }
54 |
--------------------------------------------------------------------------------
/std/html/a_html_fast_init.go:
--------------------------------------------------------------------------------
1 | // This file is generated by generate-std.joke script. Do not edit manually!
2 |
3 | //go:build !gen_code
4 | // +build !gen_code
5 |
6 | package html
7 |
8 | import (
9 | "fmt"
10 | . "github.com/candid82/joker/core"
11 | "os"
12 | )
13 |
14 | func InternsOrThunks() {
15 | if VerbosityLevel > 0 {
16 | fmt.Fprintln(os.Stderr, "Lazily running fast version of html.InternsOrThunks().")
17 | }
18 | STD_thunk_html_escape__var = __escape_
19 | STD_thunk_html_unescape__var = __unescape_
20 | }
21 |
--------------------------------------------------------------------------------
/std/html/a_html_slow_init.go:
--------------------------------------------------------------------------------
1 | // This file is generated by generate-std.joke script. Do not edit manually!
2 |
3 | //go:build gen_code
4 | // +build gen_code
5 |
6 | package html
7 |
8 | import (
9 | "fmt"
10 | . "github.com/candid82/joker/core"
11 | "os"
12 | )
13 |
14 | func InternsOrThunks() {
15 | if VerbosityLevel > 0 {
16 | fmt.Fprintln(os.Stderr, "Lazily running slow version of html.InternsOrThunks().")
17 | }
18 | htmlNamespace.ResetMeta(MakeMeta(nil, `Provides functions for escaping and unescaping HTML text.`, "1.0"))
19 |
20 | htmlNamespace.InternVar("escape", escape_,
21 | MakeMeta(
22 | NewListFrom(NewVectorFrom(MakeSymbol("s"))),
23 | `Escapes special characters like < to become <. It escapes only five such characters: <, >, &, ' and ".`, "1.0").Plus(MakeKeyword("tag"), String{S: "String"}))
24 |
25 | htmlNamespace.InternVar("unescape", unescape_,
26 | MakeMeta(
27 | NewListFrom(NewVectorFrom(MakeSymbol("s"))),
28 | `Unescapes entities like < to become <.`, "1.0").Plus(MakeKeyword("tag"), String{S: "String"}))
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/std/http.joke:
--------------------------------------------------------------------------------
1 | (ns ^{:go-imports []
2 | :doc "Provides HTTP client and server implementations."}
3 | http)
4 |
5 | (defn send
6 | "Sends an HTTP request and returns an HTTP response.
7 | request is a map with the following keys:
8 | - url (string)
9 | - method (string, keyword or symbol, defaults to :get)
10 | - body (string)
11 | - host (string, overrides Host header if provided)
12 | - headers (map).
13 | All keys except for url are optional.
14 | response is a map with the following keys:
15 | - status (int)
16 | - body (string)
17 | - headers (map)
18 | - content-length (int)"
19 | {:added "1.0"
20 | :go "sendRequest(request)"}
21 | [^Map request])
22 |
23 | (defn start-server
24 | "Starts HTTP server on the TCP network address addr."
25 | {:added "1.0"
26 | :go "startServer(addr, handler)"}
27 | [^String addr ^Callable handler])
28 |
29 | (defn start-file-server
30 | "Starts HTTP server on the TCP network address addr that
31 | serves HTTP requests with the contents of the file system rooted at root."
32 | {:added "1.0"
33 | :go "startFileServer(addr, root)"}
34 | [^String addr ^String root])
35 |
--------------------------------------------------------------------------------
/std/http/a_http.go:
--------------------------------------------------------------------------------
1 | // This file is generated by generate-std.joke script. Do not edit manually!
2 |
3 | package http
4 |
5 | import (
6 | . "github.com/candid82/joker/core"
7 | )
8 |
9 | var __send__P ProcFn = __send_
10 | var send_ Proc = Proc{Fn: __send__P, Name: "send_", Package: "std/http"}
11 |
12 | func __send_(_args []Object) Object {
13 | _c := len(_args)
14 | switch {
15 | case _c == 1:
16 | request := ExtractMap(_args, 0)
17 | _res := sendRequest(request)
18 | return _res
19 |
20 | default:
21 | PanicArity(_c)
22 | }
23 | return NIL
24 | }
25 |
26 | var __start_file_server__P ProcFn = __start_file_server_
27 | var start_file_server_ Proc = Proc{Fn: __start_file_server__P, Name: "start_file_server_", Package: "std/http"}
28 |
29 | func __start_file_server_(_args []Object) Object {
30 | _c := len(_args)
31 | switch {
32 | case _c == 2:
33 | addr := ExtractString(_args, 0)
34 | root := ExtractString(_args, 1)
35 | _res := startFileServer(addr, root)
36 | return _res
37 |
38 | default:
39 | PanicArity(_c)
40 | }
41 | return NIL
42 | }
43 |
44 | var __start_server__P ProcFn = __start_server_
45 | var start_server_ Proc = Proc{Fn: __start_server__P, Name: "start_server_", Package: "std/http"}
46 |
47 | func __start_server_(_args []Object) Object {
48 | _c := len(_args)
49 | switch {
50 | case _c == 2:
51 | addr := ExtractString(_args, 0)
52 | handler := ExtractCallable(_args, 1)
53 | _res := startServer(addr, handler)
54 | return _res
55 |
56 | default:
57 | PanicArity(_c)
58 | }
59 | return NIL
60 | }
61 |
62 | func Init() {
63 |
64 | InternsOrThunks()
65 | }
66 |
67 | var httpNamespace = GLOBAL_ENV.EnsureSymbolIsLib(MakeSymbol("joker.http"))
68 |
69 | func init() {
70 | httpNamespace.Lazy = Init
71 | }
72 |
--------------------------------------------------------------------------------
/std/http/a_http_slow_init.go:
--------------------------------------------------------------------------------
1 | // This file is generated by generate-std.joke script. Do not edit manually!
2 |
3 | package http
4 |
5 | import (
6 | "fmt"
7 | . "github.com/candid82/joker/core"
8 | "os"
9 | )
10 |
11 | func InternsOrThunks() {
12 | if VerbosityLevel > 0 {
13 | fmt.Fprintln(os.Stderr, "Lazily running slow version of http.InternsOrThunks().")
14 | }
15 | httpNamespace.ResetMeta(MakeMeta(nil, `Provides HTTP client and server implementations.`, "1.0"))
16 |
17 | httpNamespace.InternVar("send", send_,
18 | MakeMeta(
19 | NewListFrom(NewVectorFrom(MakeSymbol("request"))),
20 | `Sends an HTTP request and returns an HTTP response.
21 | request is a map with the following keys:
22 | - url (string)
23 | - method (string, keyword or symbol, defaults to :get)
24 | - body (string)
25 | - host (string, overrides Host header if provided)
26 | - headers (map).
27 | All keys except for url are optional.
28 | response is a map with the following keys:
29 | - status (int)
30 | - body (string)
31 | - headers (map)
32 | - content-length (int)`, "1.0"))
33 |
34 | httpNamespace.InternVar("start-file-server", start_file_server_,
35 | MakeMeta(
36 | NewListFrom(NewVectorFrom(MakeSymbol("addr"), MakeSymbol("root"))),
37 | `Starts HTTP server on the TCP network address addr that
38 | serves HTTP requests with the contents of the file system rooted at root.`, "1.0"))
39 |
40 | httpNamespace.InternVar("start-server", start_server_,
41 | MakeMeta(
42 | NewListFrom(NewVectorFrom(MakeSymbol("addr"), MakeSymbol("handler"))),
43 | `Starts HTTP server on the TCP network address addr.`, "1.0"))
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/std/intern.tmpl:
--------------------------------------------------------------------------------
1 | {nsName}Namespace.InternVar("{fnName}", {goName},
2 | MakeMeta(
3 | {args},
4 | {fnDocstring}, "{added}"){moreMeta})
5 |
--------------------------------------------------------------------------------
/std/io.joke:
--------------------------------------------------------------------------------
1 | (ns ^{:go-imports ["io"]
2 | :doc "Provides basic interfaces to I/O primitives."}
3 | io)
4 |
5 | (defn ^Int copy
6 | "Copies from src to dst until either EOF is reached on src or an error occurs.
7 | Returns the number of bytes copied or throws an error.
8 | src must be IOReader, e.g. as returned by joker.os/open.
9 | dst must be IOWriter, e.g. as returned by joker.os/create."
10 | {:added "1.0"
11 | :go "! n, err := io.Copy(dst, src); PanicOnErr(err); _res := int(n)"} ;; TODO: 32-bit issue
12 | [^IOWriter dst ^IOReader src])
13 |
14 | (defn pipe
15 | "Pipe creates a synchronous in-memory pipe. It can be used to connect code expecting an IOReader
16 | with code expecting an IOWriter.
17 | Returns a vector [reader, writer]."
18 | {:added "1.0"
19 | :go "pipe()"}
20 | [])
21 |
22 | (defn close
23 | "Closes f (IOWriter, IOReader, or File) if possible. Otherwise throws an error."
24 | {:added "1.0"
25 | :go "close(f)"}
26 | [^Object f])
27 |
28 | (defn ^String read
29 | "Reads up to n bytes from IOReader r and returns a string of the read bytes.
30 | May return a shorter (or blank) string if EOF is encountered."
31 | {:added "1.3.6"
32 | :go "read(r, n)"}
33 | ^String [^IOReader r ^Int n])
34 |
--------------------------------------------------------------------------------
/std/io/a_io.go:
--------------------------------------------------------------------------------
1 | // This file is generated by generate-std.joke script. Do not edit manually!
2 |
3 | package io
4 |
5 | import (
6 | . "github.com/candid82/joker/core"
7 | "io"
8 | )
9 |
10 | var __close__P ProcFn = __close_
11 | var close_ Proc = Proc{Fn: __close__P, Name: "close_", Package: "std/io"}
12 |
13 | func __close_(_args []Object) Object {
14 | _c := len(_args)
15 | switch {
16 | case _c == 1:
17 | f := ExtractObject(_args, 0)
18 | _res := close(f)
19 | return _res
20 |
21 | default:
22 | PanicArity(_c)
23 | }
24 | return NIL
25 | }
26 |
27 | var __copy__P ProcFn = __copy_
28 | var copy_ Proc = Proc{Fn: __copy__P, Name: "copy_", Package: "std/io"}
29 |
30 | func __copy_(_args []Object) Object {
31 | _c := len(_args)
32 | switch {
33 | case _c == 2:
34 | dst := ExtractIOWriter(_args, 0)
35 | src := ExtractIOReader(_args, 1)
36 | n, err := io.Copy(dst, src)
37 | PanicOnErr(err)
38 | _res := int(n)
39 | return MakeInt(_res)
40 |
41 | default:
42 | PanicArity(_c)
43 | }
44 | return NIL
45 | }
46 |
47 | var __pipe__P ProcFn = __pipe_
48 | var pipe_ Proc = Proc{Fn: __pipe__P, Name: "pipe_", Package: "std/io"}
49 |
50 | func __pipe_(_args []Object) Object {
51 | _c := len(_args)
52 | switch {
53 | case _c == 0:
54 | _res := pipe()
55 | return _res
56 |
57 | default:
58 | PanicArity(_c)
59 | }
60 | return NIL
61 | }
62 |
63 | var __read__P ProcFn = __read_
64 | var read_ Proc = Proc{Fn: __read__P, Name: "read_", Package: "std/io"}
65 |
66 | func __read_(_args []Object) Object {
67 | _c := len(_args)
68 | switch {
69 | case _c == 2:
70 | r := ExtractIOReader(_args, 0)
71 | n := ExtractInt(_args, 1)
72 | _res := read(r, n)
73 | return MakeString(_res)
74 |
75 | default:
76 | PanicArity(_c)
77 | }
78 | return NIL
79 | }
80 |
81 | func Init() {
82 |
83 | InternsOrThunks()
84 | }
85 |
86 | var ioNamespace = GLOBAL_ENV.EnsureSymbolIsLib(MakeSymbol("joker.io"))
87 |
88 | func init() {
89 | ioNamespace.Lazy = Init
90 | }
91 |
--------------------------------------------------------------------------------
/std/io/a_io_slow_init.go:
--------------------------------------------------------------------------------
1 | // This file is generated by generate-std.joke script. Do not edit manually!
2 |
3 | package io
4 |
5 | import (
6 | "fmt"
7 | . "github.com/candid82/joker/core"
8 | "os"
9 | )
10 |
11 | func InternsOrThunks() {
12 | if VerbosityLevel > 0 {
13 | fmt.Fprintln(os.Stderr, "Lazily running slow version of io.InternsOrThunks().")
14 | }
15 | ioNamespace.ResetMeta(MakeMeta(nil, `Provides basic interfaces to I/O primitives.`, "1.0"))
16 |
17 | ioNamespace.InternVar("close", close_,
18 | MakeMeta(
19 | NewListFrom(NewVectorFrom(MakeSymbol("f"))),
20 | `Closes f (IOWriter, IOReader, or File) if possible. Otherwise throws an error.`, "1.0"))
21 |
22 | ioNamespace.InternVar("copy", copy_,
23 | MakeMeta(
24 | NewListFrom(NewVectorFrom(MakeSymbol("dst"), MakeSymbol("src"))),
25 | `Copies from src to dst until either EOF is reached on src or an error occurs.
26 | Returns the number of bytes copied or throws an error.
27 | src must be IOReader, e.g. as returned by joker.os/open.
28 | dst must be IOWriter, e.g. as returned by joker.os/create.`, "1.0").Plus(MakeKeyword("tag"), String{S: "Int"}))
29 |
30 | ioNamespace.InternVar("pipe", pipe_,
31 | MakeMeta(
32 | NewListFrom(NewVectorFrom()),
33 | `Pipe creates a synchronous in-memory pipe. It can be used to connect code expecting an IOReader
34 | with code expecting an IOWriter.
35 | Returns a vector [reader, writer].`, "1.0"))
36 |
37 | ioNamespace.InternVar("read", read_,
38 | MakeMeta(
39 | NewListFrom(NewVectorFrom(MakeSymbol("r"), MakeSymbol("n"))),
40 | `Reads up to n bytes from IOReader r and returns a string of the read bytes.
41 | May return a shorter (or blank) string if EOF is encountered.`, "1.3.6").Plus(MakeKeyword("tag"), String{S: "String"}))
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/std/io/io_native.go:
--------------------------------------------------------------------------------
1 | package io
2 |
3 | import (
4 | . "github.com/candid82/joker/core"
5 | "io"
6 | )
7 |
8 | func pipe() Object {
9 | r, w := io.Pipe()
10 | res := EmptyVector()
11 | res = res.Conjoin(MakeIOReader(r))
12 | res = res.Conjoin(MakeIOWriter(w))
13 | return res
14 | }
15 |
16 | func close(f Object) Nil {
17 | if c, ok := f.(io.Closer); ok {
18 | if err := c.Close(); err != nil {
19 | panic(RT.NewError(err.Error()))
20 | }
21 | return NIL
22 | }
23 | panic(RT.NewError("Object is not closable: " + f.ToString(false)))
24 | }
25 |
26 | func read(r io.Reader, n int) string {
27 | buf := make([]byte, n)
28 | cnt, err := r.Read(buf)
29 | if err != io.EOF {
30 | PanicOnErr(err)
31 | }
32 | return string(buf[:cnt])
33 | }
34 |
--------------------------------------------------------------------------------
/std/json.joke:
--------------------------------------------------------------------------------
1 | (ns ^{:go-imports []
2 | :doc "Implements encoding and decoding of JSON as defined in RFC 4627."}
3 | json)
4 |
5 | (defn read-string
6 | "Parses the JSON-encoded data and return the result as a Joker value.
7 | Optional opts map may have the following keys:
8 | :keywords? - if true, JSON keys will be converted from strings to keywords."
9 | {:added "1.0"
10 | :go {1 "readString(s, nil)"
11 | 2 "readString(s, opts)"}}
12 | ([^String s])
13 | ([^String s ^Map opts]))
14 |
15 | (defn write-string
16 | "Returns the JSON encoding of v."
17 | {:added "1.0"
18 | :go "writeString(v)"}
19 | [^Object v])
20 |
21 | (defn json-seq
22 | "Returns the json records from rdr as a lazy sequence.
23 | rdr must be a string or implement io.Reader.
24 | Optional opts map may have the following keys:
25 | :keywords? - if true, JSON keys will be converted from strings to keywords."
26 | {:added "1.0"
27 | :go {1 "jsonSeqOpts(rdr, EmptyArrayMap())"
28 | 2 "jsonSeqOpts(rdr, opts)"}}
29 | ([^Object rdr])
30 | ([^Object rdr ^Map opts]))
31 |
--------------------------------------------------------------------------------
/std/json/a_json.go:
--------------------------------------------------------------------------------
1 | // This file is generated by generate-std.joke script. Do not edit manually!
2 |
3 | package json
4 |
5 | import (
6 | . "github.com/candid82/joker/core"
7 | )
8 |
9 | var __json_seq__P ProcFn = __json_seq_
10 | var json_seq_ Proc = Proc{Fn: __json_seq__P, Name: "json_seq_", Package: "std/json"}
11 |
12 | func __json_seq_(_args []Object) Object {
13 | _c := len(_args)
14 | switch {
15 | case _c == 1:
16 | rdr := ExtractObject(_args, 0)
17 | _res := jsonSeqOpts(rdr, EmptyArrayMap())
18 | return _res
19 |
20 | case _c == 2:
21 | rdr := ExtractObject(_args, 0)
22 | opts := ExtractMap(_args, 1)
23 | _res := jsonSeqOpts(rdr, opts)
24 | return _res
25 |
26 | default:
27 | PanicArity(_c)
28 | }
29 | return NIL
30 | }
31 |
32 | var __read_string__P ProcFn = __read_string_
33 | var read_string_ Proc = Proc{Fn: __read_string__P, Name: "read_string_", Package: "std/json"}
34 |
35 | func __read_string_(_args []Object) Object {
36 | _c := len(_args)
37 | switch {
38 | case _c == 1:
39 | s := ExtractString(_args, 0)
40 | _res := readString(s, nil)
41 | return _res
42 |
43 | case _c == 2:
44 | s := ExtractString(_args, 0)
45 | opts := ExtractMap(_args, 1)
46 | _res := readString(s, opts)
47 | return _res
48 |
49 | default:
50 | PanicArity(_c)
51 | }
52 | return NIL
53 | }
54 |
55 | var __write_string__P ProcFn = __write_string_
56 | var write_string_ Proc = Proc{Fn: __write_string__P, Name: "write_string_", Package: "std/json"}
57 |
58 | func __write_string_(_args []Object) Object {
59 | _c := len(_args)
60 | switch {
61 | case _c == 1:
62 | v := ExtractObject(_args, 0)
63 | _res := writeString(v)
64 | return _res
65 |
66 | default:
67 | PanicArity(_c)
68 | }
69 | return NIL
70 | }
71 |
72 | func Init() {
73 |
74 | InternsOrThunks()
75 | }
76 |
77 | var jsonNamespace = GLOBAL_ENV.EnsureSymbolIsLib(MakeSymbol("joker.json"))
78 |
79 | func init() {
80 | jsonNamespace.Lazy = Init
81 | }
82 |
--------------------------------------------------------------------------------
/std/json/a_json_slow_init.go:
--------------------------------------------------------------------------------
1 | // This file is generated by generate-std.joke script. Do not edit manually!
2 |
3 | package json
4 |
5 | import (
6 | "fmt"
7 | . "github.com/candid82/joker/core"
8 | "os"
9 | )
10 |
11 | func InternsOrThunks() {
12 | if VerbosityLevel > 0 {
13 | fmt.Fprintln(os.Stderr, "Lazily running slow version of json.InternsOrThunks().")
14 | }
15 | jsonNamespace.ResetMeta(MakeMeta(nil, `Implements encoding and decoding of JSON as defined in RFC 4627.`, "1.0"))
16 |
17 | jsonNamespace.InternVar("json-seq", json_seq_,
18 | MakeMeta(
19 | NewListFrom(NewVectorFrom(MakeSymbol("rdr")), NewVectorFrom(MakeSymbol("rdr"), MakeSymbol("opts"))),
20 | `Returns the json records from rdr as a lazy sequence.
21 | rdr must be a string or implement io.Reader.
22 | Optional opts map may have the following keys:
23 | :keywords? - if true, JSON keys will be converted from strings to keywords.`, "1.0"))
24 |
25 | jsonNamespace.InternVar("read-string", read_string_,
26 | MakeMeta(
27 | NewListFrom(NewVectorFrom(MakeSymbol("s")), NewVectorFrom(MakeSymbol("s"), MakeSymbol("opts"))),
28 | `Parses the JSON-encoded data and return the result as a Joker value.
29 | Optional opts map may have the following keys:
30 | :keywords? - if true, JSON keys will be converted from strings to keywords.`, "1.0"))
31 |
32 | jsonNamespace.InternVar("write-string", write_string_,
33 | MakeMeta(
34 | NewListFrom(NewVectorFrom(MakeSymbol("v"))),
35 | `Returns the JSON encoding of v.`, "1.0"))
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/std/markdown.joke:
--------------------------------------------------------------------------------
1 | (ns ^{:go-imports []
2 | :doc "Implements GitHub Flavored Markdown rendering."}
3 | markdown)
4 |
5 | (defn ^String convert-string
6 | "Returns the HTML rendering of Markdown string s.
7 | opts is an optional map of boolean rendering options (all default to true)
8 |
9 | :with-hard-wraps? - Render newlines as .
10 | :with-xhtml? - Render as XHTML.
11 | :with-unsafe? - When false, all raw html will be omitted from the output. When true html is passed through unchanged.
12 | "
13 | {:added "1.0"
14 | :go {1 "convertString(s)"
15 | 2 "convertStringOpts(s, opts)"}}
16 | ([^String s])
17 | ([^String s ^Map opts]))
18 |
--------------------------------------------------------------------------------
/std/markdown/a_markdown.go:
--------------------------------------------------------------------------------
1 | // This file is generated by generate-std.joke script. Do not edit manually!
2 |
3 | package markdown
4 |
5 | import (
6 | . "github.com/candid82/joker/core"
7 | )
8 |
9 | var __convert_string__P ProcFn = __convert_string_
10 | var convert_string_ Proc = Proc{Fn: __convert_string__P, Name: "convert_string_", Package: "std/markdown"}
11 |
12 | func __convert_string_(_args []Object) Object {
13 | _c := len(_args)
14 | switch {
15 | case _c == 1:
16 | s := ExtractString(_args, 0)
17 | _res := convertString(s)
18 | return MakeString(_res)
19 |
20 | case _c == 2:
21 | s := ExtractString(_args, 0)
22 | opts := ExtractMap(_args, 1)
23 | _res := convertStringOpts(s, opts)
24 | return MakeString(_res)
25 |
26 | default:
27 | PanicArity(_c)
28 | }
29 | return NIL
30 | }
31 |
32 | func Init() {
33 |
34 | InternsOrThunks()
35 | }
36 |
37 | var markdownNamespace = GLOBAL_ENV.EnsureSymbolIsLib(MakeSymbol("joker.markdown"))
38 |
39 | func init() {
40 | markdownNamespace.Lazy = Init
41 | }
42 |
--------------------------------------------------------------------------------
/std/markdown/a_markdown_slow_init.go:
--------------------------------------------------------------------------------
1 | // This file is generated by generate-std.joke script. Do not edit manually!
2 |
3 | package markdown
4 |
5 | import (
6 | "fmt"
7 | . "github.com/candid82/joker/core"
8 | "os"
9 | )
10 |
11 | func InternsOrThunks() {
12 | if VerbosityLevel > 0 {
13 | fmt.Fprintln(os.Stderr, "Lazily running slow version of markdown.InternsOrThunks().")
14 | }
15 | markdownNamespace.ResetMeta(MakeMeta(nil, `Implements GitHub Flavored Markdown rendering.`, "1.0"))
16 |
17 | markdownNamespace.InternVar("convert-string", convert_string_,
18 | MakeMeta(
19 | NewListFrom(NewVectorFrom(MakeSymbol("s")), NewVectorFrom(MakeSymbol("s"), MakeSymbol("opts"))),
20 | `Returns the HTML rendering of Markdown string s.
21 | opts is an optional map of boolean rendering options (all default to true)
22 |
23 | :with-hard-wraps? - Render newlines as .
24 | :with-xhtml? - Render as XHTML.
25 | :with-unsafe? - When false, all raw html will be omitted from the output. When true html is passed through unchanged.
26 | `, "1.0").Plus(MakeKeyword("tag"), String{S: "String"}))
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/std/markdown/markdown_native.go:
--------------------------------------------------------------------------------
1 | package markdown
2 |
3 | import (
4 | "bytes"
5 |
6 | "github.com/yuin/goldmark"
7 | "github.com/yuin/goldmark/extension"
8 | "github.com/yuin/goldmark/parser"
9 | "github.com/yuin/goldmark/renderer"
10 | "github.com/yuin/goldmark/renderer/html"
11 |
12 | . "github.com/candid82/joker/core"
13 | )
14 |
15 | func convertString(source string) string {
16 | return convert(source, []renderer.Option{html.WithHardWraps(), html.WithXHTML(), html.WithUnsafe()})
17 | }
18 |
19 | func getKeywordFlag(opts Map, name string, def bool) bool {
20 | ok, entry := opts.Get(MakeKeyword(name))
21 | if !ok {
22 | return def
23 | }
24 | return EnsureObjectIsBoolean(entry, name+": %s").B
25 | }
26 |
27 | func convertStringOpts(source string, options Map) string {
28 | renderOptions := []renderer.Option{}
29 | if flag := getKeywordFlag(options, "with-hard-wraps?", true); flag {
30 | renderOptions = append(renderOptions, html.WithHardWraps())
31 | }
32 | if flag := getKeywordFlag(options, "with-xhtml?", true); flag {
33 | renderOptions = append(renderOptions, html.WithXHTML())
34 | }
35 | if flag := getKeywordFlag(options, "with-unsafe?", true); flag {
36 | renderOptions = append(renderOptions, html.WithUnsafe())
37 | }
38 | return convert(source, renderOptions)
39 | }
40 |
41 | func convert(source string, renderOptions []renderer.Option) string {
42 | md := goldmark.New(
43 | goldmark.WithExtensions(
44 | extension.GFM,
45 | extension.Table,
46 | extension.DefinitionList,
47 | extension.Footnote,
48 | extension.Typographer,
49 | ),
50 | goldmark.WithParserOptions(
51 | parser.WithAutoHeadingID(),
52 | ),
53 | goldmark.WithRendererOptions(renderOptions...),
54 | )
55 | var buf bytes.Buffer
56 | if err := md.Convert([]byte(source), &buf); err != nil {
57 | panic(err)
58 | }
59 | return buf.String()
60 | }
61 |
--------------------------------------------------------------------------------
/std/math/math_native.go:
--------------------------------------------------------------------------------
1 | package math
2 |
3 | import (
4 | "fmt"
5 | "math"
6 | "math/big"
7 |
8 | . "github.com/candid82/joker/core"
9 | )
10 |
11 | func modf(x float64) Object {
12 | i, f := math.Modf(x)
13 | res := EmptyVector()
14 | res = res.Conjoin(MakeDouble(i))
15 | res = res.Conjoin(MakeDouble(f))
16 | return res
17 | }
18 |
19 | func precision(x Number) *big.Int {
20 | switch n := x.(type) {
21 | case Precision:
22 | return n.Precision()
23 | default:
24 | panic(RT.NewArgTypeError(0, x, "BigInt, BigFloat, Int, or Double"))
25 | }
26 | }
27 |
28 | func setPrecision(prec Number, n *big.Float) *big.Float {
29 | p := prec.Int().I
30 | if p < 0 {
31 | panic(RT.NewError(fmt.Sprintf("prec must be a non-negative Int, but is %d", p)))
32 | }
33 | return big.NewFloat(0).Copy(n).SetPrec(uint(p))
34 | }
35 |
--------------------------------------------------------------------------------
/std/os/sh.go:
--------------------------------------------------------------------------------
1 | //go:build !plan9
2 | // +build !plan9
3 |
4 | package os
5 |
6 | import (
7 | "bytes"
8 | "io"
9 | "os/exec"
10 | "syscall"
11 |
12 | . "github.com/candid82/joker/core"
13 | )
14 |
15 | func sh(dir string, stdin io.Reader, stdout io.Writer, stderr io.Writer, name string, args []string) Object {
16 | cmd := exec.Command(name, args...)
17 | cmd.Dir = dir
18 | cmd.Stdin = stdin
19 |
20 | var stdoutBuffer, stderrBuffer bytes.Buffer
21 | if stdout != nil {
22 | cmd.Stdout = stdout
23 | } else {
24 | cmd.Stdout = &stdoutBuffer
25 | }
26 | if stderr != nil {
27 | cmd.Stderr = stderr
28 | } else {
29 | cmd.Stderr = &stderrBuffer
30 | }
31 |
32 | err := cmd.Start()
33 | PanicOnErr(err)
34 |
35 | RT.GIL.Unlock()
36 | err = cmd.Wait()
37 | RT.GIL.Lock()
38 |
39 | res := EmptyArrayMap()
40 | res.Add(MakeKeyword("success"), Boolean{B: err == nil})
41 |
42 | var exitCode int
43 | if err != nil {
44 | res.Add(MakeKeyword("err-msg"), String{S: err.Error()})
45 | if exiterr, ok := err.(*exec.ExitError); ok {
46 | ws := exiterr.Sys().(syscall.WaitStatus)
47 | exitCode = ws.ExitStatus()
48 | } else {
49 | exitCode = defaultFailedCode
50 | }
51 | } else {
52 | ws := cmd.ProcessState.Sys().(syscall.WaitStatus)
53 | exitCode = ws.ExitStatus()
54 | }
55 | res.Add(MakeKeyword("exit"), Int{I: exitCode})
56 | if stdout == nil {
57 | res.Add(MakeKeyword("out"), String{S: string(stdoutBuffer.Bytes())})
58 | }
59 | if stderr == nil {
60 | res.Add(MakeKeyword("err"), String{S: string(stderrBuffer.Bytes())})
61 | }
62 | return res
63 | }
64 |
--------------------------------------------------------------------------------
/std/os/sh_plan9.go:
--------------------------------------------------------------------------------
1 | package os
2 |
3 | import (
4 | "bytes"
5 | "io"
6 | "os/exec"
7 |
8 | . "github.com/candid82/joker/core"
9 | )
10 |
11 | func sh(dir string, stdin io.Reader, stdout io.Writer, stderr io.Writer, name string, args []string) Object {
12 | cmd := exec.Command(name, args...)
13 | cmd.Dir = dir
14 | cmd.Stdin = stdin
15 |
16 | var stdoutBuffer, stderrBuffer bytes.Buffer
17 | if stdout != nil {
18 | cmd.Stdout = stdout
19 | } else {
20 | cmd.Stdout = &stdoutBuffer
21 | }
22 | if stderr != nil {
23 | cmd.Stderr = stderr
24 | } else {
25 | cmd.Stderr = &stderrBuffer
26 | }
27 |
28 | err := cmd.Start()
29 | PanicOnErr(err)
30 |
31 | RT.GIL.Unlock()
32 | err = cmd.Wait()
33 | RT.GIL.Lock()
34 |
35 | res := EmptyArrayMap()
36 | res.Add(MakeKeyword("success"), Boolean{B: err == nil})
37 |
38 | var exitCode int
39 | if err != nil {
40 | res.Add(MakeKeyword("err-msg"), String{S: err.Error()})
41 | exitCode = defaultFailedCode
42 | } else {
43 | exitCode = 0
44 | }
45 | res.Add(MakeKeyword("exit"), Int{I: exitCode})
46 | if stdout == nil {
47 | res.Add(MakeKeyword("out"), String{S: string(stdoutBuffer.Bytes())})
48 | }
49 | if stderr == nil {
50 | res.Add(MakeKeyword("err"), String{S: string(stderrBuffer.Bytes())})
51 | }
52 | return res
53 | }
54 |
--------------------------------------------------------------------------------
/std/package-fast.tmpl:
--------------------------------------------------------------------------------
1 | // This file is generated by generate-std.joke script. Do not edit manually!
2 |
3 | //go:build !gen_code
4 | // +build !gen_code
5 |
6 | package {nsName}
7 |
8 | import (
9 | {imports}
10 | "fmt"
11 | "os"
12 | )
13 |
14 | func InternsOrThunks() {
15 | if VerbosityLevel > 0 {
16 | fmt.Fprintln(os.Stderr, "Lazily running fast version of {nsName}.InternsOrThunks().")
17 | }
18 | {thunks}
19 | }
20 |
--------------------------------------------------------------------------------
/std/package-slow.tmpl:
--------------------------------------------------------------------------------
1 | // This file is generated by generate-std.joke script. Do not edit manually!
2 |
3 | {maybeSlowOnly}
4 | package {nsName}
5 |
6 | import (
7 | {imports}
8 | "fmt"
9 | "os"
10 | )
11 |
12 | func InternsOrThunks() {
13 | if VerbosityLevel > 0 {
14 | fmt.Fprintln(os.Stderr, "Lazily running slow version of {nsName}.InternsOrThunks().")
15 | }
16 | {nsName}Namespace.ResetMeta(MakeMeta(nil, {nsDocstring}, "1.0"))
17 |
18 | {non-fn-interns}
19 | {fn-interns}
20 | }
21 |
--------------------------------------------------------------------------------
/std/package.tmpl:
--------------------------------------------------------------------------------
1 | // This file is generated by generate-std.joke script. Do not edit manually!
2 |
3 | package {nsName}
4 |
5 | import (
6 | {imports}
7 | )
8 |
9 | {non-fn-decls}
10 | {fn-decls}
11 | func Init() {
12 | {non-fn-inits}
13 | InternsOrThunks()
14 | }
15 |
16 | var {nsName}Namespace = GLOBAL_ENV.EnsureSymbolIsLib(MakeSymbol("joker.{nsFullName}"))
17 |
18 | func init() {
19 | {nsName}Namespace.Lazy = Init
20 | }
21 |
--------------------------------------------------------------------------------
/std/runtime.joke:
--------------------------------------------------------------------------------
1 | (ns ^{:go-imports ["runtime"]
2 | :doc "Provides access to Go and Joker runtime information."}
3 | runtime)
4 |
5 | (defn ^String go-root
6 | "Returns the GOROOT string (as returned by runtime/GOROOT())."
7 | {:added "1.0"
8 | :go "runtime.GOROOT()"}
9 | [])
10 |
11 | (defn ^String go-version
12 | "Returns the Go version string (as returned by runtime/Version())."
13 | {:added "1.0"
14 | :go "runtime.Version()"}
15 | [])
16 |
17 | (defn ^String joker-version
18 | "Returns the raw Joker version string (including the leading 'v',
19 | which joker.core/joker-version omits)."
20 | {:added "1.0"
21 | :go "VERSION"}
22 | [])
23 |
--------------------------------------------------------------------------------
/std/runtime/a_runtime.go:
--------------------------------------------------------------------------------
1 | // This file is generated by generate-std.joke script. Do not edit manually!
2 |
3 | package runtime
4 |
5 | import (
6 | . "github.com/candid82/joker/core"
7 | "runtime"
8 | )
9 |
10 | var __go_root__P ProcFn = __go_root_
11 | var go_root_ Proc = Proc{Fn: __go_root__P, Name: "go_root_", Package: "std/runtime"}
12 |
13 | func __go_root_(_args []Object) Object {
14 | _c := len(_args)
15 | switch {
16 | case _c == 0:
17 | _res := runtime.GOROOT()
18 | return MakeString(_res)
19 |
20 | default:
21 | PanicArity(_c)
22 | }
23 | return NIL
24 | }
25 |
26 | var __go_version__P ProcFn = __go_version_
27 | var go_version_ Proc = Proc{Fn: __go_version__P, Name: "go_version_", Package: "std/runtime"}
28 |
29 | func __go_version_(_args []Object) Object {
30 | _c := len(_args)
31 | switch {
32 | case _c == 0:
33 | _res := runtime.Version()
34 | return MakeString(_res)
35 |
36 | default:
37 | PanicArity(_c)
38 | }
39 | return NIL
40 | }
41 |
42 | var __joker_version__P ProcFn = __joker_version_
43 | var joker_version_ Proc = Proc{Fn: __joker_version__P, Name: "joker_version_", Package: "std/runtime"}
44 |
45 | func __joker_version_(_args []Object) Object {
46 | _c := len(_args)
47 | switch {
48 | case _c == 0:
49 | _res := VERSION
50 | return MakeString(_res)
51 |
52 | default:
53 | PanicArity(_c)
54 | }
55 | return NIL
56 | }
57 |
58 | func Init() {
59 |
60 | InternsOrThunks()
61 | }
62 |
63 | var runtimeNamespace = GLOBAL_ENV.EnsureSymbolIsLib(MakeSymbol("joker.runtime"))
64 |
65 | func init() {
66 | runtimeNamespace.Lazy = Init
67 | }
68 |
--------------------------------------------------------------------------------
/std/runtime/a_runtime_slow_init.go:
--------------------------------------------------------------------------------
1 | // This file is generated by generate-std.joke script. Do not edit manually!
2 |
3 | package runtime
4 |
5 | import (
6 | "fmt"
7 | . "github.com/candid82/joker/core"
8 | "os"
9 | )
10 |
11 | func InternsOrThunks() {
12 | if VerbosityLevel > 0 {
13 | fmt.Fprintln(os.Stderr, "Lazily running slow version of runtime.InternsOrThunks().")
14 | }
15 | runtimeNamespace.ResetMeta(MakeMeta(nil, `Provides access to Go and Joker runtime information.`, "1.0"))
16 |
17 | runtimeNamespace.InternVar("go-root", go_root_,
18 | MakeMeta(
19 | NewListFrom(NewVectorFrom()),
20 | `Returns the GOROOT string (as returned by runtime/GOROOT()).`, "1.0").Plus(MakeKeyword("tag"), String{S: "String"}))
21 |
22 | runtimeNamespace.InternVar("go-version", go_version_,
23 | MakeMeta(
24 | NewListFrom(NewVectorFrom()),
25 | `Returns the Go version string (as returned by runtime/Version()).`, "1.0").Plus(MakeKeyword("tag"), String{S: "String"}))
26 |
27 | runtimeNamespace.InternVar("joker-version", joker_version_,
28 | MakeMeta(
29 | NewListFrom(NewVectorFrom()),
30 | `Returns the raw Joker version string (including the leading 'v',
31 | which joker.core/joker-version omits).`, "1.0").Plus(MakeKeyword("tag"), String{S: "String"}))
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/std/string/a_string_fast_init.go:
--------------------------------------------------------------------------------
1 | // This file is generated by generate-std.joke script. Do not edit manually!
2 |
3 | //go:build !gen_code
4 | // +build !gen_code
5 |
6 | package string
7 |
8 | import (
9 | "fmt"
10 | . "github.com/candid82/joker/core"
11 | "os"
12 | )
13 |
14 | func InternsOrThunks() {
15 | if VerbosityLevel > 0 {
16 | fmt.Fprintln(os.Stderr, "Lazily running fast version of string.InternsOrThunks().")
17 | }
18 | STD_thunk_string_isblank__var = __isblank_
19 | STD_thunk_string_capitalize__var = __capitalize_
20 | STD_thunk_string_isends_with__var = __isends_with_
21 | STD_thunk_string_escape__var = __escape_
22 | STD_thunk_string_isincludes__var = __isincludes_
23 | STD_thunk_string_index_of__var = __index_of_
24 | STD_thunk_string_join__var = __join_
25 | STD_thunk_string_last_index_of__var = __last_index_of_
26 | STD_thunk_string_lower_case__var = __lower_case_
27 | STD_thunk_string_pad_left__var = __pad_left_
28 | STD_thunk_string_pad_right__var = __pad_right_
29 | STD_thunk_string_re_quote__var = __re_quote_
30 | STD_thunk_string_replace__var = __replace_
31 | STD_thunk_string_replace_first__var = __replace_first_
32 | STD_thunk_string_reverse__var = __reverse_
33 | STD_thunk_string_split__var = __split_
34 | STD_thunk_string_split_lines__var = __split_lines_
35 | STD_thunk_string_isstarts_with__var = __isstarts_with_
36 | STD_thunk_string_trim__var = __trim_
37 | STD_thunk_string_trim_left__var = __trim_left_
38 | STD_thunk_string_trim_newline__var = __trim_newline_
39 | STD_thunk_string_trim_right__var = __trim_right_
40 | STD_thunk_string_triml__var = __triml_
41 | STD_thunk_string_trimr__var = __trimr_
42 | STD_thunk_string_upper_case__var = __upper_case_
43 | }
44 |
--------------------------------------------------------------------------------
/std/time/time_native.go:
--------------------------------------------------------------------------------
1 | package time
2 |
3 | import (
4 | . "github.com/candid82/joker/core"
5 | "time"
6 | )
7 |
8 | func inTimezone(t time.Time, tz string) time.Time {
9 | loc, err := time.LoadLocation(tz)
10 | PanicOnErr(err)
11 | return t.In(loc)
12 | }
13 |
--------------------------------------------------------------------------------
/std/url.joke:
--------------------------------------------------------------------------------
1 | (ns ^{:go-imports ["net/url"]
2 | :doc "Parses URLs and implements query escaping."}
3 | url)
4 |
5 | (defn ^String path-escape
6 | "Escapes the string so it can be safely placed inside a URL path segment."
7 | {:added "1.0"
8 | :go "url.PathEscape(s)"}
9 | [^String s])
10 |
11 | (defn ^String path-unescape
12 | "Does the inverse transformation of path-escape, converting each 3-byte encoded
13 | substring of the form \"%AB\" into the hex-decoded byte 0xAB. It also converts
14 | '+' into ' ' (space). It returns an error if any % is not followed by two hexadecimal digits.
15 |
16 | PathUnescape is identical to QueryUnescape except that it does not unescape '+' to ' ' (space)."
17 | {:added "1.0"
18 | :go "pathUnescape(s)"}
19 | [^String s])
20 |
21 | (defn ^String query-escape
22 | "Escapes the string so it can be safely placed inside a URL query."
23 | {:added "1.0"
24 | :go "url.QueryEscape(s)"}
25 | [^String s])
26 |
27 | (defn ^String query-unescape
28 | "Does the inverse transformation of query-escape, converting each 3-byte encoded
29 | substring of the form \"%AB\" into the hex-decoded byte 0xAB. It also converts
30 | '+' into ' ' (space). It returns an error if any % is not followed by two hexadecimal digits."
31 | {:added "1.0"
32 | :go "queryUnescape(s)"}
33 | [^String s])
34 |
35 | (defn parse-query
36 | "Parses the URL-encoded query string and returns a map listing the vectors of values specified for each key.
37 | Always returns a non-nil map containing all the valid query parameters found.
38 | Query is expected to be a list of key=value settings separated by ampersands. A setting without
39 | an equals sign is interpreted as a key set to an empty value. Settings containing a non-URL-encoded
40 | semicolon are considered invalid. "
41 | {:added "1.3.6"
42 | :go "parseQuery(s)"}
43 | [^String s])
44 |
--------------------------------------------------------------------------------
/std/url/a_url_slow_init.go:
--------------------------------------------------------------------------------
1 | // This file is generated by generate-std.joke script. Do not edit manually!
2 |
3 | package url
4 |
5 | import (
6 | "fmt"
7 | . "github.com/candid82/joker/core"
8 | "os"
9 | )
10 |
11 | func InternsOrThunks() {
12 | if VerbosityLevel > 0 {
13 | fmt.Fprintln(os.Stderr, "Lazily running slow version of url.InternsOrThunks().")
14 | }
15 | urlNamespace.ResetMeta(MakeMeta(nil, `Parses URLs and implements query escaping.`, "1.0"))
16 |
17 | urlNamespace.InternVar("parse-query", parse_query_,
18 | MakeMeta(
19 | NewListFrom(NewVectorFrom(MakeSymbol("s"))),
20 | `Parses the URL-encoded query string and returns a map listing the vectors of values specified for each key.
21 | Always returns a non-nil map containing all the valid query parameters found.
22 | Query is expected to be a list of key=value settings separated by ampersands. A setting without
23 | an equals sign is interpreted as a key set to an empty value. Settings containing a non-URL-encoded
24 | semicolon are considered invalid. `, "1.3.6"))
25 |
26 | urlNamespace.InternVar("path-escape", path_escape_,
27 | MakeMeta(
28 | NewListFrom(NewVectorFrom(MakeSymbol("s"))),
29 | `Escapes the string so it can be safely placed inside a URL path segment.`, "1.0").Plus(MakeKeyword("tag"), String{S: "String"}))
30 |
31 | urlNamespace.InternVar("path-unescape", path_unescape_,
32 | MakeMeta(
33 | NewListFrom(NewVectorFrom(MakeSymbol("s"))),
34 | `Does the inverse transformation of path-escape, converting each 3-byte encoded
35 | substring of the form "%AB" into the hex-decoded byte 0xAB. It also converts
36 | '+' into ' ' (space). It returns an error if any % is not followed by two hexadecimal digits.
37 |
38 | PathUnescape is identical to QueryUnescape except that it does not unescape '+' to ' ' (space).`, "1.0").Plus(MakeKeyword("tag"), String{S: "String"}))
39 |
40 | urlNamespace.InternVar("query-escape", query_escape_,
41 | MakeMeta(
42 | NewListFrom(NewVectorFrom(MakeSymbol("s"))),
43 | `Escapes the string so it can be safely placed inside a URL query.`, "1.0").Plus(MakeKeyword("tag"), String{S: "String"}))
44 |
45 | urlNamespace.InternVar("query-unescape", query_unescape_,
46 | MakeMeta(
47 | NewListFrom(NewVectorFrom(MakeSymbol("s"))),
48 | `Does the inverse transformation of query-escape, converting each 3-byte encoded
49 | substring of the form "%AB" into the hex-decoded byte 0xAB. It also converts
50 | '+' into ' ' (space). It returns an error if any % is not followed by two hexadecimal digits.`, "1.0").Plus(MakeKeyword("tag"), String{S: "String"}))
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/std/url/url_native.go:
--------------------------------------------------------------------------------
1 | package url
2 |
3 | import (
4 | "net/url"
5 |
6 | . "github.com/candid82/joker/core"
7 | )
8 |
9 | func pathUnescape(s string) string {
10 | res, err := url.PathUnescape(s)
11 | if err != nil {
12 | panic(RT.NewError("Error unescaping string: " + err.Error()))
13 | }
14 | return res
15 | }
16 |
17 | func queryUnescape(s string) string {
18 | res, err := url.QueryUnescape(s)
19 | if err != nil {
20 | panic(RT.NewError("Error unescaping string: " + err.Error()))
21 | }
22 | return res
23 | }
24 |
25 | func parseQuery(s string) Object {
26 | values, _ := url.ParseQuery(s)
27 | res := EmptyArrayMap()
28 | for k, v := range values {
29 | res.Add(MakeString(k), MakeStringVector(v))
30 | }
31 | return res
32 | }
33 |
--------------------------------------------------------------------------------
/std/uuid.joke:
--------------------------------------------------------------------------------
1 | (ns ^{:doc "Generates UUIDs."}
2 | uuid)
3 |
4 | (defn ^String new
5 | "Creates a new random UUID."
6 | {:added "1.0"
7 | :go "new()"}
8 | [])
9 |
--------------------------------------------------------------------------------
/std/uuid/a_uuid.go:
--------------------------------------------------------------------------------
1 | // This file is generated by generate-std.joke script. Do not edit manually!
2 |
3 | package uuid
4 |
5 | import (
6 | . "github.com/candid82/joker/core"
7 | )
8 |
9 | var __new__P ProcFn = __new_
10 | var new_ Proc = Proc{Fn: __new__P, Name: "new_", Package: "std/uuid"}
11 |
12 | func __new_(_args []Object) Object {
13 | _c := len(_args)
14 | switch {
15 | case _c == 0:
16 | _res := new()
17 | return MakeString(_res)
18 |
19 | default:
20 | PanicArity(_c)
21 | }
22 | return NIL
23 | }
24 |
25 | func Init() {
26 |
27 | InternsOrThunks()
28 | }
29 |
30 | var uuidNamespace = GLOBAL_ENV.EnsureSymbolIsLib(MakeSymbol("joker.uuid"))
31 |
32 | func init() {
33 | uuidNamespace.Lazy = Init
34 | }
35 |
--------------------------------------------------------------------------------
/std/uuid/a_uuid_slow_init.go:
--------------------------------------------------------------------------------
1 | // This file is generated by generate-std.joke script. Do not edit manually!
2 |
3 | package uuid
4 |
5 | import (
6 | "fmt"
7 | . "github.com/candid82/joker/core"
8 | "os"
9 | )
10 |
11 | func InternsOrThunks() {
12 | if VerbosityLevel > 0 {
13 | fmt.Fprintln(os.Stderr, "Lazily running slow version of uuid.InternsOrThunks().")
14 | }
15 | uuidNamespace.ResetMeta(MakeMeta(nil, `Generates UUIDs.`, "1.0"))
16 |
17 | uuidNamespace.InternVar("new", new_,
18 | MakeMeta(
19 | NewListFrom(NewVectorFrom()),
20 | `Creates a new random UUID.`, "1.0").Plus(MakeKeyword("tag"), String{S: "String"}))
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/std/uuid/uuid_native.go:
--------------------------------------------------------------------------------
1 | // Based on https://github.com/google/uuid
2 | // Copyright (c) 2009,2014 Google Inc. All rights reserved.
3 |
4 | package uuid
5 |
6 | import (
7 | "crypto/rand"
8 | "encoding/hex"
9 | . "github.com/candid82/joker/core"
10 | "io"
11 | )
12 |
13 | type UUID [16]byte
14 |
15 | var rander = rand.Reader // random function
16 |
17 | func (uuid UUID) String() string {
18 | var buf [36]byte
19 | encodeHex(buf[:], uuid)
20 | return string(buf[:])
21 | }
22 |
23 | func encodeHex(dst []byte, uuid UUID) {
24 | hex.Encode(dst, uuid[:4])
25 | dst[8] = '-'
26 | hex.Encode(dst[9:13], uuid[4:6])
27 | dst[13] = '-'
28 | hex.Encode(dst[14:18], uuid[6:8])
29 | dst[18] = '-'
30 | hex.Encode(dst[19:23], uuid[8:10])
31 | dst[23] = '-'
32 | hex.Encode(dst[24:], uuid[10:])
33 | }
34 |
35 | func new() string {
36 | var uuid UUID
37 | _, err := io.ReadFull(rander, uuid[:])
38 | if err != nil {
39 | panic(RT.NewError("Error generating UUID: " + err.Error()))
40 | }
41 | uuid[6] = (uuid[6] & 0x0f) | 0x40 // Version 4
42 | uuid[8] = (uuid[8] & 0x3f) | 0x80 // Variant is 10
43 | return uuid.String()
44 | }
45 |
--------------------------------------------------------------------------------
/std/yaml.joke:
--------------------------------------------------------------------------------
1 | (ns ^{:go-imports []
2 | :doc "Implements encoding and decoding of YAML."}
3 | yaml)
4 |
5 | (defn read-string
6 | "Parses the YAML-encoded data and return the result as a Joker value."
7 | {:added "1.0"
8 | :go "readString(s)"}
9 | [^String s])
10 |
11 | (defn write-string
12 | "Returns the YAML encoding of v."
13 | {:added "1.0"
14 | :go "writeString(v)"}
15 | [^Object v])
16 |
17 |
18 |
--------------------------------------------------------------------------------
/std/yaml/a_yaml.go:
--------------------------------------------------------------------------------
1 | // This file is generated by generate-std.joke script. Do not edit manually!
2 |
3 | package yaml
4 |
5 | import (
6 | . "github.com/candid82/joker/core"
7 | )
8 |
9 | var __read_string__P ProcFn = __read_string_
10 | var read_string_ Proc = Proc{Fn: __read_string__P, Name: "read_string_", Package: "std/yaml"}
11 |
12 | func __read_string_(_args []Object) Object {
13 | _c := len(_args)
14 | switch {
15 | case _c == 1:
16 | s := ExtractString(_args, 0)
17 | _res := readString(s)
18 | return _res
19 |
20 | default:
21 | PanicArity(_c)
22 | }
23 | return NIL
24 | }
25 |
26 | var __write_string__P ProcFn = __write_string_
27 | var write_string_ Proc = Proc{Fn: __write_string__P, Name: "write_string_", Package: "std/yaml"}
28 |
29 | func __write_string_(_args []Object) Object {
30 | _c := len(_args)
31 | switch {
32 | case _c == 1:
33 | v := ExtractObject(_args, 0)
34 | _res := writeString(v)
35 | return _res
36 |
37 | default:
38 | PanicArity(_c)
39 | }
40 | return NIL
41 | }
42 |
43 | func Init() {
44 |
45 | InternsOrThunks()
46 | }
47 |
48 | var yamlNamespace = GLOBAL_ENV.EnsureSymbolIsLib(MakeSymbol("joker.yaml"))
49 |
50 | func init() {
51 | yamlNamespace.Lazy = Init
52 | }
53 |
--------------------------------------------------------------------------------
/std/yaml/a_yaml_slow_init.go:
--------------------------------------------------------------------------------
1 | // This file is generated by generate-std.joke script. Do not edit manually!
2 |
3 | package yaml
4 |
5 | import (
6 | "fmt"
7 | . "github.com/candid82/joker/core"
8 | "os"
9 | )
10 |
11 | func InternsOrThunks() {
12 | if VerbosityLevel > 0 {
13 | fmt.Fprintln(os.Stderr, "Lazily running slow version of yaml.InternsOrThunks().")
14 | }
15 | yamlNamespace.ResetMeta(MakeMeta(nil, `Implements encoding and decoding of YAML.`, "1.0"))
16 |
17 | yamlNamespace.InternVar("read-string", read_string_,
18 | MakeMeta(
19 | NewListFrom(NewVectorFrom(MakeSymbol("s"))),
20 | `Parses the YAML-encoded data and return the result as a Joker value.`, "1.0"))
21 |
22 | yamlNamespace.InternVar("write-string", write_string_,
23 | MakeMeta(
24 | NewListFrom(NewVectorFrom(MakeSymbol("v"))),
25 | `Returns the YAML encoding of v.`, "1.0"))
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/std/yaml/yaml_native.go:
--------------------------------------------------------------------------------
1 | package yaml
2 |
3 | import (
4 | "fmt"
5 |
6 | "gopkg.in/yaml.v2"
7 |
8 | . "github.com/candid82/joker/core"
9 | )
10 |
11 | func fromObject(obj Object) interface{} {
12 | switch obj := obj.(type) {
13 | case Keyword:
14 | return obj.ToString(false)[1:]
15 | case Boolean:
16 | return obj.B
17 | case Number:
18 | return obj.Double().D
19 | case Nil:
20 | return nil
21 | case Vec:
22 | cnt := obj.Count()
23 | res := make([]interface{}, cnt)
24 | for i := 0; i < cnt; i++ {
25 | res[i] = fromObject(obj.Nth(i))
26 | }
27 | return res
28 | case Map:
29 | res := make(map[string]interface{})
30 | for iter := obj.Iter(); iter.HasNext(); {
31 | p := iter.Next()
32 | var k string
33 | switch p.Key.(type) {
34 | case Keyword:
35 | k = p.Key.ToString(false)[1:]
36 | default:
37 | k = p.Key.ToString(false)
38 | }
39 | res[k] = fromObject(p.Value)
40 | }
41 | return res
42 | default:
43 | return obj.ToString(false)
44 | }
45 | }
46 |
47 | func toObject(v interface{}) Object {
48 | switch v := v.(type) {
49 | case string:
50 | return MakeString(v)
51 | case float64:
52 | return Double{D: v}
53 | case int:
54 | return Int{I: v}
55 | case bool:
56 | return Boolean{B: v}
57 | case nil:
58 | return NIL
59 | case []interface{}:
60 | res := EmptyVector()
61 | for _, v := range v {
62 | res = res.Conjoin(toObject(v))
63 | }
64 | return res
65 | case map[interface{}]interface{}:
66 | res := EmptyArrayMap()
67 | for k, v := range v {
68 | res.Add(toObject(k), toObject(v))
69 | }
70 | return res
71 | default:
72 | panic(RT.NewError(fmt.Sprintf("Unknown yaml value: %v", v)))
73 | }
74 | }
75 |
76 | func readString(s string) Object {
77 | var v interface{}
78 | if err := yaml.Unmarshal([]byte(s), &v); err != nil {
79 | panic(RT.NewError("Invalid yaml: " + err.Error()))
80 | }
81 | return toObject(v)
82 | }
83 |
84 | func writeString(obj Object) String {
85 | res, err := yaml.Marshal(fromObject(obj))
86 | if err != nil {
87 | panic(RT.NewError("Cannot encode value to yaml: " + err.Error()))
88 | }
89 | return String{S: string(res)}
90 | }
91 |
--------------------------------------------------------------------------------
/test-format.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | filelist=$(find $1 -type f -name "*.clj")
4 |
5 | for f in $filelist
6 | do
7 | ./joker --format $f > /tmp/joker-format.clj
8 | cat /tmp/joker-format.clj > $f
9 | done
10 |
--------------------------------------------------------------------------------
/test-linter.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | filelist=$(find $1 -type f -name "$2" -not -name "project.clj" -not -name "user.clj")
4 |
5 | for f in $filelist
6 | do
7 | ERROR=$(./joker --lint $f 2>&1)
8 | if [ -n "$ERROR" ]; then
9 | echo $f
10 | echo "$ERROR"
11 | fi
12 | done
13 |
--------------------------------------------------------------------------------
/tests/1.clj:
--------------------------------------------------------------------------------
1 | (def f
2 | (fn [a]
3 | (def f1
4 | (fn [b]
5 | (def f11 (fn [] b))
6 | (+ a b)))
7 | (def f2 (fn [c] (+ a c)))
8 | (f1 10)
9 | (f2 20)
10 | (f11)))
11 |
--------------------------------------------------------------------------------
/tests/eval/atoms.joke:
--------------------------------------------------------------------------------
1 | ; Copyright (c) Rich Hickey. All rights reserved.
2 | ; The use and distribution terms for this software are covered by the
3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
4 | ; which can be found in the file epl-v10.html at the root of this distribution.
5 | ; By using this software in any fashion, you are agreeing to be bound by
6 | ; the terms of this license.
7 | ; You must not remove this notice, or any other, from this software.
8 |
9 | ;;Author: Frantisek Sodomka
10 |
11 | (ns joker.test-clojure.atoms
12 | (:require [joker.test :refer [deftest is are testing]]))
13 |
14 | ; http://clojure.org/atoms
15 |
16 | ; atom
17 | ; deref, @-reader-macro
18 | ; swap! reset!
19 | ; compare-and-set!
20 |
21 | (def ^:dynamic *warn-on-reflection* false)
22 |
23 | (deftest swap-vals-returns-old-value
24 | (let [a (atom 0)]
25 | (is (= [0 1] (swap-vals! a inc)))
26 | (is (= [1 2] (swap-vals! a inc)))
27 | (is (= 2 @a))))
28 |
29 | (deftest deref-swap-arities
30 | (binding [*warn-on-reflection* true]
31 | (let [a (atom 0)]
32 | (is (= [0 1] (swap-vals! a + 1)))
33 | (is (= [1 3] (swap-vals! a + 1 1)))
34 | (is (= [3 6] (swap-vals! a + 1 1 1)))
35 | (is (= [6 10] (swap-vals! a + 1 1 1 1)))
36 | (is (= 10 @a)))))
37 |
38 | (deftest deref-reset-returns-old-value
39 | (let [a (atom 0)]
40 | (is (= [0 :b] (reset-vals! a :b)))
41 | (is (= [:b 45M] (reset-vals! a 45M)))
42 | (is (= 45M @a))))
43 |
44 | (deftest reset-on-deref-reset-equality
45 | (let [a (atom :usual-value)]
46 | (is (= :usual-value (reset! a (first (reset-vals! a :almost-never-seen-value)))))))
47 |
--------------------------------------------------------------------------------
/tests/eval/better-cond-test.joke:
--------------------------------------------------------------------------------
1 | (ns joker.better-cond-test
2 | (:refer-clojure :exclude [cond if-let when-let if-some when-some])
3 | (:require [joker.test :refer [deftest are]]
4 | [joker.better-cond :refer [cond]]))
5 |
6 | (deftest better-cond
7 | (are [x y] (= x y)
8 | 2 (cond (even? 3) 5
9 | (odd? 3) 2)
10 | 2 (cond (even? 3) 5
11 | :else 2)
12 | 2 (cond
13 | :let [x 2]
14 | x)
15 | 2 (cond
16 | :when-let [x 2]
17 | x)
18 | 2 (cond
19 | :when-some [x 2]
20 | x)
21 | nil (cond
22 | :when-let [x false]
23 | 2)
24 | 2 (cond
25 | :when-let [x true]
26 | 2)
27 | nil (cond
28 | :when-let [x nil]
29 | 2)
30 | 2 (cond
31 | :when-some [x false]
32 | 2)
33 | 2 (cond
34 | :when (even? 4)
35 | 2)
36 | nil (cond
37 | :when (even? 3)
38 | 2)))
39 |
--------------------------------------------------------------------------------
/tests/eval/bolt.joke:
--------------------------------------------------------------------------------
1 | (ns joker.test-joker.bolt
2 | (:require
3 | [joker.test :refer [deftest is testing]]
4 | [joker.bolt :refer [open close create-bucket next-sequence put get]]
5 | [joker.os :refer [create-temp remove]]
6 | [joker.json :refer [write-string read-string]]))
7 |
8 | (deftest example-1
9 | (testing "example in docstring"
10 | (let [f (create-temp "" "bolt-test-")
11 | db-name (name f)
12 | _ (joker.os/close f) ; Windows requires the file itself to be closed for remove to work.
13 | db (open db-name 0600)
14 | users "users"
15 | joe "Joe Black"]
16 | (try
17 | (is (nil? (create-bucket db users)))
18 | (let [id (next-sequence db users)
19 | _ (is (= id 1))
20 | _ (is (nil? (put db users (str id) (write-string {:id id :name joe}))))
21 | m (read-string (get db users (str id)))
22 | s (str (sort m))]
23 | (is (= (format "([\"id\" %d] [\"name\" \"%s\"])" id joe)
24 | s)))
25 | (finally (close db)
26 | (remove db-name))))))
27 |
--------------------------------------------------------------------------------
/tests/eval/classpath/a/b/c.joke:
--------------------------------------------------------------------------------
1 | (ns a.b.c)
2 |
3 | (println "this is a/b/c.joke")
4 |
--------------------------------------------------------------------------------
/tests/eval/classpath/b/c.joke:
--------------------------------------------------------------------------------
1 | (ns b.c)
2 |
3 | (println "this is b/c.joke")
4 |
--------------------------------------------------------------------------------
/tests/eval/classpath/d/e/f.joke:
--------------------------------------------------------------------------------
1 | (ns d.e.f
2 | (:require g.h.i))
3 |
4 | (println "this is d/e/f.joke")
5 |
--------------------------------------------------------------------------------
/tests/eval/classpath/g/h/i.joke:
--------------------------------------------------------------------------------
1 | (ns g.h.i)
2 |
3 | (println "this is g/h/i.joke")
4 |
--------------------------------------------------------------------------------
/tests/eval/classpath/input.joke:
--------------------------------------------------------------------------------
1 | (require 'a.b.c)
2 |
3 | (binding [joker.core/*classpath* ["."]]
4 | (require 'd.e.f))
5 |
6 | (binding [joker.core/*classpath* ["." "a"]]
7 | (require 'b.c))
8 |
9 | (binding [joker.core/*classpath* ["x/y"]]
10 | (require 'z))
11 |
--------------------------------------------------------------------------------
/tests/eval/classpath/stdout.txt:
--------------------------------------------------------------------------------
1 | this is a/b/c.joke
2 | this is g/h/i.joke
3 | this is d/e/f.joke
4 | this is b/c.joke
5 | this is x/y/z.joke
6 | this is x/y/q/r/s.joke
7 |
--------------------------------------------------------------------------------
/tests/eval/classpath/x/y/q/r/s.joke:
--------------------------------------------------------------------------------
1 | (ns q.r.s)
2 |
3 | (println "this is x/y/q/r/s.joke")
4 |
--------------------------------------------------------------------------------
/tests/eval/classpath/x/y/z.joke:
--------------------------------------------------------------------------------
1 | (ns y.z)
2 |
3 | (println "this is x/y/z.joke")
4 |
5 | (require 'q.r.s)
6 |
--------------------------------------------------------------------------------
/tests/eval/core.joke:
--------------------------------------------------------------------------------
1 | (ns joker.test-joker.core
2 | (:require [joker.test :refer [deftest is]]))
3 |
4 | (deftest test-meta
5 | (is (= (try (meta) (catch Error e "caught error")) "caught error")))
6 |
--------------------------------------------------------------------------------
/tests/eval/corelibs/input.joke:
--------------------------------------------------------------------------------
1 | (doseq [ns (remove #(= % 'user) joker.core/*core-namespaces*)] (require ns))
2 |
--------------------------------------------------------------------------------
/tests/eval/corelibs/stdout.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/candid82/joker/1eed1c02c38ef1373640c42af1423808826820cc/tests/eval/corelibs/stdout.txt
--------------------------------------------------------------------------------
/tests/eval/csv.joke:
--------------------------------------------------------------------------------
1 | (ns joker.test-joker.csv
2 | (:require [joker.csv :as csv]
3 | [joker.test :refer [deftest is]]))
4 |
5 | (deftest test-csv-seq
6 | (is (= (csv/csv-seq "a,b,c\nd,e,f") '(["a" "b" "c"] ["d" "e" "f"]))))
7 |
--------------------------------------------------------------------------------
/tests/eval/deps-test.joke:
--------------------------------------------------------------------------------
1 | (ns deps-test
2 | (:require
3 | [joker.test :refer [deftest is are testing]]
4 | [deps]
5 | [test-local.lib :as lib-local]))
6 |
7 | (deftest local-lib-test
8 | (testing "require from a local source"
9 | (is (= lib-local/b :b))))
10 |
--------------------------------------------------------------------------------
/tests/eval/deps.joke:
--------------------------------------------------------------------------------
1 | (ns deps
2 | (:require [joker.os :as os]
3 | [joker.filepath :as fp]
4 | [joker.string :as str]))
5 |
6 | (def lib-dir
7 | (-> *main-file*
8 | (str/split fp/separator)
9 | (butlast)
10 | (concat ["lib"])
11 | ((fn [x] (apply str (interpose fp/separator x))))))
12 |
13 | (ns-sources
14 | {"test-local.*" {:url lib-dir}})
15 |
--------------------------------------------------------------------------------
/tests/eval/format.joke:
--------------------------------------------------------------------------------
1 | (ns joker.test-joker.format
2 | (:require [joker.test :refer [deftest is are]]))
3 |
4 | (defonce FF 1.23299299999999999999999999999999999999M)
5 |
6 | (deftest test-native
7 | (are [x y] (= x y)
8 | (format "%x" 0xFFFFFFFFFFFFFFFF) "ffffffffffffffff"
9 | (format "%g" (- FF FF)) "0"
10 | (format "%g" 1/2) "0.5" ))
11 |
--------------------------------------------------------------------------------
/tests/eval/hash.joke:
--------------------------------------------------------------------------------
1 | (ns joker.test-joker.hash
2 | (:require
3 | [joker.test :refer [deftest is testing]]))
4 |
5 | (deftest stable-hashes
6 | (testing "stable string hashes"
7 | (is (= (hash "hey") 4290027229))
8 | (is (= (hash "there") 3102463325)))
9 | (testing "stable symbol hashes"
10 | (is (= (hash 'hey) 3793824397))
11 | (is (= (hash 'there) 2940266537))
12 | (is (= (hash 'joker.core/cond) 3232247079))
13 | (is (= (hash 'joker.repl/doc) 3494663759))
14 | (is (= (hash 'user/foo) 2980260858)))
15 | (testing "stable keyword hashes"
16 | (is (= (hash :hey) 819820356))
17 | (is (= (hash :there) 1648208352))
18 | (is (= (hash ::you) 3944753178))
19 | (is (= (hash :user/foo) 1616868817))))
20 |
--------------------------------------------------------------------------------
/tests/eval/json.joke:
--------------------------------------------------------------------------------
1 | (ns joker.test-joker.json
2 | (:require [joker.json :as json]
3 | [joker.test :refer [deftest is]]))
4 |
5 | (deftest write-string
6 | (is (= "1" (json/write-string 1)))
7 | (is (= "1.2" (json/write-string 1.2)))
8 | (is (= "0.2" (json/write-string 1/5)))
9 | (is (= "1" (json/write-string 1.0)))
10 | (is (= "false" (json/write-string false)))
11 | (is (= "true" (json/write-string true)))
12 | (is (= "\"keyword\"" (json/write-string :keyword)))
13 | (is (= "null" (json/write-string nil)))
14 | (is (= "\"string\"" (json/write-string "string")))
15 | (is (= "[]" (json/write-string [])))
16 | (is (= "{\"keyword\":\"string\"}" (json/write-string {:keyword "string"})))
17 | (is (= "[1,true]" (json/write-string [1 true])))
18 | (is (= "[\"string\",null]" (json/write-string (drop 2 [1 true "string" nil]))))
19 | (is (= "[4,5]" (json/write-string (list 4 5))))
20 | (is (= "{\"m\":{\"k\":\"foo\"},\"s\":[\"string\",null],\"v\":[3]}"
21 | (json/write-string {:s (drop 2 [1 true "string" nil])
22 | :v [3]
23 | :m {:k "foo"}}))))
24 |
--------------------------------------------------------------------------------
/tests/eval/large-forked-stdout/input.joke:
--------------------------------------------------------------------------------
1 | (ns joker.tests.large-forked-stdout
2 | (:require [joker.os :as os]
3 | [joker.string :as s]))
4 |
5 | (let [exe (nth *command-line-args* 0)
6 | res (os/sh exe "lots-of-stderr.joke")]
7 | (print (:out res))
8 | (let [ev (s/split-lines (:err res))]
9 | (println-err (ev 0))
10 | (println-err (ev 1))
11 | (println-err (ev (- (count ev) 2)))))
12 |
--------------------------------------------------------------------------------
/tests/eval/large-forked-stdout/lots-of-stderr.joke:
--------------------------------------------------------------------------------
1 | (println "this is stdout; just one line.")
2 | (doseq [n (range 10000) ; Should be enough to block writing stderr until parent reads it.
3 | ]
4 | (println-err (format "A lazy dog knows %d tricks." n)))
5 |
--------------------------------------------------------------------------------
/tests/eval/large-forked-stdout/stderr.txt:
--------------------------------------------------------------------------------
1 | A lazy dog knows 0 tricks.
2 | A lazy dog knows 1 tricks.
3 | A lazy dog knows 9999 tricks.
4 |
--------------------------------------------------------------------------------
/tests/eval/large-forked-stdout/stdout.txt:
--------------------------------------------------------------------------------
1 | this is stdout; just one line.
2 |
--------------------------------------------------------------------------------
/tests/eval/load-file/input.joke:
--------------------------------------------------------------------------------
1 | (try (load-file "parse-error.joke") (catch Error e (println "Caught parse error")))
2 |
--------------------------------------------------------------------------------
/tests/eval/load-file/parse-error.joke:
--------------------------------------------------------------------------------
1 | foo
2 |
--------------------------------------------------------------------------------
/tests/eval/load-file/stdout.txt:
--------------------------------------------------------------------------------
1 | Caught parse error
2 |
--------------------------------------------------------------------------------
/tests/eval/macro-test.joke:
--------------------------------------------------------------------------------
1 | (ns joker.macro-test
2 | (:require [joker.test :refer [deftest is]]
3 | [joker.string :as s]))
4 |
5 | (defmacro try-macro [ & body ] `(try ~@body (catch Error)))
6 | (def try-macro-expand (macroexpand '(try-macro)))
7 |
8 | (deftest try-log-test
9 | (is (= '(try (catch Error))
10 | try-macro-expand)
11 | "should properly syntax-quote types"))
12 |
13 | (defmacro try-return [ & body ] `(try ~@body (catch Error t# t#)))
14 | (deftest try-expanding-typename
15 | (is (s/includes? (str (try-return (throw (ex-info "Ouch" {})))) "Exception: Ouch")))
16 |
17 | (defmacro make-fn [] (fn [] nil))
18 | (deftest try-expanding-literal
19 | (is (macroexpand '(make-fn)) "#object[Fn]")
20 | (is (str (make-fn)) "#object[Fn]"))
21 |
--------------------------------------------------------------------------------
/tests/eval/map-test.joke:
--------------------------------------------------------------------------------
1 | (ns joker.map-test
2 | (:require [joker.test :refer [deftest is]]))
3 |
4 |
5 | (deftest hash-map-conversion
6 | (let [m {1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0}]
7 | (is (= ArrayMap (type m)))
8 | (is (= ArrayMap (type (merge m {1 1}))))
9 | (is (= ArrayMap (type (assoc m 1 2))))
10 | (is (= HashMap (type (merge m {9 0}))))
11 | (is (= HashMap (type (assoc m 9 0))))))
12 |
--------------------------------------------------------------------------------
/tests/eval/markdown.joke:
--------------------------------------------------------------------------------
1 | (ns joker.test-joker.markdown
2 | (:require [joker.test :refer [deftest is are]]
3 | [joker.markdown :as md]))
4 |
5 | (def input "one\ntwo")
6 |
7 | (deftest with-hard-wraps?
8 | (is (= (md/convert-string input {:with-hard-wraps? true})
9 | "one \ntwo
\n")
10 | "add line breaks when true")
11 | (is (= (md/convert-string input {:with-hard-wraps? false})
12 | "one\ntwo
\n")
13 | "no line breaks when off")
14 | (is (= (md/convert-string input)
15 | "one \ntwo
\n")
16 | "should default to on for backwards compatibility")
17 | (is (= (md/convert-string input {:with-hard-wraps? true})
18 | (md/convert-string input))
19 | "no flag and 'true' should be the same")
20 | (is (thrown-with-msg? EvalError
21 | #"Expected Boolean, got String"
22 | (md/convert-string input {:with-hard-wraps? "foo"}))))
23 |
24 | (deftest with-xhtml?
25 | (is (= (md/convert-string input {:with-xhtml? true})
26 | "one \ntwo
\n"))
27 | (is (= (md/convert-string input {:with-xhtml? false})
28 | "one \ntwo
\n"))
29 | (is (= (md/convert-string input)
30 | (md/convert-string input {:with-xhtml? true}))))
31 |
32 |
33 | (def unsafe-input "")
34 |
35 | (deftest with-unsafe?
36 | (is (= (md/convert-string unsafe-input {:with-unsafe? true})
37 | ""))
38 | (is (= (md/convert-string unsafe-input {:with-unsafe? false})
39 | "\n"))
40 | (is (= (md/convert-string unsafe-input)
41 | (md/convert-string unsafe-input {:with-unsafe? true}))))
42 |
--------------------------------------------------------------------------------
/tests/eval/multi-methods/stdout.txt:
--------------------------------------------------------------------------------
1 | Hello!
2 | Bonjour!
3 | I don't know the Spanish language
4 | 1
5 | 1
6 | 6
7 | 5040
8 | (120 24 6 2 1)
9 | str: mink and stoat
10 | str: bear, skunk and sloth
11 | str: dog, cat, cow and horse
12 | numbers: 1 and 2
13 | Caught this expected exception: :0:0: Exception: No method in multimethod 'bat' for dispatch value: [Keyword Keyword]
14 | default: :hey then :there and finally (:you)
15 | 1
16 | 1
17 | -1
18 | Great function
19 | Better function
20 | (:foo 1 :bar)
21 | {:foo 1, :baz hello}
22 | Bob Dobbs
23 | Bob Dobbs
24 | ???
25 | Drawing a red square
26 | Drawing a green triangle
27 | 1500
28 | 1099
29 | Drawing a red square
30 | Drawing a green triangle
31 | #object[Fn]
32 | nil
33 |
--------------------------------------------------------------------------------
/tests/eval/os.joke:
--------------------------------------------------------------------------------
1 | (ns joker.test-joker.os
2 | (:require [joker.os :as os]
3 | [joker.test :refer [deftest is]]))
4 |
5 | (deftest exec-pipe
6 | (if (= (get (os/env) "TTY_TESTS") "1")
7 | (is (= 0 (:exit (os/exec "stty" {:args ["echo"] :stdin *in*}))))
8 | (println "Skipping tty tests (STDIN is not a tty)")))
9 |
--------------------------------------------------------------------------------
/tests/eval/printer.joke:
--------------------------------------------------------------------------------
1 | ; Copyright (c) Rich Hickey. All rights reserved.
2 | ; The use and distribution terms for this software are covered by the
3 | ; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
4 | ; which can be found in the file epl-v10.html at the root of this distribution.
5 | ; By using this software in any fashion, you are agreeing to be bound by
6 | ; the terms of this license.
7 | ; You must not remove this notice, or any other, from this software.
8 |
9 | ; Author: Stephen C. Gilardi
10 |
11 | (ns joker.test-joker.printer
12 | (:require [joker.test :refer [deftest is are]]))
13 |
14 | (deftest print-symbol-values
15 | (are [s v] (= s (pr-str v))
16 | "##Inf" (joker.math/inf 1)
17 | "##-Inf" (joker.math/inf -1)
18 | "##NaN" (joker.math/nan)))
19 |
20 | (deftest print-double-values
21 | (are [s v] (= s (pr-str v))
22 | "1.9999999" 1.9999999
23 | "1e-09" 1e-9
24 | "1e-07" 1e-7
25 | "0.001" 1e-3
26 | "1.0" 1e0))
27 |
28 | (deftest print-and-confirm-double-values
29 | (are [v] (= v (read-string (pr-str v)))
30 | 1.9999999
31 | 1e-9
32 | 1e-7
33 | 1e-3
34 | 1e0
35 | 99999999.0
36 | 1.0e-100
37 | 1.0e+100
38 | -2.5
39 | -2.5e-3))
40 |
--------------------------------------------------------------------------------
/tests/eval/read-line/input.joke:
--------------------------------------------------------------------------------
1 | ;;; Move this into core.joke?
2 | (defmacro while-let
3 | "Continue processing an expression as long as it is true"
4 | [binding & forms]
5 | `(loop []
6 | (when-let ~binding
7 | ~@forms
8 | (recur))))
9 |
10 | ;; Read from a String.
11 | (with-in-str (slurp "lines.txt")
12 | (while-let [line (read-line)]
13 | (println "|" line)))
14 |
15 | ;; Now read from actual stdin.txt.
16 | (while-let [line (read-line)]
17 | (println "|" line))
18 |
--------------------------------------------------------------------------------
/tests/eval/read-line/lines.txt:
--------------------------------------------------------------------------------
1 | This is test input.
2 | It is substituted for :stdin via with-in-str in the test itself.
3 |
--------------------------------------------------------------------------------
/tests/eval/read-line/stdin.txt:
--------------------------------------------------------------------------------
1 | This file becomes :stdin during the exec of Joker via run-forked-test.
2 | So it should appear in the output too.
3 |
--------------------------------------------------------------------------------
/tests/eval/read-line/stdout.txt:
--------------------------------------------------------------------------------
1 | | This is test input.
2 | | It is substituted for :stdin via with-in-str in the test itself.
3 | | This file becomes :stdin during the exec of Joker via run-forked-test.
4 | | So it should appear in the output too.
5 |
--------------------------------------------------------------------------------
/tests/eval/stdin-pipe/input.joke:
--------------------------------------------------------------------------------
1 | (ns stdin-pipe-test
2 | (:require [joker.os :as os]))
3 |
4 | (let [result (os/exec "cat" {:stdin *in*})]
5 | (print "|" (:out result)))
6 |
--------------------------------------------------------------------------------
/tests/eval/stdin-pipe/stdin.txt:
--------------------------------------------------------------------------------
1 | stdin pipe test
2 |
--------------------------------------------------------------------------------
/tests/eval/stdin-pipe/stdout.txt:
--------------------------------------------------------------------------------
1 | | stdin pipe test
2 |
--------------------------------------------------------------------------------
/tests/eval/string.joke:
--------------------------------------------------------------------------------
1 | (ns joker.test-joker.string
2 | (:require [joker.string :as str]
3 | [joker.test :refer [deftest is]]))
4 |
5 | (deftest quoted
6 | (is (= (str #"a\.\(b\.c\)") (str (str/re-quote "a.(b.c)")))))
7 |
8 | (deftest string
9 | (is (= "a.(b.c)" (str #"a.(b.c)"))))
10 |
11 | (deftest regex
12 | (is (= (str #"a.b.c") (str #"a.b.c"))))
13 |
14 | (deftest split-of-regex
15 | (is (= ["a" "c" "ef"] (str/split "abcdef" #"(b|d)"))))
16 |
17 | (deftest split-of-string
18 | (is (= ["ab" "def"] (str/split "abcdef" "c")))
19 | (is (= ["abcdef"] (str/split "abcdef" "(b|d)"))))
20 |
21 | (deftest split-N-of-regex
22 | (is (= ["a" "b/c/d"] (str/split "a/b/c/d" #"/" 2))))
23 |
24 | (deftest split-N-of-string
25 | (is (= ["a" "b/c/d"] (str/split "a/b/c/d" "/" 2))))
26 |
--------------------------------------------------------------------------------
/tests/eval/types.joke:
--------------------------------------------------------------------------------
1 | (ns joker.test-clojure.types
2 | (:require [joker.test :refer [deftest is]]))
3 |
4 | (deftest test-types
5 | (is (= (get (joker.core/types__) "Boolean") Boolean))
6 | (is (= (get (joker.core/types__) "Int") Int)))
7 |
8 | (deftest stdin
9 | (is (instance? BufferedReader *in*)
10 | "*in* must be BufferedReader (technically it must implement StringReader interface)
11 | for (read-line) to work"))
12 |
--------------------------------------------------------------------------------
/tests/eval/url-test.joke:
--------------------------------------------------------------------------------
1 | (ns joker.test-joker.url
2 | (:require [joker.test :refer [deftest is]]
3 | [joker.url :as url]))
4 |
5 | (deftest parse-query
6 | (is (= {} (url/parse-query "")))
7 | (is (= {"q" ["1"]} (url/parse-query "q=1")))
8 | (is (= {"q" [""]} (url/parse-query "q")))
9 | (is (= {"foo" ["1"] "bar" ["2" "3"]} (url/parse-query "foo=1&bar=2&bar=3"))))
10 |
--------------------------------------------------------------------------------
/tests/flags/config/.joker:
--------------------------------------------------------------------------------
1 | {:known-macros [foobar.macros/defthing]}
2 |
--------------------------------------------------------------------------------
/tests/flags/input-warning.clj:
--------------------------------------------------------------------------------
1 | (let [a 1] "foo")
2 |
--------------------------------------------------------------------------------
/tests/flags/input.clj:
--------------------------------------------------------------------------------
1 | (clojure.string/split "foobar")
2 |
--------------------------------------------------------------------------------
/tests/flags/input.cljs:
--------------------------------------------------------------------------------
1 | (.log js/console)
2 |
--------------------------------------------------------------------------------
/tests/flags/input.edn:
--------------------------------------------------------------------------------
1 | {:foobar #foo/bar "something something"}
2 |
--------------------------------------------------------------------------------
/tests/flags/input.joke:
--------------------------------------------------------------------------------
1 | (joker.string/split "ha-ha-ha-ha" #"-")
2 |
--------------------------------------------------------------------------------
/tests/flags/macro.clj:
--------------------------------------------------------------------------------
1 | (ns test.foo
2 | (:require [foobar.macros :refer [defthing]]))
3 |
4 | (defthing something
5 | "pewpew")
6 |
7 |
--------------------------------------------------------------------------------
/tests/flags/script-flags.joke:
--------------------------------------------------------------------------------
1 | (println (subvec (joker.os/args) 2))
2 |
--------------------------------------------------------------------------------
/tests/lib/test-local/lib.joke:
--------------------------------------------------------------------------------
1 | (ns test-local.lib)
2 |
3 | (def b :b)
4 |
--------------------------------------------------------------------------------
/tests/lib1.joke:
--------------------------------------------------------------------------------
1 | (in-ns 'tests.lib1)
2 | (joker.core/refer 'joker.core)
3 | (println "in lib1")
4 |
5 | (require ['tests.lib2])
6 |
7 | (def v1 1)
8 |
9 | (defn f1
10 | [s]
11 | (count s))
12 |
--------------------------------------------------------------------------------
/tests/lib2.joke:
--------------------------------------------------------------------------------
1 | (in-ns 'tests.lib2)
2 | (joker.core/refer 'joker.core)
3 |
4 | (println "in lib2")
5 |
6 | (def v2 2)
7 |
--------------------------------------------------------------------------------
/tests/lib3.joke:
--------------------------------------------------------------------------------
1 | (ns tests.lib3
2 | "Test namespace"
3 | (:require tests.lib2))
4 |
--------------------------------------------------------------------------------
/tests/linter/anonymous-fn/input.clj:
--------------------------------------------------------------------------------
1 | (#(prn {:a %, :b 2}) :c)
2 | (#(prn {:a %% :b 2}) :c)
3 |
--------------------------------------------------------------------------------
/tests/linter/anonymous-fn/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/anonymous-fn/input.clj:2:13: Read error: Arg literal must be %, %& or %integer
2 |
--------------------------------------------------------------------------------
/tests/linter/case/input.clj:
--------------------------------------------------------------------------------
1 | ;; Should PASS
2 | (case 1 ("F") false true)
3 |
4 | ;; Should FAIL
5 | (case 1 (1 2) false (2 4) true 4 false)
6 |
--------------------------------------------------------------------------------
/tests/linter/case/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/case/input.clj:5:21: Parse error: Duplicate case test constant: (2 4)
2 | tests/linter/case/input.clj:5:32: Parse error: Duplicate case test constant: 4
3 |
--------------------------------------------------------------------------------
/tests/linter/classnames/input.clj:
--------------------------------------------------------------------------------
1 | (ns test.ns)
2 |
3 | (defprotocol ITest
4 | (x [this]))
5 |
6 | (extend-protocol ITest
7 | datomic.db.Db
8 | (x [this] (println "do something")))
9 |
--------------------------------------------------------------------------------
/tests/linter/classnames/output.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/candid82/joker/1eed1c02c38ef1373640c42af1423808826820cc/tests/linter/classnames/output.txt
--------------------------------------------------------------------------------
/tests/linter/cljs-interop/input.cljs:
--------------------------------------------------------------------------------
1 | (ns foo.bar
2 | (:import goog.net.XhrIo))
3 |
4 | (XhrIo.send "http://example.com" (constantly nil))
5 | js/Math.PI
6 | (def m js/Math)
7 | m.PI
8 | (.log js/console)
9 | (Math/PI)
10 |
11 | g.PI
12 |
--------------------------------------------------------------------------------
/tests/linter/cljs-interop/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/cljs-interop/input.cljs:11:1: Parse error: Unable to resolve symbol: g
2 |
--------------------------------------------------------------------------------
/tests/linter/cond/input.clj:
--------------------------------------------------------------------------------
1 | ;; Should PASS
2 | (cond 1 2)
3 |
4 | ;; Should FAIL
5 | (cond)
6 | (cond 1)
7 |
8 |
--------------------------------------------------------------------------------
/tests/linter/cond/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/cond/input.clj:5:1: Parse warning: Empty cond
2 | tests/linter/cond/input.clj:6:7: Exception: cond requires an even number of forms
3 |
--------------------------------------------------------------------------------
/tests/linter/conditionals-clj-1/input.clj:
--------------------------------------------------------------------------------
1 | ;; Should PASS
2 |
3 | [#?(:cljs 1)]
4 | (#?(:cljs 1))
5 | {#?(:cljs 1)}
6 | {#?@(:clj [1 2])}
7 | {#?@(:clj [])}
8 | #?(:clj 1)
9 | #?@(:cljs 3)
10 | (def regexp #?(:clj re-pattern :cljs js/XRegExp))
11 |
12 |
13 | ;; Should FAIL
14 |
15 | #?(:cljs)
16 | #?(:cljs (let [] 1) :default (let [] 1))
17 | [#?@(:clj 1)]
18 | #?(:clj 234ewr :cljs 2)
19 |
20 |
--------------------------------------------------------------------------------
/tests/linter/conditionals-clj-1/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/conditionals-clj-1/input.clj:15:9: Read error: Reader conditional requires an even number of forms
2 | tests/linter/conditionals-clj-1/input.clj:16:30: Parse warning: let form with empty bindings vector
3 | tests/linter/conditionals-clj-1/input.clj:17:12: Read error: Spliced form in reader conditional must be Seqable, got Int
4 | tests/linter/conditionals-clj-1/input.clj:18:14: Read error: Invalid number: 234ewr
5 |
--------------------------------------------------------------------------------
/tests/linter/conditionals-clj-2/input.clj:
--------------------------------------------------------------------------------
1 | #?@(:cljs 3 :clj (let [_ 1]))
2 |
--------------------------------------------------------------------------------
/tests/linter/conditionals-clj-2/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/conditionals-clj-2/input.clj:1:29: Read error: Reader conditional splicing not allowed at the top level.
2 |
--------------------------------------------------------------------------------
/tests/linter/conditionals-clj-3/input.clj:
--------------------------------------------------------------------------------
1 | #?(:test 1)
2 |
--------------------------------------------------------------------------------
/tests/linter/conditionals-clj-3/output.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/candid82/joker/1eed1c02c38ef1373640c42af1423808826820cc/tests/linter/conditionals-clj-3/output.txt
--------------------------------------------------------------------------------
/tests/linter/conditionals-cljs/input.cljs:
--------------------------------------------------------------------------------
1 | ;; Should PASS
2 |
3 | #?(:clj 1)
4 | (def regexp #?(:clj re-pattern :cljs js/XRegExp))
5 | #?(:clj (let [a 1]) :cljs 3)
6 |
7 |
8 | ;; Should FAIL
9 |
10 | #?(:cljs (let [] 1) :default (let [] 1))
11 | #?@(:cljs 3)
12 | #?(:clj 234ewr :cljs 2)
13 |
14 |
--------------------------------------------------------------------------------
/tests/linter/conditionals-cljs/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/conditionals-cljs/input.cljs:10:10: Parse warning: let form with empty bindings vector
2 | tests/linter/conditionals-cljs/input.cljs:11:12: Read error: Spliced form in reader conditional must be Seqable, got Int
3 | tests/linter/conditionals-cljs/input.cljs:12:14: Read error: Invalid number: 234ewr
4 |
--------------------------------------------------------------------------------
/tests/linter/condp/input.clj:
--------------------------------------------------------------------------------
1 | (condp = 1)
2 | (condp = 1 2)
3 |
4 | (condp = 1 2 3)
5 |
--------------------------------------------------------------------------------
/tests/linter/condp/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/condp/input.clj:1:1: Parse error: condp with no clauses
2 | :0:0: Parse warning: unused binding: pred__1
3 | tests/linter/condp/input.clj:2:1: Parse warning: condp with default expression only
4 | :0:0: Parse warning: unused binding: expr__4
5 | :0:0: Parse warning: unused binding: pred__3
6 |
--------------------------------------------------------------------------------
/tests/linter/constr-call-cljs/input.cljs:
--------------------------------------------------------------------------------
1 | (def ^:private stream (js/require "stream"))
2 | (def ^:private ReadableStream (.-ReadableStream stream))
3 | (ReadableStream. #js {:read (fn [_] ())})
4 |
--------------------------------------------------------------------------------
/tests/linter/constr-call-cljs/output.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/candid82/joker/1eed1c02c38ef1373640c42af1423808826820cc/tests/linter/constr-call-cljs/output.txt
--------------------------------------------------------------------------------
/tests/linter/def/input.clj:
--------------------------------------------------------------------------------
1 | (def String "safsa")
2 | (def Comparable "asdf")
3 |
--------------------------------------------------------------------------------
/tests/linter/def/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/def/input.clj:1:6: Parse warning: Expecting var, but String is a type
2 | tests/linter/def/input.clj:2:6: Parse warning: Expecting var, but Comparable is a type
3 |
--------------------------------------------------------------------------------
/tests/linter/defmethod/input.clj:
--------------------------------------------------------------------------------
1 | (defmulti m1)
2 |
3 | ;; Should FAIL
4 | (defmethod m1 :v
5 | [_a]
6 | b)
7 |
8 | (defmethod m2 :v [] nil)
9 |
10 | (defmethod m3)
11 |
--------------------------------------------------------------------------------
/tests/linter/defmethod/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/defmethod/input.clj:6:3: Parse error: Unable to resolve symbol: b
2 | tests/linter/defmethod/input.clj:8:12: Parse error: Unable to resolve symbol: m2
3 | tests/linter/defmethod/input.clj:10:1: Eval error: Wrong number of args (1) passed to core/defmethod; expects at least 3
4 |
--------------------------------------------------------------------------------
/tests/linter/defn-0/input.clj:
--------------------------------------------------------------------------------
1 | (defn f 2)
2 |
--------------------------------------------------------------------------------
/tests/linter/defn-0/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/defn-0/input.clj:1:1: Exception: Parameter declaration "2" must be a vector
2 |
--------------------------------------------------------------------------------
/tests/linter/defn-1/input.clj:
--------------------------------------------------------------------------------
1 | (defn f "sdfsf")
2 |
--------------------------------------------------------------------------------
/tests/linter/defn-1/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/defn-1/input.clj:1:1: Exception: Parameter declaration missing
2 |
--------------------------------------------------------------------------------
/tests/linter/defn-2/input.clj:
--------------------------------------------------------------------------------
1 | (defn f ([]) 1)
2 |
--------------------------------------------------------------------------------
/tests/linter/defn-2/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/defn-2/input.clj:1:1: Exception: Invalid signature: "1" must be a list
2 |
--------------------------------------------------------------------------------
/tests/linter/defn-3/input.clj:
--------------------------------------------------------------------------------
1 | (defn f ([]) (1))
2 |
--------------------------------------------------------------------------------
/tests/linter/defn-3/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/defn-3/input.clj:1:1: Exception: Parameter declaration "1" must be a vector
2 |
--------------------------------------------------------------------------------
/tests/linter/defprotocol/.joker:
--------------------------------------------------------------------------------
1 | {:rules {:unused-fn-parameters true}}
2 |
--------------------------------------------------------------------------------
/tests/linter/defprotocol/input.clj:
--------------------------------------------------------------------------------
1 | (defprotocol P
2 | "P docstring"
3 | (m1 [a] [a b]
4 | "m1 docstring")
5 |
6 | (m2 [a])
7 |
8 | (m3)
9 |
10 | (m4 [])
11 |
12 | (m1 [a]))
13 |
--------------------------------------------------------------------------------
/tests/linter/defprotocol/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/defprotocol/input.clj:10:4: Exception: Definition of function m4 in protocol P must take at least one arg.
2 | tests/linter/defprotocol/input.clj:12:4: Exception: Function m1 in protocol P was redefined. Specify all arities in single definition.
3 | tests/linter/defprotocol/input.clj:8:4: Exception: Parameter declaration missing
4 |
--------------------------------------------------------------------------------
/tests/linter/defrecord/input.clj:
--------------------------------------------------------------------------------
1 | (ns test.test
2 | (:require [test.prococol1 :refer [TestProtocol1]]))
3 |
4 | (defprotocol TestProtocol)
5 |
6 | (defn test-method
7 | [] nil)
8 |
9 | (defrecord TestRecord [a b]
10 | TestProtocol
11 | (test-method [x y]
12 | (println x)
13 | (println x y a b c)
14 | (println a b))
15 |
16 | TestProtocol1
17 | (test-method1 [x y]
18 | (println x)
19 | (println x y a b c d)
20 | (println a b))
21 |
22 | TestProtocol2
23 | (test-method2 [x _y]
24 | (println x)))
25 |
26 | (instance? TestRecord 1)
27 | (map->TestRecord 1)
28 | (->TestRecord 1 2)
29 |
30 | (map->TestRecord 1 2)
31 | (->TestRecord 1)
32 |
33 | (defrecord ^:private TestRecord1 [])
34 | (deftype TestType [])
35 |
36 | (->TestType)
37 |
--------------------------------------------------------------------------------
/tests/linter/defrecord/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/defrecord/input.clj:13:22: Parse error: Unable to resolve symbol: c
2 | tests/linter/defrecord/input.clj:19:24: Parse error: Unable to resolve symbol: d
3 | tests/linter/defrecord/input.clj:22:3: Parse error: Unable to resolve symbol: TestProtocol2
4 | tests/linter/defrecord/input.clj:30:1: Parse warning: Wrong number of args (2) passed to test.test/map->TestRecord
5 | tests/linter/defrecord/input.clj:31:1: Parse warning: Wrong number of args (1) passed to test.test/->TestRecord
6 |
--------------------------------------------------------------------------------
/tests/linter/deftest/input.clj:
--------------------------------------------------------------------------------
1 | (ns my
2 | (:require [clojure.test :refer [deftest]]))
3 |
4 | (deftest my-test
5 | (foo/bar 1))
6 |
--------------------------------------------------------------------------------
/tests/linter/deftest/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/deftest/input.clj:5:4: Parse error: Unable to resolve symbol: foo/bar
2 |
--------------------------------------------------------------------------------
/tests/linter/do/input.clj:
--------------------------------------------------------------------------------
1 | (do)
2 |
3 | (do 1)
4 |
5 | (do 1 2)
6 |
--------------------------------------------------------------------------------
/tests/linter/do/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/do/input.clj:1:1: Parse warning: do form with empty body
2 | tests/linter/do/input.clj:3:1: Parse warning: redundant do form
3 |
--------------------------------------------------------------------------------
/tests/linter/doseq/input.clj:
--------------------------------------------------------------------------------
1 | ;; Should PASS
2 | (doseq [_ (range 10)] 1)
3 |
4 | ;; Should FAIL
5 | (doseq [_ (range 10)])
6 |
--------------------------------------------------------------------------------
/tests/linter/doseq/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/doseq/input.clj:5:8: Parse warning: doseq with empty body
2 |
--------------------------------------------------------------------------------
/tests/linter/duplicate-def/input.clj:
--------------------------------------------------------------------------------
1 | (def b)
2 | (def b 1)
3 |
4 | (declare f)
5 | (defn f [] nil)
6 |
7 | (def a 1)
8 | (def a 2)
9 |
10 | (defn f1 [] nil)
11 | (defn f1 [_a] nil)
12 |
--------------------------------------------------------------------------------
/tests/linter/duplicate-def/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/duplicate-def/input.clj:8:6: Parse warning: Duplicate def of #'user/a
2 | tests/linter/duplicate-def/input.clj:11:7: Parse warning: Duplicate def of #'user/f1
3 |
--------------------------------------------------------------------------------
/tests/linter/exclude-list/input.clj:
--------------------------------------------------------------------------------
1 | (ns foo
2 | (:refer-clojure :exclude [list]))
3 |
4 | (defmacro bar [baz]
5 | `(identity ~baz))
6 |
--------------------------------------------------------------------------------
/tests/linter/exclude-list/output.txt:
--------------------------------------------------------------------------------
1 | :0:0: Parse error: Unable to resolve symbol: list
2 |
--------------------------------------------------------------------------------
/tests/linter/extend-protocol/input.clj:
--------------------------------------------------------------------------------
1 | (defprotocol P)
2 |
3 | (extend-protocol P
4 | Integer
5 | (m1 [_a] nil)
6 | (m2))
7 |
--------------------------------------------------------------------------------
/tests/linter/extend-protocol/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/extend-protocol/input.clj:6:4: Exception: Parameter declaration missing
2 |
--------------------------------------------------------------------------------
/tests/linter/extend-type-cljs/input.cljs:
--------------------------------------------------------------------------------
1 | (defprotocol P
2 | (m [_this _a]))
3 |
4 | (extend-type object
5 | P
6 | (m [_this a]
7 | (pr-str a))
8 | (m1 ))
9 |
--------------------------------------------------------------------------------
/tests/linter/extend-type-cljs/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/extend-type-cljs/input.cljs:8:4: Exception: Parameter declaration missing
2 |
--------------------------------------------------------------------------------
/tests/linter/extend-type/input.clj:
--------------------------------------------------------------------------------
1 | (defprotocol P
2 | (m [_this _a]))
3 |
4 | (extend-type Object
5 | P
6 | (m [_this a]
7 | (pr-str a))
8 | (m1 ))
9 |
--------------------------------------------------------------------------------
/tests/linter/extend-type/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/extend-type/input.clj:8:4: Exception: Parameter declaration missing
2 |
--------------------------------------------------------------------------------
/tests/linter/fn-0/input.clj:
--------------------------------------------------------------------------------
1 | (fn 2)
2 |
--------------------------------------------------------------------------------
/tests/linter/fn-0/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/fn-0/input.clj:1:1: Exception: Parameter declaration "2" must be a vector
2 |
--------------------------------------------------------------------------------
/tests/linter/fn-1/input.clj:
--------------------------------------------------------------------------------
1 | (fn "sdfsf")
2 |
--------------------------------------------------------------------------------
/tests/linter/fn-1/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/fn-1/input.clj:1:1: Exception: Parameter declaration "sdfsf" must be a vector
2 |
--------------------------------------------------------------------------------
/tests/linter/fn-2/input.clj:
--------------------------------------------------------------------------------
1 | (fn ([]) 1)
2 |
--------------------------------------------------------------------------------
/tests/linter/fn-2/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/fn-2/input.clj:1:1: Exception: Invalid signature: "1" must be a list
2 |
--------------------------------------------------------------------------------
/tests/linter/fn-3/input.clj:
--------------------------------------------------------------------------------
1 | (fn f ([]) (1))
2 |
--------------------------------------------------------------------------------
/tests/linter/fn-3/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/fn-3/input.clj:1:1: Exception: Parameter declaration "1" must be a vector
2 |
--------------------------------------------------------------------------------
/tests/linter/fn-unused-parameters/.joker:
--------------------------------------------------------------------------------
1 | {:rules {:unused-fn-parameters true}}
2 |
--------------------------------------------------------------------------------
/tests/linter/fn-unused-parameters/input.clj:
--------------------------------------------------------------------------------
1 | (defn f [_ _a b] 1)
2 |
--------------------------------------------------------------------------------
/tests/linter/fn-unused-parameters/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/fn-unused-parameters/input.clj:1:15: Parse warning: unused parameter: b
2 |
--------------------------------------------------------------------------------
/tests/linter/fn-with-empty-body/input.clj:
--------------------------------------------------------------------------------
1 | (defn f [])
2 |
--------------------------------------------------------------------------------
/tests/linter/fn-with-empty-body/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/fn-with-empty-body/input.clj:1:1: Parse warning: fn form with empty body
2 |
--------------------------------------------------------------------------------
/tests/linter/for-1/input.clj:
--------------------------------------------------------------------------------
1 | (for [a [1 2] :le [a 1]] a)
2 |
--------------------------------------------------------------------------------
/tests/linter/for-1/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/for-1/input.clj:1:15: Exception: Invalid keyword :le in "for" form
2 |
--------------------------------------------------------------------------------
/tests/linter/for-2/input.clj:
--------------------------------------------------------------------------------
1 | (for 1 2)
2 |
--------------------------------------------------------------------------------
/tests/linter/for-2/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/for-2/input.clj:1:1: Exception: for requires a vector for its binding
2 |
--------------------------------------------------------------------------------
/tests/linter/for-3/input.clj:
--------------------------------------------------------------------------------
1 | (for [1] 2)
2 |
--------------------------------------------------------------------------------
/tests/linter/for-3/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/for-3/input.clj:1:1: Exception: for requires an even number of forms in binding vector
2 |
--------------------------------------------------------------------------------
/tests/linter/function-call-cljs/input.cljs:
--------------------------------------------------------------------------------
1 | ;; Should PASS
2 |
3 | (array 1 2)
4 |
--------------------------------------------------------------------------------
/tests/linter/function-call-cljs/output.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/candid82/joker/1eed1c02c38ef1373640c42af1423808826820cc/tests/linter/function-call-cljs/output.txt
--------------------------------------------------------------------------------
/tests/linter/function-call/input.clj:
--------------------------------------------------------------------------------
1 | (defn f1 [] nil)
2 | (defn f2 [_x] nil)
3 | (def v1 1)
4 | (def k :t)
5 | (def m {})
6 | (def s #{})
7 | ;; Should PASS
8 |
9 | (spit "test" "test" :append true)
10 | (map identity)
11 | (f1)
12 | (f2 1)
13 | (k {})
14 | ((fn [] nil))
15 | (#{} 1)
16 | (s 1)
17 | ([] 1)
18 | ([]) ;; we don't check vector call arity as it would cause false positives in some macros (like alt!!)
19 | ({1 2} 1)
20 | ({1 2} 1 2)
21 | (m 1)
22 | (m 1 2)
23 | (:t 1 2)
24 | (:t 1)
25 |
26 | ;; Should FAIL
27 | (map)
28 | (*assert*)
29 | (f1 1)
30 | (f2)
31 | (v1)
32 | (1)
33 | ("")
34 | ((fn [] nil) 1)
35 | (:t)
36 | (:t 1 2 3)
37 | ({})
38 | ({} 1 2 3)
39 | (m)
40 | (m 1 2 3)
41 | (#{})
42 | (#{} 1 2)
43 | (s)
44 | (s 1 2)
45 | (= 1)
46 | (not= 1)
47 | (< 1)
48 | (> 1)
49 | (<= 1)
50 | (>= 1)
51 | (== 1)
52 |
--------------------------------------------------------------------------------
/tests/linter/function-call/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/function-call/input.clj:27:1: Parse warning: Wrong number of args (0) passed to core/map
2 | tests/linter/function-call/input.clj:28:1: Parse warning: core/*assert* is not a function
3 | tests/linter/function-call/input.clj:29:1: Parse warning: Wrong number of args (1) passed to user/f1
4 | tests/linter/function-call/input.clj:30:1: Parse warning: Wrong number of args (0) passed to user/f2
5 | tests/linter/function-call/input.clj:31:1: Parse warning: user/v1 is not a function
6 | tests/linter/function-call/input.clj:32:1: Parse warning: 1 is not a function
7 | tests/linter/function-call/input.clj:33:1: Parse warning: is not a function
8 | tests/linter/function-call/input.clj:34:1: Parse warning: Wrong number of args (1) passed to fn
9 | tests/linter/function-call/input.clj:35:1: Parse warning: Wrong number of args (0) passed to :t
10 | tests/linter/function-call/input.clj:36:1: Parse warning: Wrong number of args (3) passed to :t
11 | tests/linter/function-call/input.clj:37:1: Parse warning: Wrong number of args (0) passed to a map
12 | tests/linter/function-call/input.clj:38:1: Parse warning: Wrong number of args (3) passed to a map
13 | tests/linter/function-call/input.clj:39:1: Parse warning: Wrong number of args (0) passed to a map
14 | tests/linter/function-call/input.clj:40:1: Parse warning: Wrong number of args (3) passed to a map
15 | tests/linter/function-call/input.clj:41:1: Parse warning: Wrong number of args (0) passed to a set
16 | tests/linter/function-call/input.clj:42:1: Parse warning: Wrong number of args (2) passed to a set
17 | tests/linter/function-call/input.clj:43:1: Parse warning: Wrong number of args (0) passed to a set
18 | tests/linter/function-call/input.clj:44:1: Parse warning: Wrong number of args (2) passed to a set
19 | tests/linter/function-call/input.clj:45:1: Parse warning: Wrong number of args (1) passed to core/=
20 | tests/linter/function-call/input.clj:46:1: Parse warning: Wrong number of args (1) passed to core/not=
21 | tests/linter/function-call/input.clj:47:1: Parse warning: Wrong number of args (1) passed to core/<
22 | tests/linter/function-call/input.clj:48:1: Parse warning: Wrong number of args (1) passed to core/>
23 | tests/linter/function-call/input.clj:49:1: Parse warning: Wrong number of args (1) passed to core/<=
24 | tests/linter/function-call/input.clj:50:1: Parse warning: Wrong number of args (1) passed to core/>=
25 | tests/linter/function-call/input.clj:51:1: Parse warning: Wrong number of args (1) passed to core/==
26 |
--------------------------------------------------------------------------------
/tests/linter/if-let-1/input.clj:
--------------------------------------------------------------------------------
1 | (if-let 1 2)
2 |
--------------------------------------------------------------------------------
/tests/linter/if-let-1/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/if-let-1/input.clj:1:1: Exception: if-let requires a vector for its binding
2 |
--------------------------------------------------------------------------------
/tests/linter/if-let-2/input.clj:
--------------------------------------------------------------------------------
1 | (if-let [1] 2)
2 |
--------------------------------------------------------------------------------
/tests/linter/if-let-2/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/if-let-2/input.clj:1:1: Exception: if-let requires exactly 2 forms in binding vector
2 |
--------------------------------------------------------------------------------
/tests/linter/if-let-3/input.clj:
--------------------------------------------------------------------------------
1 | (if-let [a 1] 1 2 3)
2 |
--------------------------------------------------------------------------------
/tests/linter/if-let-3/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/if-let-3/input.clj:1:1: Exception: if-let requires 1 or 2 forms after binding vector
2 |
--------------------------------------------------------------------------------
/tests/linter/if/.joker:
--------------------------------------------------------------------------------
1 | {:rules {:if-without-else true}}
2 |
--------------------------------------------------------------------------------
/tests/linter/if/input.clj:
--------------------------------------------------------------------------------
1 | ;; Should PASS
2 |
3 | (if 1 2 3)
4 | (if-let [a 1] a 2)
5 |
6 | ;; Should FAIL
7 |
8 | (if 1 2)
9 | (if-let [a 1] a)
10 |
--------------------------------------------------------------------------------
/tests/linter/if/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/if/input.clj:8:1: Parse warning: missing else branch
2 | tests/linter/if/input.clj:9:1: Parse warning: missing else branch
3 |
--------------------------------------------------------------------------------
/tests/linter/inline-def/input.clj:
--------------------------------------------------------------------------------
1 | (let [a 1]
2 | (def t)
3 | a)
4 |
--------------------------------------------------------------------------------
/tests/linter/inline-def/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/inline-def/input.clj:2:3: Parse warning: inline def
2 |
--------------------------------------------------------------------------------
/tests/linter/learned-macros/.jokerd/linter.clj:
--------------------------------------------------------------------------------
1 | (ns rum.core)
2 |
3 | (defmacro defc [& params]
4 | (let [[name _ _ arg-vector & body] params]
5 | `(defn ~name ~arg-vector ~@body)))
6 |
7 | (ns rum.core1)
8 |
9 | (defmacro defc1 [& params]
10 | (let [[name _ _ arg-vector & body] params]
11 | `(defn ~name ~arg-vector ~@body)))
12 |
13 | (ns rum.core2)
14 |
15 | (defmacro defc2 [& params]
16 | (let [[name _ _ arg-vector & body] params]
17 | `(defn ~name ~arg-vector ~@body)))
18 |
19 |
20 | (in-ns 'user)
21 |
--------------------------------------------------------------------------------
/tests/linter/learned-macros/input.clj:
--------------------------------------------------------------------------------
1 | (require '[rum.core :as rum])
2 | (require '[rum.core1 :as rum1])
3 |
4 | (rum/defc Foo < rum/static [{:keys [bar/foo]}] [:div (str foo)])
5 |
--------------------------------------------------------------------------------
/tests/linter/learned-macros/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/learned-macros/input.clj:2:12: Parse warning: unused namespace rum.core1
2 |
--------------------------------------------------------------------------------
/tests/linter/let-1/input.clj:
--------------------------------------------------------------------------------
1 | (let ["sdf" 1])
2 |
--------------------------------------------------------------------------------
/tests/linter/let-1/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/let-1/input.clj:1:7: Exception: Unsupported binding form: sdf
2 |
--------------------------------------------------------------------------------
/tests/linter/let/input.clj:
--------------------------------------------------------------------------------
1 | ;; Should PASS
2 |
3 | (require '[test.ns1 :as ns1])
4 |
5 | (let [a 1]
6 | a)
7 |
8 | (let [{:keys [:t ::g]} {:t 1 :user/g 2}] [t g])
9 | (let [{::ns1/keys [a]} {:test.ns1/a 1}] a)
10 |
11 | ;; Should FAIL
12 | (let [_ 1])
13 | (let [] 1)
14 | (let [foo/bar 2] bar)
15 | (let [[a & more 1] []] 1)
16 |
--------------------------------------------------------------------------------
/tests/linter/let/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/let/input.clj:12:1: Parse warning: let form with empty body
2 | tests/linter/let/input.clj:13:1: Parse warning: let form with empty bindings vector
3 | tests/linter/let/input.clj:14:7: Parse error: Can't let qualified name: foo/bar
4 | tests/linter/let/input.clj:15:6: Exception: Unsupported binding form, only :as can follow & parameter
5 |
--------------------------------------------------------------------------------
/tests/linter/letfn/input.clj:
--------------------------------------------------------------------------------
1 | (letfn [(neven? [n] (if (zero? n) true (nodd? (dec n))))
2 | (nodd? [n] (if (zero? n) false (neven? (dec n))))]
3 | (neven? 10))
4 |
5 |
6 | (letfn)
7 |
--------------------------------------------------------------------------------
/tests/linter/letfn/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/letfn/input.clj:6:1: Eval error: Wrong number of args (0) passed to core/letfn; expects at least 2
2 |
--------------------------------------------------------------------------------
/tests/linter/linter-files/.joker:
--------------------------------------------------------------------------------
1 | {:ignored-unused-namespaces [com.rpl.specter]}
2 |
--------------------------------------------------------------------------------
/tests/linter/linter-files/.jokerd/linter.clj:
--------------------------------------------------------------------------------
1 | (in-ns 'joker.core)
2 | (defn transform [apath transform-fn structure])
3 | (def MAP-VALS)
4 | (def ALL)
5 |
--------------------------------------------------------------------------------
/tests/linter/linter-files/input.clj:
--------------------------------------------------------------------------------
1 | (ns my.test (:require [com.rpl.specter :refer :all]))
2 |
3 | (transform [MAP-VALS ALL MAP-VALS even?] inc [])
4 |
--------------------------------------------------------------------------------
/tests/linter/linter-files/output.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/candid82/joker/1eed1c02c38ef1373640c42af1423808826820cc/tests/linter/linter-files/output.txt
--------------------------------------------------------------------------------
/tests/linter/macro-call-1/input.clj:
--------------------------------------------------------------------------------
1 | (deftype)
2 |
--------------------------------------------------------------------------------
/tests/linter/macro-call-1/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/macro-call-1/input.clj:1:1: Eval error: Wrong number of args (0) passed to core/deftype; expects at least 3
2 |
--------------------------------------------------------------------------------
/tests/linter/macro-call/input.clj:
--------------------------------------------------------------------------------
1 | (memfn)
2 | (..)
3 | (defstruct)
4 | (with-local-vars)
5 | (definline)
6 | (definterface)
7 | (proxy-super)
8 | (with-open)
9 | (deftype)
10 | (defrecord)
11 |
--------------------------------------------------------------------------------
/tests/linter/macro-call/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/macro-call/input.clj:1:1: Parse warning: Wrong number of args (0) passed to core/memfn
2 | tests/linter/macro-call/input.clj:2:1: Parse warning: Wrong number of args (0) passed to core/..
3 | tests/linter/macro-call/input.clj:3:1: Parse warning: Wrong number of args (0) passed to core/defstruct
4 | tests/linter/macro-call/input.clj:4:1: Parse warning: Wrong number of args (0) passed to core/with-local-vars
5 | tests/linter/macro-call/input.clj:5:1: Parse warning: Wrong number of args (0) passed to core/definline
6 | tests/linter/macro-call/input.clj:6:1: Parse warning: Wrong number of args (0) passed to core/definterface
7 | tests/linter/macro-call/input.clj:7:1: Parse warning: Wrong number of args (0) passed to core/proxy-super
8 | tests/linter/macro-call/input.clj:8:1: Parse warning: Wrong number of args (0) passed to core/with-open
9 | tests/linter/macro-call/input.clj:9:1: Eval error: Wrong number of args (0) passed to core/deftype; expects at least 3
10 | tests/linter/macro-call/input.clj:10:1: Eval error: Wrong number of args (0) passed to core/defrecord; expects at least 3
11 |
--------------------------------------------------------------------------------
/tests/linter/merge/input.clj:
--------------------------------------------------------------------------------
1 | (ns test
2 | (:require [clojure.core.async :as async]))
3 |
4 | (async/merge [])
5 |
--------------------------------------------------------------------------------
/tests/linter/merge/output.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/candid82/joker/1eed1c02c38ef1373640c42af1423808826820cc/tests/linter/merge/output.txt
--------------------------------------------------------------------------------
/tests/linter/namespaced-maps/input.clj:
--------------------------------------------------------------------------------
1 | (require 'joker.string)
2 | (alias 's 'joker.string)
3 | ;; Should PASS
4 | #:t{:g 1}
5 | #::{:g 1}
6 | #:t{:_/g 1}
7 | #:t{:h/g 1}
8 | #::s{:g 1}
9 |
10 | ;; Should FAIL
11 | #::{g 1}
12 |
--------------------------------------------------------------------------------
/tests/linter/namespaced-maps/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/namespaced-maps/input.clj:11:5: Parse error: Unable to resolve symbol: user/g
2 |
--------------------------------------------------------------------------------
/tests/linter/ns-1/input.clj:
--------------------------------------------------------------------------------
1 | (ns test
2 | (:require [test.n1 :as n1]))
3 |
4 | (n1/t)
5 |
--------------------------------------------------------------------------------
/tests/linter/ns-1/output.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/candid82/joker/1eed1c02c38ef1373640c42af1423808826820cc/tests/linter/ns-1/output.txt
--------------------------------------------------------------------------------
/tests/linter/ns-10/input.clj:
--------------------------------------------------------------------------------
1 | (ns my-ns
2 | (:require [clojure.java.io :as io]
3 | [clojure.string :as str]
4 | [clojure.test :as t]))
5 |
--------------------------------------------------------------------------------
/tests/linter/ns-10/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/ns-10/input.clj:2:14: Parse warning: unused namespace clojure.java.io
2 | tests/linter/ns-10/input.clj:3:14: Parse warning: unused namespace clojure.string
3 | tests/linter/ns-10/input.clj:4:14: Parse warning: unused namespace clojure.test
4 |
--------------------------------------------------------------------------------
/tests/linter/ns-2/input.clj:
--------------------------------------------------------------------------------
1 | (ns test
2 | (:require [test.n1 :as n1]
3 | [test.n2 :as n1]))
4 |
5 | (n1/f)
6 | (f)
7 |
--------------------------------------------------------------------------------
/tests/linter/ns-2/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/ns-2/input.clj:3:26: Parse error: Alias n1 already exists in namespace test, aliasing test.n1
2 | tests/linter/ns-2/input.clj:6:2: Parse error: Unable to resolve symbol: f
3 | tests/linter/ns-2/input.clj:3:14: Parse warning: unused namespace test.n2
4 |
--------------------------------------------------------------------------------
/tests/linter/ns-3/input.clj:
--------------------------------------------------------------------------------
1 | (ns test
2 | (:require [test.n1 :as n1
3 | test.n2 :as n2]))
4 |
5 |
--------------------------------------------------------------------------------
/tests/linter/ns-3/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/ns-3/input.clj:1:1: Eval error: No value supplied for key true
2 |
--------------------------------------------------------------------------------
/tests/linter/ns-4/input.clj:
--------------------------------------------------------------------------------
1 | (ns test
2 | (:require [tt :refer g]))
3 |
--------------------------------------------------------------------------------
/tests/linter/ns-4/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/ns-4/input.clj:2:14: Exception: :only/:refer value must be a sequential collection of symbols
2 | tests/linter/ns-4/input.clj:2:14: Parse warning: unused namespace tt
3 |
--------------------------------------------------------------------------------
/tests/linter/ns-5/input.clj:
--------------------------------------------------------------------------------
1 | (ns test
2 | (:require [test.ns1]
3 | [test.ns1]
4 | [left-pad :as lp]))
5 |
6 | (test.ns1/f)
7 | (left-pad)
8 | (lp)
9 |
--------------------------------------------------------------------------------
/tests/linter/ns-5/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/ns-5/input.clj:3:14: Parse warning: duplicate require for test.ns1
2 | tests/linter/ns-5/input.clj:7:2: Parse error: Unable to resolve symbol: left-pad
3 | tests/linter/ns-5/input.clj:8:2: Parse error: Unable to resolve symbol: lp
4 | tests/linter/ns-5/input.clj:4:14: Parse warning: unused namespace left-pad
5 |
--------------------------------------------------------------------------------
/tests/linter/ns-6/input.clj:
--------------------------------------------------------------------------------
1 | (ns test
2 | (:require [other.ns :refer [f]]))
3 |
4 | (defn map [] nil)
5 | (def f (fn []))
6 |
--------------------------------------------------------------------------------
/tests/linter/ns-6/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/ns-6/input.clj:4:7: Parse warning: WARNING: map already refers to: #'joker.core/map in namespace test, being replaced by: #'test/map
2 |
3 | tests/linter/ns-6/input.clj:5:6: Eval error: WARNING: f already refers to: #'other.ns/f in namespace test
4 | tests/linter/ns-6/input.clj:2:14: Parse warning: unused namespace other.ns
5 |
--------------------------------------------------------------------------------
/tests/linter/ns-7/input.clj:
--------------------------------------------------------------------------------
1 | (create-ns 'test.test)
2 | (require 'joker.os)
3 | (alias 'os 'joker.os)
4 | (alias 't 'test.test)
5 |
6 | (os/sh "ls")
7 | (test.test/foo)
8 | (t/bar)
9 |
--------------------------------------------------------------------------------
/tests/linter/ns-7/output.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/candid82/joker/1eed1c02c38ef1373640c42af1423808826820cc/tests/linter/ns-7/output.txt
--------------------------------------------------------------------------------
/tests/linter/ns-8/input.clj:
--------------------------------------------------------------------------------
1 | (ns example.macros
2 | (:require [ttt :default RaisedButton] :verbose))
3 |
4 | RaisedButton/t
5 |
--------------------------------------------------------------------------------
/tests/linter/ns-8/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/ns-8/input.clj:2:18: Exception: Unsupported option(s) supplied: :default
2 | tests/linter/ns-8/input.clj:4:1: Parse error: Unable to resolve symbol: RaisedButton/t
3 |
--------------------------------------------------------------------------------
/tests/linter/ns-9/input.clj:
--------------------------------------------------------------------------------
1 | (ns test
2 | (:require [clojure.string :refer [starts-with?] :rename {starts-with? begins-with?}]))
3 |
4 | (begins-with? "test" "t")
5 | (starts-with? "test" "t")
6 |
--------------------------------------------------------------------------------
/tests/linter/ns-9/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/ns-9/input.clj:5:2: Parse error: Unable to resolve symbol: starts-with?
2 |
--------------------------------------------------------------------------------
/tests/linter/ns-cljs-1/input.cljs:
--------------------------------------------------------------------------------
1 | (ns hello.world
2 | (:require [om.next :as om :refer-macros [defui]]
3 | [om.dom :as dom]))
4 |
5 | (defui HelloWorld
6 | Object
7 | (render [this]
8 | (dom/div nil "Hello, World!")))
9 |
--------------------------------------------------------------------------------
/tests/linter/ns-cljs-1/output.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/candid82/joker/1eed1c02c38ef1373640c42af1423808826820cc/tests/linter/ns-cljs-1/output.txt
--------------------------------------------------------------------------------
/tests/linter/ns-cljs-2/.joker:
--------------------------------------------------------------------------------
1 | {:known-namespaces [clojure.spec.gen.test]}
2 |
--------------------------------------------------------------------------------
/tests/linter/ns-cljs-2/input.cljs:
--------------------------------------------------------------------------------
1 | (alias 'stc 'clojure.spec.gen.test)
2 | (alias 'stc1 'clojure.spec.gen.test1)
3 |
4 | (stc/t)
5 | (stc1/t)
6 |
--------------------------------------------------------------------------------
/tests/linter/ns-cljs-2/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/ns-cljs-2/input.cljs:2:15: Parse warning: No namespace: clojure.spec.gen.test1 found
2 |
--------------------------------------------------------------------------------
/tests/linter/ns-cljs-3/input.cljs:
--------------------------------------------------------------------------------
1 | (ns example.macros
2 | (:require-macros [cljs.core.async.macros :as async])
3 | (:require [cljs.core.async :as async]
4 | [left-pad :as lp]
5 | ["material-ui/RaisedButton" :default RaisedButton]))
6 |
7 | (async/t)
8 | (left-pad)
9 | (lp 1)
10 | RaisedButton
11 | (t)
12 |
--------------------------------------------------------------------------------
/tests/linter/ns-cljs-3/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/ns-cljs-3/input.cljs:3:34: Parse error: Alias async already exists in namespace example.macros, aliasing cljs.core.async.macros
2 | tests/linter/ns-cljs-3/input.cljs:11:2: Parse error: Unable to resolve symbol: t
3 | tests/linter/ns-cljs-3/input.cljs:3:14: Parse warning: unused namespace cljs.core.async
4 |
--------------------------------------------------------------------------------
/tests/linter/ns-cljs-4/input.cljs:
--------------------------------------------------------------------------------
1 | (ns test
2 | (:require ["m1" :as ns1]
3 | ["m2/t"]
4 | ["m3/t" :as ns3]
5 | [ns1]
6 | [m1]))
7 |
8 | (ns3/f)
9 |
--------------------------------------------------------------------------------
/tests/linter/ns-cljs-4/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/ns-cljs-4/input.cljs:6:14: Parse warning: duplicate require for m1
2 | tests/linter/ns-cljs-4/input.cljs:2:14: Parse warning: unused namespace m1
3 | tests/linter/ns-cljs-4/input.cljs:3:14: Parse warning: unused namespace m2_t
4 | tests/linter/ns-cljs-4/input.cljs:5:14: Parse warning: unused namespace ns1
5 |
--------------------------------------------------------------------------------
/tests/linter/ns-cljs-5/input.cljs:
--------------------------------------------------------------------------------
1 | (ns bar.core
2 | (:require [foo.core :as foo :include-macros true :exclude [t] :only g :refer [k] :rename {} :refer-macros []]))
3 |
4 | (foo/bar)
5 |
--------------------------------------------------------------------------------
/tests/linter/ns-cljs-5/output.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/candid82/joker/1eed1c02c38ef1373640c42af1423808826820cc/tests/linter/ns-cljs-5/output.txt
--------------------------------------------------------------------------------
/tests/linter/proxy/input.clj:
--------------------------------------------------------------------------------
1 | (import org.apache.kafka.clients.producer.KafkaProducer)
2 |
3 | (proxy [KafkaProducer] []
4 | (send [producer-record] :whatever))
5 |
6 | (proxy [String] []
7 | (toString []
8 | (println this)))
9 |
10 |
11 |
--------------------------------------------------------------------------------
/tests/linter/proxy/output.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/candid82/joker/1eed1c02c38ef1373640c42af1423808826820cc/tests/linter/proxy/output.txt
--------------------------------------------------------------------------------
/tests/linter/reader/input.clj:
--------------------------------------------------------------------------------
1 | "\033[31mFOO\033[0m"
2 | (= {} (:))
3 |
--------------------------------------------------------------------------------
/tests/linter/reader/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/reader/input.clj:2:8: Read error: Invalid keyword: :
2 |
--------------------------------------------------------------------------------
/tests/linter/recur/input.clj:
--------------------------------------------------------------------------------
1 | ;; Should PASS
2 | (try 1 (catch Error e (loop [a 1] (recur (inc a)))))
3 |
4 | ;; Should FAIL
5 | (loop [a 1]
6 | (recur (inc a) nil))
7 |
--------------------------------------------------------------------------------
/tests/linter/recur/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/recur/input.clj:6:3: Parse error: Mismatched argument count to recur, expected: 1 args, got: 2
2 |
--------------------------------------------------------------------------------
/tests/linter/redundant-do/input.clj:
--------------------------------------------------------------------------------
1 | (do
2 | 3
3 | (do
4 | 1
5 | 2))
6 |
7 | (let [a 1]
8 | (do
9 | 1
10 | a))
11 |
12 | (defn f
13 | []
14 | (do 1 2))
15 |
16 | (if-let [a 1]
17 | a
18 | 2)
19 |
20 | (if-let [a 1]
21 | (do 3 a)
22 | 2)
23 |
24 | (when-let [a 1]
25 | (do 1 a))
26 |
27 | #(do (println 1) (println 2))
28 |
29 | #(do (println 1))
30 |
--------------------------------------------------------------------------------
/tests/linter/redundant-do/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/redundant-do/input.clj:3:3: Parse warning: redundant do form
2 | tests/linter/redundant-do/input.clj:8:3: Parse warning: redundant do form
3 | tests/linter/redundant-do/input.clj:14:3: Parse warning: redundant do form
4 | tests/linter/redundant-do/input.clj:25:3: Parse warning: redundant do form
5 | tests/linter/redundant-do/input.clj:29:2: Parse warning: redundant do form
6 |
--------------------------------------------------------------------------------
/tests/linter/regex/input.clj:
--------------------------------------------------------------------------------
1 | #"(paginate_by:\s*)\"(\w+)\""
2 |
--------------------------------------------------------------------------------
/tests/linter/regex/output.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/candid82/joker/1eed1c02c38ef1373640c42af1423808826820cc/tests/linter/regex/output.txt
--------------------------------------------------------------------------------
/tests/linter/reify/input.clj:
--------------------------------------------------------------------------------
1 | (defprotocol P1)
2 | (defprotocol P2)
3 |
4 | (reify
5 | P1
6 | (m1 [_a] nil)
7 | (m2 [_b] nil)
8 |
9 | P2
10 | (m3 [_c] nil)
11 | (m4))
12 |
--------------------------------------------------------------------------------
/tests/linter/reify/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/reify/input.clj:11:4: Exception: Parameter declaration "" must be a vector
2 |
--------------------------------------------------------------------------------
/tests/linter/symbol-resolution-1/.joker:
--------------------------------------------------------------------------------
1 | {:known-macros [[test.ns/test-macro [foo]]]}
2 |
--------------------------------------------------------------------------------
/tests/linter/symbol-resolution-1/input.clj:
--------------------------------------------------------------------------------
1 | (require '[test.ns :refer [test-macro]])
2 | (test-macro (do foo 1))
3 |
--------------------------------------------------------------------------------
/tests/linter/symbol-resolution-1/output.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/candid82/joker/1eed1c02c38ef1373640c42af1423808826820cc/tests/linter/symbol-resolution-1/output.txt
--------------------------------------------------------------------------------
/tests/linter/symbol-resolution-2/input.clj:
--------------------------------------------------------------------------------
1 | (ns my)
2 |
3 | (defn my-test
4 | ([]
5 | (my-test bar)))
6 |
--------------------------------------------------------------------------------
/tests/linter/symbol-resolution-2/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/symbol-resolution-2/input.clj:5:13: Parse error: Unable to resolve symbol: bar
2 |
--------------------------------------------------------------------------------
/tests/linter/symbol-resolution-cljs/input.cljs:
--------------------------------------------------------------------------------
1 | (ns tests.symbols-lint
2 | (:require [cljs.test :refer [is]]))
3 |
4 | (is (thrown? c body))
5 |
--------------------------------------------------------------------------------
/tests/linter/symbol-resolution-cljs/output.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/candid82/joker/1eed1c02c38ef1373640c42af1423808826820cc/tests/linter/symbol-resolution-cljs/output.txt
--------------------------------------------------------------------------------
/tests/linter/symbol-resolution/input.clj:
--------------------------------------------------------------------------------
1 | (ns tests.symbols-lint
2 | (:require [tests.ext1]
3 | [tests.ext2 :as ext2]
4 | [tests.ext3 :as ext3 :refer [e3]]
5 | [spec :as s]
6 | [clojure.test :refer [testing is]])
7 | (:import [java.security Security]))
8 |
9 | ;; Should PASS
10 |
11 | (defmacro test-macro [_x] nil)
12 |
13 | (def f [])
14 |
15 | (f 1)
16 | (tests.ext1/f 1)
17 | (e3 1)
18 | (ext2/g 4)
19 | (defprotocol Person)
20 | (java.security.Security/tt)
21 | (Security/hh)
22 | (Integer/parseInt 10)
23 | (java.lang.Integer/parseInt 10)
24 | (instance? Integer 10)
25 | (instance? java.lang.Integer 10)
26 | (test-macro uuu)
27 | (defrecord u5 [])
28 | (clojure.test/deftest u7)
29 | #'s/v
30 | #'e3
31 | (case 1 r 2 1 3)
32 | uuu
33 | (is (thrown? c body))
34 |
35 | ;; Should FAIL
36 |
37 | (s/def :t hh)
38 | (f jj/u1)
39 | (f u8)
40 | (f1 1)
41 | (tt/g 3)
42 | (test-macro (f u2))
43 | (test-macro (load u3))
44 | (test-macro (ext2/f u4))
45 | (testing u9)
46 | (defmethod u6 1 [] nil)
47 | #'g
48 | #'ns/gg
49 | (joker.string/split "1" #"2")
50 | (joker.os/env)
51 | (joker.time/sleep 10)
52 | (joker.json/read-string "")
53 | (joker.base64/decode-string "")
54 | (pprint 1)
55 | (pr-err 1)
56 | (prn-err 1)
57 | (print-err 1)
58 | (println-err 1)
59 | (case 1 r 2 1 h)
60 |
--------------------------------------------------------------------------------
/tests/linter/symbol-resolution/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/symbol-resolution/input.clj:28:1: Parse warning: fn form with empty body
2 | tests/linter/symbol-resolution/input.clj:37:11: Parse error: Unable to resolve symbol: hh
3 | tests/linter/symbol-resolution/input.clj:38:4: Parse error: Unable to resolve symbol: jj/u1
4 | tests/linter/symbol-resolution/input.clj:39:4: Parse error: Unable to resolve symbol: u8
5 | tests/linter/symbol-resolution/input.clj:40:2: Parse error: Unable to resolve symbol: f1
6 | tests/linter/symbol-resolution/input.clj:41:2: Parse error: Unable to resolve symbol: tt/g
7 | tests/linter/symbol-resolution/input.clj:42:16: Parse error: Unable to resolve symbol: u2
8 | tests/linter/symbol-resolution/input.clj:43:19: Parse error: Unable to resolve symbol: u3
9 | tests/linter/symbol-resolution/input.clj:44:21: Parse error: Unable to resolve symbol: u4
10 | tests/linter/symbol-resolution/input.clj:45:10: Parse error: Unable to resolve symbol: u9
11 | tests/linter/symbol-resolution/input.clj:46:12: Parse error: Unable to resolve symbol: u6
12 | tests/linter/symbol-resolution/input.clj:47:3: Parse error: Unable to resolve symbol: g
13 | tests/linter/symbol-resolution/input.clj:48:3: Parse error: Unable to resolve symbol: ns/gg
14 | tests/linter/symbol-resolution/input.clj:49:2: Parse error: Unable to resolve symbol: joker.string/split
15 | tests/linter/symbol-resolution/input.clj:50:2: Parse error: Unable to resolve symbol: joker.os/env
16 | tests/linter/symbol-resolution/input.clj:51:2: Parse error: Unable to resolve symbol: joker.time/sleep
17 | tests/linter/symbol-resolution/input.clj:52:2: Parse error: Unable to resolve symbol: joker.json/read-string
18 | tests/linter/symbol-resolution/input.clj:53:2: Parse error: Unable to resolve symbol: joker.base64/decode-string
19 | tests/linter/symbol-resolution/input.clj:54:2: Parse error: Unable to resolve symbol: pprint
20 | tests/linter/symbol-resolution/input.clj:55:2: Parse error: Unable to resolve symbol: pr-err
21 | tests/linter/symbol-resolution/input.clj:56:2: Parse error: Unable to resolve symbol: prn-err
22 | tests/linter/symbol-resolution/input.clj:57:2: Parse error: Unable to resolve symbol: print-err
23 | tests/linter/symbol-resolution/input.clj:58:2: Parse error: Unable to resolve symbol: println-err
24 | tests/linter/symbol-resolution/input.clj:59:15: Parse error: Unable to resolve symbol: h
25 |
--------------------------------------------------------------------------------
/tests/linter/tagged-literals/.joker:
--------------------------------------------------------------------------------
1 | {:known-tags [db/fn]}
2 |
--------------------------------------------------------------------------------
/tests/linter/tagged-literals/input.clj:
--------------------------------------------------------------------------------
1 | ;; Should PASS
2 |
3 | [{:db/fn #db/fn {:lang "java"
4 | :params [db e doc]
5 | :code "return list(list(\":db/add\", e, \":db/doc\", doc))"}}]
6 |
7 | #inst 1
8 | #uuid 2
9 |
10 | ;; Should FAIL
11 |
12 | #t 4
13 | #g [a]
14 |
--------------------------------------------------------------------------------
/tests/linter/tagged-literals/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/tagged-literals/input.clj:12:2: Read warning: No reader function for tag t
2 | tests/linter/tagged-literals/input.clj:13:2: Read warning: No reader function for tag g
3 | tests/linter/tagged-literals/input.clj:13:5: Parse error: Unable to resolve symbol: a
4 |
--------------------------------------------------------------------------------
/tests/linter/threading-macros-1/.joker:
--------------------------------------------------------------------------------
1 | {:rules {:no-forms-threading false}}
2 |
--------------------------------------------------------------------------------
/tests/linter/threading-macros-1/input.clj:
--------------------------------------------------------------------------------
1 | (-> 1)
2 | (->> 1)
3 | (cond-> 1)
4 | (cond->> 1)
5 | (as-> 0 n)
6 | (some-> 1)
7 | (some->> 1)
8 |
--------------------------------------------------------------------------------
/tests/linter/threading-macros-1/output.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/candid82/joker/1eed1c02c38ef1373640c42af1423808826820cc/tests/linter/threading-macros-1/output.txt
--------------------------------------------------------------------------------
/tests/linter/threading-macros/input.clj:
--------------------------------------------------------------------------------
1 | (-> 1)
2 | (->> 1)
3 | (cond-> 1)
4 | (cond->> 1)
5 | (as-> 0 n)
6 | (some-> 1)
7 | (some->> 1)
8 | (cond->> [1 2 3] true (filter odd?) false)
9 | (cond-> odd? true (filter [1 2 3]) false)
10 |
--------------------------------------------------------------------------------
/tests/linter/threading-macros/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/threading-macros/input.clj:1:1: Parse warning: No forms in ->
2 | tests/linter/threading-macros/input.clj:2:1: Parse warning: No forms in ->>
3 | tests/linter/threading-macros/input.clj:3:1: Parse warning: No forms in cond->
4 | tests/linter/threading-macros/input.clj:4:1: Parse warning: No forms in cond->>
5 | tests/linter/threading-macros/input.clj:5:1: Parse warning: No forms in as->
6 | tests/linter/threading-macros/input.clj:6:1: Parse warning: No forms in some->
7 | tests/linter/threading-macros/input.clj:7:1: Parse warning: No forms in some->>
8 | tests/linter/threading-macros/input.clj:8:1: Parse warning: Odd number of clauses in cond->>
9 | tests/linter/threading-macros/input.clj:9:1: Parse warning: Odd number of clauses in cond->
10 |
--------------------------------------------------------------------------------
/tests/linter/try/input.clj:
--------------------------------------------------------------------------------
1 | (try 1)
2 |
3 | (try (catch Error e))
4 |
5 | (try 1 (finally))
6 |
--------------------------------------------------------------------------------
/tests/linter/try/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/try/input.clj:1:1: Parse warning: try form without catch or finally
2 | tests/linter/try/input.clj:3:1: Parse warning: try form with empty body
3 | tests/linter/try/input.clj:5:8: Parse warning: finally form with empty body
4 |
--------------------------------------------------------------------------------
/tests/linter/types-2/input.clj:
--------------------------------------------------------------------------------
1 | ;; Should PASS
2 |
3 | (seq {})
4 | (seq [])
5 | (seq #{})
6 |
7 | ;; Should FAIL
8 |
9 | (seq 1)
10 | (seq first)
11 | (def v 1)
12 | (seq v)
13 | (def ^Int v1 (if 1 2 3))
14 | (seq v1)
15 | (def ^:dynamic dv 1)
16 | (seq dv)
17 |
--------------------------------------------------------------------------------
/tests/linter/types-2/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/types-2/input.clj:9:6: Parse warning: arg[0] of core/seq must have type Seqable, got Int
2 | tests/linter/types-2/input.clj:10:6: Parse warning: arg[0] of core/seq must have type Seqable, got Fn
3 | tests/linter/types-2/input.clj:12:6: Parse warning: arg[0] of core/seq must have type Seqable, got Int
4 |
--------------------------------------------------------------------------------
/tests/linter/types-4/input.clj:
--------------------------------------------------------------------------------
1 | (let [a "test"]
2 | (+ a 1))
3 |
--------------------------------------------------------------------------------
/tests/linter/types-4/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/types-4/input.clj:2:6: Parse warning: arg[0] of core/+ must have type Number, got String
2 |
--------------------------------------------------------------------------------
/tests/linter/types-cljs/input.cljs:
--------------------------------------------------------------------------------
1 | (instance? ExceptionInfo nil)
2 |
3 | (instance? 1 nil)
4 |
--------------------------------------------------------------------------------
/tests/linter/types-cljs/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/types-cljs/input.cljs:3:12: Parse warning: arg[0] of core/instance? must have type Type or Fn, got Int
2 |
--------------------------------------------------------------------------------
/tests/linter/unused-as/.joker:
--------------------------------------------------------------------------------
1 | {:rules {:unused-as false}}
2 |
--------------------------------------------------------------------------------
/tests/linter/unused-as/input.clj:
--------------------------------------------------------------------------------
1 | (let [{:keys [k] :as m} {}] k)
2 | (let [[f :as v] []] f)
3 |
--------------------------------------------------------------------------------
/tests/linter/unused-as/output.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/candid82/joker/1eed1c02c38ef1373640c42af1423808826820cc/tests/linter/unused-as/output.txt
--------------------------------------------------------------------------------
/tests/linter/unused-bindings/input.clj:
--------------------------------------------------------------------------------
1 | ;; Should PASS
2 | (let [a 1] a)
3 | (let [_ 1] 1)
4 | (loop [[a & b] [1 2]]
5 | (if a
6 | (recur b)
7 | 1))
8 |
9 | ;; Should FAIL
10 |
11 | (let [a 1 b 2] b)
12 | (let [a 1]
13 | (let [a 2]
14 | a))
15 |
16 | (loop [[a & b] [1 2]]
17 | (if 1
18 | (recur b)
19 | 1))
20 |
21 | (let [{:keys [a b]} {}] (println a))
22 |
23 | (let [_ 1 _ 2 a 1 a 2] a)
24 |
25 | (defn f [{}] 1)
26 | (defn f1 [[]] 1)
27 |
--------------------------------------------------------------------------------
/tests/linter/unused-bindings/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/unused-bindings/input.clj:11:7: Parse warning: unused binding: a
2 | tests/linter/unused-bindings/input.clj:12:7: Parse warning: unused binding: a
3 | tests/linter/unused-bindings/input.clj:16:9: Parse warning: unused binding: a
4 | tests/linter/unused-bindings/input.clj:21:17: Parse warning: unused binding: b
5 | tests/linter/unused-bindings/input.clj:23:15: Parse warning: Unused binding: a
6 | tests/linter/unused-bindings/input.clj:25:10: Parse warning: destructuring with no bindings
7 | tests/linter/unused-bindings/input.clj:26:11: Parse warning: destructuring with no bindings
8 |
--------------------------------------------------------------------------------
/tests/linter/unused-keys/.joker:
--------------------------------------------------------------------------------
1 | {:rules {:unused-keys false}}
2 |
--------------------------------------------------------------------------------
/tests/linter/unused-keys/input.clj:
--------------------------------------------------------------------------------
1 | (let [{:keys [k] :as m} {}
2 | {:strs [st]} {}
3 | {:syms [s]} {}
4 | a 1
5 | b 2]
6 | a)
7 |
--------------------------------------------------------------------------------
/tests/linter/unused-keys/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/unused-keys/input.clj:5:7: Parse warning: unused binding: b
2 | tests/linter/unused-keys/input.clj:1:22: Parse warning: unused binding: m
3 |
--------------------------------------------------------------------------------
/tests/linter/unused-ns/.joker:
--------------------------------------------------------------------------------
1 | {:ignored-unused-namespaces [ignored.test]}
2 |
--------------------------------------------------------------------------------
/tests/linter/unused-ns/input.clj:
--------------------------------------------------------------------------------
1 | (ns test
2 | (:require [test.ns1]
3 | [test.ns2 :as ns2]
4 | [test.ns3 :as ns3 :refer [f3]]
5 | [test.ns4 :as ns4 :refer [f4]]
6 | [test.ns5]
7 | [test.ns6 :as ns6]
8 | [test.ns7 :as n7]
9 | [test.ns8 :as n8]
10 | [test.ns9 :as n9]
11 | [test.n10]
12 | [ignored.test])
13 | (:import my.JavaClass))
14 |
15 | (f4)
16 | (test.ns5/f5)
17 | (ns6/f6)
18 | (#'n7/f7)
19 |
20 | (defmacro m8
21 | [& body]
22 | `(do
23 | (n8/f)
24 | ~@body))
25 |
26 | ::n9/k
27 |
28 | `(test.n10/f10)
29 |
--------------------------------------------------------------------------------
/tests/linter/unused-ns/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/unused-ns/input.clj:2:14: Parse warning: unused namespace test.ns1
2 | tests/linter/unused-ns/input.clj:3:14: Parse warning: unused namespace test.ns2
3 | tests/linter/unused-ns/input.clj:4:14: Parse warning: unused namespace test.ns3
4 |
--------------------------------------------------------------------------------
/tests/linter/unused-vars-1/input.clj:
--------------------------------------------------------------------------------
1 | ;; Should PASS
2 |
3 | (def v1)
4 | (def v2 1)
5 |
6 | ;; Should FAIL
7 |
8 | (def ^:private v3)
9 | (def ^:private v4 1)
10 | (defmacro ^:private m [x] x)
11 | (defn ^:private f [] 1)
12 |
--------------------------------------------------------------------------------
/tests/linter/unused-vars-1/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/unused-vars-1/input.clj:11:1: Parse warning: unused var f
2 | tests/linter/unused-vars-1/input.clj:10:1: Parse warning: unused var m
3 | tests/linter/unused-vars-1/input.clj:8:1: Parse warning: unused var v3
4 | tests/linter/unused-vars-1/input.clj:9:1: Parse warning: unused var v4
5 |
--------------------------------------------------------------------------------
/tests/linter/unused-vars/input.clj:
--------------------------------------------------------------------------------
1 | (ns my.test)
2 | ;; Should PASS
3 |
4 | (def v1)
5 | (def v2 1)
6 |
7 | ;; Should FAIL
8 |
9 | (def ^:private v3)
10 | (def ^:private v4 1)
11 | (defmacro ^:private m [x] x)
12 | (defn ^:private f [] 1)
13 |
14 |
15 |
--------------------------------------------------------------------------------
/tests/linter/unused-vars/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/unused-vars/input.clj:12:1: Parse warning: unused var f
2 | tests/linter/unused-vars/input.clj:11:1: Parse warning: unused var m
3 | tests/linter/unused-vars/input.clj:9:1: Parse warning: unused var v3
4 | tests/linter/unused-vars/input.clj:10:1: Parse warning: unused var v4
5 |
--------------------------------------------------------------------------------
/tests/linter/valid-indent/input.clj:
--------------------------------------------------------------------------------
1 | (def valid+& 1)
2 |
3 | (def non-ascii-да 2)
4 |
5 | (def non-core-#$:%| 3)
6 |
--------------------------------------------------------------------------------
/tests/linter/valid-indent/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/valid-indent/input.clj:3:17: Read warning: Impermissible character 'д' at 10 in "non-ascii-да" (not a (7-bit) ASCII character)
2 | tests/linter/valid-indent/input.clj:3:17: Read warning: Impermissible character 'а' at 11 in "non-ascii-да" (not a (7-bit) ASCII character)
3 | tests/linter/valid-indent/input.clj:5:19: Read warning: Impermissible character '|' at 13 in "non-core-#$:%|" (not a Letter nor (Decimal) Digit (category L nor Nd))
4 |
--------------------------------------------------------------------------------
/tests/linter/when/input.clj:
--------------------------------------------------------------------------------
1 | (when 1)
2 | (when-not 1)
3 |
--------------------------------------------------------------------------------
/tests/linter/when/output.txt:
--------------------------------------------------------------------------------
1 | tests/linter/when/input.clj:1:1: Parse warning: when form with empty body
2 | tests/linter/when/input.clj:2:1: Parse warning: when-not form with empty body
3 |
--------------------------------------------------------------------------------
/tests/main.clj:
--------------------------------------------------------------------------------
1 | (def t "docstring" 1)
2 | (fn [x] x)
3 | `(let)
4 |
--------------------------------------------------------------------------------
/tests/run-tests.joke:
--------------------------------------------------------------------------------
1 | (def exit-code 0)
2 |
3 | (defn first-diff-index
4 | [s1 s2]
5 | (let [c1 (count s1)
6 | c2 (count s2)]
7 | (loop [i 0]
8 | (if (or (= i c1)
9 | (= i c2))
10 | (if (= c1 c2)
11 | -1
12 | i)
13 | (if (= (nth s1 i) (nth s2 i))
14 | (recur (inc i))
15 | i)))))
16 |
17 | (let [[cmd root-dir output-k output-file-name] *command-line-args*
18 | output-k (keyword output-k)
19 | test-dirs (->> (joker.os/ls root-dir)
20 | (filter :dir?)
21 | (map :name))
22 | pwd (get (joker.os/env) "PWD")
23 | exe (str pwd "/joker")]
24 | (doseq [test-dir test-dirs]
25 | (let [dir (str root-dir "/" test-dir "/")
26 | filename (if (joker.os/exists? (str dir "input.clj"))
27 | (str dir "input.clj")
28 | (str dir "input.cljs"))
29 | res (joker.os/sh exe cmd filename)
30 | output (output-k res)
31 | expected (slurp (str dir output-file-name))]
32 | (when (and (= :err output-k)
33 | (not= "" output)
34 | (:success res))
35 | (println "FAILED:" test-dir "(zero exit code, yet stderr written to)")
36 | (var-set #'exit-code 1))
37 | (when (and (= :err output-k)
38 | (= "" output)
39 | (not (:success res)))
40 | (println "FAILED:" test-dir "(nonzero exit code, yet no stderr output)")
41 | (var-set #'exit-code 1))
42 | (when-not (= expected output)
43 | (println "FAILED:" test-dir)
44 | (println "EXPECTED:")
45 | (println expected)
46 | (println "ACTUAL:")
47 | (let [diff-i (first-diff-index expected output)
48 | output' (if (= -1 diff-i)
49 | output
50 | (str (subs output 0 diff-i) "❌" (subs output diff-i)))]
51 | (println output'))
52 | (var-set #'exit-code 1)))))
53 |
54 | (joker.os/exit exit-code)
55 |
--------------------------------------------------------------------------------
/tools/cljs-macros.joke:
--------------------------------------------------------------------------------
1 | (load-file "../core/data/linter_cljx.joke")
2 | (load-file "../core/data/linter_cljs.joke")
3 | (def interns (ns-interns 'joker.core))
4 |
5 | (defn exists?
6 | [line]
7 | (let [parts (joker.string/split (joker.string/trim-space line) #" ")
8 | name (second (rest parts))]
9 | (if name
10 | (get interns (symbol name))
11 | false)))
12 |
13 | (let [input (slurp "cljs-macros.input")
14 | lines (joker.string/split-lines input)]
15 | (doseq [line (remove exists? lines)]
16 | (println line)))
17 |
--------------------------------------------------------------------------------
/tools/sum256dir/.gitignore:
--------------------------------------------------------------------------------
1 | sum256dir
2 |
--------------------------------------------------------------------------------
/tools/sum256dir/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "crypto/sha256"
5 | "fmt"
6 | "io"
7 | "os"
8 | "path/filepath"
9 | )
10 |
11 | var h = sha256.New()
12 |
13 | func processFile(file string) (err error) {
14 | f, err := os.Open(file)
15 | if err != nil {
16 | return
17 | }
18 | _, err = io.Copy(h, f)
19 | return
20 | }
21 |
22 | func processEntry(path string, info os.FileInfo, err error) error {
23 | if err != nil {
24 | return err
25 | }
26 | name := info.Name()
27 | if name == ".git" {
28 | return filepath.SkipDir
29 | }
30 | if !info.IsDir() {
31 | err = processFile(path)
32 | }
33 | return err
34 | }
35 |
36 | func main() {
37 | for _, arg := range os.Args[1:] {
38 | info, err := os.Stat(arg)
39 | if err != nil {
40 | fmt.Fprintf(os.Stderr, "os.Stat: %v\n", err)
41 | os.Exit(3)
42 | }
43 | if info.IsDir() {
44 | err = filepath.Walk(arg, processEntry)
45 | } else {
46 | err = processFile(arg)
47 | }
48 | if err != nil {
49 | fmt.Fprintf(os.Stderr, "%v\n", err)
50 | os.Exit(3)
51 | }
52 | }
53 |
54 | fmt.Printf("%x\n", h.Sum(nil))
55 | }
56 |
--------------------------------------------------------------------------------