Files
meteor/examples/unfinished/jsparse-docs/jsparse-docs.html
David Greenspan 11f98e0748 include jsparse-docs app in main repo
Under examples/unfinished.  Was in my personal repo.

This app displays a nicely-formatted full reference for the jsparse syntax tree.
2012-12-10 15:27:09 -08:00

280 lines
12 KiB
HTML

<head>
<title>jsparse Docs</title>
</head>
<body>
<div id="page">
{{> page}}
</div>
</body>
<template name="page">
<div class="topnotes">
<p>This is the spec for the JavaScript syntax tree returned by <code>jsparse</code>.</p>
<p>It's notable that <em>every token</em> from the source code appears in order in this syntax tree, which
is a Concrete Syntax Tree (CST) rather than an abstract AST.</p>
{{spacer}}
<p>The tree consists of <strong>nodes</strong>
and <strong>tokens</strong>. A node consists of a name followed
by zero or more child nodes or tokens. A token consists of
one or more characters from the source code.</p>
<p>For example, the following tree, which might have come from parsing <code>1 + 2</code>,
contains nodes named <span class="str">"binary"</span>,
<span class="str">"number"</span>, and <span class="str">"number"</span>
and the tokens <span class="token">1</span>, <span class="token">+</span>,
and <span class="token">2</span>:</p>
<p>{{#nodespec}}["binary", ["number", `1`], `+`, ["number", `2`]]{{/nodespec}}</p>
{{spacer}}
<p>The following notation is used throughout this document to give schematic definitions of
the different types of nodes.</p>
<p>An <span class="ref">italicized</span> word refers to a list of one or more possible
nodes or tokens that could fill a certain spot. For example, the following is the
definition of the <span class="str">"binary"</span> node:</p>
<p>{{#nodespec}}["binary", expression, binaryOp, expression]{{/nodespec}}</p>
<p>The <span class="ref">expression</span> spot could be filled by one of over 20 types
of expression nodes, and if you look up <span class="ref">binaryOp</span> you'll see
it refers to any of a list of binary operator tokens.</p>
<p>A vertical bar (<span class="punc or">|</span>) separates alternatives, of which exactly
one must be present in the tree. An ellipsis (<span class="punc">...</span>) stands
for a sequence of <em>zero or more</em> of the preceding item. For example:</p>
{{#nodespec}}["program", (statement | functionDecl), ...]{{/nodespec}}
<p>This definition says that a program node contains zero or more items, each of which may be either a
<span class="ref">statement</span> or a <span class="ref">functionDecl</span>.</p>
<p>A question mark (<span class="punct">?</span>) indicates that the previous item
(or items enclosed in parentheses) may or may not present.</p>
<p>Token classes like <span class="tokentype">IDENTIFIER</span> match any token in the class. The <span class="tokentype">BOOLEAN</span>, <span class="tokentype">NUMBER</span>, <span class="tokentype">STRING</span>, and <span class="tokentype">REGEX</span> classes are all literals. An example <span class="tokentype">STRING</span> would be <span class="token">"hello"</span>.
{{spacer}}
<p>Some definitions with ellipses may seem strangely permissive, such as:</p>
{{#nodespec}}["varStmnt", `var`, (varDecl | `,`), ..., semi]{{/nodespec}}
<p>This seems to say that <code>var;</code> and <code>var,,x,</code> are valid statements.
The reason for this style of definition is to discourage reliance on exact comma
positions, which may occasionally vary between JavaScript implementations and versions.
For example, the 5th edition of ECMAScript allows a trailing comma in object literals whereas
the 3rd edition doesn't.</p>
<p>For most applications, the commas aren't that important, and you can read all the varDecls
by just skipping any commas you encounter.</p>
</div>
{{#nodespec}}program:{{/nodespec}}
<div class="indent">
{{#nodespec}}["program", (statement | functionDecl), ...]{{/nodespec}}
</div>
{{#nodespec}}statement:{{/nodespec}}
<div class="indent">
{{#nodespec}}["expressionStmnt", expression, semi]{{/nodespec}}
<div class="explan">
<p>Function calls and assignments are expressions.</p>
</div>
{{#nodespec}}["emptyStmnt", `;`]{{/nodespec}}
<div class="explan">
<p>Only an actual <span class="token">;</span> token can create an empty statement.</p>
</div>
{{#nodespec}}["blockStmnt", `{`, statement, ..., `}`]{{/nodespec}}
{{#nodespec}}["varStmnt", `var`, (varDecl | `,`), ..., semi]{{/nodespec}}
<div class="explan">
<p>You can assume at least one varDecl is present.</p>
</div>
{{#nodespec}}["ifStmnt", `if`, `(`, expression, `)`, statement, (`else`, statement)?]{{/nodespec}}
{{#nodespec}}["whileStmnt", `while`, `(`, expression, `)`, statement]{{/nodespec}}
{{#nodespec}}["doStmnt", `do`, statement, `while`, `(`, expression, `)`, semi]{{/nodespec}}
{{#nodespec}}["forStmnt", `for`, `(`, forSpec, `)`, statement]{{/nodespec}}
{{#nodespec}}["returnStmnt", `return`, (expression | nil), semi]{{/nodespec}}
{{#nodespec}}["continueStmnt", `continue`, (IDENTIFIER | nil), semi]{{/nodespec}}
{{#nodespec}}["breakStmnt", `break`, (IDENTIFIER | nil), semi]{{/nodespec}}
{{#nodespec}}["throwStmnt", `throw`, expression, semi]{{/nodespec}}
{{#nodespec}}["withStmnt", `with`, `(`, expression, `)`, statement]{{/nodespec}}
{{#nodespec}}["switchStmnt", `switch`, `(`, expression, `)`, `{`, (case | default), ..., `}`]{{/nodespec}}
<div class="explan">
<p>There's at most one default clause, but it can be anywhere in the list of cases and defaults.</p>
</div>
{{#nodespec}}["tryStmnt", `try`, statement, (catch | nil), (finally | nil)]{{/nodespec}}
<div class="explan">
<p>The statement is always a blockStmnt.</p>
</div>
{{#nodespec}}["labelStmnt", IDENTIFIER, `:`, statement]{{/nodespec}}
{{#nodespec}}["debuggerStmnt", `debugger`, semi]{{/nodespec}}
</div>
{{#nodespec}}functionDecl:{{/nodespec}}
<div class="indent">
{{#nodespec}}["functionDecl", `function`, IDENTIFIER, `(`, (IDENTIFIER | `,`), ..., `)`, `{`, (statement | functionDecl), ..., `}`]{{/nodespec}}
<div class="explan">
<p>Different from a functionExpr only in that the function name is required and not optional.</p>
</div>
</div>
{{#nodespec}}expression:{{/nodespec}}
<div class="indent">
{{#nodespec}}["this", `this`]{{/nodespec}}
{{#nodespec}}["null", `null`]{{/nodespec}}
{{#nodespec}}["number", NUMBER]{{/nodespec}}
{{#nodespec}}["boolean", BOOLEAN]{{/nodespec}}
{{#nodespec}}["regex", REGEX]{{/nodespec}}
{{#nodespec}}["string", STRING]{{/nodespec}}
{{#nodespec}}["identifier", IDENTIFIER]{{/nodespec}}
{{#nodespec}}["parens", `(`, expression, `)`]{{/nodespec}}
{{#nodespec}}["array", `[`, (expression | `,`), ..., `]`]{{/nodespec}}
<div class="explan">
<p>All commas are significant because of element elision, and any
combination of commas and expressions is possible.
The array <code>[,,,7,,8,,]</code> has 7 and 8 as
its 3rd and 5th elements.</p>
</div>
{{#nodespec}}["object", `{`, (prop | `,`), ..., `}`]{{/nodespec}}
{{#nodespec}}["functionExpr", `function`, (IDENTIFIER | nil), `(`, (IDENTIFIER | `,`), ..., `)`, `{`, (statement | functionDecl), ..., `}`]{{/nodespec}}
{{#nodespec}}["dot", expression, `.`, identifierName]{{/nodespec}}
{{#nodespec}}["bracket", expression, `[`, expression, `]`]{{/nodespec}}
{{#nodespec}}["call", expression, `(`, (expression | `,`), ..., `)`]{{/nodespec}}
{{#nodespec}}["new", `new`, expression]{{/nodespec}}
{{#nodespec}}["newcall", `new`, expression, `(`, (expression | `,`), ..., `)`]{{/nodespec}}
{{#nodespec}}["unary", unaryOp, expression]{{/nodespec}}
{{#nodespec}}["binary", expression, binaryOp, expression]{{/nodespec}}
{{#nodespec}}["postfix", expression, postfixOp]{{/nodespec}}
{{#nodespec}}["ternary", expression, `?`, expression, `:`, expression]{{/nodespec}}
{{#nodespec}}["assignment", expression, assignmentOp, expression]{{/nodespec}}
<div class="explan">
<p>There is no simple constraint on what the first expression can be.
A left-hand-side expression could be a simple identifier like <code>foo</code>,
or it could be any expression ending in a property access, such as <code>foo().bar[baz]</code>.
Parentheses are also allowed around the left-hand side, so surprisingly <code>((x)) = 3</code>
is completely legal and equivalent to <code>x = 3</code>. This is because
JavaScript evaluates the left-hand side all the way down to the final variable reference.</p>
</div>
{{#nodespec}}["comma", (expression | `,`), ...]{{/nodespec}}
<div class="explan"><p>You can assume there are at least two expressions, since there would have been no comma otherwise.</p></div>
</div>
{{#nodespec}}nil:{{/nodespec}}
<div class="indent">
{{#nodespec}}["nil"]{{/nodespec}}
<div class="explan"><p>Serves as a placeholder for optional parts of nodes.</p></div>
</div>
{{#nodespec}}semi:{{/nodespec}}
<div class="indent">
{{#nodespec}}[";"] | `;`{{/nodespec}}
<div class="explan">
<p>An optional semicolon at the end of a statement. Most semicolons in JavaScript can legally
be omitted if a line break follows. If the semicolon was omitted, a <span class="str">";"</span>
node takes its place.</p>
</div>
</div>
{{#nodespec}}prop:{{/nodespec}}
<div class="indent">
{{#nodespec}}["prop", propertyName, `:`, expression]{{/nodespec}}
</div>
{{#nodespec}}propertyName:{{/nodespec}}
<div class="indent">
{{#nodespec}}["idPropName", identifierName]{{/nodespec}}
{{#nodespec}}["strPropName", STRING]{{/nodespec}}
{{#nodespec}}["numPropName", NUMBER]{{/nodespec}}
<div class="explan">
<p>A property name in an object literal can be given as a bare identifier, a quoted string literal,
or a number literal. These nodes indicate which it is.</p>
</div>
</div>
{{#nodespec}}varDecl:{{/nodespec}}
<div class="indent">
{{#nodespec}}["varDecl", IDENTIFIER, (`=`, expression)?]{{/nodespec}}
</div>
{{#nodespec}}forSpec:{{/nodespec}}
<div class="indent">
{{#nodespec}}["forSpec", (expression | nil), `;`, (expression | nil), `;`, (expression | nil)]{{/nodespec}}
{{#nodespec}}["forVarSpec", `var`, (varDecl | `,`), ..., `;`, (expression | nil), `;`, (expression | nil)]{{/nodespec}}
{{#nodespec}}["forInSpec", expression, `in`, expression]{{/nodespec}}
{{#nodespec}}["forVarInSpec", `var`, varDecl, `in`, expression]{{/nodespec}}
<div class="explan">
<p>There are technically four types of for-loops in JavaScript.</p>
<p>These definitions suggest some
odd possibilities, and interestingly, they work. The form <code>for (x.foo in y)</code> will actually
set <code>x.foo</code> each time through the loop, and <code>for (var x = bar() in y)</code> will call
<code>bar()</code> and assign it first thing,
even if <code>x</code> is immediately overwritten before the first iteration of the loop.</p>
<p>The semicolons are mandatory, even at a line break.</p>
</div>
</div>
{{#nodespec}}case:{{/nodespec}}
<div class="indent">
{{#nodespec}}["case", `case`, expression, `:`, statement, ...]{{/nodespec}}
</div>
{{#nodespec}}default:{{/nodespec}}
<div class="indent">
{{#nodespec}}["default", `default`, `:`, statement, ...]{{/nodespec}}
</div>
{{#nodespec}}catch:{{/nodespec}}
<div class="indent">
{{#nodespec}}["catch", `catch`, `(`, IDENTIFIER, `)`, statement]{{/nodespec}}
<div class="explan">
<p>The statement is always a blockStmnt.</p>
</div>
</div>
{{#nodespec}}finally:{{/nodespec}}
<div class="indent">
{{#nodespec}}["finally", `finally`, statement]{{/nodespec}}
<div class="explan">
<p>The statement is always a blockStmnt.</p>
</div>
</div>
{{#nodespec}}identifierName:{{/nodespec}}
<div class="indent">
{{#nodespec}}(IDENTIFIER | KEYWORD | BOOLEAN | `null`){{/nodespec}}
<div class="explan">
<p>As of ECMAScript 5th edition, keywords and reserved words can be used in some places
where an identifier is expected. For example, <code>x.return()</code> or
<code>{true: 'yes'}</code>.</p>
</div>
</div>
{{#nodespec}}unaryOp:{{/nodespec}}
<div class="indent">
{{#nodespec}}(`delete` | `void` | `typeof` | `++` | `--` | `+` | `-` | `~` | `!`){{/nodespec}}
</div>
{{#nodespec}}binaryOp:{{/nodespec}}
<div class="indent">
{{#nodespec}}(`*` | `/` | `%` | `+` | `-` | `<<` | `>>` | `>>>` | `<` | `>` | `<=` | `>=` | `instanceof` | `in` | `==` | `!=` | `===` | `!==` | `&` | `^` | `|` | `&&` | `||`){{/nodespec}}
</div>
{{#nodespec}}postfixOp:{{/nodespec}}
<div class="indent">
{{#nodespec}}(`++` | `--`){{/nodespec}}
</div>
{{#nodespec}}assignmentOp:{{/nodespec}}
<div class="indent">
{{#nodespec}}(`=` | `*=` | `/=` | `%=` | `+=` | `-=` | `<<=` | `>>=` | `>>>=` | `&=` | `^=` | `|=`){{/nodespec}}
</div>
</template>