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
[smart pipes] Add support for question-mark tokens #9209
Changes from all commits
d030528
d2fc3c8
0541cc4
33bc375
420bcc7
5803f28
1504356
cbcd5de
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -983,29 +983,11 @@ export default class ExpressionParser extends LValParser { | |
} | ||
|
||
case tt.hash: { | ||
if (this.state.inPipeline) { | ||
node = this.startNode(); | ||
|
||
if ( | ||
this.getPluginOption("pipelineOperator", "proposal") !== "smart" | ||
) { | ||
this.raise( | ||
node.start, | ||
"Primary Topic Reference found but pipelineOperator not passed 'smart' for 'proposal' option.", | ||
); | ||
} | ||
return this.parsePrimaryTopicReference("#"); | ||
} | ||
|
||
this.next(); | ||
if (this.primaryTopicReferenceIsAllowedInCurrentTopicContext()) { | ||
this.registerTopicReference(); | ||
return this.finishNode(node, "PipelinePrimaryTopicReference"); | ||
} else { | ||
throw this.raise( | ||
node.start, | ||
`Topic reference was used in a lexical context without topic binding`, | ||
); | ||
} | ||
} | ||
case tt.question: { | ||
return this.parsePrimaryTopicReference("?"); | ||
} | ||
|
||
default: | ||
|
@@ -2110,6 +2092,82 @@ export default class ExpressionParser extends LValParser { | |
return this.finishNode(node, "YieldExpression"); | ||
} | ||
|
||
// Parses a smart-pipeline primary topic reference. | ||
// The pipelineOperator plugin must be active, and its proposal option must be "smart". | ||
// The topicToken argument is "#" or "?" and is matched against the topicToken option | ||
// given to the pipelineOperator plugin's topicToken option (which is "#" by default). | ||
|
||
parsePrimaryTopicReference( | ||
topicToken: N.PipelineProposedTopicToken, | ||
): N.PipelinePrimaryTopicReference { | ||
if (this.state.inPipeline) { | ||
const node = this.startNode(); | ||
|
||
if (this.getPluginOption("pipelineOperator", "proposal") !== "smart") { | ||
this.raise( | ||
node.start, | ||
"Topic reference found but pipelineOperator plugin was not passed 'smart' " + | ||
"for 'proposal' option.", | ||
); | ||
} | ||
|
||
this.validateTopicToken(topicToken); | ||
this.next(); | ||
|
||
if (this.primaryTopicReferenceIsAllowedInCurrentTopicContext()) { | ||
this.registerTopicReference(); | ||
return this.finishNode(node, "PipelinePrimaryTopicReference"); | ||
} else { | ||
throw this.raise( | ||
node.start, | ||
`Topic reference was used in a lexical context without topic binding`, | ||
); | ||
} | ||
} else { | ||
throw this.unexpected(); | ||
} | ||
} | ||
|
||
// Asserts that the given topic token is valid under the pipelineOperator plugin's | ||
// topicToken configuration option. | ||
|
||
validateTopicToken(topicToken: N.PipelineProposedTopicToken): void { | ||
if (!this.matchesTopicTokenConfiguration(topicToken)) { | ||
const node = this.startNode(); | ||
const topicTokenOption = this.getPipelineOperatorPluginTopicTokenOption(); | ||
const message = topicTokenOption | ||
? `Pipeline was used with ${topicToken} topic token, but ` + | ||
`pipelineOperator plugin was passed a "topicToken": ` + | ||
`"${topicTokenOption}" option` | ||
: `Pipeline was used with ${topicToken} topic token, but ` + | ||
`pipelineOperator plugin was not passed a "topicToken" option, which ` + | ||
`is "#" by default`; | ||
this.raise(node.start, message); | ||
} | ||
} | ||
|
||
// Tests whether a topic-token string is the same as the pipelineOperator plugin's | ||
// topicToken configuration option. | ||
|
||
matchesTopicTokenConfiguration( | ||
topicToken: N.PipelineProposedTopicToken, | ||
): boolean { | ||
const defaultTopicToken = "#"; | ||
const pluginConfigurationTopicToken = this.getPluginOption( | ||
"pipelineOperator", | ||
"topicToken", | ||
); | ||
const effectivePluginConfigurationTopicToken = | ||
pluginConfigurationTopicToken || defaultTopicToken; | ||
return effectivePluginConfigurationTopicToken === topicToken; | ||
} | ||
|
||
// Returns the value of the pipelineOperator plugin's topicToken configuration option. | ||
|
||
getPipelineOperatorPluginTopicTokenOption(): ?string { | ||
return this.getPluginOption("pipelineOperator", "topicToken"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think that having functions like this one is overkill: it has a name so long that it doesn't gain anything in readability neither in typing. Also, the name is basically the same as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Understood; I’ll inline this. |
||
} | ||
|
||
// Validates a pipeline (for any of the pipeline Babylon plugins) at the point | ||
// of the infix operator `|>`. | ||
|
||
|
@@ -2191,7 +2249,7 @@ export default class ExpressionParser extends LValParser { | |
if (!this.topicReferenceWasUsedInCurrentTopicContext()) { | ||
throw this.raise( | ||
startPos, | ||
`Pipeline is in topic style but does not use topic reference`, | ||
`Pipeline is in topic style but does not use any topic reference`, | ||
); | ||
} | ||
bodyNode.expression = childExpression; | ||
|
@@ -2269,8 +2327,8 @@ export default class ExpressionParser extends LValParser { | |
} | ||
} | ||
|
||
// Register the use of a primary topic reference (`#`) within the current | ||
// topic context. | ||
// For the smart-pipelines plugin. | ||
// Register the use of a primary topic reference within the current topic context. | ||
registerTopicReference(): void { | ||
this.state.topicContext.maxTopicIndex = 0; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
x |> ?; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"plugins": [["pipelineOperator", { "proposal": "smart" }]], | ||
"throws": "Pipeline was used with ? topic token, but pipelineOperator plugin was not passed a \"topicToken\" option, which is \"#\" by default (1:5)" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"plugins": [["pipelineOperator", { "proposal": "smart" }]], | ||
"throws": "Pipeline is in topic style but does not use any topic reference (1:5)" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"plugins": [["pipelineOperator", { "proposal": "smart" }]], | ||
"throws": "Pipeline is in topic style but does not use any topic reference (1:16)" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"plugins": [["pipelineOperator", { "proposal": "smart" }]], | ||
"throws": "Pipeline is in topic style but does not use any topic reference (1:5)" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"plugins": [["pipelineOperator", { "proposal": "smart" }]], | ||
"throws": "Pipeline is in topic style but does not use any topic reference (1:11)" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"plugins": [["pipelineOperator", { "proposal": "smart" }]], | ||
"throws": "Pipeline is in topic style but does not use any topic reference (1:5)" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"plugins": [["pipelineOperator", { "proposal": "smart" }]], | ||
"throws": "Pipeline is in topic style but does not use any topic reference (1:9)" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"plugins": [["pipelineOperator", { "proposal": "smart" }]], | ||
"throws": "Pipeline is in topic style but does not use any topic reference (1:9)" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"plugins": [["pipelineOperator", { "proposal": "smart" }]], | ||
"throws": "Pipeline is in topic style but does not use any topic reference (1:9)" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"plugins": [["pipelineOperator", { "proposal": "smart" }]], | ||
"throws": "Pipeline is in topic style but does not use any topic reference (1:9)" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
let result = "hello" | ||
|> doubleSay | ||
|> text.capitalize | ||
|> a.b.exclaim; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"plugins": [["pipelineOperator", { "proposal": "smart", "topicToken": "?" }]] | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add a parameter to the
getPluginOption
function for the default value? Then it would be enough to doand it wouldn't be necessary to use this separate function (that check could directly go in the if statement).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Understood; I’ll replace this.