Skip to content

Commit

Permalink
CatchExpressions
Browse files Browse the repository at this point in the history
  • Loading branch information
wcjohnson committed Oct 25, 2017
1 parent ab8ff83 commit 2810f87
Show file tree
Hide file tree
Showing 7 changed files with 104 additions and 0 deletions.
6 changes: 6 additions & 0 deletions src/config.lsc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ export getMetadata() -> {
defaultValue: "default"
stage: "1"
}
catchExpression: {
description: "Catch and transform errors while evaluating an expression."
valueType: "boolean"
stage: "0"
}
bangCall: {
description: "Call functions with paren-free syntax using `!`"
valueType: "boolean"
Expand Down Expand Up @@ -106,6 +111,7 @@ export getParserOpts(pluginOpts, initialParserOpts) ->
if pluginOpts?.placeholderArgs: plugins.push("syntacticPlaceholder")
if pluginOpts?.placeholder:
parserOpts.placeholder = pluginOpts.placeholder
if pluginOpts.catchExpression: plugins.push("catchExpression")

// TODO: watch upstream on pattern matching; default to their syntax when complete
// patternMatchingVersion = pluginOpts?.patternMatching or "v4"
Expand Down
34 changes: 34 additions & 0 deletions src/lscNodeTypes.lsc
Original file line number Diff line number Diff line change
Expand Up @@ -286,3 +286,37 @@ export registerLightscriptNodeTypes(t): void ->
},
},
});

if not t.hasType("CatchExpression"):
definePluginType("CatchExpression", {
builder: ["expression", "cases"],
visitor: ["expression", "cases"],
aliases: ["Expression"],
fields: {
expression: {
validate: assertNodeType("Expression")
},
cases: {
validate: chain(assertValueType("array"), assertEach(assertNodeType("CatchCase")))
}
}
});

if not t.hasType("CatchCase"):
definePluginType("CatchCase", {
builder: ["atoms", "binding", "consequent"],
visitor: ["atoms", "binding", "consequent"],
fields: {
atoms: {
validate: chain(assertValueType("array"), assertEach(assertNodeType("Expression")))
optional: true
}
binding: {
validate: assertNodeType("Identifier", "ArrayPattern", "ObjectPattern")
optional: true
}
consequent: {
validate: assertNodeType("Expression", "Statement")
}
}
});
40 changes: 40 additions & 0 deletions src/transforms/catchExpression.lsc
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import t, { isa } from '../types'

import {
getLoc, placeAtLoc as atLoc, placeAtNode as atNode,
getSurroundingLoc, span, traverse,
placeTreeAtLocWhenUnplaced as allAtLoc
} from 'ast-loc-utils'

import { getMatchInfo, transformMatchCases } from './match'

transformPessimizedCatchExpression(path, isLinter): void ->
{ node } = path

argRef = path.scope.generateUidIdentifier("err")~atLoc(getLoc(node)~span(1))
catchBody = getMatchInfo(path, argRef, isLinter)~transformMatchCases(path.get("cases"))

iife = t.callExpression(
t.arrowFunctionExpression(
[]
t.blockStatement([
t.tryStatement(
t.blockStatement([
t.returnStatement(node.expression)
])
t.catchClause(
argRef
t.blockStatement([catchBody])
)
)
])
node.expression~isa("AwaitExpression") // async
)
[]
)

path.replaceWith(iife)

export transformCatchExpression(path, isLinter): void ->
transformPessimizedCatchExpression(path, isLinter)

4 changes: 4 additions & 0 deletions src/visitors/main.lsc
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { maybeTransformArrayWithSpreadLoops, maybeTransformObjectWithSpreadLoops
import { transformExistentialExpression, transformSafeSpreadElement } from "../transforms/safe"
import { maybeReplaceWithInlinedOperator } from "../transforms/inlinedOperators"
import { transformForInArrayStatement, transformForInObjectStatement, lintForInArrayStatement, lintForInObjectStatement } from "../transforms/for"
import { transformCatchExpression } from "../transforms/catchExpression"

import { markIdentifier } from "../state/stdlib"

Expand Down Expand Up @@ -221,6 +222,9 @@ export default mainPass(compilerState, programPath): void ->
MatchStatement(path): void ->
matching.transformMatchStatement(path, opts.__linter)

CatchExpression(path): void ->
transformCatchExpression(path, opts.__linter)

ForOfStatement(path): void ->
// Auto-const
{ node } = path; { left } = node
Expand Down
2 changes: 2 additions & 0 deletions test/fixtures/catch-expression/basic/actual.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
a = b()
catch Error: panic()
9 changes: 9 additions & 0 deletions test/fixtures/catch-expression/basic/expected.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import _isMatch from "@oigroup/lightscript-runtime/isMatch";const a = (() => {
try {
return b();
} catch (_err) {
if (_isMatch(Error, _err)) {
return panic();
}
}
})();
9 changes: 9 additions & 0 deletions test/fixtures/catch-expression/options.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"plugins": [
["lightscript", {
"isLightScript": true,
"catchExpression": true
}]
]
}

0 comments on commit 2810f87

Please sign in to comment.