Skip to content

Commit 26f0931

Browse files
tohlhRichDom2185
andauthored
Language options (#3123)
* Add support for language options * Fix issues with prepend code on typed variant * Fix line number issues * Fix format and lint * Fix languageOptions field type * fix styles * Fix evalEditor * fix test cases * fix styles * fix styles --------- Co-authored-by: Richard Dominick <[email protected]>
1 parent 20fd8d1 commit 26f0931

File tree

7 files changed

+74
-42
lines changed

7 files changed

+74
-42
lines changed

src/commons/assessment/AssessmentTypes.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Chapter, SourceError, Variant } from 'js-slang/dist/types';
1+
import { Chapter, LanguageOptions, SourceError, Variant } from 'js-slang/dist/types';
22

33
import { ExternalLibrary, ExternalLibraryName } from '../application/types/ExternalTypes';
44

@@ -177,6 +177,7 @@ export type Library = {
177177
2?: string; // For mission control
178178
}>;
179179
moduleParams?: any;
180+
languageOptions?: LanguageOptions;
180181
};
181182

182183
export type Testcase = {

src/commons/sagas/WorkspaceSaga/helpers/blockExtraMethods.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
import type { Context } from 'js-slang';
1+
import { Context } from 'js-slang';
2+
import { Variant } from 'js-slang/dist/types';
23
import { call } from 'redux-saga/effects';
34

45
import {
56
getBlockExtraMethodsString,
7+
getBlockExtraMethodsStringTypedVariant,
68
getDifferenceInMethods,
79
getStoreExtraMethodsString
810
} from '../../../utils/JsSlangHelper';
@@ -35,7 +37,10 @@ export function* blockExtraMethods(
3537
);
3638
}
3739

38-
const nullifier = getBlockExtraMethodsString(toBeBlocked);
40+
const nullifier =
41+
context.variant === Variant.TYPED
42+
? getBlockExtraMethodsStringTypedVariant(toBeBlocked)
43+
: getBlockExtraMethodsString(toBeBlocked);
3944
const nullifierFilePath = '/nullifier.js';
4045
const nullifierFiles = {
4146
[nullifierFilePath]: nullifier

src/commons/sagas/WorkspaceSaga/helpers/clearContext.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { selectWorkspace } from '../../SafeEffects';
1010

1111
export function* clearContext(workspaceLocation: WorkspaceLocation, entrypointCode: string) {
1212
const {
13-
context: { chapter, externalSymbols: symbols, variant },
13+
context: { chapter, externalSymbols: symbols, variant, languageOptions },
1414
externalLibrary: externalLibraryName,
1515
globals
1616
} = yield* selectWorkspace(workspaceLocation);
@@ -22,7 +22,8 @@ export function* clearContext(workspaceLocation: WorkspaceLocation, entrypointCo
2222
name: externalLibraryName,
2323
symbols
2424
},
25-
globals
25+
globals,
26+
languageOptions
2627
};
2728

2829
// Clear the context, with the same chapter and externalSymbols as before.

src/commons/sagas/WorkspaceSaga/helpers/evalEditor.ts

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { FSModule } from 'browserfs/dist/node/core/FS';
2+
import { Variant } from 'js-slang/dist/types';
23
import { call, put, select, StrictEffect } from 'redux-saga/effects';
34
import WorkspaceActions from 'src/commons/workspace/WorkspaceActions';
45

@@ -82,19 +83,28 @@ export function* evalEditorSaga(
8283
const prependFiles = {
8384
[prependFilePath]: prepend
8485
};
85-
yield call(
86-
evalCodeSaga,
87-
prependFiles,
88-
prependFilePath,
89-
elevatedContext,
90-
execTime,
91-
EVAL_SILENT,
92-
workspaceLocation
93-
);
86+
if (context.variant !== Variant.TYPED) {
87+
yield call(
88+
evalCodeSaga,
89+
prependFiles,
90+
prependFilePath,
91+
elevatedContext,
92+
execTime,
93+
EVAL_SILENT,
94+
workspaceLocation
95+
);
96+
}
97+
9498
// Block use of methods from privileged context
9599
yield* blockExtraMethods(elevatedContext, context, execTime, workspaceLocation);
96100
}
97101

102+
if (context.variant === Variant.TYPED) {
103+
// Prepend was multi-line, now we need to split them by \n and join them
104+
// This is to avoid extra lines in the editor which affects the error message location
105+
const prependSingleLine = prepend.split('\n').join('');
106+
files[entrypointFilePath] = prependSingleLine + files[entrypointFilePath];
107+
}
98108
yield call(
99109
evalCodeSaga,
100110
files,

src/commons/sagas/__tests__/WorkspaceSaga.test.ts

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,8 @@ describe('EVAL_EDITOR', () => {
130130
name: ExternalLibraryName.NONE,
131131
symbols: context.externalSymbols
132132
},
133-
globals
133+
globals,
134+
languageOptions: context.languageOptions
134135
};
135136

136137
const newDefaultState = generateDefaultState(workspaceLocation, {
@@ -397,7 +398,8 @@ describe('EVAL_TESTCASE', () => {
397398
name: ExternalLibraryName.NONE,
398399
symbols: context.externalSymbols
399400
},
400-
globals
401+
globals,
402+
languageOptions: context.languageOptions
401403
};
402404

403405
const newDefaultState = generateDefaultState(workspaceLocation, {
@@ -682,30 +684,30 @@ describe('PLAYGROUND_EXTERNAL_SELECT', () => {
682684
externalLibrary: oldExternalLibraryName
683685
});
684686

685-
const symbols = externalLibraries.get(newExternalLibraryName)!;
686-
const library: Library = {
687-
chapter,
688-
external: {
689-
name: newExternalLibraryName,
690-
symbols
691-
},
692-
globals
693-
};
694-
695-
return expectSaga(workspaceSaga)
696-
.withState(newDefaultState)
697-
.put(WorkspaceActions.changeExternalLibrary(newExternalLibraryName, workspaceLocation))
698-
.put(WorkspaceActions.beginClearContext(workspaceLocation, library, true))
699-
.put(WorkspaceActions.clearReplOutput(workspaceLocation))
700-
.call(showSuccessMessage, `Switched to ${newExternalLibraryName} library`, 1000)
701-
.dispatch({
702-
type: WorkspaceActions.externalLibrarySelect.type,
703-
payload: {
704-
externalLibraryName: newExternalLibraryName,
705-
workspaceLocation
706-
}
707-
})
708-
.silentRun();
687+
return (
688+
expectSaga(workspaceSaga)
689+
.withState(newDefaultState)
690+
.put(WorkspaceActions.changeExternalLibrary(newExternalLibraryName, workspaceLocation))
691+
// beginClearContext is asserted here but the library object can contain
692+
// runtime-specific fields (like languageOptions). Match only the action
693+
// shape we care about (type, workspaceLocation and shouldInitLibrary)
694+
.put.like({
695+
action: {
696+
type: WorkspaceActions.beginClearContext.type,
697+
payload: { workspaceLocation, shouldInitLibrary: true }
698+
}
699+
})
700+
.put(WorkspaceActions.clearReplOutput(workspaceLocation))
701+
.call(showSuccessMessage, `Switched to ${newExternalLibraryName} library`, 1000)
702+
.dispatch({
703+
type: WorkspaceActions.externalLibrarySelect.type,
704+
payload: {
705+
externalLibraryName: newExternalLibraryName,
706+
workspaceLocation
707+
}
708+
})
709+
.silentRun()
710+
);
709711
});
710712

711713
test('does not call the above when oldExternalLibraryName === newExternalLibraryName', () => {
@@ -770,7 +772,8 @@ describe('BEGIN_CLEAR_CONTEXT', () => {
770772
name: newExternalLibraryName,
771773
symbols
772774
},
773-
globals
775+
globals,
776+
languageOptions: undefined
774777
};
775778

776779
return expectSaga(workspaceSaga)

src/commons/utils/JsSlangHelper.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ function loadStandardLibraries(proxyContext: Context, customBuiltIns: CustomBuil
181181
// intercepts reads from the underlying Context and returns desired values
182182
export function makeElevatedContext(context: Context) {
183183
function ProxyFrame() {}
184+
184185
ProxyFrame.prototype = context.runtime.environments[0].head;
185186
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
186187
// @ts-ignore
@@ -258,3 +259,13 @@ export function getBlockExtraMethodsString(toRemove: string[]) {
258259
)
259260
.join('\n');
260261
}
262+
263+
export function getBlockExtraMethodsStringTypedVariant(toRemove: string[]) {
264+
return toRemove
265+
.map(x =>
266+
x === 'makeUndefinedErrorFunction'
267+
? ''
268+
: `const ${x} : string = makeUndefinedErrorFunction('${x}');`
269+
)
270+
.join('\n');
271+
}

src/commons/workspace/WorkspaceReducer.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ const newWorkspaceReducer = createReducer(defaultWorkspaceManager, builder => {
101101
action.payload.library.chapter,
102102
action.payload.library.external.symbols,
103103
workspaceLocation,
104-
action.payload.library.variant
104+
action.payload.library.variant,
105+
action.payload.library.languageOptions
105106
),
106107
globals: action.payload.library.globals,
107108
externalLibrary: action.payload.library.external.name

0 commit comments

Comments
 (0)