From 7756932873c12d3190bfbb56b00b864145d0eb56 Mon Sep 17 00:00:00 2001 From: Bobbi Towers Date: Sun, 3 Sep 2023 02:42:45 -0700 Subject: [PATCH 1/2] not working, but at least nothing else broke --- main.js | 4 +- src/clj/core.clj | 3 ++ src/core.js | 112 +++++++++++++++++++++++++++++++++++++++++---- src/interpreter.js | 4 ++ src/printer.js | 5 ++ src/types.js | 23 ++++++++++ 6 files changed, 141 insertions(+), 10 deletions(-) diff --git a/main.js b/main.js index 1e83f7d..1fbcba3 100644 --- a/main.js +++ b/main.js @@ -173,6 +173,6 @@ function testExercisesUntilFail() { //testSolution(randExercise()) //testSolution("queen_attack") -//loadExercise("robot_simulator") +//loadExercise("rn") //testExercisesUntilFail() -testExercises() \ No newline at end of file +//testExercises() \ No newline at end of file diff --git a/src/clj/core.clj b/src/clj/core.clj index 1a74bf0..c68625c 100644 --- a/src/clj/core.clj +++ b/src/clj/core.clj @@ -27,6 +27,9 @@ `(def ~name (with-meta (fn ~(first fdecl) (do ~@(rest fdecl))) ~{:name (str name)}))))) +(defmacro lazy-seq [& body] + `(new LazySeq (fn [] ~@body))) + (defn not [a] (if a false true)) (defn not= [a b] (not (= a b))) (defn dec [a] (- a 1)) diff --git a/src/core.js b/src/core.js index 580d7fd..6f27c2f 100644 --- a/src/core.js +++ b/src/core.js @@ -508,10 +508,63 @@ function divide() { return res } -function take(n, coll) { +class LazyIterable { + constructor(gen) { + this.name = 'LazyIterable' + this.gen = gen; + } + [Symbol.iterator]() { + return this.gen(); + } +} + +export function lazy(f) { + return new LazyIterable(f); +} + +export function seqable_QMARK_(x) { + // String is iterable but doesn't allow `m in s` + return typeof x === 'string' || x === null || x === undefined || Symbol.iterator in x; +} + +export function iterable(x) { + // nil puns to empty iterable, support passing nil to first/rest/reduce, etc. + if (x === null || x === undefined) { + return []; + } + if (seqable_QMARK_(x)) { + return x; + } + return Object.entries(x); +} + +export class LazySeq { + constructor(f) { + this.name = 'LazySeq' + this.f = f; + } + *[Symbol.iterator]() { + yield* this.f(); + } +} + +export function take(n, coll) { if (types._lazy_range_Q(coll)) { return range(0, n) } + if (types._lazy_seq_Q(coll)) { + return lazy(function* () { + let i = n - 1; + for (const x of iterable(coll)) { + if (i-- >= 0) { + yield x; + } + if (i < 0) { + return; + } + } + }); + } if (types._iterate_Q(coll)) { for (let i = 0; i < n; i++) { coll.next() @@ -533,6 +586,42 @@ function take(n, coll) { return coll.slice(0, n) } +/* function take(n, coll) { + if (types._lazy_range_Q(coll)) { + return range(0, n) + } + if (types._lazy_seq_Q(coll)) { + let i = n - 1; + for (const x of coll) { + if (i-- >= 0) { + yield x; + } + if (i < 0) { + return; + } + } + } + if (types._iterate_Q(coll)) { + for (let i = 0; i < n; i++) { + coll.next() + } + return coll.realized.slice(0, -1) + } + if (types._cycle_Q(coll)) { + const cycles = Math.floor(n / coll.coll.length) + const mod = n % coll.coll.length + let res = [] + for (let i = 0; i < cycles; i++) { + res = res.concat(coll.coll) + } + if (mod != 0) { + res = res.concat(coll.coll.slice(0, mod)) + } + return res + } + return coll.slice(0, n) +} */ + function drop(n, coll) { return coll.slice(n) } @@ -750,18 +839,25 @@ function require(lib) { } } -export class LazySeq { - constructor(f) { - this.f = f; - } - *[Symbol.iterator]() { - yield* this.f(); - } +function downloadObjectAsJson(exportObj, exportName) { + var dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(exportObj)); + var downloadAnchorNode = document.createElement('a'); + downloadAnchorNode.setAttribute("href", dataStr); + downloadAnchorNode.setAttribute("download", exportName); + document.body.appendChild(downloadAnchorNode); // required for firefox + downloadAnchorNode.click(); + downloadAnchorNode.remove(); +} + +function spit_json(name, obj) { + return downloadObjectAsJson(obj, name) } // types.ns is namespace of type functions export var ns = { 'env': printEnv, + 'spit-json': spit_json, + 'LazySeq': LazySeq, 'require': require, 'type': types._obj_type, '=': types.allEqual, diff --git a/src/interpreter.js b/src/interpreter.js index 4079162..579439b 100644 --- a/src/interpreter.js +++ b/src/interpreter.js @@ -268,6 +268,10 @@ function _EVAL(ast, env) { } else { return types._function(EVAL, Env, a2, env, a1, a0); } + case "new": + var constructor = EVAL(a1, env) + var args = EVAL([types._symbol('do')].concat(ast.slice(2)), env) + return new constructor(args) default: var el = eval_ast(ast, env), f = el[0]; //console.log("f:", f, PRINT(ast), env) diff --git a/src/printer.js b/src/printer.js index c78129a..58dd5bb 100644 --- a/src/printer.js +++ b/src/printer.js @@ -13,6 +13,11 @@ export function _pr_str(obj, print_readably) { switch (ot) { case 'lazy-range': return "(0 1 2 3 4 5 6 7 8 9 10 ...)"; + case 'lazy-seq': + return obj + case 'lazy-iterable': + var ret = [...obj].map(function (e) { return _pr_str(e, _r); }); + return "(" + ret.join(' ') + ")"; case 'iterate': return "#iterate[" + obj.f + "]"; case 'cycle': diff --git a/src/types.js b/src/types.js index f1b3c8b..c6bd0f2 100644 --- a/src/types.js +++ b/src/types.js @@ -2,6 +2,7 @@ import { Fraction } from 'fraction.js' import { PRINT, READ } from './interpreter.js' export function _obj_type(obj) { + //console.log("[obj_type]", obj) //console.log("obj_type:", typeof obj) if (_symbol_Q(obj)) { return 'symbol'; } else if (_hash_map_Q(obj)) { return 'hash-map'; } @@ -9,6 +10,8 @@ export function _obj_type(obj) { else if (_vector_Q(obj)) { return 'vector'; } else if (_ratio_Q(obj)) { return 'ratio'; } else if (_lazy_range_Q(obj)) { return 'lazy-range'; } + else if (_lazy_iterable_Q(obj)) { return 'lazy-iterable'; } + else if (_lazy_seq_Q(obj)) { return 'lazy-seq'; } else if (_iterate_Q(obj)) { return 'iterate'; } else if (_cycle_Q(obj)) { return 'cycle'; } else if (_function_Q(obj)) { return 'function'; } @@ -58,6 +61,26 @@ export function _lazy_range_Q(x) { return false } +export function _lazy_iterable_Q(x) { + if (x === null) { + return false + } + if (typeof (x) === "object") { + return Object.hasOwn(x, 'name') && x.name === 'LazyIterable' + } + return false +} + +export function _lazy_seq_Q(x) { + if (x === null) { + return false + } + if (typeof (x) === "object") { + return Object.hasOwn(x, 'name') && x.name === 'LazySeq' + } + return false +} + export function _sequential_Q(lst) { return _list_Q(lst) || _vector_Q(lst); } From 9e3cbad4cc20014eac1f15f3815399335138efec Mon Sep 17 00:00:00 2001 From: Bobbi Towers Date: Sun, 3 Sep 2023 02:45:45 -0700 Subject: [PATCH 2/2] remove redundant code --- src/core.js | 37 +------------------------------------ 1 file changed, 1 insertion(+), 36 deletions(-) diff --git a/src/core.js b/src/core.js index 6f27c2f..53f0a68 100644 --- a/src/core.js +++ b/src/core.js @@ -508,6 +508,7 @@ function divide() { return res } +// https://github.com/squint-cljs/squint/blob/main/src/squint/core.js class LazyIterable { constructor(gen) { this.name = 'LazyIterable' @@ -586,42 +587,6 @@ export function take(n, coll) { return coll.slice(0, n) } -/* function take(n, coll) { - if (types._lazy_range_Q(coll)) { - return range(0, n) - } - if (types._lazy_seq_Q(coll)) { - let i = n - 1; - for (const x of coll) { - if (i-- >= 0) { - yield x; - } - if (i < 0) { - return; - } - } - } - if (types._iterate_Q(coll)) { - for (let i = 0; i < n; i++) { - coll.next() - } - return coll.realized.slice(0, -1) - } - if (types._cycle_Q(coll)) { - const cycles = Math.floor(n / coll.coll.length) - const mod = n % coll.coll.length - let res = [] - for (let i = 0; i < cycles; i++) { - res = res.concat(coll.coll) - } - if (mod != 0) { - res = res.concat(coll.coll.slice(0, mod)) - } - return res - } - return coll.slice(0, n) -} */ - function drop(n, coll) { return coll.slice(n) }