Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: Java CI

on: [push]

jobs:
build:
timeout-minutes: 5
strategy:
matrix:
jdk: ['8', '11', '17', '19']
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Set up JDK ${{ matrix.jdk }}
uses: actions/setup-java@v2
with:
java-version: ${{ matrix.jdk }}
distribution: 'temurin'
cache: maven
- name: Build with Maven
run: mvn test
- name: Configure settings.xml
run: |
mkdir -p ~/.m2
echo "<settings><servers><server><id>clojars</id><username>${{ secrets.CLOJARS_USER }}-clojars</username><password>${{ secrets.CLOJARS_PASSWORD }}</password></server></servers></settings>" > ~/.m2/settings.xml
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@ maven-classpath
maven-classpath.properties
.idea/
*.iml
.cpcache
deps.edn
.nrepl-*
38 changes: 38 additions & 0 deletions deps.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
;; https://clojure.org/dev/developing_patches#_run_an_individual_test
{:paths ["test"
"target/test-classes"]
:deps
{org.clojure/clojure {:local/root "."
:deps/manifest :pom} #_{:mvn/version "RELEASE"}
org.clojure/test.check {:mvn/version "1.1.1"}
org.clojure/test.generative {:mvn/version "1.0.0"}}
:aliases
{:dbg {:classpath-overrides {org.clojure/clojure "target/classes"}
:extra-deps {criterium/criterium {:mvn/version "0.4.4"}}}
:cognitest {:extra-deps {io.github.cognitect-labs/test-runner
{:git/tag "v0.5.0" :git/sha "b3fd0d2"}}
:main-opts ["-m" "cognitect.test-runner"]
:exec-fn cognitect.test-runner.api/test
:exec-args {:dirs ["test"]
:patterns [;; FIXME clojure.test-clojure.ns-libs has a test that is sensitive to loading order
;; FIXME clojure.test-clojure.java-interop doesn't seem to work on JDK 17 (untested on others)
;; regex ref: https://stackoverflow.com/a/2387072
"^((?!(clojure.test-clojure.ns-libs|clojure.test-clojure.java-interop)).)*$"
]}}
:test-example-script {:jvm-opts [;; from build.xml
"-Dclojure.test-clojure.exclude-namespaces=#{clojure.test-clojure.compilation.load-ns clojure.test-clojure.ns-libs-load-later}"
"-Dclojure.compiler.direct-linking=true"]
:main-opts ["-e" "(load-file,\"src/script/run_test.clj\")"]}
:test-generative-script {:jvm-opts [;; from build.xml
"-Dclojure.compiler.direct-linking=true"]
:main-opts ["-e" "(load-file,\"src/script/run_test_generative.clj\")"]}

:kaocha {:extra-deps {lambdaisland/kaocha {:mvn/version "1.60.977"}}
:exec-fn kaocha.runner/exec-fn
:exec-args {;:watch? true
:tests [{:id :unit
:test-paths ["test"]
:ns-patterns [".*"]}]
:reporter kaocha.report/dots
;; :plugins [:kaocha.plugin/profiling :kaocha.plugin/notifier]
}}}}
29 changes: 28 additions & 1 deletion src/jvm/clojure/lang/AFn.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@

public abstract class AFn implements IFn {

// if your class Foo extends AFn and only implements fixed IFn/invoke arities,
// return Foo.class. When passed more than 20 arguments via `apply`, instead
// of walking the possibly infinite sequence of args, just throw an arity exception.
// Returning null means "I don't know if this class implements rest args" and is the default.
public Class clojure_lang_AFn_onlyFixedArgs() {
return null;
}

public Object call() {
return invoke();
}
Expand Down Expand Up @@ -145,6 +153,10 @@ public Object applyTo(ISeq arglist) {
}

static public Object applyToHelper(IFn ifn, ISeq arglist) {
return applyToHelper(ifn, arglist, false, null);
}

static public Object applyToHelper(IFn ifn, ISeq arglist, final boolean knownNoRest, final String arityExceptionName) {
switch(RT.boundedLength(arglist, 20))
{
case 0:
Expand Down Expand Up @@ -400,6 +412,18 @@ static public Object applyToHelper(IFn ifn, ISeq arglist) {
, Util.ret1((arglist = arglist.next()).first(),arglist = null)
);
default:
if (ifn instanceof AFn) {
final AFn afn = (AFn)ifn;
if (afn instanceof AFunction || //assume that AFunction never has rest args
afn.getClass() == afn.clojure_lang_AFn_onlyFixedArgs()) {
afn.throwArity(21, true);
}
} else if (knownNoRest) {
throw new ArityException(21,
(arityExceptionName!=null ? arityExceptionName : ifn.getClass().toString()),
null,
true);
}
return ifn.invoke(arglist.first()
, (arglist = arglist.next()).first()
, (arglist = arglist.next()).first()
Expand All @@ -425,7 +449,10 @@ static public Object applyToHelper(IFn ifn, ISeq arglist) {
}

public Object throwArity(int n){
return throwArity(n, false);
}
public Object throwArity(int n, boolean nIsMinimum){
String name = getClass().getName();
throw new ArityException(n, name);
throw new ArityException(n, name, null, nIsMinimum);
}
}
7 changes: 5 additions & 2 deletions src/jvm/clojure/lang/ArityException.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,12 @@ public ArityException(int actual, String name) {
}

public ArityException(int actual, String name, Throwable cause) {
super("Wrong number of args (" + actual + ") passed to: " + Compiler.demunge(name), cause);
this(actual, name, cause, false);
}

public ArityException(int actual, String name, Throwable cause, boolean actualIsMinimum) {
super("Wrong number of args (" + actual + (actualIsMinimum ? "+" : "") + ") passed to: " + Compiler.demunge(name), cause);
this.actual = actual;
this.name = name;
}

}
2 changes: 1 addition & 1 deletion src/jvm/clojure/lang/Keyword.java
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object


public Object applyTo(ISeq arglist) {
return AFn.applyToHelper(this, arglist);
return AFn.applyToHelper(this, arglist, true, toString());
}


Expand Down
4 changes: 4 additions & 0 deletions src/jvm/clojure/lang/MapEntry.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ public MapEntry(Object key, Object val){
this._val = val;
}

public Class clojure_lang_AFn_onlyFixedArgs() {
return MapEntry.class;
}

public Object key(){
return _key;
}
Expand Down
5 changes: 5 additions & 0 deletions src/jvm/clojure/lang/MultiFn.java
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,11 @@ public Object invoke(Object arg1, Object arg2, Object arg3, Object arg4, Object
args);
}

public Object applyTo(ISeq arglist) {
return getFn(dispatchFn.applyTo(arglist)).
applyTo(arglist);
}

public IPersistentMap getMethodTable() {
return methodTable;
}
Expand Down
8 changes: 8 additions & 0 deletions src/jvm/clojure/lang/PersistentArrayMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ public class PersistentArrayMap extends APersistentMap implements IObj, IEditabl
public static final PersistentArrayMap EMPTY = new PersistentArrayMap();
private final IPersistentMap _meta;

public Class clojure_lang_AFn_onlyFixedArgs() {
return PersistentArrayMap.class;
}

static public IPersistentMap create(Map other){
ITransientMap ret = EMPTY.asTransient();
for(Object o : other.entrySet())
Expand Down Expand Up @@ -494,6 +498,10 @@ public TransientArrayMap(Object[] array){
System.arraycopy(array, 0, this.array, 0, array.length);
this.len = array.length;
}

public Class clojure_lang_AFn_onlyFixedArgs() {
return TransientArrayMap.class;
}

private int indexOf(Object key){
for(int i = 0; i < len; i += 2)
Expand Down
8 changes: 8 additions & 0 deletions src/jvm/clojure/lang/PersistentHashMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ public class PersistentHashMap extends APersistentMap implements IEditableCollec
final Object nullValue;
final IPersistentMap _meta;

public Class clojure_lang_AFn_onlyFixedArgs() {
return PersistentHashMap.class;
}

final public static PersistentHashMap EMPTY = new PersistentHashMap(0, null, false, null);
final private static Object NOT_FOUND = new Object();

Expand Down Expand Up @@ -313,6 +317,10 @@ static final class TransientHashMap extends ATransientMap {
this.nullValue = nullValue;
}

public Class clojure_lang_AFn_onlyFixedArgs() {
return TransientHashMap.class;
}

ITransientMap doAssoc(Object key, Object val) {
if (key == null) {
if (this.nullValue != val)
Expand Down
8 changes: 8 additions & 0 deletions src/jvm/clojure/lang/PersistentHashSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ static public PersistentHashSet createWithCheck(ISeq items){
this._meta = meta;
}

public Class clojure_lang_AFn_onlyFixedArgs() {
return clojure.lang.PersistentHashSet.class;
}

public IPersistentSet disjoin(Object key) {
if(contains(key))
return new PersistentHashSet(meta(),impl.without(key));
Expand Down Expand Up @@ -127,6 +131,10 @@ static final class TransientHashSet extends ATransientSet {
public IPersistentCollection persistent() {
return new PersistentHashSet(null, impl.persistent());
}

public Class clojure_lang_AFn_onlyFixedArgs() {
return TransientHashSet.class;
}
}

}
4 changes: 4 additions & 0 deletions src/jvm/clojure/lang/PersistentTreeMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ static public PersistentTreeMap create(Comparator comp, ISeq items){
return (PersistentTreeMap) ret;
}

public Class clojure_lang_AFn_onlyFixedArgs() {
return PersistentTreeMap.class;
}

public boolean containsKey(Object key){
return entryAt(key) != null;
}
Expand Down
4 changes: 4 additions & 0 deletions src/jvm/clojure/lang/PersistentTreeSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ static public PersistentTreeSet create(Comparator comp, ISeq items){
this._meta = meta;
}

public Class clojure_lang_AFn_onlyFixedArgs() {
return PersistentTreeSet.class;
}

public boolean equals(Object obj){
try {
return super.equals(obj);
Expand Down
8 changes: 8 additions & 0 deletions src/jvm/clojure/lang/PersistentVector.java
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ static public PersistentVector create(Object... items){
this.tail = tail;
}

public Class clojure_lang_AFn_onlyFixedArgs() {
return PersistentVector.class;
}

public TransientVector asTransient(){
return new TransientVector(this);
}
Expand Down Expand Up @@ -614,6 +618,10 @@ static final class TransientVector extends AFn implements ITransientVector, ITra
this(v.cnt, v.shift, editableRoot(v.root), editableTail(v.tail));
}

public Class clojure_lang_AFn_onlyFixedArgs() {
return TransientVector.class;
}

public int count(){
ensureEditable();
return cnt;
Expand Down
4 changes: 4 additions & 0 deletions src/jvm/clojure/lang/Symbol.java
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ public Object invoke(Object obj, Object notFound) {
return RT.get(obj, this, notFound);
}

public Class clojure_lang_AFn_onlyFixedArgs() {
return Symbol.class;
}

public IPersistentMap meta(){
return _meta;
}
Expand Down
4 changes: 4 additions & 0 deletions src/jvm/clojure/lang/Var.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ public String toString(){
public Object throwArity(int n){
throw new IllegalStateException("Attempting to call unbound fn: " + v);
}

public Class clojure_lang_AFn_onlyFixedArgs() {
return Unbound.class;
}
}

static class Frame{
Expand Down
Loading