Skip to content

Commit

Permalink
feat(Js): Catching exceptions during parsing/execution
Browse files Browse the repository at this point in the history
  • Loading branch information
beneboy committed Sep 2, 2019
1 parent 81942ec commit e499eb4
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 11 deletions.
4 changes: 2 additions & 2 deletions py/stencila/schema/interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,8 +219,8 @@ def parse(self, chunk: CodeChunk) -> CodeChunkParseResult:
return CodeChunkParseResult(None, error=exception_to_code_error(e))

# If this is True, then there should be a call to 'open' somewhere in the code, which means the parser should
# try to find it. This is a basic check so there might not be one (like if the code did , but if 'open(' is NOT in
# the string then there definitely ISN'T one
# try to find it. This is a basic check so there might not be one (like if the code did , but if 'open(' is NOT
# in the string then there definitely ISN'T one
search_for_open = 'open(' in chunk.text

for statement in chunk_ast.body:
Expand Down
67 changes: 58 additions & 9 deletions ts/executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import fs from 'fs'
import {
Article,
CodeChunk,
codeError,
CodeError,
CodeExpression,
EnumSchema,
Function,
Expand Down Expand Up @@ -135,6 +137,12 @@ function parseItem(
item.alters = parseResult.alters
item.uses = parseResult.uses

if (parseResult.errors.length > 0) {
if (item.errors === undefined) {
item.errors = []
}
item.errors = item.errors.concat(parseResult.errors)
}
code.push({
codeChunk: item,
parseResult: parseResult
Expand All @@ -155,7 +163,7 @@ function parseItem(
}

class CodeChunkParseResult {
public chunkAst: Program
public chunkAst: Program | null

public imports: string[] = []

Expand All @@ -167,11 +175,13 @@ class CodeChunkParseResult {

public uses: string[] = []

public errors: CodeError[] = []

private seenIdentifiers: string[] = []

private possibleVariables: string[] = []

public constructor(chunkAst: Program) {
public constructor(chunkAst: Program | null) {
this.chunkAst = chunkAst
}

Expand Down Expand Up @@ -445,8 +455,34 @@ function parseStatement(
}
}

function exceptionToCodeError(error: Error | string): CodeError {
if (typeof error === 'string') {
return codeError('Exception', { message: error })
} else {
return codeError(error.name, { message: error.message, trace: error.stack })
}
}

function setCodeError(
code: CodeChunk | CodeExpression,
error: Error | string
): void {
if (code.errors === undefined) {
code.errors = []
}
code.errors.push(exceptionToCodeError(error))
}

function parseCodeChunk(codeChunk: CodeChunk): CodeChunkParseResult {
const chunkAst = parse(codeChunk.text, { module: true })
let chunkAst: Program | null = null

try {
chunkAst = parse(codeChunk.text, { module: true })
} catch (e) {
const badParseResult: CodeChunkParseResult = new CodeChunkParseResult(null)
badParseResult.errors.push(exceptionToCodeError(e))
return badParseResult
}

const parseResult: CodeChunkParseResult = new CodeChunkParseResult(chunkAst)

Expand All @@ -463,8 +499,12 @@ function parseCodeChunk(codeChunk: CodeChunk): CodeChunkParseResult {
* Uses `eval`, so should only be called with trusted code.
*/
function executeCodeExpression(code: CodeExpression): void {
// eslint-disable-next-line no-eval
code.output = eval(code.text)
try {
// eslint-disable-next-line no-eval
code.output = eval(code.text)
} catch (e) {
setCodeError(code, e)
}
}

/**
Expand All @@ -478,6 +518,9 @@ function executeCodeChunk(code: CodeChunkExecution): void {
const outputs: any[] = []

const ast = code.parseResult.chunkAst

if (ast === null) return

const chunk = code.codeChunk

ast.body.forEach(statement => {
Expand All @@ -499,9 +542,15 @@ function executeCodeChunk(code: CodeChunkExecution): void {
loggedData += s
}

// @ts-ignore
// eslint-disable-next-line no-eval
const res = (1, eval)(generatedCode)
let res

try {
// @ts-ignore
// eslint-disable-next-line no-eval
res = (1, eval)(generatedCode)
} catch (e) {
setCodeError(chunk, e)
}

console.log = oldCl

Expand Down Expand Up @@ -591,7 +640,7 @@ async function readInput(path: string): Promise<string> {
* Write the executed document (`Article`) to a file or stdout.
*/
function outputArticle(path: string, output: Article): void {
const j = JSON.stringify(output)
const j = JSON.stringify(output, null, 2)

if (path === '-') {
console.log(j)
Expand Down

0 comments on commit e499eb4

Please sign in to comment.