-
Notifications
You must be signed in to change notification settings - Fork 108
Old and Unused Transpiler Techniques
Here we document techniques tried but ultimately replaced.
One major problem of using eval is that eval('const a = 1;'); does not let us access the variable a again as it is not declared in the same scope. This would not allow the REPL to work, so there needs to be another way. The first idea that came to mind worked out well for the most part.
Store declared global variables in a global constant named STUDENT_GLOBALS.
Code will be appended to the end of the student's code to store the currently declared global variables into STUDENT_GLOBALS.
e.g.
//Student's main code
const PI = 3;
let sum = 0;
sum = sum + 1;//Transpiled code
//reset STUDENT_GLOBALS
// student's main code
const PI = 3;
let sum = 0;
sum = sum + 1;
//end of student's main code
//save declared studentglobals
STUDENT_GLOBALS["PI"] = {kind: "const", value: PI};
STUDENT_GLOBALS["sum"] = {kind: "let", value: sum};Before exectution of REPL code in the same context (so previously declared global variables have to be accessible), all keys of STUDENT_GLOBALS will be looped through and <kind> <key> = STUDENT_GLOBALS["<key>"]; will be prepended. For all variables (those declared with let), STUDENT_GLOBALS["<key>"] = <key>; will be appended to student's code to update the variable's value at the end of the code's execution.
Assuming the previous "main" code has been executed already, PI and sum will have already been saved.
So for the following code in the REPL:
// student's repl code
sum = sum + PI;// transpiled code
const PI = STUDENT_GLOBALS["PI"].value; // we need to put back these variables
let sum = STUDENT_GLOBALS["sum"].value; // this too
// student's repl code
sum = sum + PI;
// end of student's code
STUDENT_GLOBALS["sum"] = {kind: 'let', value: sum}; // store back variable sum
// PI does not need to be copied back since it's constant.const one = 1;
if (true) {
1;
} else {
one;
}should result in 1 being returned as it's the value of the last statement evaluated. However, because of the the statements to store back the variables,
const one = 1;
if (true) {
1;
} else {
one;
}
STUDENT_GLOBALS['one'] = {kind: 'const', value: one};the last line value is now incorrect. Luckily eval is here yet again. All that needs to be done is to save the value of the last statement and then return it at the end, so we do that by transforming the last statement into a string and then evaling it:
const one = 1;
const lastLineResult = eval(`if (true) {
1;
} else {
one;
}
`);
STUDENT_GLOBALS['one'] = {kind: 'const', value: one};
lastLineResult;and boom, problem solved...
not.
If the last line is a variable declaration statement, it would get transformed into:
const lastLineResult = eval('const two = 2;'); // last line transformed into eval
STUDENT_GLOBALS['two'] = {kind: 'const', value: two};
lastLineResult;But then two is not defined in the outer scope, it's defined only within the eval scope, so its value wouldn't get saved. Luckily again, the return value of a declaration is undefined, so if the last line of code is a declaration statement it does not get changed into eval, and we append undefined; at the end of the code:
const two = 2; // last line not transformed into eval
STUDENT_GLOBALS['two'] = {kind: 'const', value: two};
undefined;Phew.