@@ -19,12 +19,13 @@ import { initModuleContext, loadModuleBundle } from '../modules/moduleLoader'
19
19
import { ImportTransformOptions } from '../modules/moduleTypes'
20
20
import { checkEditorBreakpoints } from '../stdlib/inspector'
21
21
import { checkProgramForUndefinedVariables } from '../transpiler/transpiler'
22
- import { Context , ContiguousArrayElements , RawBlockStatement , Result , Value } from '../types'
22
+ import { Context , ContiguousArrayElements , Result , StatementSequence , Value } from '../types'
23
23
import assert from '../utils/assert'
24
24
import { filterImportDeclarations } from '../utils/ast/helpers'
25
25
import * as ast from '../utils/astCreator'
26
26
import { evaluateBinaryExpression , evaluateUnaryExpression } from '../utils/operators'
27
27
import * as rttc from '../utils/rttc'
28
+ import * as seq from '../utils/statementSeqTransform'
28
29
import {
29
30
Continuation ,
30
31
getContinuationControl ,
@@ -72,7 +73,6 @@ import {
72
73
isBlockStatement ,
73
74
isInstr ,
74
75
isNode ,
75
- isRawBlockStatement ,
76
76
isSimpleFunction ,
77
77
popEnvironment ,
78
78
pushEnvironment ,
@@ -95,7 +95,7 @@ type CmdEvaluator = (
95
95
* It contains syntax tree nodes or instructions.
96
96
*/
97
97
export class Control extends Stack < ControlItem > {
98
- public constructor ( program ?: es . Program ) {
98
+ public constructor ( program ?: es . Program | StatementSequence ) {
99
99
super ( )
100
100
101
101
// Load program into control stack
@@ -109,20 +109,18 @@ export class Control extends Stack<ControlItem> {
109
109
110
110
/**
111
111
* 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 .
113
113
* @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
115
116
*/
116
117
private static simplifyBlocksWithoutDeclarations ( ...items : ControlItem [ ] ) : ControlItem [ ] {
117
118
const itemsNew : ControlItem [ ] = [ ]
118
119
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 )
126
124
} else {
127
125
itemsNew . push ( item )
128
126
}
@@ -169,6 +167,7 @@ export function evaluate(program: es.Program, context: Context, options: IOption
169
167
context . errors . push ( error )
170
168
return new CseError ( error )
171
169
}
170
+ seq . transform ( program )
172
171
173
172
try {
174
173
context . runtime . isRunning = true
@@ -311,8 +310,11 @@ export function* generateCSEMachineStateStream(
311
310
312
311
let command = control . peek ( )
313
312
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
+ }
316
318
317
319
while ( command ) {
318
320
// Return to capture a snapshot of the control and stash after the target step count is reached
@@ -369,7 +371,7 @@ export function* generateCSEMachineStateStream(
369
371
370
372
/**
371
373
* 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.
373
375
*/
374
376
const cmdEvaluators : { [ type : string ] : CmdEvaluator } = {
375
377
/**
@@ -400,31 +402,17 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = {
400
402
const next = command . body [ 0 ]
401
403
cmdEvaluators [ next . type ] ( next , context , control , stash , isPrelude )
402
404
} 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 )
412
408
}
413
409
} ,
414
410
415
411
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
423
412
// To restore environment after block ends
424
413
// If there is an env instruction on top of the stack, or if there are no declarations
425
414
// 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.
428
416
const next = control . peek ( )
429
417
// Push ENVIRONMENT instruction if needed
430
418
if ( ! next || ! ( isInstr ( next ) && next . instrType === InstrType . ENVIRONMENT ) ) {
@@ -435,15 +423,27 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = {
435
423
declareFunctionsAndVariables ( context , command , environment )
436
424
pushEnvironment ( context , environment )
437
425
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 ) )
445
445
}
446
- control . push ( rawCopy )
446
+ return
447
447
} ,
448
448
449
449
WhileStatement : function (
@@ -981,7 +981,7 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = {
981
981
// Value is a function
982
982
// Check for number of arguments mismatch error
983
983
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.
985
985
try {
986
986
const result = func ( ...args )
987
987
stash . push ( result )
0 commit comments