-
Notifications
You must be signed in to change notification settings - Fork 170
/
Copy pathCseMachine.tsx
161 lines (150 loc) · 5.7 KB
/
CseMachine.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
import { Context } from 'js-slang';
import { Control, Stash } from 'js-slang/dist/cse-machine/interpreter';
import React from 'react';
import { Layout } from './CseMachineLayout';
import { EnvTree } from './CseMachineTypes';
import { deepCopyTree, getEnvId } from './CseMachineUtils';
type SetVis = (vis: React.ReactNode) => void;
type SetEditorHighlightedLines = (segments: [number, number][]) => void;
type SetisStepLimitExceeded = (isControlEmpty: boolean) => void;
/** CSE Machine is exposed from this class */
export default class CseMachine {
/** callback function to update the visualization state in the SideContentCseMachine component */
private static setVis: SetVis;
/** function to highlight editor lines */
public static setEditorHighlightedLines: SetEditorHighlightedLines;
/** callback function to update the step limit exceeded state in the SideContentCseMachine component */
private static setIsStepLimitExceeded: SetisStepLimitExceeded;
private static printableMode: boolean = false;
private static controlStash: boolean = false; // TODO: discuss if the default should be true
private static stackTruncated: boolean = false;
private static environmentTree: EnvTree | undefined;
private static currentEnvId: string;
private static control: Control | undefined;
private static stash: Stash | undefined;
public static togglePrintableMode(): void {
CseMachine.printableMode = !CseMachine.printableMode;
}
public static toggleControlStash(): void {
CseMachine.controlStash = !CseMachine.controlStash;
}
public static toggleStackTruncated(): void {
CseMachine.stackTruncated = !CseMachine.stackTruncated;
}
public static getCurrentEnvId(): string {
return CseMachine.currentEnvId;
}
public static getPrintableMode(): boolean {
return CseMachine.printableMode;
}
public static getControlStash(): boolean {
return CseMachine.controlStash;
}
public static getStackTruncated(): boolean {
return CseMachine.stackTruncated;
}
public static isControl(): boolean {
return this.control ? !this.control.isEmpty() : false;
}
/** SideContentCseMachine initializes this onMount with the callback function */
static init(
setVis: SetVis,
width: number,
height: number,
setEditorHighlightedLines: (segments: [number, number][]) => void,
setIsStepLimitExceeded: SetisStepLimitExceeded
) {
Layout.visibleHeight = height;
Layout.visibleWidth = width;
this.setVis = setVis;
this.setEditorHighlightedLines = setEditorHighlightedLines;
this.setIsStepLimitExceeded = setIsStepLimitExceeded;
}
static clear() {
Layout.values.clear();
}
/** updates the visualization state in the SideContentCseMachine component based on
* the JS Slang context passed in */
static drawCse(context: Context) {
// store environmentTree at last breakpoint.
CseMachine.environmentTree = deepCopyTree(context.runtime.environmentTree as EnvTree);
CseMachine.currentEnvId = getEnvId(context.runtime.environments[0]);
if (!this.setVis || !context.runtime.control || !context.runtime.stash)
throw new Error('CSE machine not initialized');
CseMachine.control = context.runtime.control;
CseMachine.stash = context.runtime.stash;
Layout.setContext(
context.runtime.environmentTree as EnvTree,
context.runtime.control,
context.runtime.stash,
context.chapter
);
this.setVis(Layout.draw());
this.setIsStepLimitExceeded(context.runtime.control.isEmpty());
Layout.updateDimensions(Layout.visibleWidth, Layout.visibleHeight);
}
static redraw() {
if (CseMachine.environmentTree && CseMachine.control && CseMachine.stash) {
// checks if the required diagram exists, and updates the dom node using setVis
if (
CseMachine.getPrintableMode() &&
CseMachine.getControlStash() &&
CseMachine.getStackTruncated() &&
Layout.currentStackTruncLight !== undefined
) {
this.setVis(Layout.currentStackTruncLight);
} else if (
CseMachine.getPrintableMode() &&
CseMachine.getControlStash() &&
!CseMachine.getStackTruncated() &&
Layout.currentStackLight !== undefined
) {
this.setVis(Layout.currentStackLight);
} else if (
!CseMachine.getPrintableMode() &&
CseMachine.getControlStash() &&
CseMachine.getStackTruncated() &&
Layout.currentStackTruncDark !== undefined
) {
this.setVis(Layout.currentStackTruncDark);
} else if (
!CseMachine.getPrintableMode() &&
CseMachine.getControlStash() &&
!CseMachine.getStackTruncated() &&
Layout.currentStackDark !== undefined
) {
this.setVis(Layout.currentStackDark);
} else if (
CseMachine.getPrintableMode() &&
!CseMachine.getControlStash() &&
Layout.currentLight !== undefined
) {
this.setVis(Layout.currentLight);
} else if (
!CseMachine.getPrintableMode() &&
!CseMachine.getControlStash() &&
Layout.currentDark !== undefined
) {
this.setVis(Layout.currentDark);
} else {
Layout.setContext(CseMachine.environmentTree, CseMachine.control, CseMachine.stash);
this.setVis(Layout.draw());
}
Layout.updateDimensions(Layout.visibleWidth, Layout.visibleHeight);
}
}
static updateDimensions(width: number, height: number) {
if (Layout.stageRef != null && width !== null && height !== null) {
Layout.updateDimensions(width, height);
}
}
static clearCse() {
if (this.setVis) {
this.setVis(undefined);
CseMachine.environmentTree = undefined;
CseMachine.control = undefined;
CseMachine.stash = undefined;
}
this.clear();
}
}