Skip to content

Commit 00f3153

Browse files
Implement statement sequence for the CSE machine (#1575)
* Creation of StatementSequence, custom Node type and changes in CSE machine * fix formatting * Implement AST transformer and transformation * formatting * bug fix #1 * limit places where transformed tree is run * Sent statementSequence transformer to utils + transform happens immediately before execution * format * remove debug * i am actually so stupid * Completion of CSE machine handling of StatementSequence * Clousre creation now accounts for StatementSequence * hasBreak/Continue/Return now accounts for StatementSequence * astToString now works on StatementSequence * wait this should not be here * Add Program to StatementSequence transformer + update CSE machine implementation * minor suggestions from code review --------- Co-authored-by: Martin Henz <[email protected]>
1 parent 746eb8b commit 00f3153

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+938
-410
lines changed

src/cse-machine/instrCreator.ts

+20-24
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import * as es from 'estree'
66

7-
import { Environment } from '../types'
7+
import { Environment, Node } from '../types'
88
import {
99
AppInstr,
1010
ArrLitInstr,
@@ -21,16 +21,12 @@ import {
2121
WhileInstr
2222
} from './types'
2323

24-
export const resetInstr = (srcNode: es.Node): Instr => ({
24+
export const resetInstr = (srcNode: Node): Instr => ({
2525
instrType: InstrType.RESET,
2626
srcNode
2727
})
2828

29-
export const whileInstr = (
30-
test: es.Expression,
31-
body: es.Statement,
32-
srcNode: es.Node
33-
): WhileInstr => ({
29+
export const whileInstr = (test: es.Expression, body: es.Statement, srcNode: Node): WhileInstr => ({
3430
instrType: InstrType.WHILE,
3531
test,
3632
body,
@@ -42,7 +38,7 @@ export const forInstr = (
4238
test: es.Expression,
4339
update: es.Expression,
4440
body: es.Statement,
45-
srcNode: es.Node
41+
srcNode: Node
4642
): ForInstr => ({
4743
instrType: InstrType.FOR,
4844
init,
@@ -56,7 +52,7 @@ export const assmtInstr = (
5652
symbol: string,
5753
constant: boolean,
5854
declaration: boolean,
59-
srcNode: es.Node
55+
srcNode: Node
6056
): AssmtInstr => ({
6157
instrType: InstrType.ASSIGNMENT,
6258
symbol,
@@ -65,19 +61,19 @@ export const assmtInstr = (
6561
srcNode
6662
})
6763

68-
export const unOpInstr = (symbol: es.UnaryOperator, srcNode: es.Node): UnOpInstr => ({
64+
export const unOpInstr = (symbol: es.UnaryOperator, srcNode: Node): UnOpInstr => ({
6965
instrType: InstrType.UNARY_OP,
7066
symbol,
7167
srcNode
7268
})
7369

74-
export const binOpInstr = (symbol: es.BinaryOperator, srcNode: es.Node): BinOpInstr => ({
70+
export const binOpInstr = (symbol: es.BinaryOperator, srcNode: Node): BinOpInstr => ({
7571
instrType: InstrType.BINARY_OP,
7672
symbol,
7773
srcNode
7874
})
7975

80-
export const popInstr = (srcNode: es.Node): Instr => ({ instrType: InstrType.POP, srcNode })
76+
export const popInstr = (srcNode: Node): Instr => ({ instrType: InstrType.POP, srcNode })
8177

8278
export const appInstr = (numOfArgs: number, srcNode: es.CallExpression): AppInstr => ({
8379
instrType: InstrType.APPLICATION,
@@ -88,67 +84,67 @@ export const appInstr = (numOfArgs: number, srcNode: es.CallExpression): AppInst
8884
export const branchInstr = (
8985
consequent: es.Expression | es.Statement,
9086
alternate: es.Expression | es.Statement | null | undefined,
91-
srcNode: es.Node
87+
srcNode: Node
9288
): BranchInstr => ({
9389
instrType: InstrType.BRANCH,
9490
consequent,
9591
alternate,
9692
srcNode
9793
})
9894

99-
export const envInstr = (env: Environment, srcNode: es.Node): EnvInstr => ({
95+
export const envInstr = (env: Environment, srcNode: Node): EnvInstr => ({
10096
instrType: InstrType.ENVIRONMENT,
10197
env,
10298
srcNode
10399
})
104100

105-
export const arrLitInstr = (arity: number, srcNode: es.Node): ArrLitInstr => ({
101+
export const arrLitInstr = (arity: number, srcNode: Node): ArrLitInstr => ({
106102
instrType: InstrType.ARRAY_LITERAL,
107103
arity,
108104
srcNode
109105
})
110106

111-
export const arrAccInstr = (srcNode: es.Node): Instr => ({
107+
export const arrAccInstr = (srcNode: Node): Instr => ({
112108
instrType: InstrType.ARRAY_ACCESS,
113109
srcNode
114110
})
115111

116-
export const arrAssmtInstr = (srcNode: es.Node): Instr => ({
112+
export const arrAssmtInstr = (srcNode: Node): Instr => ({
117113
instrType: InstrType.ARRAY_ASSIGNMENT,
118114
srcNode
119115
})
120116

121-
export const markerInstr = (srcNode: es.Node): Instr => ({
117+
export const markerInstr = (srcNode: Node): Instr => ({
122118
instrType: InstrType.MARKER,
123119
srcNode
124120
})
125121

126-
export const contInstr = (srcNode: es.Node): Instr => ({
122+
export const contInstr = (srcNode: Node): Instr => ({
127123
instrType: InstrType.CONTINUE,
128124
srcNode
129125
})
130126

131-
export const contMarkerInstr = (srcNode: es.Node): Instr => ({
127+
export const contMarkerInstr = (srcNode: Node): Instr => ({
132128
instrType: InstrType.CONTINUE_MARKER,
133129
srcNode
134130
})
135131

136-
export const breakInstr = (srcNode: es.Node): Instr => ({
132+
export const breakInstr = (srcNode: Node): Instr => ({
137133
instrType: InstrType.BREAK,
138134
srcNode
139135
})
140136

141-
export const breakMarkerInstr = (srcNode: es.Node): Instr => ({
137+
export const breakMarkerInstr = (srcNode: Node): Instr => ({
142138
instrType: InstrType.BREAK_MARKER,
143139
srcNode
144140
})
145141

146-
export const genContInstr = (srcNode: es.Node): GenContInstr => ({
142+
export const genContInstr = (srcNode: Node): GenContInstr => ({
147143
instrType: InstrType.GENERATE_CONT,
148144
srcNode
149145
})
150146

151-
export const resumeContInstr = (srcNode: es.Node): ResumeContInstr => ({
147+
export const resumeContInstr = (srcNode: Node): ResumeContInstr => ({
152148
instrType: InstrType.RESUME_CONT,
153149
srcNode
154150
})

src/cse-machine/interpreter.ts

+42-42
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,13 @@ import { initModuleContext, loadModuleBundle } from '../modules/moduleLoader'
1919
import { ImportTransformOptions } from '../modules/moduleTypes'
2020
import { checkEditorBreakpoints } from '../stdlib/inspector'
2121
import { checkProgramForUndefinedVariables } from '../transpiler/transpiler'
22-
import { Context, ContiguousArrayElements, RawBlockStatement, Result, Value } from '../types'
22+
import { Context, ContiguousArrayElements, Result, StatementSequence, Value } from '../types'
2323
import assert from '../utils/assert'
2424
import { filterImportDeclarations } from '../utils/ast/helpers'
2525
import * as ast from '../utils/astCreator'
2626
import { evaluateBinaryExpression, evaluateUnaryExpression } from '../utils/operators'
2727
import * as rttc from '../utils/rttc'
28+
import * as seq from '../utils/statementSeqTransform'
2829
import {
2930
Continuation,
3031
getContinuationControl,
@@ -72,7 +73,6 @@ import {
7273
isBlockStatement,
7374
isInstr,
7475
isNode,
75-
isRawBlockStatement,
7676
isSimpleFunction,
7777
popEnvironment,
7878
pushEnvironment,
@@ -95,7 +95,7 @@ type CmdEvaluator = (
9595
* It contains syntax tree nodes or instructions.
9696
*/
9797
export class Control extends Stack<ControlItem> {
98-
public constructor(program?: es.Program) {
98+
public constructor(program?: es.Program | StatementSequence) {
9999
super()
100100

101101
// Load program into control stack
@@ -109,20 +109,18 @@ export class Control extends Stack<ControlItem> {
109109

110110
/**
111111
* Before pushing block statements on the control stack, we check if the block statement has any declarations.
112-
* If not (and its not a raw block statement), instead of pushing the entire block, just the body is pushed since the block is not adding any value.
112+
* If not, the block is converted to a StatementSequence.
113113
* @param items The items being pushed on the control.
114-
* @returns The same set of control items, but with block statements without declarations simplified.
114+
* @returns The same set of control items, but with block statements without declarations converted to StatementSequences.
115+
* NOTE: this function handles any case where StatementSequence has to be converted back into BlockStatement due to type issues
115116
*/
116117
private static simplifyBlocksWithoutDeclarations(...items: ControlItem[]): ControlItem[] {
117118
const itemsNew: ControlItem[] = []
118119
items.forEach(item => {
119-
if (
120-
isNode(item) &&
121-
isBlockStatement(item) &&
122-
!hasDeclarations(item) &&
123-
!isRawBlockStatement(item)
124-
) {
125-
itemsNew.push(...Control.simplifyBlocksWithoutDeclarations(...handleSequence(item.body)))
120+
if (isNode(item) && isBlockStatement(item) && !hasDeclarations(item)) {
121+
// Push block body as statement sequence
122+
const seq: StatementSequence = ast.statementSequence(item.body, item.loc)
123+
itemsNew.push(seq)
126124
} else {
127125
itemsNew.push(item)
128126
}
@@ -169,6 +167,7 @@ export function evaluate(program: es.Program, context: Context, options: IOption
169167
context.errors.push(error)
170168
return new CseError(error)
171169
}
170+
seq.transform(program)
172171

173172
try {
174173
context.runtime.isRunning = true
@@ -311,8 +310,11 @@ export function* generateCSEMachineStateStream(
311310

312311
let command = control.peek()
313312

314-
// First node will be a Program
315-
context.runtime.nodes.unshift(command as es.Program)
313+
// Push first node to be evaluated into context.
314+
// The typeguard is there to guarantee that we are pushing a node (which should always be the case)
315+
if (command && isNode(command)) {
316+
context.runtime.nodes.unshift(command)
317+
}
316318

317319
while (command) {
318320
// Return to capture a snapshot of the control and stash after the target step count is reached
@@ -369,7 +371,7 @@ export function* generateCSEMachineStateStream(
369371

370372
/**
371373
* Dictionary of functions which handle the logic for the response of the three registers of
372-
* the ASE machine to each ControlItem.
374+
* the CSE machine to each ControlItem.
373375
*/
374376
const cmdEvaluators: { [type: string]: CmdEvaluator } = {
375377
/**
@@ -400,31 +402,17 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = {
400402
const next = command.body[0]
401403
cmdEvaluators[next.type](next, context, control, stash, isPrelude)
402404
} else {
403-
// Push raw block statement
404-
const rawCopy: RawBlockStatement = {
405-
type: 'BlockStatement',
406-
range: command.range,
407-
loc: command.loc,
408-
body: command.body,
409-
isRawBlock: 'true'
410-
}
411-
control.push(rawCopy)
405+
// Push block body as statement sequence
406+
const seq: StatementSequence = ast.statementSequence(command.body, command.loc)
407+
control.push(seq)
412408
}
413409
},
414410

415411
BlockStatement: function (command: es.BlockStatement, context: Context, control: Control) {
416-
if (isRawBlockStatement(command)) {
417-
// Raw block statement: unpack and push body
418-
// Push block body only
419-
control.push(...handleSequence(command.body))
420-
return
421-
}
422-
// Normal block statement: do environment setup
423412
// To restore environment after block ends
424413
// If there is an env instruction on top of the stack, or if there are no declarations
425414
// we do not need to push another one
426-
// The no declarations case is handled by Control :: simplifyBlocksWithoutDeclarations, so no blockStatement node
427-
// without declarations should end up here.
415+
// The no declarations case is handled at the transform stage, so no blockStatement node without declarations should end up here.
428416
const next = control.peek()
429417
// Push ENVIRONMENT instruction if needed
430418
if (!next || !(isInstr(next) && next.instrType === InstrType.ENVIRONMENT)) {
@@ -435,15 +423,27 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = {
435423
declareFunctionsAndVariables(context, command, environment)
436424
pushEnvironment(context, environment)
437425

438-
// Push raw block statement
439-
const rawCopy: RawBlockStatement = {
440-
type: 'BlockStatement',
441-
range: command.range,
442-
loc: command.loc,
443-
body: command.body,
444-
isRawBlock: 'true'
426+
// Push block body as statement sequence
427+
const seq: StatementSequence = ast.statementSequence(command.body, command.loc)
428+
control.push(seq)
429+
},
430+
431+
StatementSequence: function (
432+
command: StatementSequence,
433+
context: Context,
434+
control: Control,
435+
stash: Stash,
436+
isPrelude: boolean
437+
) {
438+
if (command.body.length == 1) {
439+
// If sequence only consists of one statement, evaluate it immediately
440+
const next = command.body[0]
441+
cmdEvaluators[next.type](next, context, control, stash, isPrelude)
442+
} else {
443+
// unpack and push individual nodes in body
444+
control.push(...handleSequence(command.body))
445445
}
446-
control.push(rawCopy)
446+
return
447447
},
448448

449449
WhileStatement: function (
@@ -981,7 +981,7 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = {
981981
// Value is a function
982982
// Check for number of arguments mismatch error
983983
checkNumberOfArguments(context, func, args, command.srcNode)
984-
// Directly stash result of applying pre-built functions without the ASE machine.
984+
// Directly stash result of applying pre-built functions without the CSE machine.
985985
try {
986986
const result = func(...args)
987987
stash.push(result)

src/cse-machine/types.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as es from 'estree'
22

3-
import { Environment } from '../types'
3+
import { Environment, Node } from '../types'
44

55
export enum InstrType {
66
RESET = 'Reset',
@@ -28,7 +28,7 @@ export enum InstrType {
2828

2929
interface BaseInstr {
3030
instrType: InstrType
31-
srcNode: es.Node
31+
srcNode: Node
3232
}
3333

3434
export interface WhileInstr extends BaseInstr {
@@ -90,7 +90,7 @@ export type Instr =
9090
| GenContInstr
9191
| ResumeContInstr
9292

93-
export type ControlItem = es.Node | Instr
93+
export type ControlItem = Node | Instr
9494

9595
// Special class that cannot be found on the stash so is safe to be used
9696
// as an indicator of a breakpoint from running the CSE machine

0 commit comments

Comments
 (0)