Skip to content

Commit

Permalink
Arrays without tests
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisrink10 committed Mar 14, 2020
1 parent 7533772 commit 4b49f90
Show file tree
Hide file tree
Showing 4 changed files with 247 additions and 15 deletions.
137 changes: 137 additions & 0 deletions src/basilisp/core.lpy
Original file line number Diff line number Diff line change
Expand Up @@ -1448,6 +1448,143 @@
integers."
short)

;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Arrays (Python List) ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;

(defn to-array
"Return a Python list with the contents of coll."
[coll]
(python/list coll))

(defn to-array-2d
"Return a two-dimensional Python list from the contents of coll.
Python lists do not specify a fixed size, so the resulting two-dimensional
list may be ragged (in the Java sense of the word) if the inner collections
of the input are ragged."
[coll]
(python/list (python/map python/list coll)))

(defn into-array
"Returns a Python list with the values from aseq.
The type argument is ignored and is provided only for Clojure compatibility."
([aseq]
(python/list aseq))
([^:no-warn-when-unused type aseq]
(python/list aseq)))

(defn make-array
"Create a Python list with initial size. If multiple sizes are provided, produces
a multi-dimensional list-of-lists. There is no efficient way to allocate such
multi-dimensional lists in Python, so this function will run in polynomial time.
Python lists do not support pre-allocation by capacity, so this function pre-
fills the created list(s) with `nil`.
The type argument is ignored and is provided only for Clojure compatibility."
([size]
(operator/mul #py [nil] size))
([^:no-warn-when-unused type size]
(operator/mul #py [nil] size))
([^:no-warn-when-unused type size & more-sizes]
(let [final #py []]
(loop [size size]
(if (pos? size)
(do
(.append final (apply make-array type more-sizes))
(recur (dec size)))
final)))))

(defn object-array
"Create an array of objects.
If `init-val-or-seq` and is a `seq` yielding fewer than `size` elements, then the
remaining indices of the resulting array will be filled with `nil` values.
This function does not coerce its argument and is provided for Clojure compatibility."
([size-or-seq]
(if (int? size-or-seq)
(make-array size-or-seq)
(to-array size-or-seq)))
([size init-val-or-seq]
(if (and (seqable? init-val-or-seq) (seq init-val-or-seq))
(let [final #py []]
(loop [arr-seq (seq init-val-or-seq)
idx 0]
(when (< idx size)
(.append final (first arr-seq))
(recur (rest arr-seq) (inc idx))))
final)
(operator/mul #py [init-val-or-seq] size))))

(defn aclone
"Return a clone of the Python list."
[array]
(python/list array))

(defn aget
"Return the value of the Python list at the index (or indices)."
([array idx]
(operator/getitem array idx))
([array idx & idxs]
(if (seq idxs)
(recur (operator/getitem array idx) (first idxs) (rest idxs))
(operator/getitem array idx))))

(defn aset
"Sets the value of the Python list at the index (or indices). Returns val."
([array idx val]
(operator/setitem array idx val)
val)
([array idx idx2 & idxs]
(loop [target (operator/getitem array idx)
idx idx2
idx2 (first idxs)
idxs (rest idxs)]
(if (seq idxs)
(recur (operator/getitem target idx) idx2 (first idxs) (rest idxs))
(do
(operator/setitem target idx idx2)
idx2)))))

(defn alength
"Return the length of the Python list."
[array]
(python/len array))

;; (amap #py [1 2 3] idx ret (+ idx (aget #py [1 2 3] idx)))
(defmacro amap
"Map `expr` over the Python list `array`, returning a new Python list with
the result.
This macro initially binds the symbol named by `ret` to a clone of `array`.
On each iteration, the index (named by `idx`) of `ret` is set to the return
value of `expr`."
[array idx ret expr]
`(let [len# (alength ~array)
~ret (aclone ~array)]
(loop [~idx 0]
(when (< ~idx len#)
(aset ~ret ~idx ~expr)
(recur (inc ~idx))))
~ret))

;; (areduce arr idx ret 0 (+ ret (aget arr idx)))
(defmacro areduce
"Reduce the Python list `array` by `expr`, returning the reduced expression.
This macro initially binds the symbol named by `ret` to `init`. On each
iteration, `ret` is rebound to the return value of `expr`."
[array idx ret init expr]
`(let [len# (alength ~array)]
(loop [~ret ~init
~idx 0]
(if (< ~idx len#)
(recur ~expr (inc ~idx))
~ret))))

;;;;;;;;;;;;;;;;
;; Exceptions ;;
;;;;;;;;;;;;;;;;
Expand Down
28 changes: 14 additions & 14 deletions src/basilisp/lang/obj.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,6 @@ def seq_lrepr(
return f"{start}{seq_lrepr}{end}"


@singledispatch
def lrepr( # pylint: disable=too-many-arguments
o: Any,
human_readable: bool = False,
Expand Down Expand Up @@ -192,6 +191,7 @@ def lrepr( # pylint: disable=too-many-arguments
)


@singledispatch
def _lrepr_fallback( # pylint: disable=too-many-arguments
o: Any,
human_readable: bool = False,
Expand Down Expand Up @@ -246,17 +246,17 @@ def _lrepr_fallback( # pylint: disable=too-many-arguments
return repr(o)


@lrepr.register(bool)
@_lrepr_fallback.register(bool)
def _lrepr_bool(o: bool, **_) -> str:
return repr(o).lower()


@lrepr.register(type(None))
@_lrepr_fallback.register(type(None))
def _lrepr_nil(_: None, **__) -> str:
return "nil"


@lrepr.register(str)
@_lrepr_fallback.register(str)
def _lrepr_str(
o: str, human_readable: bool = False, print_readably: bool = PRINT_READABLY, **_
) -> str:
Expand All @@ -267,53 +267,53 @@ def _lrepr_str(
return f'"{o.encode("unicode_escape").decode("utf-8")}"'


@lrepr.register(list)
@_lrepr_fallback.register(list)
def _lrepr_py_list(o: list, **kwargs) -> str:
return f"#py {seq_lrepr(o, '[', ']', **kwargs)}"


@lrepr.register(dict)
@_lrepr_fallback.register(dict)
def _lrepr_py_dict(o: dict, **kwargs) -> str:
return f"#py {map_lrepr(o.items, '{', '}', **kwargs)}"


@lrepr.register(set)
@_lrepr_fallback.register(set)
def _lrepr_py_set(o: set, **kwargs) -> str:
return f"#py {seq_lrepr(o, '#{', '}', **kwargs)}"


@lrepr.register(tuple)
@_lrepr_fallback.register(tuple)
def _lrepr_py_tuple(o: tuple, **kwargs) -> str:
return f"#py {seq_lrepr(o, '(', ')', **kwargs)}"


@lrepr.register(complex)
@_lrepr_fallback.register(complex)
def _lrepr_complex(o: complex, **_) -> str:
return repr(o).upper()


@lrepr.register(datetime.datetime)
@_lrepr_fallback.register(datetime.datetime)
def _lrepr_datetime(o: datetime.datetime, **_) -> str:
return f'#inst "{o.isoformat()}"'


@lrepr.register(Decimal)
@_lrepr_fallback.register(Decimal)
def _lrepr_decimal(o: Decimal, print_dup: bool = PRINT_DUP, **_) -> str:
if print_dup:
return f"{str(o)}M"
return str(o)


@lrepr.register(Fraction)
@_lrepr_fallback.register(Fraction)
def _lrepr_fraction(o: Fraction, **_) -> str:
return f"{o.numerator}/{o.denominator}"


@lrepr.register(type(re.compile("")))
@_lrepr_fallback.register(type(re.compile("")))
def _lrepr_pattern(o: Pattern, **_) -> str:
return f'#"{o.pattern}"'


@lrepr.register(uuid.UUID)
@_lrepr_fallback.register(uuid.UUID)
def _lrepr_uuid(o: uuid.UUID, **_) -> str:
return f'#uuid "{str(o)}"'
93 changes: 93 additions & 0 deletions tests/basilisp/core_fns_test.lpy
Original file line number Diff line number Diff line change
Expand Up @@ -334,3 +334,96 @@
(is (thrown? python/IndexError (subs "hello world" 3 12)))
(is (= "lo w" (subs "hello world" 3 7)))
(is (thrown? python/IndexError (subs "hello world" 12 3))))

(deftest to-array-test
(is (= #py [] (to-array [])))
(is (= #py [] (to-array '())))
(is (= #py [1] (to-array [1])))
(is (= #py [1 2 3] (to-array [1 2 3])))
(is (= #py [1] (to-array '(1))))
(is (= #py [1 2 3] (to-array '(1 2 3)))))

(deftest to-array-2d-test
(is (= #py [] (to-array-2d [])))
(is (= #py [] (to-array-2d '())))

(is (= #py [#py [] #py []] (to-array-2d [[] ()])))
(is (= #py [#py [] #py []] (to-array-2d '([] ()))))

(is (= #py [#py [1 2 3] #py [:a :b :c]]
(to-array-2d [[1 2 3] '(:a :b :c)])))

(is (= #py [#py [1 2 3] #py [:a :b :c]]
(to-array-2d '([1 2 3] (:a :b :c)))))

(is (thrown? python/TypeError)
(to-array-2d [[1 2 3] :b])))

(deftest into-array-test
(testing "with no type"
(is (= #py [] (into-array [])))
(is (= #py [] (into-array '())))
(is (= #py [1] (into-array [1])))
(is (= #py [1 2 3] (into-array [1 2 3])))
(is (= #py [1] (into-array '(1))))
(is (= #py [1 2 3] (into-array '(1 2 3)))))

(testing "with (ignored) type argument"
(is (= #py [] (into-array nil [])))
(is (= #py [] (into-array nil '())))
(is (= #py [1] (into-array python/int [1])))
(is (= #py [1 2 3] (into-array python/int [1 2 3])))
(is (= #py [1] (into-array python/float '(1))))
(is (= #py [1 2 3] (into-array python/float '(1 2 3))))))

(deftest make-array-test
(testing "with no type"
(is (= #py [] (make-array 0)))
(is (= #py [nil] (make-array 1)))
(is (= #py [nil nil nil] (make-array 3))))

(testing "with (ignored) type argument"
(is (= #py [] (make-array python/int 0)))
(is (= #py [nil] (make-array python/int 1)))
(is (= #py [nil nil nil] (make-array python/int 3))))

(testing "multi-dimensional"
(is (= #py [#py [] #py []]
(make-array python/int 2 0)))
(is (= #py [#py [nil nil nil] #py [nil nil nil]]
(make-array python/int 2 3)))
(is (= #py [#py [#py [nil nil] #py [nil nil]]
#py [#py [nil nil] #py [nil nil]]]
(make-array python/int 2 2 2)))))

(deftest object-array-tests
(testing "only size"
(is (= #py [] (object-array 0)))
(is (= #py [nil] (object-array 1)))
(is (= #py [nil nil nil] (object-array 3))))

(testing "only seq"
(is (= #py [] (object-array [])))
(is (= #py [] (object-array '())))
(is (= #py [1] (object-array [1])))
(is (= #py [1 2 3] (object-array [1 2 3])))
(is (= #py [1] (object-array '(1))))
(is (= #py [1 2 3] (object-array '(1 2 3)))))

(testing "size and init val"
(is (= #py [] (object-array 0 :a)))
(is (= #py [:a] (object-array 1 :a)))
(is (= #py [:a :a :a] (object-array 3 :a))))

(testing "size and seq"
(is (= #py [] (object-array 0 (range 1 3))))
(is (= #py [1 2 3] (object-array 3 (range 1 4))))
(is (= #py [1 2 3 nil nil] (object-array 5 (range 1 4))))))

(deftest aclone-test
(is (= #py [] (aclone [])))
(is (= #py [] (aclone '())))
(is (= #py [1] (aclone [1])))
(is (= #py [1 2 3] (aclone [1 2 3])))
(is (= #py [1] (aclone '(1))))
(is (= #py [1 2 3] (aclone '(1 2 3)))))
4 changes: 3 additions & 1 deletion tests/basilisp/prompt_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ def patch_completions(self, completions: Iterable[str]):
(
"macroexpand",
"macroexpand-1",
"make-array",
"map",
"map-entry",
"map-entry?",
Expand All @@ -81,6 +82,7 @@ def patch_completions(self, completions: Iterable[str]):
(
"macroexpand",
"macroexpand-1",
"make-array",
"map",
"map-entry",
"map-entry?",
Expand All @@ -104,7 +106,7 @@ def patch_completions(self, completions: Iterable[str]):
"mapv",
),
),
("mak", (),),
("mav", (),),
("(map-", ("map-entry", "map-entry?", "map-indexed",),),
],
)
Expand Down

0 comments on commit 4b49f90

Please sign in to comment.