~subsetpark/jnj

20af4e4459865688c49e779bbc2f64d15b14aeea — Zach Smith 2 years ago 063dc8a
Add some validation around janet matrices
4 files changed, 84 insertions(+), 19 deletions(-)

M jnj.c
M test/j.janet
A test/jnjc-errors.janet
M test/jnjc.janet
M jnj.c => jnj.c +6 -2
@@ 346,6 346,9 @@ static je_t *janet_get_abstract_je(Janet *argv, const uint8_t idx) {
static D *janet_number_array_to_jd(JanetArray *val) {
  D *jd = janet_malloc(sizeof(D) * val->count);
  for (I i = 0; i < val->count; i++) {
    if (!janet_checktype(val->data[i], JANET_NUMBER)) {
      janet_panicf("Expected a 1-dimensional number array");
    }
    jd[i] = janet_unwrap_number(val->data[i]);
  }
  return jd;


@@ 355,6 358,9 @@ static D *janet_number_array_to_jd(JanetArray *val) {
static D *janet_number_tuple_to_jd(JanetTupleHead *val) {
  D *jd = janet_malloc(sizeof(D) * val->length);
  for (I i = 0; i < val->length; i++) {
    if (!janet_checktype(val->data[i], JANET_NUMBER)) {
      janet_panicf("Expected a 1-dimensional number tuple");
    }
    jd[i] = janet_unwrap_number(val->data[i]);
  }
  return jd;


@@ 372,7 378,6 @@ static int setm_num(J j, C *name, D val) {

// Set a variable on the J engine from an array
static int setm_array(J j, C *name, JanetArray *val) {
  // TODO: Right now this only works for rank-1 arrays.
  I jt = JTFloat, jr = 1, *jl = janet_malloc(sizeof(I));
  *jl = val->count;
  D *jd = janet_number_array_to_jd(val);


@@ 386,7 391,6 @@ static int setm_array(J j, C *name, JanetArray *val) {

// Set a variable on the J engine from a tuple
static int setm_tuple(J j, C *name, JanetTupleHead *val) {
  // TODO: Right now this only works for rank-1 arrays.
  I jt = JTFloat, jr = 1, *jl = janet_malloc(sizeof(I));
  *jl = val->length;
  D *jd = janet_number_tuple_to_jd(val);

M test/j.janet => test/j.janet +40 -0
@@ 3,6 3,25 @@
(import jnj-primitives)
(import /jnj)

(defn test-array
  [ja count array? rank shape expected-values &opt matrix-form]
  (default matrix-form expected-values)

  (is (== expected-values (values ja)) "Array values")
  (is (= rank (jnj-primitives/rank ja)) "Array rank")
  (is (== shape (jnj-primitives/shape ja)) "Array shape")

  (when (> count 0)
    (is (= (expected-values 0) (ja 0)))
    (is (= 0 (next ja)) "First available index")
    (is (= (if (> count 1) 1 nil) (next ja 0)) "Second available index")
    (is (= nil (next ja (dec count))) "Last available index")
    (is (== (values ja) (values (unmarshal (marshal ja)))) "Marshal and unmarshal")
    (when array?
      (is (== expected-values (jnj-primitives/values ja)) "to-array")
      (is (== matrix-form (jnj/from-j-value ja)) "to-matrix"))))


(defmacro with-j
  [& body]
  ~(let [j (jnj-primitives/init)]


@@ 18,6 37,10 @@
    (let [resp (jnj/j* j "+" @[100 25 3.5 10] 66)]
      (is (= '(166 91 69.5 76) resp)))))

(deftest matrix-validation
  (with-j
    (is (thrown? (jnj/j* j "+" @[[100] [25] [3.5] [10]] 66)) "Can't set with a matrix")))

(deftest matrix-resp
  (with-j
    (let [resp (jnj/j* j "$" @[3 4] 66)]


@@ 67,4 90,21 @@
               ("#" arglist))]
    (is (= 2 resp))))

(deftest to-j-value-test
  (let [j-a (jnj/to-j-value @[])]
    (test-array j-a 0 true 1 [0] [])))

(deftest to-j-value-ints-test
  (let [j-a (jnj/to-j-value @[1 2 3])]
    (test-array j-a 3 true 1 [3] [1 2 3])))

(deftest to-j-value-ints-tuple-test
  (let [j-a (jnj/to-j-value [1 2 3])]
    (test-array j-a 3 true 1 [3] [1 2 3])))

(deftest to-j-value-matrix-test
  (let [j-a (jnj/to-j-value [[1 2 3]
                             [3 4 5]])]
    (test-array j-a 6 true 2 [2 3] [1 2 3 3 4 5] [[1 2 3] [3 4 5]])))

(run-tests!)

A test/jnjc-errors.janet => test/jnjc-errors.janet +38 -0
@@ 0,0 1,38 @@
(use testament)

(import /jnj)
(import jnj-primitives)

(deftest jdo
  (let [je (jnj-primitives/init)]
    (is (thrown? (jnj-primitives/do "x" 0)) "Requires a je")
    (is (thrown? (jnj-primitives/do je 0)) "Requires a string")
    (is (== 0 (jnj-primitives/do je "")) "Base sentence")
    (is (== 21 (jnj-primitives/do je "x")) "unknown symbol")
    (is (== 19 (jnj-primitives/do je "x=:")) "syntax error")))

(deftest jgetm
  (let [je (jnj-primitives/init)]
    (is (thrown? (jnj-primitives/getm 10 "x")) "Requires a je")
    (is (thrown? (jnj-primitives/getm je 10)) "Requires a string")
    (is (thrown? (jnj-primitives/getm je "x")) "Unknown symbol")))

(deftest jsetm
  (let [je (jnj-primitives/init)]
    (is (thrown? (jnj-primitives/setm 10 "x" true)) "Requires a je")
    (is (thrown? (jnj-primitives/setm je 10 true)) "Requires a string")
    (is (thrown? (jnj-primitives/setm je "x" (ev/thread-chan))) "Unknown data type")

    (is (thrown? (jnj-primitives/setm je "x" @[@[1 1 1] @[1 1] @[1 1 1]])) "Expected 1d number array")))

(deftest jvalue-operations
  (is (thrown? (jnj-primitives/rank "ok")) "Requires a jvalue")
  (is (thrown? (jnj-primitives/shape "ok")) "Requires a jvalue")
  (is (thrown? (jnj-primitives/type "ok")) "Requires a jvalue")
  (is (thrown? (jnj-primitives/values "ok")) "Requires a jvalue")
  (let [je (jnj-primitives/init)]
    (jnj-primitives/do je "x =: 10")
    (def ja (jnj-primitives/getm je "x"))
    (is (thrown? (jnj-primitives/values ja)) "Requires an array")))

(run-tests!)

M test/jnjc.janet => test/jnjc.janet +0 -17
@@ 102,21 102,4 @@
      (is (= 0 resp))
      (test-array i 5 true 1 [5] [0 1 0 1 0]))))

(deftest to-j-value-test
  (let [j-a (jnj/to-j-value @[])]
    (test-array j-a 0 true 1 [0] [])))

(deftest to-j-value-ints-test
  (let [j-a (jnj/to-j-value @[1 2 3])]
    (test-array j-a 3 true 1 [3] [1 2 3])))

(deftest to-j-value-ints-tuple-test
  (let [j-a (jnj/to-j-value [1 2 3])]
    (test-array j-a 3 true 1 [3] [1 2 3])))

(deftest to-j-value-matrix-test
  (let [j-a (jnj/to-j-value [[1 2 3]
                             [3 4 5]])]
    (test-array j-a 6 true 2 [2 3] [1 2 3 3 4 5] [[1 2 3] [3 4 5]])))

(run-tests!)