Skip to content

Commit

Permalink
make plugin work
Browse files Browse the repository at this point in the history
  • Loading branch information
JosiasAurel committed Feb 1, 2024
1 parent e0e8ef3 commit 0c970c9
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 2 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@
"tinykeys": "^1.4.0"
},
"devDependencies": {
"@babel/standalone": "^7.23.8",
"@prefresh/vite": "^2.2.9",
"@types/babel__standalone": "^7.1.7",
"@types/debounce": "^1.2.1",
"@types/esprima": "^4.0.3",
"@types/grecaptcha": "^3.0.4",
Expand Down
12 changes: 10 additions & 2 deletions src/components/big-interactive-pages/editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ import { nanoid } from 'nanoid'
import TutorialWarningModal from '../popups-etc/tutorial-warning'
import { isDark } from '../../lib/state'

import * as Babel from "@babel/standalone";
import TransformDetectInfiniteLoop from '../../lib/transform-detect-infinite-loop'

interface EditorProps {
persistenceState: Signal<PersistenceState>
cookies: {
Expand Down Expand Up @@ -168,8 +171,13 @@ export default function Editor({ persistenceState, cookies }: EditorProps) {
errorLog.value = []

const code = codeMirror.value?.state.doc.toString() ?? ''
const res = runGame(code, screen.current, (error) => {
errorLog.value = [ ...errorLog.value, error ]
const transformResult = Babel.transform(code, {
plugins: [ TransformDetectInfiniteLoop ],
retainLines: true
});

const res = runGame(transformResult.code!, screen.current, (error) => {
errorLog.value = [...errorLog.value, error]
})

screen.current.focus()
Expand Down
89 changes: 89 additions & 0 deletions src/lib/transform-detect-infinite-loop.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Based on https://repl.it/site/blog/infinite-loops by Amjad Masad.

export default function TransformDetectInfiniteLoop({ types: t }) {
const MAX_ITERATIONS = 2000;
const MAX_LOOP_TIME_MS = 1500;

return {
visitor: {
'WhileStatement|ForStatement|DoWhileStatement': (path: any) => {
const startTime = t.identifier('startTime');
path.scope.parent.push({
id: startTime,
init: t.numericLiteral(0)
});

// An iterator that is incremented with each iteration
const iterator = t.identifier('loopIt');
path.scope.parent.push({
id: iterator,
init: t.numericLiteral(0)
});

// re-initialize counter variable
const countReInitializer = t.assignmentExpression('=', t.identifier(iterator.name), t.numericLiteral(0));
// re-initialize counter variable for this loop
path.insertBefore(t.expressionStatement(countReInitializer));

// re-initialize time variable
// will begin counting execution time from before the loop starts
const timeReInitializer = t.assignmentExpression('=', t.identifier('startTime'), t.callExpression(
t.identifier('performance.now'),
[]
));
path.insertBefore(t.expressionStatement(timeReInitializer));


/*
* throw RangeError if loop
* 1. does over MAX_ITERATIONS iterations
* 2. takes more than MAX_LOOP_TIME_MS to complete
*/
const guard = t.ifStatement(
t.logicalExpression(
'&&',
t.binaryExpression(
'>',
t.updateExpression(
'++',
iterator,
true,
),
t.numericLiteral(MAX_ITERATIONS),
),
t.binaryExpression(
'>',
t.binaryExpression(
'-',
t.callExpression(t.identifier('performance.now'), []),
startTime
),
t.numericLiteral(MAX_LOOP_TIME_MS)
),
),
t.throwStatement(
t.newExpression(
t.identifier('RangeError'),
[t.stringLiteral(
'Potential infinite loop',
)],
),
),
);

// No block statment e.g. `while (1) 1;`
if (!path.get('body').isBlockStatement()) {
const statement = path.get('body').node;
path.get('body').replaceWith(
t.blockStatement([
guard,
statement,
]),
);
} else {
path.get('body').unshiftContainer('body', guard);
}
}
}
}
}
23 changes: 23 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,11 @@
"@babel/plugin-syntax-jsx" "^7.22.5"
"@babel/types" "^7.22.15"

"@babel/standalone@^7.23.8":
version "7.23.8"
resolved "https://registry.yarnpkg.com/@babel/standalone/-/standalone-7.23.8.tgz#534b991afed6aead40ff925ef465c781bd8f7e77"
integrity sha512-i0tPn3dyKHbEZPDV66ry/7baC1pznRU02R8sU6eJSBfTOwMkukRdYuT3ks/j/cvTl4YkHMRmhTejET+iyPZVvQ==

"@babel/template@^7.18.10", "@babel/template@^7.20.7":
version "7.20.7"
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.20.7.tgz#a15090c2839a83b02aa996c0b4994005841fd5a8"
Expand Down Expand Up @@ -1326,6 +1331,17 @@
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf"
integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==

"@types/babel__core@^7.1.0":
version "7.20.5"
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017"
integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==
dependencies:
"@babel/parser" "^7.20.7"
"@babel/types" "^7.20.7"
"@types/babel__generator" "*"
"@types/babel__template" "*"
"@types/babel__traverse" "*"

"@types/babel__core@^7.20.1":
version "7.20.2"
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.2.tgz#215db4f4a35d710256579784a548907237728756"
Expand All @@ -1344,6 +1360,13 @@
dependencies:
"@babel/types" "^7.0.0"

"@types/babel__standalone@^7.1.7":
version "7.1.7"
resolved "https://registry.yarnpkg.com/@types/babel__standalone/-/babel__standalone-7.1.7.tgz#8ab09548a24f54015e7d84a55486148180bc4ace"
integrity sha512-4RUJX9nWrP/emaZDzxo/+RYW8zzLJTXWJyp2k78HufG459HCz754hhmSymt3VFOU6/Wy+IZqfPvToHfLuGOr7w==
dependencies:
"@types/babel__core" "^7.1.0"

"@types/babel__template@*":
version "7.4.1"
resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969"
Expand Down

0 comments on commit 0c970c9

Please sign in to comment.