From 9afac5eb79b4f9bae2d791b78cc82f20eac45d7a Mon Sep 17 00:00:00 2001 From: Kyriel Abad Date: Mon, 15 Apr 2024 07:47:43 +0800 Subject: [PATCH] update frontend for scheme data visualisation (#2916) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Switch Scheme languages fully to CSE Machine * Updated tests with windows machine * Ran tests on different windows machine * resolve all issues with scheme CSE machine * update tests * reenable csc machine for scheme * add prototype visualisations for scheme data types * update tests * simplify logic for checking prelude * Make cse refer to correct closure * Centralise logic for alternate languages * separate scheme as its own file * add scheme primitive representation to cse machine * update representation of control * Squashed commit of the following: commit 27f3fe40837dcf9efc185e8f3550acc3e360f1e3 Author: Martin Henz Date: Sun Apr 14 15:21:16 2024 +0800 bumping js-slang (#2934) commit 812393a0f136179abf834cfd3e0439200f77c381 Author: Richard Dominick <34370238+RichDom2185@users.noreply.github.com> Date: Sun Apr 14 13:28:11 2024 +0800 Migrate to TypeScript v5 (#2850) * Bump TypeScript to v5.4 Also updated tsconfig.json to remove a deprecated config. * Fix type error * Fix type error * Fix type error * Fix type error * Fix type error * Fix lint dependencies and config * Fix type errors * Fix type error * Fix format * Fix type errors Also standardized React hooks import style. * Fix type error * Fix type error * Fix format * Bump typescript to v5.4.3 * Fix type errors * Add some `as any` assertions FIXMEs were also incorporated for future refactoring. * Update lockfile post-merge * Bump dependencies * Update lockfile post-merge * Create type-safe object helpers * Fix type error * Fix type error * Fix type error * Create more type helpers * Fix type error * Fix type error Also removed unnecessary type annotation. * Fix type error * Fix type error * Fix type errors * Fix type error * Fix type error * Fix type errors * Fix type error * Fix type error * Refactor filter logic to fix type error * Fix types * Address comments commit 87e646dc337aac0453c843f8e5c29145e3ffac8d Author: CZX Date: Sat Apr 13 23:05:04 2024 +0800 CSE UI/UX: Animations & UI improvements (#2931) * display array indices * animate moving numbers from agenda to stash * add code to read from previous agenda * Add animation components and some abstraction * Change test cases * Fix bug Properly disable animations when control and stash option is not enabled * display array indices * animate moving numbers from agenda to stash * add code to read from previous agenda * Add animation components and some abstraction * Change test cases * Fix bug Properly disable animations when control and stash option is not enabled * Fix issues with names after rebase * Fix animation bugs and refactoring of animation classes and logic * Fix mistake in test snapshot * Revert "Merge branch 'cse-uiux' of https://github.com/source-academy/frontend into cse-uiux" This reverts commit 7ef87d81a9073d13d28a5146f74692ca70bdaf80, reversing changes made to efa8c57c379ebb5d41a4aaca141d0774902941d2. * Restructure animation classes * Add binary operator animation * Add unary operator animation * Begin work on block separation animation * Improve binary operation animation, and improve the versatility of the base animation components * Improve the unary operation and block animations * Update test cases and remove block animation conditions * Add pop animation (linear movement) * Improve pop animation, and cleanup code for pull request * Revert envVisualizer test snapshot changes * Add assignment animation * Work on binding lookup function * Improve assignment animation and touch up on other animations, added experimental Column component * Add lookup animation (Identifier) * Improve lookup animation * Hide arrows for lookup animation and show them when it's finished * Remove AnimationUtils.tsx file replaced with AnimationUtils.ts * Slow down assignment and lookup animations * Fix issues with merging * Add environment animation * Refactor setDestination and animate to new method animateTo * Improve env animation and rename a utility function * Added animated arrows and also modified GenericArrow and improve assignment animation * Update test snapshot and formatting changes * Add arrow animation to lookup animation, and fix animateTo function behavior * Add FrameCreationAnimation * Rewrote all animation components for greater flexibility and performance * Shorten duration and delay names, and add listener functionality * Move experimental file * Fix issues with `this` keyword * Rewrite AnimatedTextbox to make it easier for both Text and Rect within it to be individually animated * Improve FrameCreationAnimation and bunch of other fixes * Fix some issues with `undefined` inside the control and stash * Make compact components the new default and remove any mentions to the old components. Also removes the experimental button toggle. * Update test snapshots * Clean up testing code a little * Formatting changes * Fix issues after merge * Revert some incorrect merges * Add FunctionFrameCreationAnimation if possible, reusing AssignmentAnimation would make handling fade-in of values easier * Add getNodeDimensions and getNodeLocation * Add ArrowFunctionExpressionAnimation * Add BranchAnimation simple animation for replacing a branch item in the control with the correct code block * Sort instr types in alphabetical order * Add ArrayLiteralAnimation * Added cases for block splitting for/while loops and conditional expressions * Improve animations for arrow functions and branch instruction * Update function application animation * Special changes for js-slang branch: add new objectCount property and filter program bindings * Change dummy binding behavior to match js-slang update * Fix array references being lost in frames due to cloning property descriptors * Simplify code * Add ArrayAccessAnimation * Begin work on ArrayAssignmentAnimation todo: animate arrows for object assignment * Fix application animation for predeclared funcs * Changes to solve issue 2700 and some fixes regarding global frame * Re-add animations * Fix many issues regarding displaying objects on global frame * Formatting * Simplify merging of environment heaps and drawing of bindings * Fix infinite loop in `findObjects` * Disable animations if control is truncated Could allow such functionality in the future, but currently animations break with a truncated control. * Fix AssignmentAnimation previous use of binding.height() causes positioning issues with nested array assignment * Increase space between closure and frame * Change for/while instr to use BranchAnimation * Initial Commit * More fixes and added faded gc objects * Disable variadic function animation * Increase spacing for global closure between closure circles and global frame border * Add missing case 'FunctionExpression' animates the moving of a functionexpression to the stash as a closure * Fix variadic function checker * Improve FunctionApplicationAnimation for nullary functions, allow the closure stash item to fade away * Improve assignment animation * Run format * Simplify check frame creation * Fix params text and added SourceObject to display runes correctly * bumping js-slang * Revamp unreferenced behavior and update snapshots * Run format * Update snapshot * Bump js-slang * Fix issues after merge * Fix frames creeping to the left * Improve rune display, revamp color system and add color interpolation * UI & animation improvements * Big improvements for many animations * More improvements, better transitions between border colors * More improvements and update snapshot * Update types * Remove explicit fragment * Remove explicit fragment again * Update typings * Merge branch 'cse-uiux2' of https://github.com/source-academy/frontend into cse-uiux2 * Fix findObjects * Add docs * Re-add color dependencies for Java CSE * Re-add color dependencies for Java CSE * Fix format * Array access & asgn animation improvements, general polish * Cleanup and update java cse machine colors to use new functions * Move type helpers from animation utils to global type helpers file * Run format * Fix fn to frame arrow, and cleanup arrow code --------- Co-authored-by: notnotmax <156508404+notnotmax@users.noreply.github.com> Co-authored-by: Richard Dominick <34370238+RichDom2185@users.noreply.github.com> Co-authored-by: henz commit 4f6be6b6a756174bfa4530fa086f430a339be5eb Author: Richard Dominick <34370238+RichDom2185@users.noreply.github.com> Date: Sat Apr 13 21:05:41 2024 +0800 Refactor frontend part 7 (#2846) * Improve useRef type arguments for HTML elements * Use named imports for React hooks * Refactor MobileWorkspace * Replace if statements with optional invocation * Move constant `SideContentTab`s out of FC body * Simplify classnames call * Remove unnecessary braces around string attributes Only done for non-UI (non-message/label) strings as these UI strings will be pulled out for internationalization in the future. * Deduplicate dependencies * Create `useTokens` hook * Update default throw behavior for `useTokens` * Render SICP chatbot only when logged in * Fix overloaded types for `useTokens` Done following default behavior change. * Use `useTokens` where applicable * Refactor SICP chatbox * Use `useTokens` * Move API call to separate file * Update React import to default import * Refactor SICP chatbox further * Update imports * Create and use ChatMessage type alias * Reorganize SICP chatbot files * Refactor chat completion logic * Use dependency injection in prompt builder * Refactor prompt builder logic * Refactor prompt builder to separate file * Create type definitions * Move, type, rename SICP section summaries * Improve typing * Refactor SICP chat box component * Remove unnecessary template literal * Refactor constants out of component * Create type definitions * Create `CONTEXT_SIZE` constant to replace magic numbers * Refactor logic to use `CONTEXT_SIZE` constant * Remove unnecessary state variables * Refactor payload generation * Move fetching logic from event handler to effect callback instead * Rename `cleanMessage` to `resetChat` * Decouple rendering logic from chat completion logic * Only store string content in `ChatMessage` type * Move rendering function outside component to prevent unnecessary recreation * Update render function signature * Restore GPT-generated output warning for bot messages * Refactor render function logic * Fix React render warnings * Add TODOs for full Markdown/stories-like parsing Also uses non-greedy regex to match and split code blocks: * Only match JavaScript code blocks * Fix false matches * Supports multiple code blocks in a single message * Fix whitespace issue * Fix filename capitalization * Remove duplicated badge code * Fix double request * Block chat input when loading response commit c1abec115e489e1271ff6709425396b05c4166fb Author: Richard Dominick <34370238+RichDom2185@users.noreply.github.com> Date: Sat Apr 13 20:35:47 2024 +0800 Bump Blueprint; remove obsolete hotfixes, deprecations (#2773) * Bump minimum Blueprint version Done to allow compatibility with new React 18 `createRoot`. * Migrate from deprecated `Tooltip2`, `Popover2` Done partially so far, with the full migration in a subsequent commit. * Migrate more components to fix deprecations * Update test snapshots * Migrate remaining components to fix deprecations * Remove deprecated package from `requireProvider` This would necessitate a corresponding change in modules to ensure they don't import the deprecated package, or simply just mark it as non-external. * Remove `@blueprintjs/popover2` package completely * Fix format * Fix format * Reformat files post-merge * Bump Blueprint version * Use BP `Classes` utility instead of raw strings Prevents regressions when the CSS namespace changes in the meantime while we still have yet to migrate away fully from the CSS API. * Fix lint * Migrate to new notifications API Removes the old hotfix now that Blueprint supports it. commit d2b322a703d07e5df0a6977c4b40778fd129b821 Author: Josh Thoo Jen Sen <110712708+josh1248@users.noreply.github.com> Date: Sat Apr 13 20:03:17 2024 +0800 Implement isGradingPublished (plus related features) (#2856) * Dummy publish grading function * skeleton redux loop for publishGrading, update GradingOverview * New column filter for isPublished (WIP) * Implement anticipated backend format and route implementations for publish and unpublish buttons * Remove misleading devnote and simplify message contents * fix: Change gradingOverviews to use backend response * Readjust publish button from HTML icon button to Blueprintjs text button * Publish and unpublish buttons set up * set up frontend-only type submissionProgress derived from backend status and isPublished * Implement derived submissionProgress frontend field from status and isGradingPublished from backend * Improve type safety in Grading page * Implement business logic to disable unsubmission if published or not submitted * Use notPublished param in backend * minor type safety change * Update new actions post-merge conflicts * Update tests * Update jsdocs and field names from ungraded to unpublished * adjust field names in test from unpublishedFilter to publishedFilter * Updated showGrading to be based on published status * Update getAssessmentOverviews to compute submission progress * Fix tests * Scaffold function for comprehensive progress status (WIP) * Update RequestsSaga.ts * fix crash * Introduce soon-to-be comprehensive field into table * Shift conversion functions into utils * Update business logic using comprehensive state * Introduce progress status to assessment overviews * clean up display of progressStatus * remove derived submissionProgress field, add in status field from backend * remove direct gradingStatus use in grading page * remove gradingStatus from assessments * Remove more references to gradingStatus * Replace references to gradingStatus with progress * there is a lot of reference to gradingStatus. * Replace gradingStatus with progress in testing * Fully remove gradingStatus and replace with progress * Fix accidental import * Update to use new backend parameter names in backend * Remove isPublished field entirely from grading overviews to avoid confusion with publishing within assessment overviews * Update tests * Dummy publish all button in ground control * redux loop for publishall and unpublishall (part 1) * Remove re-autograde for published or non-submitted assessments * Add publishAll button * Replace deprecated ag-grid functions with current versions * Implement unpublish all button * Add unique key, avoid specialkey flag from react * Fix button layout * Fix button format * increase width for accessibility * autoPublish settings inserted into admin panel configs * cleanup of isAutoPublished field within assessment configs * update tests for assessmentConfiguration * remove un-needed import * remove debug-only submissionStatus in grading submissions table * Revert accidental removal of XP field * bp5-minimal tag to clean up bulk publishing buttons - thanks gabriel :) * Fix errors post-merge * Fix lint error * feat: Implement published and unpublished notifications and remove deprecated ones * chore: Remove commented code * Fix compile error * Remove unnecessary typecast * Remove unnecessary typecast * Remove unused import * update notification types to reflect backend * change notification types to reflect backend changes * remove git stash artifacts * remove git stash artefacts * add tooltips, update assessment fields * remove development artifacts * remove TODO comment as issue has been raised * Update GradingUtils.ts jsdocs * linting * readjust progress statuses and conversion functions * update colours and logos * expose backend isGradingPublished field and update tests * update assessment cards to show purely based on isGradingPublished status without further check for graded * remove hardcoded assessment status * linting * revert yarn lock change * Update yarn.lock * update mocks and tests * remove un-needed import * linting * Use enum values instead of strings for color keys * Use prop over BP CSS API * remove un-needed field calculation, fix typos * update student username to show nusnet id instead of duplicating student name (thanks gabriel :D) --------- Co-authored-by: GabrielCWT <77312579+GabrielCWT@users.noreply.github.com> Co-authored-by: Richard Dominick <34370238+RichDom2185@users.noreply.github.com> commit 4556d3fcceb9499a073edf2eb0790db5daf9d7b7 Author: Liew Xin Yi Date: Sat Apr 13 19:43:51 2024 +0800 Implement and Integrate `java-slang` CSEC Visualizer (#2926) * Update ControlBarChapterSelect with Java * Implement Java CSEC Visualizer * Integrate CSEC Visualizer * Linting errors for java-slang-csec * Fix frontend test: rename Object to Obj to avoid potential name clash? * Update snapshot * Update imports from java-slang * Fix lint * Update snapshot * Fix linting * Fix typo Co-authored-by: Richard Dominick <34370238+RichDom2185@users.noreply.github.com> * Add TODO for err source node location --------- Co-authored-by: joel chan Co-authored-by: Richard Dominick <34370238+RichDom2185@users.noreply.github.com> commit 612f68b474ea641cf7b31823e935f1528f4e3515 Author: Lai Mei Tin <77192251+1001mei@users.noreply.github.com> Date: Sat Apr 13 18:02:16 2024 +0800 Integrate Java type checker and compiler into frontend (#2925) * Integrate Java compiler into frontend * Add typechecker from java-slang * Add program terminated succesfully output to Java * Bump java-slang to 1.0.7 * Remove program terminated output from java in frontend * Change ProgramTerminatedSuccessfully to anonymous class in java * Bump java-slang to 1.0.8 * Bump java-slang to 1.0.9 * Add process/browser to craco polyfill * Add java-parser to jest transform ignore patterns * Bump java-slang to 1.0.13 * Add mocks for java-slang functions * Fix wrong error label in java helper * Increase max file size to cache to 20 --------- Co-authored-by: Bryan Loh Co-authored-by: Martin Henz commit d1c0a458436f5057fb3bb4bc35d69285d964a388 Author: Richard Dominick <34370238+RichDom2185@users.noreply.github.com> Date: Sat Apr 13 14:53:02 2024 +0800 Migrate to Redux Toolkit part 5 (#2866) * Migrate remaining workspace reducers to RTK * Migrate remaining action creators to RTK * Remove `typesafe-actions` dependency Type safety is now achieved via Redux Toolkit. * Update testcase * Fix format * Fix compile error * Fix errors * Restore old NOTIFY_PROGRAM_EVALUATED reducer Done to optimize the diff and will be removed later. commit 0c456069a5a745571aae1bb121ecfc60ba2212a1 Author: Martin Henz Date: Fri Apr 12 12:34:11 2024 +0800 bumping js-slang (#2929) commit 02059bf71764a57b6529985efdf68ebd51e10d4d Author: John Wong Date: Fri Apr 12 01:59:37 2024 +0800 Modify mobile keyboard to be scrollable (#2915) * Modify mobile keyboard to be scrollable * Mobile Keyboard is now swipeable * Remove mobile-keyboard-row-toggle styles * Fix formatting * Remove console.log statements --------- Co-authored-by: Joven Soh <34702990+JovenSoh@users.noreply.github.com> commit 4cc020404450f6e821ad2246c89c7b555bf63824 Author: John Wong Date: Thu Apr 11 03:28:57 2024 +0800 Add full-screen button for Playground side content (#2911) * Added fullscreen button to playground side content * Refactor fullscreen button to use class as reference and Blueprint's Tooltip * updating snapshots * Remove unnecessary comments * Replace icon with button For more correct semantics. * Remove unnecessary styles Following the change from icon to button, `cursor: pointer` is no longer needed. Also lowered the z-index to a more reasonable value. * Fix format * Update test snapshots --------- Co-authored-by: henz Co-authored-by: Richard Dominick <34370238+RichDom2185@users.noreply.github.com> commit e2abe187df040bc9fcc235e5b6455ae8260329ab Author: John Wong Date: Thu Apr 11 02:16:49 2024 +0800 Add a fullscreen button for the game div container (#2855) * Add a fullscreen button for the game div container * Modify code to use the useFullscreen hook from the @mantine/hooks package * Bump dependencies * Use `IconNames` instead of magic strings --------- Co-authored-by: Richard Dominick <34370238+RichDom2185@users.noreply.github.com> Co-authored-by: Martin Henz Co-authored-by: Lee Hyung Woon / 이형운 commit f4d6e78aefb55c73f10b145a8fc73e2c21aa410d Author: Richard Dominick <34370238+RichDom2185@users.noreply.github.com> Date: Wed Apr 10 16:10:22 2024 +0800 Fix `xlsx` security vulnerability (#2914) * Bump and use recommended XLSX version from CDN * Deduplicate dependencies commit 571f8b750285d2d929b4951ccde45d97d669e7ff Author: Martin Henz Date: Wed Apr 10 14:31:39 2024 +0800 bumping js-slang (#2922) commit c859f1b2e8ad615d64e9d741c3e71e648fe52d8f Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed Apr 10 14:14:57 2024 +0800 Bump tar from 6.1.15 to 6.2.1 (#2920) Bumps [tar](https://github.com/isaacs/node-tar) from 6.1.15 to 6.2.1. - [Release notes](https://github.com/isaacs/node-tar/releases) - [Changelog](https://github.com/isaacs/node-tar/blob/main/CHANGELOG.md) - [Commits](https://github.com/isaacs/node-tar/compare/v6.1.15...v6.2.1) --- updated-dependencies: - dependency-name: tar dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> commit bb790df146591d36f42341866562a5e3f4b0c349 Author: Martin Henz Date: Wed Apr 10 14:05:51 2024 +0800 bumping java-slang to 1.0.6 (#2924) commit 27e318161872723192136f8b638bf40f8270f2e4 Author: Martin Henz Date: Wed Apr 10 13:30:30 2024 +0800 bumping java-slang to 1.0.5 (#2923) commit 5dba6a5b719fa70b2d8c82e37b9d2bec9eb2b6f3 Author: CZX Date: Wed Apr 10 07:58:53 2024 +0800 CSE Machine: Fixes for variadic function & global closures, added faded unreferenced objects (#2906) * Initial Commit * More fixes and added faded gc objects * Run format * Fix params text and added SourceObject to display runes correctly * bumping js-slang * Revamp unreferenced behavior and update snapshots * Run format * Update snapshot * Bump js-slang --------- Co-authored-by: henz * update tests --------- Co-authored-by: Richard Dominick <34370238+RichDom2185@users.noreply.github.com> Co-authored-by: Martin Henz --- src/commons/application/ApplicationTypes.ts | 16 ++++- .../__snapshots__/ApplicationTypes.ts.snap | 5 ++ src/commons/sagas/PlaygroundSaga.ts | 6 +- .../sagas/WorkspaceSaga/helpers/evalCode.ts | 5 +- src/features/cseMachine/CseMachine.tsx | 3 +- src/features/cseMachine/CseMachineLayout.tsx | 19 ++++-- src/features/cseMachine/CseMachineUtils.ts | 68 +++++++++++++++++-- .../cseMachine/components/ControlStack.tsx | 10 ++- .../cseMachine/components/StashStack.tsx | 8 ++- src/features/cseMachine/components/Text.tsx | 3 + src/features/cseMachine/utils/altLangs.ts | 56 +++++++++++++++ src/features/cseMachine/utils/scheme.ts | 16 +++++ 12 files changed, 192 insertions(+), 23 deletions(-) create mode 100644 src/features/cseMachine/utils/altLangs.ts create mode 100644 src/features/cseMachine/utils/scheme.ts diff --git a/src/commons/application/ApplicationTypes.ts b/src/commons/application/ApplicationTypes.ts index 0743db122c..85e1498ef4 100644 --- a/src/commons/application/ApplicationTypes.ts +++ b/src/commons/application/ApplicationTypes.ts @@ -198,9 +198,23 @@ const schemeSubLanguages: Array { - return { ...sublang, mainLanguage: SupportedLanguage.SCHEME, supports: { repl: true } }; + return { + ...sublang, + mainLanguage: SupportedLanguage.SCHEME, + supports: { repl: true, cseMachine: true } + }; }); +export function isSchemeLanguage(chapter: Chapter): boolean { + return [ + Chapter.SCHEME_1, + Chapter.SCHEME_2, + Chapter.SCHEME_3, + Chapter.SCHEME_4, + Chapter.FULL_SCHEME + ].includes(chapter); +} + const pySubLanguages: Array> = [ { chapter: Chapter.PYTHON_1, variant: Variant.DEFAULT, displayName: 'Python \xa71' } //{ chapter: Chapter.PYTHON_2, variant: Variant.DEFAULT, displayName: 'Python \xa72' }, diff --git a/src/commons/application/__tests__/__snapshots__/ApplicationTypes.ts.snap b/src/commons/application/__tests__/__snapshots__/ApplicationTypes.ts.snap index ca5fc6211d..3f9a03a47a 100644 --- a/src/commons/application/__tests__/__snapshots__/ApplicationTypes.ts.snap +++ b/src/commons/application/__tests__/__snapshots__/ApplicationTypes.ts.snap @@ -21,6 +21,7 @@ Array [ "displayName": "Scheme §1", "mainLanguage": "Scheme", "supports": Object { + "cseMachine": true, "repl": true, }, "variant": "explicit-control", @@ -30,6 +31,7 @@ Array [ "displayName": "Scheme §2", "mainLanguage": "Scheme", "supports": Object { + "cseMachine": true, "repl": true, }, "variant": "explicit-control", @@ -39,6 +41,7 @@ Array [ "displayName": "Scheme §3", "mainLanguage": "Scheme", "supports": Object { + "cseMachine": true, "repl": true, }, "variant": "explicit-control", @@ -48,6 +51,7 @@ Array [ "displayName": "Scheme §4", "mainLanguage": "Scheme", "supports": Object { + "cseMachine": true, "repl": true, }, "variant": "explicit-control", @@ -57,6 +61,7 @@ Array [ "displayName": "Full Scheme", "mainLanguage": "Scheme", "supports": Object { + "cseMachine": true, "repl": true, }, "variant": "explicit-control", diff --git a/src/commons/sagas/PlaygroundSaga.ts b/src/commons/sagas/PlaygroundSaga.ts index e7acf4fe01..ab212d471b 100644 --- a/src/commons/sagas/PlaygroundSaga.ts +++ b/src/commons/sagas/PlaygroundSaga.ts @@ -13,7 +13,7 @@ import { updateShortURL } from '../../features/playground/PlaygroundActions'; import { GENERATE_LZ_STRING, SHORTEN_URL } from '../../features/playground/PlaygroundTypes'; -import { isSourceLanguage, OverallState } from '../application/ApplicationTypes'; +import { isSchemeLanguage, isSourceLanguage, OverallState } from '../application/ApplicationTypes'; import { ExternalLibraryName } from '../application/types/ExternalTypes'; import { retrieveFilesInWorkspaceAsRecord } from '../fileSystem/utils'; import { visitSideContent } from '../sideContent/SideContentActions'; @@ -122,6 +122,10 @@ export default function* PlaygroundSaga(): SagaIterator { yield put(toggleUsingCse(true, workspaceLocation)); } } + + if (isSchemeLanguage(playgroundSourceChapter) && newId === SideContentType.cseMachine) { + yield put(toggleUsingCse(true, workspaceLocation)); + } } ); } diff --git a/src/commons/sagas/WorkspaceSaga/helpers/evalCode.ts b/src/commons/sagas/WorkspaceSaga/helpers/evalCode.ts index 0dae58611d..29426be942 100644 --- a/src/commons/sagas/WorkspaceSaga/helpers/evalCode.ts +++ b/src/commons/sagas/WorkspaceSaga/helpers/evalCode.ts @@ -14,7 +14,7 @@ import { notifyStoriesEvaluated } from 'src/features/stories/StoriesActions'; import { EVAL_STORY } from 'src/features/stories/StoriesTypes'; import { EventType } from '../../../../features/achievement/AchievementTypes'; -import { OverallState } from '../../../application/ApplicationTypes'; +import { isSchemeLanguage, OverallState } from '../../../application/ApplicationTypes'; import { BEGIN_DEBUG_PAUSE, BEGIN_INTERRUPT_EXECUTION, @@ -95,7 +95,8 @@ export function* evalCode( .currentStep ) : -1; - const cseActiveAndCorrectChapter = context.chapter >= 3 && cseIsActive; + const cseActiveAndCorrectChapter = + (isSchemeLanguage(context.chapter) || context.chapter >= 3) && cseIsActive; if (cseActiveAndCorrectChapter) { context.executionMethod = 'cse-machine'; } diff --git a/src/features/cseMachine/CseMachine.tsx b/src/features/cseMachine/CseMachine.tsx index ce6b61f94a..f829344807 100644 --- a/src/features/cseMachine/CseMachine.tsx +++ b/src/features/cseMachine/CseMachine.tsx @@ -84,7 +84,8 @@ export default class CseMachine { Layout.setContext( context.runtime.environmentTree as EnvTree, context.runtime.control, - context.runtime.stash + context.runtime.stash, + context.chapter ); this.setVis(Layout.draw()); this.setIsStepLimitExceeded(context.runtime.control.isEmpty()); diff --git a/src/features/cseMachine/CseMachineLayout.tsx b/src/features/cseMachine/CseMachineLayout.tsx index eb7aa4c5e2..07615cbf90 100644 --- a/src/features/cseMachine/CseMachineLayout.tsx +++ b/src/features/cseMachine/CseMachineLayout.tsx @@ -1,6 +1,6 @@ import Heap from 'js-slang/dist/cse-machine/heap'; import { Control, Stash } from 'js-slang/dist/cse-machine/interpreter'; -import { Frame } from 'js-slang/dist/types'; +import { Chapter, Frame } from 'js-slang/dist/types'; import { KonvaEventObject } from 'konva/lib/Node'; import React, { RefObject } from 'react'; import { Layer, Rect, Stage } from 'react-konva'; @@ -137,7 +137,12 @@ export class Layout { } /** processes the runtime context from JS Slang */ - static setContext(envTree: EnvTree, control: Control, stash: Stash): void { + static setContext( + envTree: EnvTree, + control: Control, + stash: Stash, + chapter: Chapter = Chapter.SOURCE_4 + ): void { Layout.currentLight = undefined; Layout.currentDark = undefined; Layout.currentStackDark = undefined; @@ -160,7 +165,7 @@ export class Layout { // initialize levels and frames Layout.initializeGrid(); // initialize control and stash - Layout.initializeControlStash(); + Layout.initializeControlStash(chapter); if (CseMachine.getControlStash()) { Layout.controlStashHeight = Math.max( @@ -193,11 +198,11 @@ export class Layout { CseAnimation.updateAnimation(); } - static initializeControlStash() { + static initializeControlStash(chapter: Chapter) { Layout.previousControlComponent = Layout.controlComponent; Layout.previousStashComponent = Layout.stashComponent; - this.controlComponent = new ControlStack(this.control); - this.stashComponent = new StashStack(this.stash); + this.controlComponent = new ControlStack(this.control, chapter); + this.stashComponent = new StashStack(this.stash, chapter); } /** @@ -205,7 +210,7 @@ export class Layout { * objects into the global environment head and heap */ private static removePreludeEnv() { - if (!Layout.globalEnvNode.children) return; + if (!Layout.globalEnvNode.children || Layout.globalEnvNode.children.length === 0) return; const preludeEnvNode = Layout.globalEnvNode.children[0]; const preludeEnv = preludeEnvNode.environment; diff --git a/src/features/cseMachine/CseMachineUtils.ts b/src/features/cseMachine/CseMachineUtils.ts index 780ccf6d45..f83ebf8caf 100644 --- a/src/features/cseMachine/CseMachineUtils.ts +++ b/src/features/cseMachine/CseMachineUtils.ts @@ -1,3 +1,5 @@ +import { estreeDecode } from 'js-slang/dist/alt-langs/scheme/scm-slang/src/utils/encoder-visitor'; +import { unparse } from 'js-slang/dist/alt-langs/scheme/scm-slang/src/utils/reverse_parser'; import JsSlangClosure from 'js-slang/dist/cse-machine/closure'; import { AppInstr, @@ -10,13 +12,14 @@ import { InstrType, UnOpInstr } from 'js-slang/dist/cse-machine/types'; -import { Environment, Value as StashValue } from 'js-slang/dist/types'; +import { Chapter, Environment, Value as StashValue } from 'js-slang/dist/types'; import { astToString } from 'js-slang/dist/utils/ast/astToString'; import { Group } from 'konva/lib/Group'; import { Node } from 'konva/lib/Node'; import { Shape } from 'konva/lib/Shape'; import { Text } from 'konva/lib/shapes/Text'; import { cloneDeep, isObject } from 'lodash'; +import { isSchemeLanguage } from 'src/commons/application/ApplicationTypes'; import classes from 'src/styles/Draggable.module.scss'; import { ArrayUnit } from './components/ArrayUnit'; @@ -49,7 +52,11 @@ import { StreamFn, Unassigned } from './CseMachineTypes'; - +import { + getAlternateControlItemComponent, + isCustomPrimitive, + needsNewRepresentation +} from './utils/altLangs'; class AssertionError extends Error { constructor(msg?: string) { super(msg); @@ -195,7 +202,8 @@ export function isPrimitiveData(data: Data): data is Primitive { isString(data) || isNumber(data) || isBoolean(data) || - isSourceObject(data) + isSourceObject(data) || + isCustomPrimitive(data) ); } @@ -568,12 +576,39 @@ export function getControlItemComponent( stackHeight: number, index: number, highlightOnHover: () => void, - unhighlightOnHover: () => void + unhighlightOnHover: () => void, + chapter: Chapter ): ControlItemComponent { const topItem = CseMachine.getStackTruncated() ? index === Math.min(Layout.control.size() - 1, 9) : index === Layout.control.size() - 1; if (!isInstr(controlItem)) { + // there's no reason to provide an alternate representation + // for a instruction. + if (needsNewRepresentation(chapter)) { + return getAlternateControlItemComponent( + controlItem, + stackHeight, + highlightOnHover, + unhighlightOnHover, + topItem, + chapter + ); + } + + if (isSchemeLanguage(chapter)) { + // use the js-slang decoder on the control item + controlItem = estreeDecode(controlItem as any); + const text = unparse(controlItem as any); + return new ControlItemComponent( + text, + text, + stackHeight, + highlightOnHover, + unhighlightOnHover, + topItem + ); + } switch (controlItem.type) { case 'Program': // If the control item is the whole program @@ -792,6 +827,24 @@ export function getControlItemComponent( unhighlightOnHover, topItem ); + case InstrType.GENERATE_CONT: + return new ControlItemComponent( + 'generate cont', + 'Generate continuation', + stackHeight, + highlightOnHover, + unhighlightOnHover, + topItem + ); + case InstrType.RESUME_CONT: + return new ControlItemComponent( + 'call cont', + 'call a continuation', + stackHeight, + highlightOnHover, + unhighlightOnHover, + topItem + ); default: return new ControlItemComponent( 'INSTRUCTION', @@ -805,7 +858,12 @@ export function getControlItemComponent( } } -export function getStashItemComponent(stashItem: StashValue, stackHeight: number, index: number) { +export function getStashItemComponent( + stashItem: StashValue, + stackHeight: number, + index: number, + _chapter: Chapter +): StashItemComponent { let arrowTo: ArrayValue | FnValue | GlobalFnValue | undefined; if (isFunction(stashItem) || isDataArray(stashItem)) { if (isClosure(stashItem) || isDataArray(stashItem)) { diff --git a/src/features/cseMachine/components/ControlStack.tsx b/src/features/cseMachine/components/ControlStack.tsx index 7b4673f265..6f0850380c 100644 --- a/src/features/cseMachine/components/ControlStack.tsx +++ b/src/features/cseMachine/components/ControlStack.tsx @@ -1,5 +1,6 @@ import { Control } from 'js-slang/dist/cse-machine/interpreter'; import { ControlItem, Instr } from 'js-slang/dist/cse-machine/types'; +import { Chapter, StatementSequence } from 'js-slang/dist/types'; import { Node } from 'js-slang/dist/types'; import { KonvaEventObject } from 'konva/lib/Node'; import React from 'react'; @@ -28,7 +29,8 @@ export class ControlStack extends Visible implements IHoverable { constructor( /** the control object */ - readonly control: Control + readonly control: Control, + readonly chapter: Chapter ) { super(); this._x = ControlStashConfig.ControlPosX; @@ -36,6 +38,7 @@ export class ControlStack extends Visible implements IHoverable { this._width = ControlStashConfig.ControlItemWidth; this._height = ControlStashConfig.StashItemHeight + ControlStashConfig.StashItemTextPadding * 2; this.control = control; + this.chapter = chapter; // Function to convert the stack items to their components let i = 0; @@ -57,7 +60,8 @@ export class ControlStack extends Visible implements IHoverable { this._height, i, highlightOnHover, - unhighlightOnHover + unhighlightOnHover, + this.chapter ); this._height += component.height(); i += 1; @@ -141,6 +145,6 @@ export const isInstr = (command: ControlItem): command is Instr => { * @param command A ControlItem * @returns true if the ControlItem is an esNode and false if it is an instruction. */ -export const isNode = (command: ControlItem): command is Node => { +export const isNode = (command: ControlItem): command is Node | StatementSequence => { return (command as Node).type !== undefined; }; diff --git a/src/features/cseMachine/components/StashStack.tsx b/src/features/cseMachine/components/StashStack.tsx index b02e47e8fb..e4e2486c79 100644 --- a/src/features/cseMachine/components/StashStack.tsx +++ b/src/features/cseMachine/components/StashStack.tsx @@ -1,5 +1,5 @@ import { Stash } from 'js-slang/dist/cse-machine/interpreter'; -import { Value } from 'js-slang/dist/types'; +import { Chapter, Value } from 'js-slang/dist/types'; import React from 'react'; import CseMachine from '../CseMachine'; @@ -14,18 +14,20 @@ export class StashStack extends Visible { constructor( /** the stash object */ - readonly stash: Stash + readonly stash: Stash, + readonly chapter: Chapter ) { super(); this._x = ControlStashConfig.StashPosX; this._y = ControlStashConfig.StashPosY; this._width = 0; this._height = 0; + this.chapter = chapter; // Function to convert the stack items to their components let i = 0; const stashItemToComponent = (stashItem: Value) => { - const component = getStashItemComponent(stashItem, this._width, i); + const component = getStashItemComponent(stashItem, this._width, i, this.chapter); this._width += component.width(); this._height = Math.max(this._height, component.height()); i += 1; diff --git a/src/features/cseMachine/components/Text.tsx b/src/features/cseMachine/components/Text.tsx index d199c97b22..2a5d93e19e 100644 --- a/src/features/cseMachine/components/Text.tsx +++ b/src/features/cseMachine/components/Text.tsx @@ -15,6 +15,7 @@ import { setHoveredCursor, setUnhoveredCursor } from '../CseMachineUtils'; +import { isCustomPrimitive } from '../utils/altLangs'; import { Visible } from './Visible'; export interface TextOptions { @@ -64,6 +65,8 @@ export class Text extends Visible implements IHoverable { this.fullStr = this.partialStr = isSourceObject(data) ? data.toReplString() + : isCustomPrimitive(data) + ? String(data) : isStringIdentifiable ? JSON.stringify(data) || String(data) : String(data); diff --git a/src/features/cseMachine/utils/altLangs.ts b/src/features/cseMachine/utils/altLangs.ts new file mode 100644 index 0000000000..77201a6029 --- /dev/null +++ b/src/features/cseMachine/utils/altLangs.ts @@ -0,0 +1,56 @@ +// alternate representations of data types + +import { ControlItem } from 'js-slang/dist/cse-machine/types'; +import { Chapter, Node } from 'js-slang/dist/types'; +import { isSchemeLanguage } from 'src/commons/application/ApplicationTypes'; + +import { ControlItemComponent } from '../components/ControlItemComponent'; +import { Data } from '../CseMachineTypes'; +import { convertNodeToScheme, isSchemeNumber } from './scheme'; + +// used to define custom primitives from alternate languages. +// MAKE SURE the custom primitive has a toString() method! +export function isCustomPrimitive(data: Data): boolean { + return isSchemeNumber(data); +} + +// tells the CSE machine whether a new representation is needed. +// expand when necessary. +export function needsNewRepresentation(chapter: Chapter): boolean { + return isSchemeLanguage(chapter); +} + +export function getAlternateControlItemComponent( + controlItem: ControlItem, + stackHeight: number, + highlightOnHover: () => void, + unhighlightOnHover: () => void, + topItem: boolean, + chapter: Chapter +) { + // keep in mind that the controlItem is a node. + // there's no reason to provide an alternate representation + // for a instruction. + const node = controlItem as Node; + switch (chapter) { + case Chapter.SCHEME_1: + case Chapter.SCHEME_2: + case Chapter.SCHEME_3: + case Chapter.SCHEME_4: + case Chapter.FULL_SCHEME: + const text = convertNodeToScheme(node); + return new ControlItemComponent( + text, + text, + stackHeight, + highlightOnHover, + unhighlightOnHover, + topItem + ); + default: + // this only happens if + // a chapter needing an alternate representation + // is not handled. + throw new Error('Unknown Chapter'); + } +} diff --git a/src/features/cseMachine/utils/scheme.ts b/src/features/cseMachine/utils/scheme.ts new file mode 100644 index 0000000000..80882d277e --- /dev/null +++ b/src/features/cseMachine/utils/scheme.ts @@ -0,0 +1,16 @@ +import { estreeDecode } from 'js-slang/dist/alt-langs/scheme/scm-slang/src/utils/encoder-visitor'; +import { unparse } from 'js-slang/dist/alt-langs/scheme/scm-slang/src/utils/reverse_parser'; +import { Node } from 'js-slang/dist/types'; + +import { Data } from '../CseMachineTypes'; + +/** Returns `true` if `data` is a scheme number + * TODO: make this less hacky. + */ +export function isSchemeNumber(data: Data): boolean { + return (data as any)?.numberType !== undefined; +} + +export function convertNodeToScheme(node: Node): string { + return unparse(estreeDecode(node as any)); +}