Skip to content

Commit 2c969aa

Browse files
committed
Implement sort function for Glojure
- Add SortSlice 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 SortSlice - Add transformation for clojure.lang.Util.compare to use Compare function 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 2c969aa

13 files changed

Lines changed: 178 additions & 6 deletions

Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,10 @@ $(TEST_TARGETS): gocmd
6060

6161
.PHONY: test
6262
test: vet $(TEST_TARGETS)
63+
64+
.PHONY: format
65+
format:
66+
@if go fmt ./... | grep -q .; then \
67+
echo "Files were formatted. Please commit the changes."; \
68+
exit 1; \
69+
fi

internal/deps/pull.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1 @@
11
package deps
2-
3-

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.SortSlice", github_com_glojurelang_glojure_pkg_lang.SortSlice)
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.SortSlice", github_com_glojurelang_glojure_pkg_lang.SortSlice)
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.SortSlice", github_com_glojurelang_glojure_pkg_lang.SortSlice)
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.SortSlice", github_com_glojurelang_glojure_pkg_lang.SortSlice)
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.SortSlice", github_com_glojurelang_glojure_pkg_lang.SortSlice)
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.SortSlice", github_com_glojurelang_glojure_pkg_lang.SortSlice)
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.SortSlice", github_com_glojurelang_glojure_pkg_lang.SortSlice)
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
}

0 commit comments

Comments
 (0)