Skip to content
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

Remove Interpreter and Testing Refactor #1745

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
Prev Previous commit
Next Next commit
Revert "Add tests for parser rules"
This reverts commit ed8eb2c.
leeyi45 committed Mar 7, 2025
commit f98dcea8a5e7d93a246f485b0fdf0779c5d4428f
10 changes: 6 additions & 4 deletions src/parser/source/index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { parse as acornParse, Token, tokenizer } from 'acorn'
import type * as es from 'estree'
import * as es from 'estree'

import { DEFAULT_ECMA_VERSION } from '../../constants'
import { Chapter, Context, Node, SourceError, Variant } from '../../types'
import { Chapter, Context, Node, Rule, SourceError, Variant } from '../../types'
import { ancestor, AncestorWalkerFn } from '../../utils/walkers'
import { DisallowedConstructError, FatalSyntaxError } from '../errors'
import type { AcornOptions, Rule, Parser } from '../types'
import { AcornOptions, Parser } from '../types'
import { createAcornParserOptions, positionToSourceLocation } from '../utils'
import { mapToObj } from '../../utils/misc'
import defaultRules from './rules'
import syntaxBlacklist from './syntax'

@@ -18,6 +17,9 @@ const combineAncestorWalkers =
w2(node, state, ancestors)
}

const mapToObj = <T>(map: Map<string, T>) =>
Array.from(map).reduce((obj, [k, v]) => Object.assign(obj, { [k]: v }), {})

export class SourceParser implements Parser<AcornOptions> {
private chapter: Chapter
private variant: Variant
97 changes: 0 additions & 97 deletions src/parser/source/rules/__tests__/rules.ts

This file was deleted.

33 changes: 17 additions & 16 deletions src/parser/source/rules/bracesAroundFor.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
import { generate } from 'astring'
import type { ForStatement } from 'estree'
import { type Rule, RuleError } from '../../types'
import * as es from 'estree'

const errorMsg = 'Missing curly braces around "for" block.'
import { UNKNOWN_LOCATION } from '../../../constants'
import { ErrorSeverity, ErrorType, Node, Rule, SourceError } from '../../../types'

export class BracesAroundForError implements SourceError {
public type = ErrorType.SYNTAX
public severity = ErrorSeverity.ERROR

constructor(public node: es.ForStatement) {}

get location() {
return this.node.loc ?? UNKNOWN_LOCATION
}

export class BracesAroundForError extends RuleError<ForStatement> {
public explain() {
return errorMsg
return 'Missing curly braces around "for" block.'
}

public elaborate() {
@@ -20,19 +29,11 @@ export class BracesAroundForError extends RuleError<ForStatement> {
}
}

const bracesAroundFor: Rule<ForStatement> = {
const bracesAroundFor: Rule<es.ForStatement> = {
name: 'braces-around-for',
testSnippets: [
[
`
let j = 0;
for (let i = 0; i < 1; i = i + 1) j = j + 1;
`,
errorMsg
]
],

checkers: {
ForStatement(node: ForStatement) {
ForStatement(node: es.ForStatement, _ancestors: [Node]) {
if (node.body.type !== 'BlockStatement') {
return [new BracesAroundForError(node)]
} else {
34 changes: 15 additions & 19 deletions src/parser/source/rules/bracesAroundIfElse.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import { generate } from 'astring'
import type { IfStatement } from 'estree'
import type { SourceError } from '../../../types'
import { type Rule, RuleError } from '../../types'
import * as es from 'estree'

import { UNKNOWN_LOCATION } from '../../../constants'
import { ErrorSeverity, ErrorType, Node, Rule, SourceError } from '../../../types'
import { stripIndent } from '../../../utils/formatters'

export class BracesAroundIfElseError extends RuleError<IfStatement> {
constructor(public node: IfStatement, private branch: 'consequent' | 'alternate') {
super(node)
export class BracesAroundIfElseError implements SourceError {
public type = ErrorType.SYNTAX
public severity = ErrorSeverity.ERROR

constructor(public node: es.IfStatement, private branch: 'consequent' | 'alternate') {}

get location() {
return this.node.loc ?? UNKNOWN_LOCATION
}

public explain() {
@@ -63,21 +69,11 @@ export class BracesAroundIfElseError extends RuleError<IfStatement> {
}
}

const bracesAroundIfElse: Rule<IfStatement> = {
const bracesAroundIfElse: Rule<es.IfStatement> = {
name: 'braces-around-if-else',
testSnippets: [
[
`
function f() {
if (true) return false;
else return true;
}
`,
'Line 3: Missing curly braces around "if" block.'
]
],

checkers: {
IfStatement(node: IfStatement) {
IfStatement(node: es.IfStatement, _ancestors: [Node]) {
const errors: SourceError[] = []
if (node.consequent && node.consequent.type !== 'BlockStatement') {
errors.push(new BracesAroundIfElseError(node, 'consequent'))
31 changes: 17 additions & 14 deletions src/parser/source/rules/bracesAroundWhile.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
import { generate } from 'astring'
import type { WhileStatement } from 'estree'
import { type Rule, RuleError } from '../../types'
import * as es from 'estree'

import { UNKNOWN_LOCATION } from '../../../constants'
import { ErrorSeverity, ErrorType, Node, Rule, SourceError } from '../../../types'

export class BracesAroundWhileError implements SourceError {
public type = ErrorType.SYNTAX
public severity = ErrorSeverity.ERROR

constructor(public node: es.WhileStatement) {}

get location() {
return this.node.loc ?? UNKNOWN_LOCATION
}

export class BracesAroundWhileError extends RuleError<WhileStatement> {
public explain() {
return 'Missing curly braces around "while" block.'
}
@@ -15,19 +26,11 @@ export class BracesAroundWhileError extends RuleError<WhileStatement> {
}
}

const bracesAroundWhile: Rule<WhileStatement> = {
const bracesAroundWhile: Rule<es.WhileStatement> = {
name: 'braces-around-while',
testSnippets: [
[
`
let i = 0;
while (true) i = i + 1;
`,
'Line 3: Missing curly braces around "while" block.'
]
],

checkers: {
WhileStatement(node: WhileStatement) {
WhileStatement(node: es.WhileStatement, _ancestors: [Node]) {
if (node.body.type !== 'BlockStatement') {
return [new BracesAroundWhileError(node)]
} else {
27 changes: 15 additions & 12 deletions src/parser/source/rules/forStatementMustHaveAllParts.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import type { ForStatement } from 'estree'
import { type Rule, RuleError } from '../../types'
import * as es from 'estree'

import { UNKNOWN_LOCATION } from '../../../constants'
import { ErrorSeverity, ErrorType, Rule, SourceError } from '../../../types'
import { stripIndent } from '../../../utils/formatters'

export class ForStatmentMustHaveAllParts extends RuleError<ForStatement> {
constructor(public node: ForStatement, private missingParts: string[]) {
super(node)
export class ForStatmentMustHaveAllParts implements SourceError {
public type = ErrorType.SYNTAX
public severity = ErrorSeverity.ERROR

constructor(public node: es.ForStatement, private missingParts: string[]) {}

get location() {
return this.node.loc ?? UNKNOWN_LOCATION
}

public explain() {
@@ -20,15 +27,11 @@ export class ForStatmentMustHaveAllParts extends RuleError<ForStatement> {
}
}

const forStatementMustHaveAllParts: Rule<ForStatement> = {
const forStatementMustHaveAllParts: Rule<es.ForStatement> = {
name: 'for-statement-must-have-all-parts',
testSnippets: [
['let i = 0; for (; i < 0; i = i + 1) {}', 'Line 1: Missing init expression in for statement.'],
['for (let i = 0; ; i = i + 1) {}', 'Line 1: Missing test expression in for statement.'],
['for (let i = 0; i < 0;) {}', 'Line 1: Missing update expression in for statement']
],

checkers: {
ForStatement(node: ForStatement) {
ForStatement(node: es.ForStatement) {
const missingParts = ['init', 'test', 'update'].filter(part => node[part] === null)
if (missingParts.length > 0) {
return [new ForStatmentMustHaveAllParts(node, missingParts)]
5 changes: 3 additions & 2 deletions src/parser/source/rules/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { Node } from '../../../types'
import type { Rule } from '../../types'
import { Node, Rule } from '../../../types'
import bracesAroundFor from './bracesAroundFor'
import bracesAroundIfElse from './bracesAroundIfElse'
import bracesAroundWhile from './bracesAroundWhile'
@@ -11,6 +10,7 @@ import noExportNamedDeclarationWithDefault from './noExportNamedDeclarationWithD
import noFunctionDeclarationWithoutIdentifier from './noFunctionDeclarationWithoutIdentifier'
import noHolesInArrays from './noHolesInArrays'
import noIfWithoutElse from './noIfWithoutElse'
import noImplicitDeclareUndefined from './noImplicitDeclareUndefined'
import noImplicitReturnUndefined from './noImplicitReturnUndefined'
import noImportSpecifierWithDefault from './noImportSpecifierWithDefault'
import noNull from './noNull'
@@ -34,6 +34,7 @@ const rules: Rule<Node>[] = [
noFunctionDeclarationWithoutIdentifier,
noIfWithoutElse,
noImportSpecifierWithDefault,
noImplicitDeclareUndefined,
noImplicitReturnUndefined,
noNull,
noUnspecifiedLiteral,
29 changes: 18 additions & 11 deletions src/parser/source/rules/noDeclareMutable.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,41 @@
import { generate } from 'astring'
import type { VariableDeclaration } from 'estree'
import { Chapter } from '../../../types'
import { type Rule, RuleError } from '../../types'
import { getVariableDeclarationName } from '../../../utils/ast/astCreator'
import * as es from 'estree'

import { UNKNOWN_LOCATION } from '../../../constants'
import { Chapter, ErrorSeverity, ErrorType, Node, Rule, SourceError } from '../../../types'

const mutableDeclarators = ['let', 'var']

export class NoDeclareMutableError extends RuleError<VariableDeclaration> {
export class NoDeclareMutableError implements SourceError {
public type = ErrorType.SYNTAX
public severity = ErrorSeverity.ERROR

constructor(public node: es.VariableDeclaration) {}

get location() {
return this.node.loc ?? UNKNOWN_LOCATION
}

public explain() {
return (
'Mutable variable declaration using keyword ' + `'${this.node.kind}'` + ' is not allowed.'
)
}

public elaborate() {
const name = getVariableDeclarationName(this.node)
const name = (this.node.declarations[0].id as es.Identifier).name
const value = generate(this.node.declarations[0].init)

return `Use keyword "const" instead, to declare a constant:\n\n\tconst ${name} = ${value};`
}
}

const noDeclareMutable: Rule<VariableDeclaration> = {
const noDeclareMutable: Rule<es.VariableDeclaration> = {
name: 'no-declare-mutable',
disableFromChapter: Chapter.SOURCE_3,
testSnippets: [
['let i = 0;', "Line 1: Mutable variable declaration using keyword 'let' is not allowed."]
],

checkers: {
VariableDeclaration(node: VariableDeclaration) {
VariableDeclaration(node: es.VariableDeclaration, _ancestors: [Node]) {
if (mutableDeclarators.includes(node.kind)) {
return [new NoDeclareMutableError(node)]
} else {
Loading

Unchanged files with check annotations Beta

* @returns The corresponding promise.
*/
export function CSEResultPromise(context: Context, value: Value): Promise<Result> {
return new Promise((resolve, reject) => {

Check warning on line 332 in src/cse-machine/interpreter.ts

GitHub Actions / build

'reject' is defined but never used. Allowed unused args must match /^_/u
if (value instanceof CSEBreak) {
resolve({ status: 'suspended-cse-eval', context })
} else if (value instanceof CseError) {
command: es.WhileStatement,
context: Context,
control: Control,
stash: Stash

Check warning on line 567 in src/cse-machine/interpreter.ts

GitHub Actions / build

'stash' is defined but never used. Allowed unused args must match /^_/u
) {
if (hasBreakStatement(command.body as es.BlockStatement)) {
control.push(instr.breakMarkerInstr(command))
command: es.IfStatement,
context: Context,
control: Control,
stash: Stash

Check warning on line 648 in src/cse-machine/interpreter.ts

GitHub Actions / build

'stash' is defined but never used. Allowed unused args must match /^_/u
) {
control.push(...reduceConditional(command))
},
command: es.ContinueStatement,
context: Context,
control: Control,
stash: Stash

Check warning on line 721 in src/cse-machine/interpreter.ts

GitHub Actions / build

'stash' is defined but never used. Allowed unused args must match /^_/u
) {
control.push(instr.contInstr(command))
},
command: es.BreakStatement,
context: Context,
control: Control,
stash: Stash

Check warning on line 730 in src/cse-machine/interpreter.ts

GitHub Actions / build

'stash' is defined but never used. Allowed unused args must match /^_/u
) {
control.push(instr.breakInstr(command))
},
command: es.MemberExpression,
context: Context,
control: Control,
stash: Stash

Check warning on line 783 in src/cse-machine/interpreter.ts

GitHub Actions / build

'stash' is defined but never used. Allowed unused args must match /^_/u
) {
control.push(instr.arrAccInstr(command))
control.push(command.property)
command: es.ConditionalExpression,
context: Context,
control: Control,
stash: Stash

Check warning on line 794 in src/cse-machine/interpreter.ts

GitHub Actions / build

'stash' is defined but never used. Allowed unused args must match /^_/u
) {
control.push(...reduceConditional(command))
},
* Instructions
*/
[InstrType.RESET]: function (command: Instr, context: Context, control: Control, stash: Stash) {

Check warning on line 857 in src/cse-machine/interpreter.ts

GitHub Actions / build

'stash' is defined but never used. Allowed unused args must match /^_/u
// Keep pushing reset instructions until marker is found.
const cmdNext: ControlItem | undefined = control.pop()
if (cmdNext && (!isInstr(cmdNext) || cmdNext.instrType !== InstrType.MARKER)) {
-1
)
// Run the new CSE Machine fully to obtain the result in the stash
for (const _ of gen) {

Check warning on line 55 in src/cse-machine/closure.ts

GitHub Actions / build

'_' is assigned a value but never used
}
// Also don't forget to update object count in original context
context.runtime.objectCount = newContext.runtime.objectCount
'call_cc(f)',
context.variant === Variant.EXPLICIT_CONTROL
? call_with_current_continuation
: (f: any) => {

Check warning on line 382 in src/createContext.ts

GitHub Actions / build

'f' is defined but never used. Allowed unused args must match /^_/u
throw new Error('call_cc is only available in Explicit-Control variant')
}
)