Skip to content

Rewrite: Stepper #1742

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 71 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
9e2f130
Feat: Implement contraction and redex for basic AST nodes
kavishsathia Feb 28, 2025
694cb98
Merge branch 'master' into rewrite/stepper
martin-henz Mar 4, 2025
d817339
Feat: Add Program and ExpressionStatement
kavishsathia Mar 8, 2025
c67c36f
Merge branch 'rewrite/stepper' of https://github.com/source-academy/j…
CATISNOTSODIUM Mar 8, 2025
0b93acd
add program, statements, and variable declaration handler
CATISNOTSODIUM Mar 8, 2025
e32d110
restructure project, add substitution
CATISNOTSODIUM Mar 8, 2025
cc125fa
(feat) block scope handling
CATISNOTSODIUM Mar 9, 2025
e86cf6a
(feat) adding freeName
CATISNOTSODIUM Mar 9, 2025
496160b
Merge branch 'master' into rewrite/stepper
martin-henz Mar 10, 2025
fe6ecbc
(feat) add alpha renaming
CATISNOTSODIUM Mar 10, 2025
00aa05f
Merge branch 'rewrite/stepper' of https://github.com/source-academy/j…
CATISNOTSODIUM Mar 10, 2025
873bfee
(fix) alpha renaming for multiple variables
CATISNOTSODIUM Mar 11, 2025
9210965
(fix) edit source runner for stepper
CATISNOTSODIUM Mar 14, 2025
34736ee
Feat: Add IfStatements
kavishsathia Mar 15, 2025
355a65a
Feat: Add ConditionalExpressions
kavishsathia Mar 15, 2025
819fae7
Feat: Add ArrowFunctionExpressions and FunctionApplications
kavishsathia Mar 15, 2025
b09fb3d
(feat) add explanation handler
CATISNOTSODIUM Mar 17, 2025
20961b3
Feat: ArrowFunctions with BlockStatement bodies
kavishsathia Mar 17, 2025
52ad7ef
Feat: Add MuTerms v1
kavishsathia Mar 17, 2025
89d4290
Feat: Add Alpha Renaming for Arrow Functions v1
kavishsathia Mar 18, 2025
003f193
(feat) add explanation handler
CATISNOTSODIUM Mar 18, 2025
00d8cfb
Merge branch 'rewrite/stepper' of https://github.com/source-academy/j…
CATISNOTSODIUM Mar 18, 2025
c907c83
Feat: Add Alpha-renaming for ArrowFunctionExpressions
kavishsathia Mar 20, 2025
c3aa835
Fix: Remove ReturnStatements
kavishsathia Mar 20, 2025
d556243
Feat: Add BlockExpressions
kavishsathia Mar 21, 2025
58bb457
Feat: Add FunctionDeclarations
kavishsathia Mar 25, 2025
5aac4dc
Fix: Modify ReturnStatement Contraction Logic
kavishsathia Mar 25, 2025
095f610
Fix: Modify ArrowFunctionExpression Substituter
kavishsathia Mar 25, 2025
d4ec978
Fix: Add lte and gte to BinaryExpressions
kavishsathia Mar 25, 2025
dc6ab86
Chore: Move stepperV2 to tracer
kavishsathia Mar 26, 2025
0f29f36
Feat: Add Support for Math Builtins
kavishsathia Mar 26, 2025
51a572f
Feat: Add Support for Misc Builtins
kavishsathia Mar 26, 2025
fad5740
Feat: Add LogicalExpressions with Short-circuiting
kavishsathia Mar 26, 2025
ef6daf3
fix: remove substitution scope usage
CATISNOTSODIUM Mar 27, 2025
0d02471
fix: handle undefined statements
CATISNOTSODIUM Mar 28, 2025
67fd0cf
feat: add test case
CATISNOTSODIUM Mar 28, 2025
f968894
feat: fix function declaration
CATISNOTSODIUM Mar 29, 2025
93edeff
fix: handle return statement
CATISNOTSODIUM Mar 29, 2025
a67de42
feat: add prelude constant
CATISNOTSODIUM Mar 29, 2025
b0e293e
feat: add predeclared functions with arity
CATISNOTSODIUM Mar 30, 2025
254ea29
ci: adding test cases
CATISNOTSODIUM Mar 31, 2025
8000189
fix: convert negated number to literal during initialization
CATISNOTSODIUM Mar 31, 2025
3d71c27
feat: add predeclared list functions
CATISNOTSODIUM Mar 31, 2025
0206491
feat: cover more explanations
CATISNOTSODIUM Mar 31, 2025
71e0cab
Feat: Add Support for Auxiliary Builtins
kavishsathia Apr 1, 2025
9c675a4
fix: function declaration with if else block
CATISNOTSODIUM Apr 2, 2025
b00da05
fix: edit source runner for new stepper
CATISNOTSODIUM Apr 5, 2025
d6b365b
fix: mu term declaration after substitution
CATISNOTSODIUM Apr 5, 2025
b393712
fix: add raw field to the result from math builtin
CATISNOTSODIUM Apr 5, 2025
d4b0fea
fix: Block-statement-empty-reduce
CATISNOTSODIUM Apr 5, 2025
108afbd
fix: is_function
CATISNOTSODIUM Apr 5, 2025
a677cba
fix: feature parity
CATISNOTSODIUM Apr 5, 2025
953a57c
fix: alpha renaming with multiple clashes
CATISNOTSODIUM Apr 5, 2025
c6de056
fix: #1714 steps appear as if capturing happens
CATISNOTSODIUM Apr 6, 2025
8f6d7b0
Feat: Add Error Handling during Runtime
kavishsathia Apr 7, 2025
e596e75
Feat: Add Support for NaN and Infinity
kavishsathia Apr 7, 2025
210a8b7
Fix: Preserve Line Number for Array, ArrowFunction, and BinaryExpress…
kavishsathia Apr 7, 2025
b03e8a4
Fix: Preserve Line Number for Conditional, FunctionApplication, Ident…
kavishsathia Apr 7, 2025
5da68e8
Fix: Preserve Line Number for UnaryExpressions
kavishsathia Apr 7, 2025
f7d1609
Fix: Preserve Line Number for Statements
kavishsathia Apr 7, 2025
a7691fb
Fix: Preserve Line Number for BlockExpressions
kavishsathia Apr 7, 2025
5b2fcf1
Feat: Add Errors for Binary, FunctionApplication, Logical, and UnaryE…
kavishsathia Apr 7, 2025
a28a8ac
Feat: Add Errors for ConditionalExpressions
kavishsathia Apr 7, 2025
1e8e18b
Chore: Code Reordering
kavishsathia Apr 7, 2025
20cb359
Fix: Resolve Issue with Negative Infinity
kavishsathia Apr 7, 2025
61d2bc5
feat: add more tests
CATISNOTSODIUM Apr 8, 2025
6a63b7a
fix: remove unnecessary renaming
CATISNOTSODIUM Apr 8, 2025
c009f97
chore: lint fix
CATISNOTSODIUM Apr 8, 2025
2b3a255
fix: explanation for function application
CATISNOTSODIUM Apr 14, 2025
e92a776
chore: eslint fix
CATISNOTSODIUM Apr 14, 2025
9231fe2
doc: update README.md
CATISNOTSODIUM Apr 14, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -124,5 +124,5 @@
]
]
},
"packageManager": "yarn@4.6.0"
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}
26 changes: 3 additions & 23 deletions src/runner/sourceRunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,6 @@ import { defaultAnalysisOptions } from '../modules/preprocessor/analyzer'
import { defaultLinkerOptions } from '../modules/preprocessor/linker'
import { parse } from '../parser/parser'
import { AsyncScheduler, PreemptiveScheduler } from '../schedulers'
import {
callee,
getEvaluationSteps,
getRedex,
type IStepperPropContents,
redexify
} from '../stepper/stepper'
import { sandboxedEval } from '../transpiler/evalContainer'
import { transpile } from '../transpiler/transpiler'
import { Chapter, type Context, type RecursivePartial, type Scheduler, Variant } from '../types'
Expand All @@ -31,6 +24,7 @@ import { compileForConcurrent } from '../vm/svml-compiler'
import { runWithProgram } from '../vm/svml-machine'
import type { FileGetter } from '../modules/moduleTypes'
import { mapResult } from '../alt-langs/mapper'
import { getSteps } from '../tracer/steppers'
import { toSourceError } from './errors'
import { fullJSRunner } from './fullJSRunner'
import { determineExecutionMethod, determineVariant, resolvedErrorPromise } from './utils'
Expand Down Expand Up @@ -88,25 +82,11 @@ function runSubstitution(
context: Context,
options: IOptions
): Promise<Result> {
const steps = getEvaluationSteps(program, context, options)
if (context.errors.length > 0) {
return resolvedErrorPromise
}
const redexedSteps: IStepperPropContents[] = []
for (const step of steps) {
const redex = getRedex(step[0], step[1])
const redexed = redexify(step[0], step[1])
redexedSteps.push({
code: redexed[0],
redex: redexed[1],
explanation: step[2],
function: callee(redex, context)
})
}
const steps = getSteps(program, options)
return Promise.resolve({
status: 'finished',
context,
value: redexedSteps
value: steps
})
}

Expand Down
96 changes: 96 additions & 0 deletions src/tracer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Stepper Documentation (Draft)
- [Stepper Documentation (Draft)](#stepper-documentation-draft)
- [Key changes](#key-changes)
- [Quickstart](#quickstart)
- [Implementation Details](#implementation-details)
- [Entry point](#entry-point)
- [Reduction](#reduction)
- [Stepper ASTs (To be updated)](#stepper-asts-to-be-updated)
- [`UndefinedNode`](#undefinednode)
- [`StepperProgram`](#stepperprogram)
- [Reduction](#reduction-1)
- [`VariableDeclaration`](#variabledeclaration)
- [Reduction](#reduction-2)

## Key changes
- Rewritten the code to be more cohesive and readable.
- Better visualisation of recursion using lambda calculus concepts such as µ-terms.

## Quickstart
First of all, make sure that you have already installed `js-slang` using `yarn`. There are many possible ways that you can work and test the code. One of my personal solution is using `yarn test`. During the development, you can edit the file from `../__test__/tracer_debug.ts` and run it with the following command:
```bash
yarn test -- tracer_debug.ts > testOutput.log
```
Note that the flag `--silence=false` is set in order to see the output from `console.log`. In order to fully test the stepper, you can execute the following command.
```bash
yarn test -- tracer_full.ts`
```
## Implementation Details
Starting to work from raw estree is quite tricky, as it prevents us from using OOP principles directly. Therefore, we decided to create classes based on the original estree while implementing the `StepperBaseNode` interface. Note that this interface is subjected to change when adding more features to the stepper.
```typescript
// interface.ts
export interface StepperBaseNode {
type: string
isContractible(): boolean
isOneStepPossible(): boolean
contract(): StepperBaseNode
oneStep(): StepperBaseNode
substitute(id: StepperPattern, value: StepperExpression): StepperBaseNode
}
```
### Entry point
The starting point of our stepper is at `steppers.ts` with the function `getSteps`. This function is responsible for triggering reduction until it cannot be proceed. The result from our evaluation is then stored in array `steps`. Here is the shorten version of `getSteps`.

```typescript
export function getSteps(node: StepperBaseNode) {
const steps = []
function evaluate(node) {
const isOneStepPossible = node.isOneStepPossible()
if (isOneStepPossible) {
const oldNode = node
const newNode = node.oneStep() // entry point
{... read global state redex and add them to steps array}
return evaluate(newNode)
} else {
return node
}
}
evaluate(node)
return steps
}

```

In order to keep track of the node that is reduced (i.e., the node highlighted in orange and green in the current SICP stepper), we use the global state redex to track all nodes that should be highlighted. This state is then updated dynamically during the contraction process.

```typescript
export let redex: { preRedex: StepperBaseNode[]; postRedex: StepperBaseNode[] } = {
preRedex: [],
postRedex: []
}
// How to use global state
redex.preRedex = [node]
const ret = someSortOfReduction(node)
redex.postRedex = [ret]
```
### Reduction
The main entry point of our stepper is `oneStep()`. It is where our stepper start crawling down the tree and find the node that is ready to be `contract()`. Here is a quick example.
```typescript
1 + 2 * 3 // (+ 1 (* 2 3))
```
The binary expression `(+ 1 (* 2 3))` should not be contracted since its inner node `(* 2 3)` can be contracted to `6`, before contracting the outer expression. The methods `isContractible` and `isOneStepPossible` help maneuver the logic of where to contract.
## Stepper ASTs (To be updated)
### `UndefinedNode`
- Global node, literal, representing undefined

### `StepperProgram`
#### Reduction
- If `node.body.length === 0`, the program is reduced to `StepperUndefined`.
- If the first two statements are `oneStepPossible()`, reduce the first two statements first.
- If the first two statements are value-inducing (e.g., `1; 2;`), remove the first statement using `contractEmpty()`.

### `VariableDeclaration`
#### Reduction
- Reduce the `init` field first. `const x = 1 + 1;`: `1+1` is an init field.
- If the `init` field is reduced, toggle substitution and reduce the statement to `StepperUndefined`.
- VariableDeclaration is always contractable. PreRedex is the variable declaration statement. PostRedexes are all variables substituted.
Loading