Skip to content

Commit 1d93242

Browse files
committed
Implement sort function for Glojure
- Add SortArray function in pkg/lang/sort.go that performs stable in-place sorting - Add Compare function to support Clojure's compare semantics (nil handling, cross-type numeric comparison) - Update ToSlice to handle all required types: nil→empty, IPersistentVector, IPersistentMap, string→char array - Add transformation in rewrite.clj to replace java.util.Arrays.sort with SortArray - Add transformation for clojure.lang.Util.compare to use Compare function - Remove inline metadata from compare function that referenced Java classes The implementation matches Clojure JVM semantics: - Stable sort (equal elements maintain order) - Comparator contract (-1/0/1 return values) - Proper nil handling (nil sorts before non-nil) - Support for custom comparators
1 parent 55fff5d commit 1d93242

File tree

11 files changed

+212
-53
lines changed

11 files changed

+212
-53
lines changed

pkg/gen/gljimports/gljimports_darwin_amd64.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3466,6 +3466,7 @@ func RegisterImports(_register func(string, interface{})) {
34663466
_register("github.com/glojurelang/glojure/pkg/lang.ChunkedCons", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.ChunkedCons)(nil)).Elem())
34673467
_register("github.com/glojurelang/glojure/pkg/lang.*ChunkedCons", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.ChunkedCons)(nil)))
34683468
_register("github.com/glojurelang/glojure/pkg/lang.CloneThreadBindingFrame", github_com_glojurelang_glojure_pkg_lang.CloneThreadBindingFrame)
3469+
_register("github.com/glojurelang/glojure/pkg/lang.Compare", github_com_glojurelang_glojure_pkg_lang.Compare)
34693470
_register("github.com/glojurelang/glojure/pkg/lang.Comparer", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.Comparer)(nil)).Elem())
34703471
_register("github.com/glojurelang/glojure/pkg/lang.ConcatStrings", github_com_glojurelang_glojure_pkg_lang.ConcatStrings)
34713472
_register("github.com/glojurelang/glojure/pkg/lang.Conj", github_com_glojurelang_glojure_pkg_lang.Conj)
@@ -3888,6 +3889,7 @@ func RegisterImports(_register func(string, interface{})) {
38883889
_register("github.com/glojurelang/glojure/pkg/lang.SliceSeq", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.SliceSeq)(nil)).Elem())
38893890
_register("github.com/glojurelang/glojure/pkg/lang.*SliceSeq", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.SliceSeq)(nil)))
38903891
_register("github.com/glojurelang/glojure/pkg/lang.SliceSet", github_com_glojurelang_glojure_pkg_lang.SliceSet)
3892+
_register("github.com/glojurelang/glojure/pkg/lang.SortArray", github_com_glojurelang_glojure_pkg_lang.SortArray)
38913893
_register("github.com/glojurelang/glojure/pkg/lang.StackFrame", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.StackFrame)(nil)).Elem())
38923894
_register("github.com/glojurelang/glojure/pkg/lang.*StackFrame", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.StackFrame)(nil)))
38933895
_register("github.com/glojurelang/glojure/pkg/lang.Stacker", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.Stacker)(nil)).Elem())

pkg/gen/gljimports/gljimports_darwin_arm64.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3466,6 +3466,7 @@ func RegisterImports(_register func(string, interface{})) {
34663466
_register("github.com/glojurelang/glojure/pkg/lang.ChunkedCons", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.ChunkedCons)(nil)).Elem())
34673467
_register("github.com/glojurelang/glojure/pkg/lang.*ChunkedCons", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.ChunkedCons)(nil)))
34683468
_register("github.com/glojurelang/glojure/pkg/lang.CloneThreadBindingFrame", github_com_glojurelang_glojure_pkg_lang.CloneThreadBindingFrame)
3469+
_register("github.com/glojurelang/glojure/pkg/lang.Compare", github_com_glojurelang_glojure_pkg_lang.Compare)
34693470
_register("github.com/glojurelang/glojure/pkg/lang.Comparer", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.Comparer)(nil)).Elem())
34703471
_register("github.com/glojurelang/glojure/pkg/lang.ConcatStrings", github_com_glojurelang_glojure_pkg_lang.ConcatStrings)
34713472
_register("github.com/glojurelang/glojure/pkg/lang.Conj", github_com_glojurelang_glojure_pkg_lang.Conj)
@@ -3888,6 +3889,7 @@ func RegisterImports(_register func(string, interface{})) {
38883889
_register("github.com/glojurelang/glojure/pkg/lang.SliceSeq", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.SliceSeq)(nil)).Elem())
38893890
_register("github.com/glojurelang/glojure/pkg/lang.*SliceSeq", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.SliceSeq)(nil)))
38903891
_register("github.com/glojurelang/glojure/pkg/lang.SliceSet", github_com_glojurelang_glojure_pkg_lang.SliceSet)
3892+
_register("github.com/glojurelang/glojure/pkg/lang.SortArray", github_com_glojurelang_glojure_pkg_lang.SortArray)
38913893
_register("github.com/glojurelang/glojure/pkg/lang.StackFrame", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.StackFrame)(nil)).Elem())
38923894
_register("github.com/glojurelang/glojure/pkg/lang.*StackFrame", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.StackFrame)(nil)))
38933895
_register("github.com/glojurelang/glojure/pkg/lang.Stacker", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.Stacker)(nil)).Elem())

pkg/gen/gljimports/gljimports_js_wasm.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3466,6 +3466,7 @@ func RegisterImports(_register func(string, interface{})) {
34663466
_register("github.com/glojurelang/glojure/pkg/lang.ChunkedCons", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.ChunkedCons)(nil)).Elem())
34673467
_register("github.com/glojurelang/glojure/pkg/lang.*ChunkedCons", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.ChunkedCons)(nil)))
34683468
_register("github.com/glojurelang/glojure/pkg/lang.CloneThreadBindingFrame", github_com_glojurelang_glojure_pkg_lang.CloneThreadBindingFrame)
3469+
_register("github.com/glojurelang/glojure/pkg/lang.Compare", github_com_glojurelang_glojure_pkg_lang.Compare)
34693470
_register("github.com/glojurelang/glojure/pkg/lang.Comparer", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.Comparer)(nil)).Elem())
34703471
_register("github.com/glojurelang/glojure/pkg/lang.ConcatStrings", github_com_glojurelang_glojure_pkg_lang.ConcatStrings)
34713472
_register("github.com/glojurelang/glojure/pkg/lang.Conj", github_com_glojurelang_glojure_pkg_lang.Conj)
@@ -3888,6 +3889,7 @@ func RegisterImports(_register func(string, interface{})) {
38883889
_register("github.com/glojurelang/glojure/pkg/lang.SliceSeq", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.SliceSeq)(nil)).Elem())
38893890
_register("github.com/glojurelang/glojure/pkg/lang.*SliceSeq", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.SliceSeq)(nil)))
38903891
_register("github.com/glojurelang/glojure/pkg/lang.SliceSet", github_com_glojurelang_glojure_pkg_lang.SliceSet)
3892+
_register("github.com/glojurelang/glojure/pkg/lang.SortArray", github_com_glojurelang_glojure_pkg_lang.SortArray)
38913893
_register("github.com/glojurelang/glojure/pkg/lang.StackFrame", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.StackFrame)(nil)).Elem())
38923894
_register("github.com/glojurelang/glojure/pkg/lang.*StackFrame", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.StackFrame)(nil)))
38933895
_register("github.com/glojurelang/glojure/pkg/lang.Stacker", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.Stacker)(nil)).Elem())

pkg/gen/gljimports/gljimports_linux_amd64.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3466,6 +3466,7 @@ func RegisterImports(_register func(string, interface{})) {
34663466
_register("github.com/glojurelang/glojure/pkg/lang.ChunkedCons", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.ChunkedCons)(nil)).Elem())
34673467
_register("github.com/glojurelang/glojure/pkg/lang.*ChunkedCons", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.ChunkedCons)(nil)))
34683468
_register("github.com/glojurelang/glojure/pkg/lang.CloneThreadBindingFrame", github_com_glojurelang_glojure_pkg_lang.CloneThreadBindingFrame)
3469+
_register("github.com/glojurelang/glojure/pkg/lang.Compare", github_com_glojurelang_glojure_pkg_lang.Compare)
34693470
_register("github.com/glojurelang/glojure/pkg/lang.Comparer", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.Comparer)(nil)).Elem())
34703471
_register("github.com/glojurelang/glojure/pkg/lang.ConcatStrings", github_com_glojurelang_glojure_pkg_lang.ConcatStrings)
34713472
_register("github.com/glojurelang/glojure/pkg/lang.Conj", github_com_glojurelang_glojure_pkg_lang.Conj)
@@ -3888,6 +3889,7 @@ func RegisterImports(_register func(string, interface{})) {
38883889
_register("github.com/glojurelang/glojure/pkg/lang.SliceSeq", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.SliceSeq)(nil)).Elem())
38893890
_register("github.com/glojurelang/glojure/pkg/lang.*SliceSeq", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.SliceSeq)(nil)))
38903891
_register("github.com/glojurelang/glojure/pkg/lang.SliceSet", github_com_glojurelang_glojure_pkg_lang.SliceSet)
3892+
_register("github.com/glojurelang/glojure/pkg/lang.SortArray", github_com_glojurelang_glojure_pkg_lang.SortArray)
38913893
_register("github.com/glojurelang/glojure/pkg/lang.StackFrame", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.StackFrame)(nil)).Elem())
38923894
_register("github.com/glojurelang/glojure/pkg/lang.*StackFrame", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.StackFrame)(nil)))
38933895
_register("github.com/glojurelang/glojure/pkg/lang.Stacker", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.Stacker)(nil)).Elem())

pkg/gen/gljimports/gljimports_linux_arm64.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3466,6 +3466,7 @@ func RegisterImports(_register func(string, interface{})) {
34663466
_register("github.com/glojurelang/glojure/pkg/lang.ChunkedCons", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.ChunkedCons)(nil)).Elem())
34673467
_register("github.com/glojurelang/glojure/pkg/lang.*ChunkedCons", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.ChunkedCons)(nil)))
34683468
_register("github.com/glojurelang/glojure/pkg/lang.CloneThreadBindingFrame", github_com_glojurelang_glojure_pkg_lang.CloneThreadBindingFrame)
3469+
_register("github.com/glojurelang/glojure/pkg/lang.Compare", github_com_glojurelang_glojure_pkg_lang.Compare)
34693470
_register("github.com/glojurelang/glojure/pkg/lang.Comparer", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.Comparer)(nil)).Elem())
34703471
_register("github.com/glojurelang/glojure/pkg/lang.ConcatStrings", github_com_glojurelang_glojure_pkg_lang.ConcatStrings)
34713472
_register("github.com/glojurelang/glojure/pkg/lang.Conj", github_com_glojurelang_glojure_pkg_lang.Conj)
@@ -3888,6 +3889,7 @@ func RegisterImports(_register func(string, interface{})) {
38883889
_register("github.com/glojurelang/glojure/pkg/lang.SliceSeq", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.SliceSeq)(nil)).Elem())
38893890
_register("github.com/glojurelang/glojure/pkg/lang.*SliceSeq", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.SliceSeq)(nil)))
38903891
_register("github.com/glojurelang/glojure/pkg/lang.SliceSet", github_com_glojurelang_glojure_pkg_lang.SliceSet)
3892+
_register("github.com/glojurelang/glojure/pkg/lang.SortArray", github_com_glojurelang_glojure_pkg_lang.SortArray)
38913893
_register("github.com/glojurelang/glojure/pkg/lang.StackFrame", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.StackFrame)(nil)).Elem())
38923894
_register("github.com/glojurelang/glojure/pkg/lang.*StackFrame", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.StackFrame)(nil)))
38933895
_register("github.com/glojurelang/glojure/pkg/lang.Stacker", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.Stacker)(nil)).Elem())

pkg/gen/gljimports/gljimports_windows_amd64.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3466,6 +3466,7 @@ func RegisterImports(_register func(string, interface{})) {
34663466
_register("github.com/glojurelang/glojure/pkg/lang.ChunkedCons", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.ChunkedCons)(nil)).Elem())
34673467
_register("github.com/glojurelang/glojure/pkg/lang.*ChunkedCons", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.ChunkedCons)(nil)))
34683468
_register("github.com/glojurelang/glojure/pkg/lang.CloneThreadBindingFrame", github_com_glojurelang_glojure_pkg_lang.CloneThreadBindingFrame)
3469+
_register("github.com/glojurelang/glojure/pkg/lang.Compare", github_com_glojurelang_glojure_pkg_lang.Compare)
34693470
_register("github.com/glojurelang/glojure/pkg/lang.Comparer", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.Comparer)(nil)).Elem())
34703471
_register("github.com/glojurelang/glojure/pkg/lang.ConcatStrings", github_com_glojurelang_glojure_pkg_lang.ConcatStrings)
34713472
_register("github.com/glojurelang/glojure/pkg/lang.Conj", github_com_glojurelang_glojure_pkg_lang.Conj)
@@ -3888,6 +3889,7 @@ func RegisterImports(_register func(string, interface{})) {
38883889
_register("github.com/glojurelang/glojure/pkg/lang.SliceSeq", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.SliceSeq)(nil)).Elem())
38893890
_register("github.com/glojurelang/glojure/pkg/lang.*SliceSeq", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.SliceSeq)(nil)))
38903891
_register("github.com/glojurelang/glojure/pkg/lang.SliceSet", github_com_glojurelang_glojure_pkg_lang.SliceSet)
3892+
_register("github.com/glojurelang/glojure/pkg/lang.SortArray", github_com_glojurelang_glojure_pkg_lang.SortArray)
38913893
_register("github.com/glojurelang/glojure/pkg/lang.StackFrame", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.StackFrame)(nil)).Elem())
38923894
_register("github.com/glojurelang/glojure/pkg/lang.*StackFrame", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.StackFrame)(nil)))
38933895
_register("github.com/glojurelang/glojure/pkg/lang.Stacker", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.Stacker)(nil)).Elem())

pkg/gen/gljimports/gljimports_windows_arm.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3466,6 +3466,7 @@ func RegisterImports(_register func(string, interface{})) {
34663466
_register("github.com/glojurelang/glojure/pkg/lang.ChunkedCons", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.ChunkedCons)(nil)).Elem())
34673467
_register("github.com/glojurelang/glojure/pkg/lang.*ChunkedCons", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.ChunkedCons)(nil)))
34683468
_register("github.com/glojurelang/glojure/pkg/lang.CloneThreadBindingFrame", github_com_glojurelang_glojure_pkg_lang.CloneThreadBindingFrame)
3469+
_register("github.com/glojurelang/glojure/pkg/lang.Compare", github_com_glojurelang_glojure_pkg_lang.Compare)
34693470
_register("github.com/glojurelang/glojure/pkg/lang.Comparer", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.Comparer)(nil)).Elem())
34703471
_register("github.com/glojurelang/glojure/pkg/lang.ConcatStrings", github_com_glojurelang_glojure_pkg_lang.ConcatStrings)
34713472
_register("github.com/glojurelang/glojure/pkg/lang.Conj", github_com_glojurelang_glojure_pkg_lang.Conj)
@@ -3888,6 +3889,7 @@ func RegisterImports(_register func(string, interface{})) {
38883889
_register("github.com/glojurelang/glojure/pkg/lang.SliceSeq", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.SliceSeq)(nil)).Elem())
38893890
_register("github.com/glojurelang/glojure/pkg/lang.*SliceSeq", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.SliceSeq)(nil)))
38903891
_register("github.com/glojurelang/glojure/pkg/lang.SliceSet", github_com_glojurelang_glojure_pkg_lang.SliceSet)
3892+
_register("github.com/glojurelang/glojure/pkg/lang.SortArray", github_com_glojurelang_glojure_pkg_lang.SortArray)
38913893
_register("github.com/glojurelang/glojure/pkg/lang.StackFrame", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.StackFrame)(nil)).Elem())
38923894
_register("github.com/glojurelang/glojure/pkg/lang.*StackFrame", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.StackFrame)(nil)))
38933895
_register("github.com/glojurelang/glojure/pkg/lang.Stacker", reflect.TypeOf((*github_com_glojurelang_glojure_pkg_lang.Stacker)(nil)).Elem())

pkg/lang/slices.go

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,57 @@ func SliceSet(slc any, idx int, val any) {
1111
}
1212

1313
func ToSlice(x any) []any {
14+
// Handle nil - Clojure returns empty array for nil
1415
if IsNil(x) {
15-
return nil
16+
return []any{}
1617
}
18+
19+
// Handle []any - return as-is
20+
if slice, ok := x.([]any); ok {
21+
return slice
22+
}
23+
24+
// Handle IPersistentVector
25+
if vec, ok := x.(IPersistentVector); ok {
26+
count := vec.Count()
27+
res := make([]any, count)
28+
for i := 0; i < count; i++ {
29+
res[i] = vec.Nth(i)
30+
}
31+
return res
32+
}
33+
34+
// Handle IPersistentMap - convert to array of MapEntry objects
35+
if m, ok := x.(IPersistentMap); ok {
36+
seq := m.Seq()
37+
res := make([]any, 0, m.Count())
38+
for seq != nil {
39+
res = append(res, seq.First()) // Each element is a MapEntry
40+
seq = seq.Next()
41+
}
42+
return res
43+
}
44+
45+
// Handle string - convert to character array
46+
if s, ok := x.(string); ok {
47+
runes := []rune(s) // Important: use runes for proper Unicode handling
48+
res := make([]any, len(runes))
49+
for i, ch := range runes {
50+
res[i] = NewChar(ch) // Convert each rune to Char
51+
}
52+
return res
53+
}
54+
55+
// Handle ISeq
1756
if s, ok := x.(ISeq); ok {
1857
res := make([]interface{}, 0, Count(x))
1958
for s := Seq(s); s != nil; s = s.Next() {
2059
res = append(res, s.First())
2160
}
2261
return res
2362
}
63+
64+
// Handle reflection-based slice/array
2465
xVal := reflect.ValueOf(x)
2566
if xVal.Kind() == reflect.Slice || xVal.Kind() == reflect.Array {
2667
res := make([]interface{}, xVal.Len())
@@ -29,5 +70,7 @@ func ToSlice(x any) []any {
2970
}
3071
return res
3172
}
32-
panic(fmt.Errorf("ToSlice not supported on type: %T", x))
73+
74+
// Error with Clojure-style message
75+
panic(NewIllegalArgumentError(fmt.Sprintf("Unable to convert: %T to Object[]", x)))
3376
}

pkg/lang/sort.go

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package lang
2+
3+
import (
4+
"fmt"
5+
"sort"
6+
)
7+
8+
// SortArray performs an in-place stable sort on the given array using the provided comparator.
9+
// This matches java.util.Arrays.sort semantics:
10+
// - Stable sort (equal elements maintain their relative order)
11+
// - In-place modification of the array
12+
// - Comparator returns -1 for less than, 0 for equal, 1 for greater than
13+
func SortArray(arr any, comp any) error {
14+
// arr is already a []any from the to-array call in core.glj
15+
slice, ok := arr.([]any)
16+
if !ok {
17+
// This shouldn't happen if called from sort function, but be defensive
18+
panic(NewIllegalArgumentError(fmt.Sprintf("SortArray requires []any, got %T", arr)))
19+
}
20+
21+
// comp is a Clojure function that acts as a comparator
22+
compFn, ok := comp.(IFn)
23+
if !ok {
24+
panic(NewIllegalArgumentError("Comparator must be a function"))
25+
}
26+
27+
// Use sort.SliceStable for stable sorting (maintains relative order of equal elements)
28+
sort.SliceStable(slice, func(i, j int) bool {
29+
// Call the comparator function with the two elements
30+
result := compFn.Invoke(slice[i], slice[j])
31+
32+
// Comparator returns:
33+
// -1 if first arg is less than second
34+
// 0 if args are equal
35+
// 1 if first arg is greater than second
36+
// We return true for "less than" case
37+
resultInt, ok := AsInt(result)
38+
if !ok {
39+
panic(NewIllegalArgumentError(fmt.Sprintf("Comparator must return a number, got %T", result)))
40+
}
41+
return resultInt < 0
42+
})
43+
44+
// Return nil to match the Java void return type
45+
return nil
46+
}
47+
48+
// Compare implements Clojure's compare function.
49+
// Returns a negative number, zero, or a positive number when x is logically
50+
// 'less than', 'equal to', or 'greater than' y.
51+
// Handles nil values (nil is less than everything except nil).
52+
func Compare(x, y any) int {
53+
// Handle nil cases first
54+
if IsNil(x) {
55+
if IsNil(y) {
56+
return 0
57+
}
58+
return -1
59+
}
60+
if IsNil(y) {
61+
return 1
62+
}
63+
64+
// Handle numbers - convert to float64 for comparison
65+
xNum, xIsNum := AsNumber(x)
66+
yNum, yIsNum := AsNumber(y)
67+
if xIsNum && yIsNum {
68+
xFloat := AsFloat64(xNum)
69+
yFloat := AsFloat64(yNum)
70+
if xFloat < yFloat {
71+
return -1
72+
} else if xFloat > yFloat {
73+
return 1
74+
}
75+
return 0
76+
}
77+
78+
// Handle strings
79+
if xStr, xOk := x.(string); xOk {
80+
if yStr, yOk := y.(string); yOk {
81+
if xStr < yStr {
82+
return -1
83+
} else if xStr > yStr {
84+
return 1
85+
}
86+
return 0
87+
}
88+
}
89+
90+
// Handle keywords
91+
if xKw, xOk := x.(Keyword); xOk {
92+
if yKw, yOk := y.(Keyword); yOk {
93+
return Compare(xKw.String(), yKw.String())
94+
}
95+
}
96+
97+
// Handle symbols
98+
if xSym, xOk := x.(Symbol); xOk {
99+
if ySym, yOk := y.(Symbol); yOk {
100+
// Compare namespace first
101+
nsComp := Compare(xSym.Namespace(), ySym.Namespace())
102+
if nsComp != 0 {
103+
return nsComp
104+
}
105+
// Then compare name
106+
return Compare(xSym.Name(), ySym.Name())
107+
}
108+
}
109+
110+
// If we can't compare, panic with an error
111+
panic(NewIllegalArgumentError(fmt.Sprintf("Cannot compare %T with %T", x, y)))
112+
}

0 commit comments

Comments
 (0)