From 369b8cdcc6f1e9c99357bacd8ef84177a3f5f9b5 Mon Sep 17 00:00:00 2001 From: felix Date: Thu, 14 Sep 2017 14:56:39 -0700 Subject: [PATCH] Clarify details for the execution environment for actions (#531) * Clarify execution environment of actions and predicates * Makes a new section for describing the common execution environment * Add the new section to TOC * Clarify start/end for predicates * Clarify the scope of labels --- README.md | 181 ++++++++++++++++++++++++++---------------------------- 1 file changed, 87 insertions(+), 94 deletions(-) diff --git a/README.md b/README.md index c3ad4c3..c567001 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ Table of Contents * [Case-insensitivity](#case-insensitivity) * [Backtracking](#backtracking) * [Parsing Expression Types](#parsing-expression-types) + * [Action Execution Environment](#action-execution-environment) - [Error Messages](#error-messages) - [Compatibility](#compatibility) - [Development](#development) @@ -430,69 +431,31 @@ Try to match the expression. If the match does not succeed, just return #### & { *predicate* } -The predicate is a piece of JavaScript code that is executed as if it was inside -a function. It gets the match results of labeled expressions in preceding -expression as its arguments. It should return some JavaScript value using the -`return` statement. If the returned value evaluates to `true` in boolean -context, just return `undefined` and do not consume any input; otherwise -consider the match failed. - -The code inside the predicate can access all variables and functions defined in -the initializer at the beginning of the grammar. +This is a positive assertion. No input is consumed. -The code inside the predicate can also access location information using the -`location` function. It returns an object like this: +The predicate should be JavaScript code, and it's executed as a +function. Curly braces in the predicate must be balanced. -```javascript -{ - start: { offset: 23, line: 5, column: 6 }, - end: { offset: 23, line: 5, column: 6 } -} -``` +The predicate should `return` a boolean value. If the result is +truthy, the match result is `undefined`, otherwise the match is +considered failed. -The `start` and `end` properties both refer to the current parse position. The -`offset` property contains an offset as a zero-based index and `line` and -`column` properties contain a line and a column as one-based indices. - -Line and column are somewhat expensive to compute, so if you just need the -offset, there's also a function `offset` that returns just the start offset, -and a function `range` that returns the array `[start, end]` offsets. - -The code inside the predicate can also access options passed to the parser using -the `options` variable. - -Note that curly braces in the predicate code must be balanced. +The predicate has access to all variables and functions in the +[Action Execution Environment](#action-execution-environment). #### ! { *predicate* } -The predicate is a piece of JavaScript code that is executed as if it was inside -a function. It gets the match results of labeled expressions in preceding -expression as its arguments. It should return some JavaScript value using the -`return` statement. If the returned value evaluates to `false` in boolean -context, just return `undefined` and do not consume any input; otherwise -consider the match failed. - -The code inside the predicate can access all variables and functions defined in -the initializer at the beginning of the grammar. +This is a negative assertion. No input is consumed. -The code inside the predicate can also access location information using the -`location` function. It returns an object like this: +The predicate should be JavaScript code, and it's executed as a +function. Curly braces in the predicate must be balanced. -```javascript -{ - start: { offset: 23, line: 5, column: 6 }, - end: { offset: 23, line: 5, column: 6 } -} -``` - -The `start` and `end` properties both refer to the current parse position. The -`offset` property contains an offset as a zero-based index and `line` and -`column` properties contain a line and a column as one-based indices. - -The code inside the predicate can also access options passed to the parser using -the `options` variable. +The predicate should `return` a boolean value. If the result is +falsy, the match result is `undefined`, otherwise the match is +considered failed. -Note that curly braces in the predicate code must be balanced. +The predicate has access to all variables and functions in the +[Action Execution Environment](#action-execution-environment). #### $ *expression* @@ -513,60 +476,90 @@ Match a sequence of expressions and return their match results in an array. #### *expression* { *action* } -Match the expression. If the match is successful, run the action, otherwise +If the expression matches successfully, run the action, otherwise consider the match failed. -The action is a piece of JavaScript code that is executed as if it was inside a -function. It gets the match results of labeled expressions in preceding -expression as its arguments. The action should return some JavaScript value -using the `return` statement. This value is considered match result of the -preceding expression. +The action should be JavaScript code, and it's executed as a +function. Curly braces in the action must be balanced. -To indicate an error, the code inside the action can invoke the `expected` -function, which makes the parser throw an exception. The function takes two -parameters — a description of what was expected at the current position and -optional location information (the default is what `location` would return — see -below). The description will be used as part of a message of the thrown -exception. +The action should `return` some value, which will be used as the +match result of the expression. -The code inside an action can also invoke the `error` function, which also makes -the parser throw an exception. The function takes two parameters — an error -message and optional location information (the default is what `location` would -return — see below). The message will be used by the thrown exception. +The action has access to all variables and functions in the +[Action Execution Environment](#action-execution-environment). -The code inside the action can access all variables and functions defined in the -initializer at the beginning of the grammar. Curly braces in the action code -must be balanced. +#### *expression1* / *expression2* / ... / *expressionn* -The code inside the action can also access the text matched by the expression -using the `text` function. +Try to match the first expression, if it does not succeed, try the second one, +etc. Return the match result of the first successfully matched expression. If no +expression matches, consider the match failed. +### Action Execution Environment -The code inside the action can also access location information using the -`location` function. It returns an object like this: +Actions and predicates have these variables and functions +available to them. -```javascript -{ - start: { offset: 23, line: 5, column: 6 }, - end: { offset: 25, line: 5, column: 8 } -} -``` +* All variables and functions defined in the initializer at the + beginning of the grammar are available. -The `start` property refers to the position at the beginning of the expression, -the `end` property refers to position after the end of the expression. The -`offset` property contains an offset as a zero-based index and `line` and -`column` properties contain a line and a column as one-based indices. +* Labels from preceding expressions are available as local + variables, which will have the match result of the labelled + expressions. -The code inside the action can also access options passed to the parser using -the `options` variable. + A label is only available after its labelled expression is + matched: -Note that curly braces in the action code must be balanced. + ```pegjs + rule = A:('a' B:'b' { /* B is available, A is not */ } ) + ``` -#### *expression1* / *expression2* / ... / *expressionn* + A label in a sub-expression is only valid within the + sub-expression: -Try to match the first expression, if it does not succeed, try the second one, -etc. Return the match result of the first successfully matched expression. If no -expression matches, consider the match failed. + ```pegjs + rule = A:'a' (B: 'b') (C: 'b' { /* A and C are available, B is not */ }) + ``` + + +* `options` is a variable that contains the parser options. + +* `error(message, where)` will report an error and throw an + exception. `where` is optional; the default is the value of + `location()`. + +* `expected(message, where)` is similar to `error`, but reports + > Expected _message_ but "_other_" found. + +* `location()` returns an object like this: + + ```javascript + { + start: { offset: 23, line: 5, column: 6 }, + end: { offset: 25, line: 5, column: 8 } + } + ``` + + For actions, `start` refers to the position at the beginning of + the preceding expression, and `end` refers to the position + after the end of the preceding expression. + + For predicates, `start` and `end` are the same, the location + where the predicate is evaluated. + + `offset` is a 0-based character index within the source text. + `line` and `column` are 1-based indices. + + Note that `line` and `column` are somewhat expensive to + compute, so if you need location frequently, you might want to + use `offset()` or `range()` instead. + +* `offset()` returns the start offset. + +* `range()` returns an array containing the start and end + offsets, such as `[23, 25]`. + +* `text()` returns the source text between `start` and `end` + (which will be "" for predicates). Error Messages --------------