Skip to content

Commit

Permalink
CSE Machine: Implement two-step block statement evaluation (#1538)
Browse files Browse the repository at this point in the history
* Implement two step block statement evaluation

* push a raw copy instead of modifying the block statement itself

* Refactor logic

* Restore whitespace for readability
* Refactor if-else to use early return instead
* Standardize capitalization of comments
* Update comment for clarity

---------

Co-authored-by: Richard Dominick <[email protected]>
  • Loading branch information
NhatMinh0208 and RichDom2185 authored Feb 18, 2024
1 parent 32b7f64 commit 3dac647
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 9 deletions.
44 changes: 36 additions & 8 deletions src/cse-machine/interpreter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { initModuleContext, loadModuleBundle } from '../modules/moduleLoader'
import { ImportTransformOptions } from '../modules/moduleTypes'
import { checkEditorBreakpoints } from '../stdlib/inspector'
import { checkProgramForUndefinedVariables } from '../transpiler/transpiler'
import { Context, ContiguousArrayElements, Result, Value } from '../types'
import { Context, ContiguousArrayElements, RawBlockStatement, Result, Value } from '../types'
import assert from '../utils/assert'
import { filterImportDeclarations } from '../utils/ast/helpers'
import * as ast from '../utils/astCreator'
Expand Down Expand Up @@ -62,6 +62,7 @@ import {
isBlockStatement,
isInstr,
isNode,
isRawBlockStatement,
isSimpleFunction,
popEnvironment,
pushEnvironment,
Expand Down Expand Up @@ -97,15 +98,20 @@ export class Control extends Stack<ControlItem> {
}

/**
* Before pushing block statements on the control, we check if the block statement has any declarations.
* If not, instead of pushing the entire block, just the body is pushed since the block is not adding any value.
* Before pushing block statements on the control stack, we check if the block statement has any declarations.
* 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.
* @param items The items being pushed on the control.
* @returns The same set of control items, but with block statements without declarations simplified.
*/
private static simplifyBlocksWithoutDeclarations(...items: ControlItem[]): ControlItem[] {
const itemsNew: ControlItem[] = []
items.forEach(item => {
if (isNode(item) && isBlockStatement(item) && !hasDeclarations(item)) {
if (
isNode(item) &&
isBlockStatement(item) &&
!hasDeclarations(item) &&
!isRawBlockStatement(item)
) {
itemsNew.push(...Control.simplifyBlocksWithoutDeclarations(...handleSequence(item.body)))
} else {
itemsNew.push(item)
Expand Down Expand Up @@ -342,12 +348,26 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = {
const next = command.body[0]
cmdEvaluators[next.type](next, context, control, stash, isPrelude)
} else {
// Push block body
control.push(...handleSequence(command.body))
// Push raw block statement
const rawCopy: RawBlockStatement = {
type: 'BlockStatement',
range: command.range,
loc: command.loc,
body: command.body,
isRawBlock: 'true'
}
control.push(rawCopy)
}
},

BlockStatement: function (command: es.BlockStatement, context: Context, control: Control) {
if (isRawBlockStatement(command)) {
// Raw block statement: unpack and push body
// Push block body only
control.push(...handleSequence(command.body))
return
}
// Normal block statement: do environment setup
// To restore environment after block ends
// If there is an env instruction on top of the stack, or if there are no declarations, or there is no next control item
// we do not need to push another one
Expand All @@ -362,8 +382,16 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = {
const environment = createBlockEnvironment(context, 'blockEnvironment')
declareFunctionsAndVariables(context, command, environment)
pushEnvironment(context, environment)
// Push block body
control.push(...handleSequence(command.body))

// Push raw block statement
const rawCopy: RawBlockStatement = {
type: 'BlockStatement',
range: command.range,
loc: command.loc,
body: command.body,
isRawBlock: 'true'
}
control.push(rawCopy)
},

WhileStatement: function (
Expand Down
12 changes: 11 additions & 1 deletion src/cse-machine/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Context } from '..'
import * as errors from '../errors/errors'
import { RuntimeSourceError } from '../errors/runtimeSourceError'
import Closure from '../interpreter/closure'
import { Environment, Frame, Value } from '../types'
import { Environment, Frame, RawBlockStatement, Value } from '../types'
import * as ast from '../utils/astCreator'
import * as instr from './instrCreator'
import { Control } from './interpreter'
Expand Down Expand Up @@ -124,6 +124,16 @@ export const isBlockStatement = (node: es.Node): node is es.BlockStatement => {
return (node as es.BlockStatement).type == 'BlockStatement'
}

/**
* Typeguard for RawBlockStatement. To verify if an esNode is a raw block statement (i.e. passed environment creation).
*
* @param node an esNode
* @returns true if node is a RawBlockStatement, false otherwise.
*/
export const isRawBlockStatement = (node: es.Node): node is RawBlockStatement => {
return (node as RawBlockStatement).isRawBlock === 'true'
}

/**
* Typeguard for esRestElement. To verify if an esNode is a block statement.
*
Expand Down
8 changes: 8 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,14 @@ export interface BlockExpression extends es.BaseExpression {

export type substituterNodes = es.Node | BlockExpression

/**
* For use in the CSE machine: block statements are handled in two steps:
* environment creation, then unpacking
*/
export interface RawBlockStatement extends es.BlockStatement {
isRawBlock: 'true'
}

export {
Instruction as SVMInstruction,
Program as SVMProgram,
Expand Down

0 comments on commit 3dac647

Please sign in to comment.