Skip to content

Commit

Permalink
broken lazy sequences
Browse files Browse the repository at this point in the history
I suppose it's fine that they're broken because you can just... not use them
  • Loading branch information
bobbicodes authored Sep 3, 2023
2 parents ef84f02 + 9e3cbad commit fbc0958
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 10 deletions.
4 changes: 2 additions & 2 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,6 @@ function testExercisesUntilFail() {

//testSolution(randExercise())
//testSolution("queen_attack")
//loadExercise("robot_simulator")
//loadExercise("rn")
//testExercisesUntilFail()
testExercises()
//testExercises()
3 changes: 3 additions & 0 deletions src/clj/core.clj
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
77 changes: 69 additions & 8 deletions src/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -508,10 +508,64 @@ function divide() {
return res
}

function take(n, coll) {
// https://github.com/squint-cljs/squint/blob/main/src/squint/core.js
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()
Expand Down Expand Up @@ -750,18 +804,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,
Expand Down
4 changes: 4 additions & 0 deletions src/interpreter.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
5 changes: 5 additions & 0 deletions src/printer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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':
Expand Down
23 changes: 23 additions & 0 deletions src/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ 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'; }
else if (_list_Q(obj)) { return 'list'; }
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'; }
Expand Down Expand Up @@ -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); }


Expand Down

0 comments on commit fbc0958

Please sign in to comment.