diff options
| -rw-r--r-- | docs/spec/evaluate.html | 2 | ||||
| -rw-r--r-- | docs/spec/grammar.html | 38 | ||||
| -rw-r--r-- | docs/spec/inferred.html | 2 | ||||
| -rw-r--r-- | docs/spec/scope.html | 8 | ||||
| -rw-r--r-- | spec/evaluate.md | 2 | ||||
| -rw-r--r-- | spec/grammar.md | 38 | ||||
| -rw-r--r-- | spec/inferred.md | 2 | ||||
| -rw-r--r-- | spec/scope.md | 8 |
8 files changed, 52 insertions, 48 deletions
diff --git a/docs/spec/evaluate.html b/docs/spec/evaluate.html index 13d0c455..5d4a0eb7 100644 --- a/docs/spec/evaluate.html +++ b/docs/spec/evaluate.html @@ -13,7 +13,7 @@ <p>The result of parsing a valid BQN program is a <code><span class='Function'>PROGRAM</span></code>, and the program is run by evaluating this term.</p> <p>A <code><span class='Function'>PROGRAM</span></code> or <code><span class='Function'>BODY</span></code> is a list of <code><span class='Function'>STMT</span></code>s, which are evaluated in program order. A <code><span class='Function'>BODY</span></code> also allows an <code><span class='Function'>EXPR</span></code> followed by <code><span class='String'>"?"</span></code> in place of an <code><span class='Function'>STMT</span></code>: then the expression is evaluated as usual but its result is checked as discussed below. A result is always required for <code><span class='Function'>BODY</span></code> nodes, and sometimes for <code><span class='Function'>PROGRAM</span></code> nodes (for example, when loaded with <code><span class='Function'>β’Import</span></code>). If any identifiers in the node's scope are exported, or any of its statements is an <code><span class='Function'>EXPORT</span></code>, then the result is the namespace created in order to evaluate the node. If a result is required but the namespace case doesn't apply, then the last <code><span class='Function'>STMT</span></code> node must be an <code><span class='Function'>EXPR</span></code> and its result is used. The statement <code><span class='Function'>EXPR</span></code> evaluates some BQN code and possibly assigns the results, while <code><span class='Value'>nothing</span></code> evaluates any <code><span class='Value'>subject</span></code> or <code><span class='Function'>Derv</span></code> terms it contains but discards the results. An <code><span class='Function'>EXPORT</span></code> statement performs no action.</p> <p>A block consists of several <code><span class='Function'>BODY</span></code> terms, some of which may have an accompanying header describing accepted inputs and how they are processed. An immediate block <code><span class='Value'>brImm</span></code> can only have one <code><span class='Function'>BODY</span></code>, and is evaluated by evaluating it. Other types of blocks don't evaluate any <code><span class='Function'>BODY</span></code> immediately, but instead return a function or modifier that obtains its result by evaluating a particular <code><span class='Function'>BODY</span></code>. The <code><span class='Function'>BODY</span></code> is identified and evaluated once the block has received enough inputs (operands or arguments), which for modifiers can take one or two calls: if two calls are required, then on the first call the operands are simply stored and no code is evaluated yet. The stored values can be accessed by equality checking, or <code><span class='Function'>β’Decompose</span></code> if defined. Two calls are required if there is more than one <code><span class='Function'>BODY</span></code> term, if the <code><span class='Function'>BODY</span></code> contains the special names <code><span class='Value'>π¨π©π€</span><span class='Function'>πππ</span></code>, or if its header specifies arguments (the header-body combination is a <code><span class='Modifier'>_mCase</span></code> or <code><span class='Modifier2'>_cCase_</span></code>). Otherwise only one is required.</p> -<p>To evaluate a block when enough inputs have been received, first the correct case must be identified. To do this, first each special case (<code><span class='Function'>FCase</span></code>, <code><span class='Modifier'>_mCase</span></code>, or <code><span class='Modifier2'>_cCase_</span></code>), excluding <code><span class='Function'>FCase</span></code> nodes containing <code><span class='Function'>UndoHead</span></code>, is checked in order to see if its arguments are strucurally compatible with the given arguments. That is, is <code><span class='Value'>headW</span></code> is a <code><span class='Value'>subject</span></code>, there must be a left argument matching that structure, and if <code><span class='Value'>headX</span></code> is a <code><span class='Value'>subject</span></code>, the right argument must match that structure. This means that <code><span class='Value'>π¨</span></code> not only matches any left argument but also no argument. The test for compatibility is the same as for multiple assignment described below, except that the header may contain constants, which must match the corresponding part of the given argument. If no special case matches, then an appropriate general case (<code><span class='Function'>FMain</span></code>, <code><span class='Modifier'>_mMain</span></code>, or <code><span class='Modifier2'>_cMain_</span></code>) is used: if there are two, the first is used with no left argument and the second with a left argument; if there are one, it is always used, and if there are none, an error results.</p> +<p>To evaluate a block when enough inputs have been received, first the correct case must be identified. To do this, first each special case (<code><span class='Function'>I_CASE</span></code> or <code><span class='Function'>A_CASE</span></code>), excluding <code><span class='Function'>A_CASE</span></code> nodes whose <code><span class='Function'>ARG_HEAD</span></code> contains <code><span class='String'>"βΌ"</span></code>, is checked in order to see if its arguments are strucurally compatible with the given arguments. That is, is <code><span class='Value'>headW</span></code> is a <code><span class='Value'>subject</span></code>, there must be a left argument matching that structure, and if <code><span class='Value'>headX</span></code> is a <code><span class='Value'>subject</span></code>, the right argument must match that structure. This means that <code><span class='Value'>π¨</span></code> not only matches any left argument but also no argument. The test for compatibility is the same as for multiple assignment described below, except that the header may contain constants, which must match the corresponding part of the given argument. If no special case matches, then an appropriate general <code><span class='Function'>CASE</span></code> is used: if there are two, the first is used with no left argument and the second with a left argument; if there are one, it is always used, and if there are none, an error results.</p> <p>When a predicate <code><span class='String'>"?"</span></code> is evaluated, it may change the choice of case. The associated <code><span class='Function'>EXPR</span></code> is evaluated and its result is checked. If it's not one of the numbers <code><span class='Number'>0</span></code> or <code><span class='Number'>1</span></code>, an error results. If it's <code><span class='Number'>1</span></code>, evaluation of the <code><span class='Function'>BODY</span></code> continues as usual. If it's <code><span class='Number'>0</span></code>, evaluation is stopped and the next compatible <code><span class='Function'>BODY</span></code> term is evaluated using the block's original inputs.</p> <p>Inputs and other names are bound when evaluation of a <code><span class='Function'>BODY</span></code> is begun. Special names are always bound when applicable: <code><span class='Value'>π¨π©π€</span></code> if arguments are used, <code><span class='Value'>π¨</span></code> if there is a left argument, <code><span class='Value'>ππ</span></code> if operands are used, and <code><span class='Modifier'>_π£</span></code> and <code><span class='Modifier2'>_π£_</span></code> for modifiers and combinators, respectively. Any names in the header are also bound, allowing multiple assignment for arguments.</p> <p>If there is no left argument, but the <code><span class='Function'>BODY</span></code> contains <code><span class='Value'>π¨</span></code> or <code><span class='Function'>π</span></code> at the top level, then it is conceptually re-parsed with <code><span class='Value'>π¨</span></code> replaced by <code><span class='Nothing'>Β·</span></code> to give a monadic version before application; this modifies the syntax tree by replacing some instances of <code><span class='Value'>subject</span></code>, <code><span class='Value'>arg</span></code>, or <code><span class='Function'>Operand</span></code> with <code><span class='Value'>nothing</span></code>. The token <code><span class='Function'>π</span></code> is not allowed in this case and causes an error. Re-parsing <code><span class='Value'>π¨</span></code> can also cause an error if it's used as an operand or list element, where <code><span class='Value'>nothing</span></code> is not allowed by the grammar. Note that these errors must not appear if the block is always called with two arguments. True re-parsing is not required, as the same effect can also be achieved dynamically by treating <code><span class='Nothing'>Β·</span></code> as a value and checking for it during execution. If it's used as a left argument, then the function should instead be called with no left argument (and similarly in trains); if it's used as a right argument, then the function and its left argument are evaluated but rather than calling the function <code><span class='Nothing'>Β·</span></code> is "returned" immediately; and if it's used in another context then it causes an error.</p> diff --git a/docs/spec/grammar.html b/docs/spec/grammar.html index 66814649..7c9d038b 100644 --- a/docs/spec/grammar.html +++ b/docs/spec/grammar.html @@ -16,10 +16,10 @@ </pre> <p>Here we define the "atomic" forms of functions and modifiers, which are either single tokens or enclosed in paired symbols. Stranded lists with <code><span class='Ligature'>βΏ</span></code>, which binds more tightly than any form of execution, are also included.</p> <pre><span class='Function'>ANY</span> <span class='Function'>=</span> <span class='Value'>atom</span> <span class='Function'>|</span> <span class='Function'>Func</span> <span class='Function'>|</span> <span class='Modifier'>_mod1</span> <span class='Function'>|</span> <span class='Modifier2'>_mod2_</span> -<span class='Modifier2'>_mod2_</span> <span class='Function'>=</span> <span class='Paren'>(</span> <span class='Value'>atom</span> <span class='String'>"."</span> <span class='Paren'>)</span><span class='Value'>?</span> <span class='Modifier2'>_c_</span> <span class='Function'>|</span> <span class='Modifier2'>_cl_</span> <span class='Function'>|</span> <span class='String'>"("</span> <span class='Modifier2'>_m1Expr_</span> <span class='String'>")"</span> <span class='Function'>|</span> <span class='Modifier2'>_brMod2_</span> -<span class='Modifier'>_mod1</span> <span class='Function'>=</span> <span class='Paren'>(</span> <span class='Value'>atom</span> <span class='String'>"."</span> <span class='Paren'>)</span><span class='Value'>?</span> <span class='Modifier'>_m</span> <span class='Function'>|</span> <span class='Modifier'>_ml</span> <span class='Function'>|</span> <span class='String'>"("</span> <span class='Modifier'>_m2Expr</span> <span class='String'>")"</span> <span class='Function'>|</span> <span class='Modifier'>_brMod1</span> -<span class='Function'>Func</span> <span class='Function'>=</span> <span class='Paren'>(</span> <span class='Value'>atom</span> <span class='String'>"."</span> <span class='Paren'>)</span><span class='Value'>?</span> <span class='Function'>F</span> <span class='Function'>|</span> <span class='Function'>Fl</span> <span class='Function'>|</span> <span class='String'>"("</span> <span class='Function'>FuncExpr</span> <span class='String'>")"</span> <span class='Function'>|</span> <span class='Function'>BrFunc</span> -<span class='Value'>atom</span> <span class='Function'>=</span> <span class='Paren'>(</span> <span class='Value'>atom</span> <span class='String'>"."</span> <span class='Paren'>)</span><span class='Value'>?</span> <span class='Value'>s</span> <span class='Function'>|</span> <span class='Value'>sl</span> <span class='Function'>|</span> <span class='String'>"("</span> <span class='Value'>subExpr</span> <span class='String'>")"</span> <span class='Function'>|</span> <span class='Value'>brSub</span> <span class='Function'>|</span> <span class='Value'>list</span> +<span class='Modifier2'>_mod2_</span> <span class='Function'>=</span> <span class='Paren'>(</span> <span class='Value'>atom</span> <span class='String'>"."</span> <span class='Paren'>)</span><span class='Value'>?</span> <span class='Modifier2'>_c_</span> <span class='Function'>|</span> <span class='Modifier2'>_cl_</span> <span class='Function'>|</span> <span class='String'>"("</span> <span class='Modifier2'>_m1Expr_</span> <span class='String'>")"</span> <span class='Function'>|</span> <span class='Modifier2'>_blMod2_</span> +<span class='Modifier'>_mod1</span> <span class='Function'>=</span> <span class='Paren'>(</span> <span class='Value'>atom</span> <span class='String'>"."</span> <span class='Paren'>)</span><span class='Value'>?</span> <span class='Modifier'>_m</span> <span class='Function'>|</span> <span class='Modifier'>_ml</span> <span class='Function'>|</span> <span class='String'>"("</span> <span class='Modifier'>_m2Expr</span> <span class='String'>")"</span> <span class='Function'>|</span> <span class='Modifier'>_blMod1</span> +<span class='Function'>Func</span> <span class='Function'>=</span> <span class='Paren'>(</span> <span class='Value'>atom</span> <span class='String'>"."</span> <span class='Paren'>)</span><span class='Value'>?</span> <span class='Function'>F</span> <span class='Function'>|</span> <span class='Function'>Fl</span> <span class='Function'>|</span> <span class='String'>"("</span> <span class='Function'>FuncExpr</span> <span class='String'>")"</span> <span class='Function'>|</span> <span class='Function'>BlFunc</span> +<span class='Value'>atom</span> <span class='Function'>=</span> <span class='Paren'>(</span> <span class='Value'>atom</span> <span class='String'>"."</span> <span class='Paren'>)</span><span class='Value'>?</span> <span class='Value'>s</span> <span class='Function'>|</span> <span class='Value'>sl</span> <span class='Function'>|</span> <span class='String'>"("</span> <span class='Value'>subExpr</span> <span class='String'>")"</span> <span class='Function'>|</span> <span class='Value'>blSub</span> <span class='Function'>|</span> <span class='Value'>list</span> <span class='Value'>list</span> <span class='Function'>=</span> <span class='String'>"β¨"</span> <span class='Separator'>β</span><span class='Value'>?</span> <span class='Paren'>(</span> <span class='Paren'>(</span> <span class='Function'>EXPR</span> <span class='Separator'>β</span> <span class='Paren'>)</span><span class='Value'>*</span> <span class='Function'>EXPR</span> <span class='Separator'>β</span><span class='Value'>?</span> <span class='Paren'>)</span><span class='Value'>?</span> <span class='String'>"β©"</span> <span class='Value'>subject</span> <span class='Function'>=</span> <span class='Value'>atom</span> <span class='Function'>|</span> <span class='Function'>ANY</span> <span class='Paren'>(</span> <span class='String'>"βΏ"</span> <span class='Function'>ANY</span> <span class='Paren'>)</span><span class='Function'>+</span> </pre> @@ -80,19 +80,21 @@ <span class='Function'>|</span> <span class='Value'>headW?</span> <span class='Function'>IMM_HEAD</span> <span class='String'>"βΌ"</span><span class='Value'>?</span> <span class='Value'>headX</span> <span class='Function'>|</span> <span class='Value'>headW</span> <span class='Function'>IMM_HEAD</span> <span class='String'>"Λ"</span> <span class='String'>"βΌ"</span> <span class='Value'>headX</span> <span class='Function'>|</span> <span class='Function'>FuncName</span> <span class='String'>"Λ"</span><span class='Value'>?</span> <span class='String'>"βΌ"</span> - <span class='Function'>|</span> <span class='Function'>CaseHead</span> -<span class='Function'>CaseHead</span> <span class='Function'>=</span> <span class='Value'>sl</span> <span class='Function'>|</span> <span class='String'>"("</span> <span class='Value'>subExpr</span> <span class='String'>")"</span> <span class='Function'>|</span> <span class='Value'>brSub</span> <span class='Function'>|</span> <span class='Value'>list</span> <span class='Comment'># subject, + <span class='Function'>|</span> <span class='Value'>xHead</span> +<span class='Value'>xHead</span> <span class='Function'>=</span> <span class='Value'>sl</span> <span class='Function'>|</span> <span class='String'>"("</span> <span class='Value'>subExpr</span> <span class='String'>")"</span> <span class='Function'>|</span> <span class='Value'>blSub</span> <span class='Function'>|</span> <span class='Value'>list</span> <span class='Comment'># subject, </span> <span class='Function'>|</span> <span class='Function'>ANY</span> <span class='Paren'>(</span> <span class='String'>"βΏ"</span> <span class='Function'>ANY</span> <span class='Paren'>)</span><span class='Function'>+</span> <span class='Comment'># but not s </span></pre> <p>A braced block contains bodies, which are lists of statements, separated by semicolons and possibly preceded by headers, which are separated from the body with a colon. A non-final expression can be made into a predicate by following it with the separator-like <code><span class='Value'>?</span></code>. Multiple bodies allow different handling for various cases, which are pattern-matched by headers. A block can have any number of bodies with headers. After these there can be bodies without headersβup to one for an immediate block and up to two for a block with arguments. If a block with arguments has one such body, it's ambivalent, but two of them refer to the monadic and dyadic cases.</p> <pre><span class='Function'>BODY</span> <span class='Function'>=</span> <span class='Separator'>β</span><span class='Value'>?</span> <span class='Paren'>(</span> <span class='Function'>STMT</span> <span class='Separator'>β</span> <span class='Function'>|</span> <span class='Function'>EXPR</span> <span class='Separator'>β</span><span class='Value'>?</span> <span class='String'>"?"</span> <span class='Separator'>β</span><span class='Value'>?</span> <span class='Paren'>)</span><span class='Value'>*</span> <span class='Function'>STMT</span> <span class='Separator'>β</span><span class='Value'>?</span> -<span class='Function'>IMM_BLK</span> <span class='Function'>=</span> <span class='String'>"{"</span> <span class='Paren'>(</span> <span class='Separator'>β</span><span class='Value'>?</span> <span class='Function'>IMM_HEAD</span> <span class='Separator'>β</span><span class='Value'>?</span> <span class='String'>":"</span> <span class='Function'>BODY</span> <span class='String'>";"</span> <span class='Paren'>)</span><span class='Value'>*</span> <span class='Function'>BODY</span><span class='Value'>?</span> <span class='String'>"}"</span> -<span class='Function'>ARG_BLK</span> <span class='Function'>=</span> <span class='String'>"{"</span> <span class='Paren'>(</span> <span class='Separator'>β</span><span class='Value'>?</span> <span class='Function'>ARG_HEAD</span> <span class='Separator'>β</span><span class='Value'>?</span> <span class='String'>":"</span> <span class='Function'>BODY</span> <span class='String'>";"</span> <span class='Paren'>)</span><span class='Value'>*</span> <span class='Paren'>(</span> <span class='Function'>BODY</span> <span class='Paren'>(</span> <span class='String'>";"</span> <span class='Function'>BODY</span> <span class='Paren'>)</span><span class='Value'>?</span> <span class='Paren'>)</span><span class='Value'>?</span> <span class='String'>"}"</span> -<span class='Function'>BLOCK</span> <span class='Function'>=</span> <span class='Function'>IMM_BLOCK</span> <span class='Function'>|</span> <span class='Function'>ARG_BLOCK</span> -<span class='Value'>brSub</span> <span class='Function'>=</span> <span class='String'>"{"</span> <span class='Paren'>(</span> <span class='Separator'>β</span><span class='Value'>?</span> <span class='Value'>s</span> <span class='String'>":"</span> <span class='Paren'>)</span><span class='Value'>?</span> <span class='Function'>BODY</span> <span class='String'>"}"</span> -<span class='Function'>BrFunc</span> <span class='Function'>=</span> <span class='Function'>BLOCK</span> -<span class='Modifier'>_brMod1</span> <span class='Function'>=</span> <span class='Function'>BLOCK</span> -<span class='Modifier2'>_brMod2_</span> <span class='Function'>=</span> <span class='Function'>BLOCK</span> +<span class='Function'>CASE</span> <span class='Function'>=</span> <span class='Function'>BODY</span> +<span class='Function'>I_CASE</span> <span class='Function'>=</span> <span class='Separator'>β</span><span class='Value'>?</span> <span class='Function'>IMM_HEAD</span> <span class='Separator'>β</span><span class='Value'>?</span> <span class='String'>":"</span> <span class='Function'>BODY</span> +<span class='Function'>A_CASE</span> <span class='Function'>=</span> <span class='Separator'>β</span><span class='Value'>?</span> <span class='Function'>ARG_HEAD</span> <span class='Separator'>β</span><span class='Value'>?</span> <span class='String'>":"</span> <span class='Function'>BODY</span> +<span class='Function'>IMM_BLK</span> <span class='Function'>=</span> <span class='String'>"{"</span> <span class='Paren'>(</span> <span class='Function'>I_CASE</span> <span class='String'>";"</span> <span class='Paren'>)</span><span class='Value'>*</span> <span class='Paren'>(</span> <span class='Function'>I_CASE</span> <span class='Function'>|</span> <span class='Function'>CASE</span> <span class='Paren'>)</span> <span class='String'>"}"</span> +<span class='Function'>ARG_BLK</span> <span class='Function'>=</span> <span class='String'>"{"</span> <span class='Paren'>(</span> <span class='Function'>A_CASE</span> <span class='String'>";"</span> <span class='Paren'>)</span><span class='Value'>*</span> <span class='Paren'>(</span> <span class='Function'>A_CASE</span> <span class='Function'>|</span> <span class='Function'>CASE</span> <span class='Paren'>(</span> <span class='String'>";"</span> <span class='Function'>CASE</span> <span class='Paren'>)</span><span class='Value'>?</span> <span class='Paren'>)</span> <span class='String'>"}"</span> +<span class='Value'>blSub</span> <span class='Function'>=</span> <span class='String'>"{"</span> <span class='Paren'>(</span> <span class='Separator'>β</span><span class='Value'>?</span> <span class='Value'>s</span> <span class='Separator'>β</span><span class='Value'>?</span> <span class='String'>":"</span> <span class='Paren'>)</span><span class='Value'>?</span> <span class='Function'>BODY</span> <span class='String'>"}"</span> +<span class='Function'>BlFunc</span> <span class='Function'>=</span> <span class='Function'>ARG_BLK</span> +<span class='Modifier'>_blMod1</span> <span class='Function'>=</span> <span class='Function'>IMM_BLK</span> <span class='Function'>|</span> <span class='Function'>ARG_BLK</span> +<span class='Modifier2'>_blMod2_</span> <span class='Function'>=</span> <span class='Function'>IMM_BLK</span> <span class='Function'>|</span> <span class='Function'>ARG_BLK</span> </pre> <p>Three additional rules apply to blocks, allowing the ambiguous grammar above to be disambiguated. They are shown in the table below. First, each block type allows the special names in its row to be used as the given token types within <code><span class='Function'>BODY</span></code> terms (not headers). Except for the spaces labelled "None", each of these four columns is cumulative, so that a given entry also includes all the entries above it. Second, a block can't contain one of the tokens from the "label" column of a different row. Third, each <code><span class='Function'>BrFunc</span></code>, <code><span class='Modifier'>_brMod1</span></code>, and <code><span class='Modifier2'>_brMod2_</span></code> term <em>must</em> contain one of the names on, and not above, the corresponding row (including the "label" column).</p> <table> @@ -108,7 +110,7 @@ </thead> <tbody> <tr> -<td><code><span class='Value'>brSub</span></code>, <code><span class='Function'>PROGRAM</span></code></td> +<td><code><span class='Value'>blSub</span></code>, <code><span class='Function'>PROGRAM</span></code></td> <td>None</td> <td>None</td> <td>None</td> @@ -116,7 +118,7 @@ <td>None</td> </tr> <tr> -<td><code><span class='Function'>BrFunc</span></code></td> +<td><code><span class='Function'>BlFunc</span></code></td> <td><code><span class='Value'>π¨π©π€</span></code></td> <td><code><span class='Function'>πππ</span></code></td> <td></td> @@ -124,7 +126,7 @@ <td><code><span class='Function'>FuncLab</span></code></td> </tr> <tr> -<td><code><span class='Modifier'>_brMod1</span></code></td> +<td><code><span class='Modifier'>_blMod1</span></code></td> <td><code><span class='Value'>ππ£</span></code></td> <td><code><span class='Function'>π½</span></code></td> <td><code><span class='Modifier'>_π£</span></code></td> @@ -132,7 +134,7 @@ <td><code><span class='Function'>Mod1Lab</span></code></td> </tr> <tr> -<td><code><span class='Modifier2'>_brMod2_</span></code></td> +<td><code><span class='Modifier2'>_blMod2_</span></code></td> <td><code><span class='Value'>π</span></code></td> <td><code><span class='Function'>πΎ</span></code></td> <td>None</td> @@ -141,7 +143,7 @@ </tr> </tbody> </table> -<p>The rules for special name can be expressed in BNF by making many copies of all expression rules above. For each "level", or row in the table, a new version of every rule should be made that allows that level but not higher ones, and another version should be made that requires exactly that level. The values themselves should be included in <code><span class='Value'>s</span></code>, <code><span class='Function'>F</span></code>, <code><span class='Modifier'>_m</span></code>, and <code><span class='Modifier2'>_c_</span></code> for these copies. Then the "allowed" rules are made simply by replacing the terms they contain (excluding <code><span class='Value'>brSub</span></code> and so on) with the same "allowed" versions, and "required" rules are constructed using both "allowed" and "required" rules. For every part of a production rule, an alternative should be created that requires the relevant name in that part while allowing it in the others. For example, <code><span class='Paren'>(</span> <span class='Value'>subject</span> <span class='Function'>|</span> <span class='Value'>nothing</span> <span class='Paren'>)</span><span class='Value'>?</span> <span class='Function'>Derv</span> <span class='Value'>arg</span></code> would be transformed to</p> +<p>The rules for special names can be expressed in BNF by making many copies of all expression rules above. For each "level", or row in the table, a new version of every rule should be made that allows that level but not higher ones, and another version should be made that requires exactly that level. The values themselves should be included in <code><span class='Value'>s</span></code>, <code><span class='Function'>F</span></code>, <code><span class='Modifier'>_m</span></code>, and <code><span class='Modifier2'>_c_</span></code> for these copies. Then the "allowed" rules are made simply by replacing the terms they contain (excluding <code><span class='Value'>blSub</span></code> and so on) with the same "allowed" versions, and "required" rules are constructed using both "allowed" and "required" rules. For every part of a production rule, an alternative should be created that requires the relevant name in that part while allowing it in the others. For example, <code><span class='Paren'>(</span> <span class='Value'>subject</span> <span class='Function'>|</span> <span class='Value'>nothing</span> <span class='Paren'>)</span><span class='Value'>?</span> <span class='Function'>Derv</span> <span class='Value'>arg</span></code> would be transformed to</p> <pre><span class='Value'>arg_req1</span> <span class='Function'>=</span> <span class='Value'>subExpr_req1</span> <span class='Function'>|</span> <span class='Paren'>(</span> <span class='Value'>subject_req1</span> <span class='Function'>|</span> <span class='Value'>nothing_req1</span> <span class='Paren'>)</span> <span class='Function'>Derv_allow1</span> <span class='Value'>arg_allow1</span> <span class='Function'>|</span> <span class='Paren'>(</span> <span class='Value'>subject_allow1</span> <span class='Function'>|</span> <span class='Value'>nothing_allow1</span> <span class='Paren'>)</span><span class='Value'>?</span> <span class='Function'>Derv_req1</span> <span class='Value'>arg_allow1</span> diff --git a/docs/spec/inferred.html b/docs/spec/inferred.html index a0ffd819..a221ede0 100644 --- a/docs/spec/inferred.html +++ b/docs/spec/inferred.html @@ -470,7 +470,7 @@ </tbody> </table> <h3 id="undo-headers"><a class="header" href="#undo-headers">Undo headers</a></h3> -<p>An <code><span class='Function'>UndoHead</span></code> header specifies how a block function acts when undone. Like ordinary headers, undo headers are searched for a match when a block function <code><span class='Function'>F</span></code> is undone, or when <code><span class='Function'>F</span><span class='Modifier'>Λ</span></code> is undone with two arguments (including the two modifier cases <code><span class='Function'>π½</span><span class='Modifier2'>β</span><span class='Value'>k</span></code> and <code><span class='Function'>π½πΎ</span><span class='Value'>k</span></code> from the previous section). An <code><span class='Function'>UndoHead</span></code> without <code><span class='String'>"Λ"</span></code> matches the <code><span class='Function'>F</span><span class='Modifier'>βΌ</span></code> case while one with <code><span class='String'>"Λ"</span></code> matches the <code><span class='Function'>F</span><span class='Modifier'>ΛβΌ</span></code> case. The left and right arguments are matched to <code><span class='Value'>headW</span></code> and <code><span class='Value'>headX</span></code> as with ordinary headers, and the first matching case is evaluated to give the result of the Undo-derived function.</p> +<p>An <code><span class='Function'>ARG_HEAD</span></code> header containing <code><span class='String'>"βΌ"</span></code> specifies how a block function acts when undone. Like ordinary headers, undo headers are searched for a match when a block function <code><span class='Function'>F</span></code> is undone, or when <code><span class='Function'>F</span><span class='Modifier'>Λ</span></code> is undone with two arguments (including the two modifier cases <code><span class='Function'>π½</span><span class='Modifier2'>β</span><span class='Value'>k</span></code> and <code><span class='Function'>π½πΎ</span><span class='Value'>k</span></code> from the previous section). An <code><span class='Function'>ARG_HEAD</span></code> without <code><span class='String'>"Λ"</span></code> matches the <code><span class='Function'>F</span><span class='Modifier'>βΌ</span></code> case while one with <code><span class='String'>"Λ"</span></code> matches the <code><span class='Function'>F</span><span class='Modifier'>ΛβΌ</span></code> case. The left and right arguments are matched to <code><span class='Value'>headW</span></code> and <code><span class='Value'>headX</span></code> as with ordinary headers, and the first matching case is evaluated to give the result of the Undo-derived function.</p> <h2 id="under"><a class="header" href="#under">Under</a></h2> <p>The Under 2-modifier <code><span class='Modifier2'>βΎ</span></code> conceptually applies its left operand under the action of its right operand. Setting <code><span class='Value'>z</span><span class='Gets'>β</span><span class='Value'>π¨</span><span class='Function'>π½</span><span class='Modifier2'>βΎ</span><span class='Function'>πΎ</span><span class='Value'>π©</span></code>, it satisfies <code><span class='Paren'>(</span><span class='Value'>π¨</span><span class='Function'>π½</span><span class='Modifier2'>β</span><span class='Function'>πΎ</span><span class='Value'>π©</span><span class='Paren'>)</span> <span class='Function'>β‘</span> <span class='Function'>πΎ</span><span class='Value'>z</span></code>. We might say that <code><span class='Function'>πΎ</span></code> transforms values to a new domain, and <code><span class='Modifier2'>βΎ</span><span class='Function'>πΎ</span></code> lifts actions <code><span class='Function'>π½</span></code> performed in this domain to the original domain of values. For example, addition in the logarithmic domain corresponds to multiplication in the linear domain: <code><span class='Function'>+</span><span class='Modifier2'>βΎ</span><span class='Paren'>(</span><span class='Function'>β</span><span class='Modifier'>βΌ</span><span class='Paren'>)</span></code> is <code><span class='Function'>Γ</span></code> (but less precise if computed in floating point).</p> <p>Let <code><span class='Value'>v</span><span class='Gets'>β</span><span class='Value'>π¨</span><span class='Function'>π½</span><span class='Modifier2'>β</span><span class='Function'>πΎ</span><span class='Value'>π©</span></code>, so that <code><span class='Value'>v</span><span class='Function'>β‘πΎ</span><span class='Value'>z</span></code>. <code><span class='Value'>v</span></code> is of course well-defined, so the inference step is to find <code><span class='Value'>z</span></code> based on <code><span class='Value'>v</span></code> and possibly the original inputs. We distinguish three cases for Under:</p> diff --git a/docs/spec/scope.html b/docs/spec/scope.html index a4663def..2a230ede 100644 --- a/docs/spec/scope.html +++ b/docs/spec/scope.html @@ -9,7 +9,7 @@ <p>A running BQN program manipulates variables during its <a href="evaluate.html">execution</a>, but it is important to distinguish these variables from the identifiers that refer to them. As defined in the <a href="token.html">tokenization rules</a>, an identifier is a particular kind of token found in a program's source code. The lexical scoping rules in this page define which identifiers are considered the same; these identifiers will refer to the same variables when the program is run. While each variable has only one identifier, an identifier can refer to any number of variables because a new variable is created for that identifier each time its containing scope is instantiated (that is, each time the contents of the block are evaluated).</p> <h2 id="identifier-equivalence-with-lexical-scoping"><a class="header" href="#identifier-equivalence-with-lexical-scoping">Identifier equivalence with lexical scoping</a></h2> <p>In this section the concept of an identifier's definition, a possibly different instance of that identifier, is specified. The definition determines when identifiers refer to the "same thing". In concrete terms, identifiers with the same definition all manipulate the same variable in a particular instance of the definition's containing scope.</p> -<p>A <em>scope</em> is a <code><span class='Function'>PROGRAM</span></code>, <code><span class='Value'>brSub</span></code>, <code><span class='Function'>FCase</span></code>, <code><span class='Function'>FMain</span></code>, <code><span class='Modifier'>_mCase</span></code>, <code><span class='Modifier'>_mMain</span></code>, <code><span class='Modifier2'>_cCase_</span></code>, <code><span class='Modifier2'>_cMain_</span></code>, or <code><span class='Value'>brNS</span></code> node as defined by the BQN <a href="grammar.html">grammar</a>. An <em>identifier instance</em> is an <code><span class='Value'>s</span></code>, <code><span class='Function'>F</span></code>, <code><span class='Modifier'>_m</span></code>, or <code><span class='Modifier2'>_c_</span></code> node; its <em>containing scope</em> is the "smallest" scope that contains itβthe scope that contains the identifier but not any other scopes containing the identifier. An identifier instance is <em>defined</em> when it is contained in the left hand side of an <code><span class='Gets'>β</span></code> assignment expression, that is, the leftmost component of one of the five grammatical rules with <code><span class='Function'>ASGN</span></code>, provided that the <code><span class='Function'>ASGN</span></code> node is <code><span class='String'>"β"</span></code> or <code><span class='String'>"β"</span></code>, or in a scope header, that is, a component immediately preceding <code><span class='String'>":"</span></code>. Each identifier instance in a valid BQN program corresponds to exactly one such defined identifier, called its <em>definition</em>, and two instances are considered to refer to the same identifier if they have the same definition.</p> +<p>A <em>scope</em> is a <code><span class='Function'>PROGRAM</span></code>, <code><span class='Value'>blSub</span></code>, <code><span class='Function'>CASE</span></code>, <code><span class='Function'>I_CASE</span></code>, or <code><span class='Function'>A_CASE</span></code> node as defined by the BQN <a href="grammar.html">grammar</a>. An <em>identifier instance</em> is an <code><span class='Value'>s</span></code>, <code><span class='Function'>F</span></code>, <code><span class='Modifier'>_m</span></code>, or <code><span class='Modifier2'>_c_</span></code> node; its <em>containing scope</em> is the "smallest" scope that contains itβthe scope that contains the identifier but not any other scopes containing the identifier. An identifier instance is <em>defined</em> when it is contained in the left hand side of an <code><span class='Gets'>β</span></code> assignment expression, that is, the leftmost component of one of the four grammatical rules with <code><span class='Function'>ASGN</span></code>, provided that the <code><span class='Function'>ASGN</span></code> node is <code><span class='String'>"β"</span></code> or <code><span class='String'>"β"</span></code>, or in a scope header, that is, <code><span class='Function'>IMM_HEAD</span></code>, <code><span class='Function'>ARG_HEAD</span></code>, or the <code><span class='Value'>s</span></code> term in <code><span class='Value'>blSub</span></code>. Each identifier instance in a valid BQN program corresponds to exactly one such defined identifier, called its <em>definition</em>, and two instances are considered to refer to the same identifier if they have the same definition.</p> <p>Two identifier instances have the <em>same name</em> if their tokens, as strings, match after removing all underscores <code><span class='Modifier2'>_</span></code> and ignoring case (so that the letters a to z are equal to their uppercase equivalents A to Z for this comparison). However, instances with the same name are not necessarily the same identifier, as they must also have the same definition. A defined identifier is a <em>potential definition</em> of another identifier instance if the two have the same name, and either:</p> <ul> <li>The defined identifier's containing scope contains the other identifier's containing scope, or</li> @@ -17,11 +17,11 @@ <li>The two identifiers are the same instance (a defined variable is its own definition).</li> </ul> <p>The definition for an identifier is chosen from the potential definitions based on their containing scopes: it is the one whose containing scope does not contain or match the containing scope of any other potential definition. If for any identifier there is no definition, then the program is not valid and results in an error. This can occur if the identifier has no potential definition, and also if two potential definitions appear in the same scope. In fact, under this scheme it is never valid to make two definitions with the same name at the top level of a single scope, because both definitions would be potential definitions for the one that comes second in program order. Both definitions have the same containing scope, and any potential definition must contain or match this scope, so no potential definition can be selected.</p> -<p>The definition of <em>program order</em> for identifier tokens follows the order of BQN <a href="evaluate.html">execution</a>. It corresponds to the order of a particular traversal of the abstract syntax tree for a program. To find the relative ordering of two identifiers in a program, we consider the highest-depth node that they both belong to; in this node they must occur in different components, or that component would be a higher-depth node containing both of them. In most nodes, the program order goes from right to left: components further to the right come earlier in program order. The exceptions are <code><span class='Function'>PROGRAM</span></code>, <code><span class='Function'>BODY</span></code>, <code><span class='Function'>NS_BODY</span></code>, <code><span class='Value'>list</span></code>, <code><span class='Value'>subject</span></code> (for stranding), and body case (<code><span class='Function'>FCase</span></code>, <code><span class='Modifier'>_mCase</span></code>, <code><span class='Modifier2'>_cCase_</span></code>, <code><span class='Function'>FMain</span></code>, <code><span class='Modifier'>_mMain</span></code>, <code><span class='Modifier2'>_cMain_</span></code>, <code><span class='Value'>brSub</span></code>, <code><span class='Function'>BrFunc</span></code>, <code><span class='Modifier'>_brMod1</span></code>, and <code><span class='Modifier2'>_brMod2_</span></code>) nodes, in which program order goes in the opposite order, from left to right (some assignment target nodes also contain lists or strands, but their ordering is irrelevant because if two identifiers with the same name appear in such a list, then it can't be a definition).</p> -<p>A subject label is the <code><span class='Value'>s</span></code> term in a <code><span class='Value'>brSub</span></code> node. As part of a header, it can serve as the definition for an identifier. However, it's defined to be a syntax error if another instance of this identifier appears, except in a <code><span class='Function'>Return</span></code> node (which cannot access its value).</p> +<p>The definition of <em>program order</em> for identifier tokens follows the order of BQN <a href="evaluate.html">execution</a>. It corresponds to the order of a particular traversal of the abstract syntax tree for a program. To find the relative ordering of two identifiers in a program, we consider the highest-depth node that they both belong to; in this node they must occur in different components, or that component would be a higher-depth node containing both of them. In most nodes, the program order goes from right to left: components further to the right come earlier in program order. The exceptions are <code><span class='Function'>PROGRAM</span></code>, <code><span class='Function'>BODY</span></code>, <code><span class='Value'>list</span></code>, <code><span class='Value'>subject</span></code> (for stranding), and body structure (<code><span class='Function'>I_CASE</span></code>, <code><span class='Function'>A_CASE</span></code>, <code><span class='Function'>IMM_BLK</span></code>, <code><span class='Function'>ARG_BLK</span></code>, and <code><span class='Value'>blSub</span></code>) nodes, in which program order goes in the opposite order, from left to right (some assignment target nodes also contain lists or strands, but their ordering is irrelevant because if two identifiers with the same name appear in such a list, then it can't be a definition).</p> +<p>A subject label is the <code><span class='Value'>s</span></code> term in a <code><span class='Value'>blSub</span></code> node. As part of a header, it can serve as the definition for an identifier. However, it's defined to be a syntax error if another instance of this identifier appears.</p> <h3 id="special-names"><a class="header" href="#special-names">Special names</a></h3> <p>Special names such as <code><span class='Value'>π©</span></code> or <code><span class='Value'>π£</span></code> refer to variables, but have no definition and do not use scoping. Instead, they always refer to the immediately enclosing scope, and are defined automatically when the block is evaluated.</p> -<p>The six special names are <code><span class='Value'>π¨π©πππ€π£</span></code>, and the tokens <code><span class='Function'>πππ½πΎπ</span></code>, <code><span class='Modifier'>_π£</span></code>, and <code><span class='Modifier2'>_π£_</span></code> are alternate spellings of these names as described in the <a href="token.html">tokenization rules</a>. Special names may be modified with <code><span class='Gets'>β©</span></code> assignment but cannot appear as the target of other kinds of assignment. Two special names represent the same identifier if they are the same name and appear in the same body. The initial value these names have is defined by the <a href="evaluate.html">evaluation rules</a>; the grammar for blocks ensures that all special names used in a block will be defined (possibly as the special value <code><span class='Nothing'>Β·</span></code> in the case of <code><span class='Value'>π¨</span></code>).</p> +<p>The six special names are <code><span class='Value'>π¨π©πππ€π£</span></code>, and the tokens <code><span class='Function'>πππ½πΎπ</span></code>, <code><span class='Modifier'>_π£</span></code>, and <code><span class='Modifier2'>_π£_</span></code> are alternate spellings of these names as described in the <a href="token.html">tokenization rules</a>. Special names may be modified with <code><span class='Gets'>β©</span></code> assignment but cannot appear as the target of other kinds of assignment. Two special names represent the same identifier if they are the same name and appear in the same body (more precisely, the set of <code><span class='Function'>BODY</span></code> nodes that contains each is the same). The initial value these names have is defined by the <a href="evaluate.html">evaluation rules</a>; the grammar for blocks ensures that all special names used in a block will be defined (possibly as the special value <code><span class='Nothing'>Β·</span></code> in the case of <code><span class='Value'>π¨</span></code>).</p> <h3 id="imports-and-exports"><a class="header" href="#imports-and-exports">Imports and exports</a></h3> <p>Names that are preceded by an <code><span class='Value'>atom</span> <span class='String'>"."</span></code> term, or that appear as <code><span class='Function'>LHS_NAME</span></code> terms in an <code><span class='Function'>NS_VAR</span></code> or <code><span class='Value'>lhsNs</span></code>, are variable references in a namespace: in the first case, the result of the <code><span class='Value'>atom</span></code> node, and in the second, of the overall assignments <code><span class='Value'>subExpr</span></code> right hand side. These names do not follow lexical scoping; in general they must be stored in order to perform a name lookup when the namespace is available. Such a name in <code><span class='Value'>lhsNs</span></code>, or in <code><span class='Function'>NS_VAR</span></code> with no accompanying <code><span class='Value'>lhs</span> <span class='String'>"β"</span></code> term, additionally serves as an identifier within the actual enclosing scope, which works like any other assignment.</p> <p>An identifier is <em>exported</em> if the <code><span class='Function'>ASGN</span></code> node in its definition is <code><span class='String'>"β"</span></code>, or if it appears anywhere in an <code><span class='Function'>EXPORT</span></code> term. An identifier can only be exported in the scope where it is defined, and not in a containing scope. An <code><span class='Function'>EXPORT</span></code> term that includes an identifier from such a scope causes an error.</p> diff --git a/spec/evaluate.md b/spec/evaluate.md index c991e3c6..fbc97087 100644 --- a/spec/evaluate.md +++ b/spec/evaluate.md @@ -18,7 +18,7 @@ A `PROGRAM` or `BODY` is a list of `STMT`s, which are evaluated in program order A block consists of several `BODY` terms, some of which may have an accompanying header describing accepted inputs and how they are processed. An immediate block `brImm` can only have one `BODY`, and is evaluated by evaluating it. Other types of blocks don't evaluate any `BODY` immediately, but instead return a function or modifier that obtains its result by evaluating a particular `BODY`. The `BODY` is identified and evaluated once the block has received enough inputs (operands or arguments), which for modifiers can take one or two calls: if two calls are required, then on the first call the operands are simply stored and no code is evaluated yet. The stored values can be accessed by equality checking, or `β’Decompose` if defined. Two calls are required if there is more than one `BODY` term, if the `BODY` contains the special names `π¨π©π€πππ`, or if its header specifies arguments (the header-body combination is a `_mCase` or `_cCase_`). Otherwise only one is required. -To evaluate a block when enough inputs have been received, first the correct case must be identified. To do this, first each special case (`FCase`, `_mCase`, or `_cCase_`), excluding `FCase` nodes containing `UndoHead`, is checked in order to see if its arguments are strucurally compatible with the given arguments. That is, is `headW` is a `subject`, there must be a left argument matching that structure, and if `headX` is a `subject`, the right argument must match that structure. This means that `π¨` not only matches any left argument but also no argument. The test for compatibility is the same as for multiple assignment described below, except that the header may contain constants, which must match the corresponding part of the given argument. If no special case matches, then an appropriate general case (`FMain`, `_mMain`, or `_cMain_`) is used: if there are two, the first is used with no left argument and the second with a left argument; if there are one, it is always used, and if there are none, an error results. +To evaluate a block when enough inputs have been received, first the correct case must be identified. To do this, first each special case (`I_CASE` or `A_CASE`), excluding `A_CASE` nodes whose `ARG_HEAD` contains `"βΌ"`, is checked in order to see if its arguments are strucurally compatible with the given arguments. That is, is `headW` is a `subject`, there must be a left argument matching that structure, and if `headX` is a `subject`, the right argument must match that structure. This means that `π¨` not only matches any left argument but also no argument. The test for compatibility is the same as for multiple assignment described below, except that the header may contain constants, which must match the corresponding part of the given argument. If no special case matches, then an appropriate general `CASE` is used: if there are two, the first is used with no left argument and the second with a left argument; if there are one, it is always used, and if there are none, an error results. When a predicate `"?"` is evaluated, it may change the choice of case. The associated `EXPR` is evaluated and its result is checked. If it's not one of the numbers `0` or `1`, an error results. If it's `1`, evaluation of the `BODY` continues as usual. If it's `0`, evaluation is stopped and the next compatible `BODY` term is evaluated using the block's original inputs. diff --git a/spec/grammar.md b/spec/grammar.md index 5167dac9..7e4ca950 100644 --- a/spec/grammar.md +++ b/spec/grammar.md @@ -17,10 +17,10 @@ A program is a list of statements. Almost all statements are expressions. Namesp Here we define the "atomic" forms of functions and modifiers, which are either single tokens or enclosed in paired symbols. Stranded lists with `βΏ`, which binds more tightly than any form of execution, are also included. ANY = atom | Func | _mod1 | _mod2_ - _mod2_ = ( atom "." )? _c_ | _cl_ | "(" _m1Expr_ ")" | _brMod2_ - _mod1 = ( atom "." )? _m | _ml | "(" _m2Expr ")" | _brMod1 - Func = ( atom "." )? F | Fl | "(" FuncExpr ")" | BrFunc - atom = ( atom "." )? s | sl | "(" subExpr ")" | brSub | list + _mod2_ = ( atom "." )? _c_ | _cl_ | "(" _m1Expr_ ")" | _blMod2_ + _mod1 = ( atom "." )? _m | _ml | "(" _m2Expr ")" | _blMod1 + Func = ( atom "." )? F | Fl | "(" FuncExpr ")" | BlFunc + atom = ( atom "." )? s | sl | "(" subExpr ")" | blSub | list list = "β¨" β? ( ( EXPR β )* EXPR β? )? "β©" subject = atom | ANY ( "βΏ" ANY )+ @@ -86,31 +86,33 @@ There are some extra possibilities for a header that specifies arguments. As a s | headW? IMM_HEAD "βΌ"? headX | headW IMM_HEAD "Λ" "βΌ" headX | FuncName "Λ"? "βΌ" - | CaseHead - CaseHead = sl | "(" subExpr ")" | brSub | list # subject, + | xHead + xHead = sl | "(" subExpr ")" | blSub | list # subject, | ANY ( "βΏ" ANY )+ # but not s A braced block contains bodies, which are lists of statements, separated by semicolons and possibly preceded by headers, which are separated from the body with a colon. A non-final expression can be made into a predicate by following it with the separator-like `?`. Multiple bodies allow different handling for various cases, which are pattern-matched by headers. A block can have any number of bodies with headers. After these there can be bodies without headersβup to one for an immediate block and up to two for a block with arguments. If a block with arguments has one such body, it's ambivalent, but two of them refer to the monadic and dyadic cases. BODY = β? ( STMT β | EXPR β? "?" β? )* STMT β? - IMM_BLK = "{" ( β? IMM_HEAD β? ":" BODY ";" )* BODY? "}" - ARG_BLK = "{" ( β? ARG_HEAD β? ":" BODY ";" )* ( BODY ( ";" BODY )? )? "}" - BLOCK = IMM_BLOCK | ARG_BLOCK - brSub = "{" ( β? s ":" )? BODY "}" - BrFunc = BLOCK - _brMod1 = BLOCK - _brMod2_ = BLOCK + CASE = BODY + I_CASE = β? IMM_HEAD β? ":" BODY + A_CASE = β? ARG_HEAD β? ":" BODY + IMM_BLK = "{" ( I_CASE ";" )* ( I_CASE | CASE ) "}" + ARG_BLK = "{" ( A_CASE ";" )* ( A_CASE | CASE ( ";" CASE )? ) "}" + blSub = "{" ( β? s β? ":" )? BODY "}" + BlFunc = ARG_BLK + _blMod1 = IMM_BLK | ARG_BLK + _blMod2_ = IMM_BLK | ARG_BLK Three additional rules apply to blocks, allowing the ambiguous grammar above to be disambiguated. They are shown in the table below. First, each block type allows the special names in its row to be used as the given token types within `BODY` terms (not headers). Except for the spaces labelled "None", each of these four columns is cumulative, so that a given entry also includes all the entries above it. Second, a block can't contain one of the tokens from the "label" column of a different row. Third, each `BrFunc`, `_brMod1`, and `_brMod2_` term *must* contain one of the names on, and not above, the corresponding row (including the "label" column). | Term | `s` | `F` | `_m` | `_c_` | label |--------------------|--------|--------|---------|----------|------- -| `brSub`, `PROGRAM` | None | None | None | None | None -| `BrFunc` | `π¨π©π€` | `πππ` | | | `FuncLab` -| `_brMod1` | `ππ£` | `π½` | `_π£` | | `Mod1Lab` -| `_brMod2_` | `π` | `πΎ` | None | `_π£_` | `Mod2Lab` +| `blSub`, `PROGRAM` | None | None | None | None | None +| `BlFunc` | `π¨π©π€` | `πππ` | | | `FuncLab` +| `_blMod1` | `ππ£` | `π½` | `_π£` | | `Mod1Lab` +| `_blMod2_` | `π` | `πΎ` | None | `_π£_` | `Mod2Lab` -The rules for special name can be expressed in BNF by making many copies of all expression rules above. For each "level", or row in the table, a new version of every rule should be made that allows that level but not higher ones, and another version should be made that requires exactly that level. The values themselves should be included in `s`, `F`, `_m`, and `_c_` for these copies. Then the "allowed" rules are made simply by replacing the terms they contain (excluding `brSub` and so on) with the same "allowed" versions, and "required" rules are constructed using both "allowed" and "required" rules. For every part of a production rule, an alternative should be created that requires the relevant name in that part while allowing it in the others. For example, `( subject | nothing )? Derv arg` would be transformed to +The rules for special names can be expressed in BNF by making many copies of all expression rules above. For each "level", or row in the table, a new version of every rule should be made that allows that level but not higher ones, and another version should be made that requires exactly that level. The values themselves should be included in `s`, `F`, `_m`, and `_c_` for these copies. Then the "allowed" rules are made simply by replacing the terms they contain (excluding `blSub` and so on) with the same "allowed" versions, and "required" rules are constructed using both "allowed" and "required" rules. For every part of a production rule, an alternative should be created that requires the relevant name in that part while allowing it in the others. For example, `( subject | nothing )? Derv arg` would be transformed to arg_req1 = subExpr_req1 | ( subject_req1 | nothing_req1 ) Derv_allow1 arg_allow1 diff --git a/spec/inferred.md b/spec/inferred.md index 847bd83c..5ed454b7 100644 --- a/spec/inferred.md +++ b/spec/inferred.md @@ -164,7 +164,7 @@ Inverses of other modifiers and derived functions or modifiers obtained from the ### Undo headers -An `UndoHead` header specifies how a block function acts when undone. Like ordinary headers, undo headers are searched for a match when a block function `F` is undone, or when `FΛ` is undone with two arguments (including the two modifier cases `π½βk` and `π½πΎk` from the previous section). An `UndoHead` without `"Λ"` matches the `FβΌ` case while one with `"Λ"` matches the `FΛβΌ` case. The left and right arguments are matched to `headW` and `headX` as with ordinary headers, and the first matching case is evaluated to give the result of the Undo-derived function. +An `ARG_HEAD` header containing `"βΌ"` specifies how a block function acts when undone. Like ordinary headers, undo headers are searched for a match when a block function `F` is undone, or when `FΛ` is undone with two arguments (including the two modifier cases `π½βk` and `π½πΎk` from the previous section). An `ARG_HEAD` without `"Λ"` matches the `FβΌ` case while one with `"Λ"` matches the `FΛβΌ` case. The left and right arguments are matched to `headW` and `headX` as with ordinary headers, and the first matching case is evaluated to give the result of the Undo-derived function. ## Under diff --git a/spec/scope.md b/spec/scope.md index 893348fb..d03ef29d 100644 --- a/spec/scope.md +++ b/spec/scope.md @@ -10,7 +10,7 @@ A running BQN program manipulates variables during its [execution](evaluate.md), In this section the concept of an identifier's definition, a possibly different instance of that identifier, is specified. The definition determines when identifiers refer to the "same thing". In concrete terms, identifiers with the same definition all manipulate the same variable in a particular instance of the definition's containing scope. -A *scope* is a `PROGRAM`, `brSub`, `FCase`, `FMain`, `_mCase`, `_mMain`, `_cCase_`, `_cMain_`, or `brNS` node as defined by the BQN [grammar](grammar.md). An *identifier instance* is an `s`, `F`, `_m`, or `_c_` node; its *containing scope* is the "smallest" scope that contains itβthe scope that contains the identifier but not any other scopes containing the identifier. An identifier instance is *defined* when it is contained in the left hand side of an `β` assignment expression, that is, the leftmost component of one of the five grammatical rules with `ASGN`, provided that the `ASGN` node is `"β"` or `"β"`, or in a scope header, that is, a component immediately preceding `":"`. Each identifier instance in a valid BQN program corresponds to exactly one such defined identifier, called its *definition*, and two instances are considered to refer to the same identifier if they have the same definition. +A *scope* is a `PROGRAM`, `blSub`, `CASE`, `I_CASE`, or `A_CASE` node as defined by the BQN [grammar](grammar.md). An *identifier instance* is an `s`, `F`, `_m`, or `_c_` node; its *containing scope* is the "smallest" scope that contains itβthe scope that contains the identifier but not any other scopes containing the identifier. An identifier instance is *defined* when it is contained in the left hand side of an `β` assignment expression, that is, the leftmost component of one of the four grammatical rules with `ASGN`, provided that the `ASGN` node is `"β"` or `"β"`, or in a scope header, that is, `IMM_HEAD`, `ARG_HEAD`, or the `s` term in `blSub`. Each identifier instance in a valid BQN program corresponds to exactly one such defined identifier, called its *definition*, and two instances are considered to refer to the same identifier if they have the same definition. Two identifier instances have the *same name* if their tokens, as strings, match after removing all underscores `_` and ignoring case (so that the letters a to z are equal to their uppercase equivalents A to Z for this comparison). However, instances with the same name are not necessarily the same identifier, as they must also have the same definition. A defined identifier is a *potential definition* of another identifier instance if the two have the same name, and either: - The defined identifier's containing scope contains the other identifier's containing scope, or @@ -18,15 +18,15 @@ Two identifier instances have the *same name* if their tokens, as strings, match - The two identifiers are the same instance (a defined variable is its own definition). The definition for an identifier is chosen from the potential definitions based on their containing scopes: it is the one whose containing scope does not contain or match the containing scope of any other potential definition. If for any identifier there is no definition, then the program is not valid and results in an error. This can occur if the identifier has no potential definition, and also if two potential definitions appear in the same scope. In fact, under this scheme it is never valid to make two definitions with the same name at the top level of a single scope, because both definitions would be potential definitions for the one that comes second in program order. Both definitions have the same containing scope, and any potential definition must contain or match this scope, so no potential definition can be selected. -The definition of *program order* for identifier tokens follows the order of BQN [execution](evaluate.md). It corresponds to the order of a particular traversal of the abstract syntax tree for a program. To find the relative ordering of two identifiers in a program, we consider the highest-depth node that they both belong to; in this node they must occur in different components, or that component would be a higher-depth node containing both of them. In most nodes, the program order goes from right to left: components further to the right come earlier in program order. The exceptions are `PROGRAM`, `BODY`, `NS_BODY`, `list`, `subject` (for stranding), and body case (`FCase`, `_mCase`, `_cCase_`, `FMain`, `_mMain`, `_cMain_`, `brSub`, `BrFunc`, `_brMod1`, and `_brMod2_`) nodes, in which program order goes in the opposite order, from left to right (some assignment target nodes also contain lists or strands, but their ordering is irrelevant because if two identifiers with the same name appear in such a list, then it can't be a definition). +The definition of *program order* for identifier tokens follows the order of BQN [execution](evaluate.md). It corresponds to the order of a particular traversal of the abstract syntax tree for a program. To find the relative ordering of two identifiers in a program, we consider the highest-depth node that they both belong to; in this node they must occur in different components, or that component would be a higher-depth node containing both of them. In most nodes, the program order goes from right to left: components further to the right come earlier in program order. The exceptions are `PROGRAM`, `BODY`, `list`, `subject` (for stranding), and body structure (`I_CASE`, `A_CASE`, `IMM_BLK`, `ARG_BLK`, and `blSub`) nodes, in which program order goes in the opposite order, from left to right (some assignment target nodes also contain lists or strands, but their ordering is irrelevant because if two identifiers with the same name appear in such a list, then it can't be a definition). -A subject label is the `s` term in a `brSub` node. As part of a header, it can serve as the definition for an identifier. However, it's defined to be a syntax error if another instance of this identifier appears, except in a `Return` node (which cannot access its value). +A subject label is the `s` term in a `blSub` node. As part of a header, it can serve as the definition for an identifier. However, it's defined to be a syntax error if another instance of this identifier appears. ### Special names Special names such as `π©` or `π£` refer to variables, but have no definition and do not use scoping. Instead, they always refer to the immediately enclosing scope, and are defined automatically when the block is evaluated. -The six special names are `π¨π©πππ€π£`, and the tokens `πππ½πΎπ`, `_π£`, and `_π£_` are alternate spellings of these names as described in the [tokenization rules](token.md). Special names may be modified with `β©` assignment but cannot appear as the target of other kinds of assignment. Two special names represent the same identifier if they are the same name and appear in the same body. The initial value these names have is defined by the [evaluation rules](evaluate.md); the grammar for blocks ensures that all special names used in a block will be defined (possibly as the special value `Β·` in the case of `π¨`). +The six special names are `π¨π©πππ€π£`, and the tokens `πππ½πΎπ`, `_π£`, and `_π£_` are alternate spellings of these names as described in the [tokenization rules](token.md). Special names may be modified with `β©` assignment but cannot appear as the target of other kinds of assignment. Two special names represent the same identifier if they are the same name and appear in the same body (more precisely, the set of `BODY` nodes that contains each is the same). The initial value these names have is defined by the [evaluation rules](evaluate.md); the grammar for blocks ensures that all special names used in a block will be defined (possibly as the special value `Β·` in the case of `π¨`). ### Imports and exports |
