Skip to content

Stepper

Niklas Forsström edited this page Mar 22, 2020 · 17 revisions

Usage

To use the stepper in a REPL, you can run the repl with subst as its last command line argument:

cd js-slang
yarn build && node dist/repl/repl.js 1 subst

WIP: documentation of the stepper tool

Niklas documentation (probably subject to errors but might be useful to someone)

getEvaluationSteps(program: es.Program, context: Context): es.Program[]

The primary point of entry for the stepper tool is via the getEvaluationSteps-function. This function takes a program an array. This array contains the different program states as the program is being evaluated.

  • The method starts off by replacing all predefined constants (such as math_PI) in the program with their corresponding value. This is done via the substPredefinedConstants function.
  • The next step is to substitute all predefined functions in the program. This is done with the help of the substPredefinedFns function.
  • It then repeatedly reduces the program (which basically means doing repeated one step evaluations) with the help of the reduce function. For every reduction it performs it stores the program state in the return-array. This allows for playback through the evaluation steps.

substPredefinedConstants(program: es.Program): es.Program

The function uses an array, mathConstants, that contains all predefined mathematical constants. Each entry of this array is of the form [name, value] - where "name" is the name of the constant (e.g. math_PI) & "value" is the corresponding value (e.g. 3.141592653589793).

The method loops through all elements of mathConstants and replaces all occurrences of the name in the program with the associated value. it does so via the substituteMain method.

substPredefinedFns(program: es.Program, context: Context): [es.Program, Context]

This method substitutes all predefined functions in the program. What does substituting these mean?

substituteMain(name: es.Identifier, replacement: irreducibleNodes, target: substituterNodes): substituterNodes

This is a wrapper function for the substitute function. It provides the substitute function with "substituters", which is a datastructure full of functions. Each function describes how to replace a specific target type.

It also provides a map "seenBefore". This map is re-initialized every time substituteMain is called and therefore only keeps track of the targets seen within the substituteMain function. The reason why it's needed is that the substitute function will be called recursively, which would have the potential for creating infinite loops. Keeping track of what targets have been seen before allows us to only evaluate a target once.

In summary the substituteMain function is to provide a closure in which we can keep seenBefore like a "global variable" in the eyes of the substitute function

substitute(target: substituterNodes): substituterNodes

This function performs substitution of the provided target.

apply(callee: es.FunctionExpression | es.ArrowFunctionExpression, args: irreducibleNodes[]): BlockExpression | es.Expression

reduce(node: substituterNodes, context: Context): [substituterNodes, Context]

The reduce function is given the task of reducing the program, which basically means taking the first statement in the program and doing one step evaluation on it. Repeated application of this function will therefore cause the program to fully evaluate.

In order to perform the one step evaluation reduce uses the datastructure "reducers". Much like the substituters datastructure it contains instructions for how to handle all types of statements that we could potentially encounter.

treeifyMain(target: substituterNodes): substituterNodes

This function ....

...