From 45a9783812846db030552ed188507d5b2119ed28 Mon Sep 17 00:00:00 2001 From: Martin Henz Date: Sat, 26 Jun 2021 13:21:37 +0800 Subject: [PATCH] bumping js-slang (#1827) * bumping js-slang * Update to new js-slang Co-authored-by: openorclose --- package.json | 2 +- src/commons/sagas/__tests__/WorkspaceSaga.ts | 2 +- src/commons/utils/InfiniteLoopReporter.ts | 42 +++++++------------ .../game/scenes/roomPreview/RoomPreview.ts | 1 - yarn.lock | 8 ++-- 5 files changed, 22 insertions(+), 33 deletions(-) diff --git a/package.json b/package.json index b927811d25..75228d3e6f 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "connected-react-router": "^6.9.1", "flexboxgrid": "^6.3.1", "flexboxgrid-helpers": "^1.1.3", - "js-slang": "^0.5.3", + "js-slang": "^0.5.4", "konva": "^7.2.5", "lodash": "^4.17.21", "lz-string": "^1.4.4", diff --git a/src/commons/sagas/__tests__/WorkspaceSaga.ts b/src/commons/sagas/__tests__/WorkspaceSaga.ts index 878fffc0d2..08720a02f5 100644 --- a/src/commons/sagas/__tests__/WorkspaceSaga.ts +++ b/src/commons/sagas/__tests__/WorkspaceSaga.ts @@ -858,7 +858,7 @@ describe('evalCode', () => { .call( reportInfiniteLoopError, 'source_protection_recursion', - 'const test=[x => x,2,3,[x => x],5];\nfunction f(x) {\n return f(x);\n}\n{f(1);}' + 'function is_list(xs) {\n return is_null(xs) || is_pair(xs) && is_list(tail(xs));\n}\nfunction equal(xs, ys) {\n return is_pair(xs) ? is_pair(ys) && equal(head(xs), head(ys)) && equal(tail(xs), tail(ys)) : is_null(xs) ? is_null(ys) : is_number(xs) ? is_number(ys) && xs === ys : is_boolean(xs) ? is_boolean(ys) && (xs && ys || !xs && !ys) : is_string(xs) ? is_string(ys) && xs === ys : is_undefined(xs) ? is_undefined(ys) : is_function(ys) && xs === ys;\n}\nfunction length(xs) {\n return is_null(xs) ? 0 : 1 + length(tail(xs));\n}\nfunction map(f, xs) {\n return is_null(xs) ? null : pair(f(head(xs)), map(f, tail(xs)));\n}\nfunction build_list(fun, n) {\n function build(i, fun, already_built) {\n return i < 0 ? already_built : build(i - 1, fun, pair(fun(i), already_built));\n }\n return build(n - 1, fun, null);\n}\nfunction for_each(fun, xs) {\n if (is_null(xs)) {\n return true;\n } else {\n fun(head(xs));\n return for_each(fun, tail(xs));\n }\n}\nfunction list_to_string(xs) {\n return is_null(xs) ? "null" : is_pair(xs) ? "[" + list_to_string(head(xs)) + "," + list_to_string(tail(xs)) + "]" : stringify(xs);\n}\nfunction reverse(xs) {\n function rev(original, reversed) {\n return is_null(original) ? reversed : rev(tail(original), pair(head(original), reversed));\n }\n return rev(xs, null);\n}\nfunction append(xs, ys) {\n return is_null(xs) ? ys : pair(head(xs), append(tail(xs), ys));\n}\nfunction member(v, xs) {\n return is_null(xs) ? null : v === head(xs) ? xs : member(v, tail(xs));\n}\nfunction remove(v, xs) {\n return is_null(xs) ? null : v === head(xs) ? tail(xs) : pair(head(xs), remove(v, tail(xs)));\n}\nfunction remove_all(v, xs) {\n return is_null(xs) ? null : v === head(xs) ? remove_all(v, tail(xs)) : pair(head(xs), remove_all(v, tail(xs)));\n}\nfunction filter(pred, xs) {\n return is_null(xs) ? xs : pred(head(xs)) ? pair(head(xs), filter(pred, tail(xs))) : filter(pred, tail(xs));\n}\nfunction enum_list(start, end) {\n return start > end ? null : pair(start, enum_list(start + 1, end));\n}\nfunction list_ref(xs, n) {\n return n === 0 ? head(xs) : list_ref(tail(xs), n - 1);\n}\nfunction accumulate(f, initial, xs) {\n return is_null(xs) ? initial : f(head(xs), accumulate(f, initial, tail(xs)));\n}\nfunction is_stream(xs) {\n return is_null(xs) || is_pair(xs) && is_stream(stream_tail(xs));\n}\nfunction list_to_stream(xs) {\n return is_null(xs) ? null : pair(head(xs), () => list_to_stream(tail(xs)));\n}\nfunction stream_to_list(xs) {\n return is_null(xs) ? null : pair(head(xs), stream_to_list(stream_tail(xs)));\n}\nfunction stream_length(xs) {\n return is_null(xs) ? 0 : 1 + stream_length(stream_tail(xs));\n}\nfunction stream_map(f, s) {\n return is_null(s) ? null : pair(f(head(s)), () => stream_map(f, stream_tail(s)));\n}\nfunction build_stream(fun, n) {\n function build(i) {\n return i >= n ? null : pair(fun(i), () => build(i + 1));\n }\n return build(0);\n}\nfunction stream_for_each(fun, xs) {\n if (is_null(xs)) {\n return true;\n } else {\n fun(head(xs));\n return stream_for_each(fun, stream_tail(xs));\n }\n}\nfunction stream_reverse(xs) {\n function rev(original, reversed) {\n return is_null(original) ? reversed : rev(stream_tail(original), pair(head(original), () => reversed));\n }\n return rev(xs, null);\n}\nfunction stream_append(xs, ys) {\n return is_null(xs) ? ys : pair(head(xs), () => stream_append(stream_tail(xs), ys));\n}\nfunction stream_member(x, s) {\n return is_null(s) ? null : head(s) === x ? s : stream_member(x, stream_tail(s));\n}\nfunction stream_remove(v, xs) {\n return is_null(xs) ? null : v === head(xs) ? stream_tail(xs) : pair(head(xs), () => stream_remove(v, stream_tail(xs)));\n}\nfunction stream_remove_all(v, xs) {\n return is_null(xs) ? null : v === head(xs) ? stream_remove_all(v, stream_tail(xs)) : pair(head(xs), () => stream_remove_all(v, stream_tail(xs)));\n}\nfunction stream_filter(p, s) {\n return is_null(s) ? null : p(head(s)) ? pair(head(s), () => stream_filter(p, stream_tail(s))) : stream_filter(p, stream_tail(s));\n}\nfunction enum_stream(start, end) {\n return start > end ? null : pair(start, () => enum_stream(start + 1, end));\n}\nfunction integers_from(n) {\n return pair(n, () => integers_from(n + 1));\n}\nfunction eval_stream(s, n) {\n function es(s, n) {\n return n === 1 ? list(head(s)) : pair(head(s), es(stream_tail(s), n - 1));\n }\n return n === 0 ? null : es(s, n);\n}\nfunction stream_ref(s, n) {\n return n === 0 ? head(s) : stream_ref(stream_tail(s), n - 1);\n}\nconst test=[x => x,2,3,[x => x],5];\nfunction f(x) {\n return f(x);\n}' ) .silentRun(); }); diff --git a/src/commons/utils/InfiniteLoopReporter.ts b/src/commons/utils/InfiniteLoopReporter.ts index 48e98dba1b..260729ffda 100644 --- a/src/commons/utils/InfiniteLoopReporter.ts +++ b/src/commons/utils/InfiniteLoopReporter.ts @@ -1,6 +1,6 @@ import * as Sentry from '@sentry/browser'; import { infiniteLoopErrorType } from 'js-slang/dist/infiniteLoops/errorMessages'; -import { Context, NativeStorage, SourceError } from 'js-slang/dist/types'; +import { Context, SourceError } from 'js-slang/dist/types'; function getInfiniteLoopErrors(errors: SourceError[]) { for (const error of errors) { @@ -58,30 +58,25 @@ function stringifyArray(arr: any[]) { * NOTE: variables trapped in closures can not be saved/recovered, e.g. * function f(x) {return (y)=>(x+y)}; //f(2).tostring() = "(y)=>(x+y)", 2 is gone forever * - * @param {Globals} scope - Globals object from context.nativeStorage + * @param {Globals} previousIdentifiers - Globals object from context.nativeStorage * * @returns {string} code */ -function getPreviousCode(scope: NativeStorage['globals'] | null): Array { - const output = []; - while (scope !== null) { - let code = ''; - for (const [key, value] of scope.variables.entries()) { - const theVar = value.getValue(); - //add newline for readability - if (code !== '') code += '\n'; - if (typeof theVar === 'function') { - code += `${theVar.toString()}`; - } else if (Array.isArray(theVar)) { - code += `const ${key}=${stringifyArray(theVar)};`; - } else { - code += `const ${key}=${JSON.stringify(theVar)};`; - } +function getPreviousCode(context: Context): string { + let code = ''; + for (const key of context.nativeStorage.previousProgramsIdentifiers) { + const theVar = context.nativeStorage.evaller!(key); + //add newline for readability + if (code !== '') code += '\n'; + if (typeof theVar === 'function') { + code += `${theVar.toString()}`; + } else if (Array.isArray(theVar)) { + code += `const ${key}=${stringifyArray(theVar)};`; + } else { + code += `const ${key}=${JSON.stringify(theVar)};`; } - output.unshift(code); - scope = scope.previousScope; } - return output; + return code; } /** @@ -99,12 +94,7 @@ function getPreviousCode(scope: NativeStorage['globals'] | null): Array export function getInfiniteLoopData(context: Context, code: string) { const errors = getInfiniteLoopErrors(context.errors); if (errors) { - const innerCode = getPreviousCode(context.nativeStorage.globals); - innerCode.shift(); - if (context.chapter >= 2) innerCode.shift(); - let fullCode = innerCode.reduce((acc: string, current: string) => acc + current + '\n{'); - fullCode += code + '}'.repeat(innerCode.length - 1); - return [errors, fullCode]; + return [errors, getPreviousCode(context)]; } else { return null; } diff --git a/src/features/game/scenes/roomPreview/RoomPreview.ts b/src/features/game/scenes/roomPreview/RoomPreview.ts index 77cc03706a..74c0c58c35 100644 --- a/src/features/game/scenes/roomPreview/RoomPreview.ts +++ b/src/features/game/scenes/roomPreview/RoomPreview.ts @@ -133,7 +133,6 @@ export default class RoomPreview extends Phaser.Scene { * Hence, we replace the scope instead of appending * new one each time. */ - this.context!.nativeStorage.globals = this.context!.nativeStorage.globals!.previousScope; this.eval(`update();`); } diff --git a/yarn.lock b/yarn.lock index f0dd438ace..621d0c0143 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8181,10 +8181,10 @@ jest@26.6.0: import-local "^3.0.2" jest-cli "^26.6.0" -js-slang@^0.5.3: - version "0.5.3" - resolved "https://registry.yarnpkg.com/js-slang/-/js-slang-0.5.3.tgz#5600f6782eae2a684debdf3577ff0b1849fc91d2" - integrity sha512-4dFdk8vPqKuuEV4gSw85wS7GLh5i9V4yFrXl65qbJoZ50PJ38c9MP626ylTk6xNCaB5A0C8WWpzu8KDmAGy+0A== +js-slang@^0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/js-slang/-/js-slang-0.5.4.tgz#6fcd717ebf17fd42058f28676474d510ef09e18b" + integrity sha512-QN5g4d6rnD5y8nlDbPyjEHIVzpoW35O9al04W/b/SKYSehNQqL5qMP8sc2xHgdUqiDfdqGg9ywkSGbFyE92pGA== dependencies: "@types/estree" "0.0.47" acorn "^8.0.3"