Get in-browser compilation working using brfs

This commit is contained in:
Tony Garnock-Jones 2016-03-19 14:49:44 -04:00
parent e4ae3b1f95
commit 45d1de7358
5 changed files with 639 additions and 3 deletions

View File

@ -6,7 +6,7 @@ var fs = require('fs');
var path = require('path');
var ohm = require('ohm-js');
var ES5 = require('ohm-js/examples/ecmascript/es5.js');
var ES5 = require('./es5.js');
var grammarSource = fs.readFileSync(path.join(__dirname, 'syndicate.ohm')).toString();
var grammar = ohm.grammar(grammarSource, { ES5: ES5.grammar });

94
js/compiler/es5.js Normal file
View File

@ -0,0 +1,94 @@
//===========================================================================
// Copy of ohm-js/examples/ecmascript/es5.js to get browserify+brfs to work
//===========================================================================
/* eslint-env node */
'use strict';
// --------------------------------------------------------------------
// Imports
// --------------------------------------------------------------------
var fs = require('fs');
var path = require('path');
var ohm = require('ohm-js');
// --------------------------------------------------------------------
// Helpers
// --------------------------------------------------------------------
function isUndefined(x) { return x === void 0; }
// Take an Array of nodes, and whenever an _iter node is encountered, splice in its
// recursively-flattened children instead.
function flattenIterNodes(nodes) {
var result = [];
for (var i = 0; i < nodes.length; ++i) {
if (nodes[i]._node.ctorName === '_iter') {
result.push.apply(result, flattenIterNodes(nodes[i].children));
} else {
result.push(nodes[i]);
}
}
return result;
}
// Comparison function for sorting nodes based on their interval's start index.
function compareByInterval(node, otherNode) {
return node.interval.startIdx - otherNode.interval.startIdx;
}
// Semantic actions for the `modifiedSource` attribute (see below).
var modifiedSourceActions = {
_nonterminal: function(children) {
var flatChildren = flattenIterNodes(children).sort(compareByInterval);
var childResults = flatChildren.map(function(n) { return n.modifiedSource; });
if (flatChildren.length === 0 || childResults.every(isUndefined)) {
return undefined;
}
var code = '';
var interval = flatChildren[0].interval.collapsedLeft();
for (var i = 0; i < flatChildren.length; ++i) {
if (childResults[i] == null) {
// Grow the interval to include this node.
interval = interval.coverageWith(flatChildren[i].interval.collapsedRight());
} else {
interval = interval.coverageWith(flatChildren[i].interval.collapsedLeft());
code += interval.contents + childResults[i];
interval = flatChildren[i].interval.collapsedRight();
}
}
code += interval.contents;
return code;
},
_iter: function(_) {
throw new Error('_iter semantic action should never be hit');
},
_terminal: function() {
return undefined;
}
};
// Instantiate the ES5 grammar.
var contents = fs.readFileSync(path.join(__dirname, 'es5.ohm'));
var g = ohm.grammars(contents).ES5;
var semantics = g.semantics();
// An attribute whose value is either a string representing the modified source code for the
// node, or undefined (which means that the original source code should be used).
semantics.addAttribute('modifiedSource', modifiedSourceActions);
// A simple wrapper around the `modifiedSource` attribute, which always returns a string
// containing the ES5 source code for the node.
semantics.addAttribute('asES5', {
_nonterminal: function(children) {
return isUndefined(this.modifiedSource) ? this.interval.contents : this.modifiedSource;
}
});
module.exports = {
grammar: g,
semantics: semantics
};

502
js/compiler/es5.ohm Normal file
View File

@ -0,0 +1,502 @@
/*
This grammar was originally based on Tom Van Cutsem's ES5 parser from the
es-lab project (https://github.com/tvcutsem/es-lab/blob/master/src/parser/es5parser.ojs),
and was adapted to Ohm by Tony Garnock-Jones <tonygarnockjones@gmail.com> in 2014.
The original copyright and license follows:
*/
// Copyright (C) 2009 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/* (end of original copyright and license) */
ES5 {
Program = Directive* SourceElement*
// §A.1 Lexical Grammar -- http://ecma-international.org/ecma-262/5.1/#sec-A.1
/*
Note: the following lexical conventions (see http://ecma-international.org/ecma-262/5.1/#sec-7)
are not implemented in this parser.
// Goal production in contexts where a leading "/" or "/=" is permitted:
InputElementDiv = whitespace | lineTerminator | comment | token | DivPunctuator
// Goal production in contexts where a leading "/" or "/=' is not permitted:
InputElementRegExp = whitespace | lineTerminator | comment | token | regularExpressionLiteral
*/
sourceCharacter = any
// Override Ohm's built-in definition of space.
space := whitespace | lineTerminator | comment
whitespace = "\t"
| "\x0B" -- verticalTab
| "\x0C" -- formFeed
| " "
| "\u00A0" -- noBreakSpace
| "\uFEFF" -- byteOrderMark
| unicodeSpaceSeparator
lineTerminator = "\n" | "\r" | "\u2028" | "\u2029"
lineTerminatorSequence = "\n" | "\r" ~"\n" | "\u2028" | "\u2029" | "\r\n"
comment = multiLineComment | singleLineComment
multiLineComment = "/*" (~"*/" sourceCharacter)* "*/"
singleLineComment = "//" (~lineTerminator sourceCharacter)*
identifier (an indentifier) = ~reservedWord identifierName
identifierName = identifierStart identifierPart*
identifierStart = letter | "$" | "_"
| "\\" unicodeEscapeSequence -- escaped
identifierPart = identifierStart | unicodeCombiningMark
| unicodeDigit | unicodeConnectorPunctuation
| "\u200C" | "\u200D"
letter += unicodeCategoryNl
unicodeCategoryNl
= "\u2160".."\u2182" | "\u3007" | "\u3021".."\u3029"
unicodeDigit (a digit)
= "\u0030".."\u0039" | "\u0660".."\u0669" | "\u06F0".."\u06F9" | "\u0966".."\u096F" | "\u09E6".."\u09EF" | "\u0A66".."\u0A6F" | "\u0AE6".."\u0AEF" | "\u0B66".."\u0B6F" | "\u0BE7".."\u0BEF" | "\u0C66".."\u0C6F" | "\u0CE6".."\u0CEF" | "\u0D66".."\u0D6F" | "\u0E50".."\u0E59" | "\u0ED0".."\u0ED9" | "\u0F20".."\u0F29" | "\uFF10".."\uFF19"
unicodeCombiningMark (a Unicode combining mark)
= "\u0300".."\u0345" | "\u0360".."\u0361" | "\u0483".."\u0486" | "\u0591".."\u05A1" | "\u05A3".."\u05B9" | "\u05BB".."\u05BD" | "\u05BF".."\u05BF" | "\u05C1".."\u05C2" | "\u05C4".."\u05C4" | "\u064B".."\u0652" | "\u0670".."\u0670" | "\u06D6".."\u06DC" | "\u06DF".."\u06E4" | "\u06E7".."\u06E8" | "\u06EA".."\u06ED" | "\u0901".."\u0902" | "\u093C".."\u093C" | "\u0941".."\u0948" | "\u094D".."\u094D" | "\u0951".."\u0954" | "\u0962".."\u0963" | "\u0981".."\u0981" | "\u09BC".."\u09BC" | "\u09C1".."\u09C4" | "\u09CD".."\u09CD" | "\u09E2".."\u09E3" | "\u0A02".."\u0A02" | "\u0A3C".."\u0A3C" | "\u0A41".."\u0A42" | "\u0A47".."\u0A48" | "\u0A4B".."\u0A4D" | "\u0A70".."\u0A71" | "\u0A81".."\u0A82" | "\u0ABC".."\u0ABC" | "\u0AC1".."\u0AC5" | "\u0AC7".."\u0AC8" | "\u0ACD".."\u0ACD" | "\u0B01".."\u0B01" | "\u0B3C".."\u0B3C" | "\u0B3F".."\u0B3F" | "\u0B41".."\u0B43" | "\u0B4D".."\u0B4D" | "\u0B56".."\u0B56" | "\u0B82".."\u0B82" | "\u0BC0".."\u0BC0" | "\u0BCD".."\u0BCD" | "\u0C3E".."\u0C40" | "\u0C46".."\u0C48" | "\u0C4A".."\u0C4D" | "\u0C55".."\u0C56" | "\u0CBF".."\u0CBF" | "\u0CC6".."\u0CC6" | "\u0CCC".."\u0CCD" | "\u0D41".."\u0D43" | "\u0D4D".."\u0D4D" | "\u0E31".."\u0E31" | "\u0E34".."\u0E3A" | "\u0E47".."\u0E4E" | "\u0EB1".."\u0EB1" | "\u0EB4".."\u0EB9" | "\u0EBB".."\u0EBC" | "\u0EC8".."\u0ECD" | "\u0F18".."\u0F19" | "\u0F35".."\u0F35" | "\u0F37".."\u0F37" | "\u0F39".."\u0F39" | "\u0F71".."\u0F7E" | "\u0F80".."\u0F84" | "\u0F86".."\u0F87" | "\u0F90".."\u0F95" | "\u0F97".."\u0F97" | "\u0F99".."\u0FAD" | "\u0FB1".."\u0FB7" | "\u0FB9".."\u0FB9" | "\u20D0".."\u20DC" | "\u20E1".."\u20E1" | "\u302A".."\u302F" | "\u3099".."\u309A" | "\uFB1E".."\uFB1E" | "\uFE20".."\uFE23"
unicodeConnectorPunctuation = "\u005F" | "\u203F".."\u2040" | "\u30FB" | "\uFE33".."\uFE34" | "\uFE4D".."\uFE4F" | "\uFF3F" | "\uFF65"
unicodeSpaceSeparator = "\u2000".."\u200B" | "\u3000"
reservedWord = keyword | futureReservedWord | nullLiteral | booleanLiteral
// Note: keywords that are the complete prefix of another keyword should
// be prioritized (e.g. 'in' should come before 'instanceof')
keyword = break | do | instanceof | typeof
| case | else | new | var
| catch | finally | return | void
| continue | for | switch | while
| debugger | function | this | with
| default | if | throw
| delete | in | try
futureReservedWordLax = class | enum | extends
| super | const | export
| import
futureReservedWordStrict = futureReservedWordLax
| implements | let | private | public
| interface | package | protected | static
| yield
futureReservedWord = futureReservedWordStrict
/*
Note: Punctuator and DivPunctuator (see https://es5.github.io/x7.html#x7.7) are
not currently used by this grammar.
*/
literal = nullLiteral | booleanLiteral | numericLiteral
| stringLiteral | regularExpressionLiteral // spec forgot Regexp literals in appendix?
nullLiteral = "null" ~identifierPart
booleanLiteral = ("true" | "false") ~identifierPart
// For semantics on how decimal literals are constructed, see section 7.8.3
// Note that the ordering of hexIntegerLiteral and decimalLiteral is reversed w.r.t. the spec
// This is intentional: the order decimalLiteral | hexIntegerLiteral will parse
// "0x..." as a decimal literal "0" followed by "x..."
numericLiteral = octalIntegerLiteral | hexIntegerLiteral | decimalLiteral
decimalLiteral = decimalIntegerLiteral "." decimalDigit* exponentPart -- bothParts
| "." decimalDigit+ exponentPart -- decimalsOnly
| decimalIntegerLiteral exponentPart -- integerOnly
decimalIntegerLiteral = nonZeroDigit decimalDigit* -- nonZero
| "0" -- zero
decimalDigit = "0".."9"
nonZeroDigit = "1".."9"
exponentPart = exponentIndicator signedInteger -- present
| -- absent
exponentIndicator = "e" | "E"
signedInteger = "+" decimalDigit* -- positive
| "-" decimalDigit* -- negative
| decimalDigit+ -- noSign
hexIntegerLiteral = "0x" hexDigit+
| "0X" hexDigit+
// hexDigit defined in Ohm's built-in rules (otherwise: hexDigit = "0".."9" | "a".."f" | "A".."F")
octalIntegerLiteral = "0" octalDigit+
octalDigit = "0".."7"
// For semantics on how string literals are constructed, see section 7.8.4
stringLiteral = "\"" doubleStringCharacter* "\""
| "'" singleStringCharacter* "'"
doubleStringCharacter = ~("\"" | "\\" | lineTerminator) sourceCharacter -- nonEscaped
| "\\" escapeSequence -- escaped
| lineContinuation -- lineContinuation
singleStringCharacter = ~("'" | "\\" | lineTerminator) sourceCharacter -- nonEscaped
| "\\" escapeSequence -- escaped
| lineContinuation -- lineContinuation
lineContinuation = "\\" lineTerminatorSequence
escapeSequence = unicodeEscapeSequence
| hexEscapeSequence
| octalEscapeSequence
| characterEscapeSequence // Must come last.
characterEscapeSequence = singleEscapeCharacter
| nonEscapeCharacter
singleEscapeCharacter = "'" // -> ( String.fromCharCode(0039) ) /*\u0027*/
| "\"" // -> ( String.fromCharCode(0034) ) /*\u0022*/
| "\\" // -> ( String.fromCharCode(0092) ) /*\u005C*/
| "b" // -> ( String.fromCharCode(0008) ) /*\u0008*/
| "f" // -> ( String.fromCharCode(0012) ) /*\u000C*/
| "n" // -> ( String.fromCharCode(0010) ) /*\u000A*/
| "r" // -> ( String.fromCharCode(0013) ) /*\u000D*/
| "t" // -> ( String.fromCharCode(0009) ) /*\u0009*/
| "v" // -> ( String.fromCharCode(0011) ) /*\u000B*/
nonEscapeCharacter = ~(escapeCharacter | lineTerminator) sourceCharacter
escapeCharacter = singleEscapeCharacter | decimalDigit | "x" | "u"
octalEscapeSequence = zeroToThree octalDigit octalDigit -- whole
| fourToSeven octalDigit -- eightTimesfourToSeven
| zeroToThree octalDigit ~decimalDigit -- eightTimesZeroToThree
| octalDigit ~decimalDigit -- octal
hexEscapeSequence = "x" hexDigit hexDigit
unicodeEscapeSequence = "u" hexDigit hexDigit hexDigit hexDigit
zeroToThree = "0".."3"
fourToSeven = "4".."7"
// §7.8.5 Regular Expression Literals -- http://ecma-international.org/ecma-262/5.1/#sec-7.8.5
regularExpressionLiteral = "/" regularExpressionBody "/" regularExpressionFlags
regularExpressionBody = regularExpressionFirstChar regularExpressionChar*
regularExpressionFirstChar = ~("*" | "\\" | "/" | "[") regularExpressionNonTerminator
| regularExpressionBackslashSequence
| regularExpressionClass
regularExpressionChar = ~("\\" | "/" | "[") regularExpressionNonTerminator
| regularExpressionBackslashSequence
| regularExpressionClass
regularExpressionBackslashSequence = "\\" regularExpressionNonTerminator
regularExpressionNonTerminator = ~(lineTerminator) sourceCharacter
regularExpressionClass = "[" regularExpressionClassChar* "]"
regularExpressionClassChar = ~("]" | "\\") regularExpressionNonTerminator
| regularExpressionBackslashSequence
regularExpressionFlags = identifierPart*
// === Implementation-level rules (not part of the spec) ===
multiLineCommentNoNL = "/*" (~("*/" | lineTerminator) sourceCharacter)* "*/"
// does not accept lineTerminators, not even implicit ones in a multiLineComment (cf. section 7.4)
spacesNoNL = (whitespace | singleLineComment | multiLineCommentNoNL)*
// A semicolon is "automatically inserted" if a newline is reached the end of the input stream
// is reached, or the offending token is "}".
// See http://ecma-international.org/ecma-262/5.1/#sec-7.9 for more information.
// NOTE: Applications of this rule *must* appear in a lexical context -- either in the body of a
// lexical rule, or inside `#()`.
sc = space* (";" | end)
| spacesNoNL (lineTerminator | ~multiLineCommentNoNL multiLineComment | &"}")
// Convenience rules for parsing keyword tokens.
break = "break" ~identifierPart
do = "do" ~identifierPart
instanceof = "instanceof" ~identifierPart
typeof = "typeof" ~identifierPart
case = "case" ~identifierPart
else = "else" ~identifierPart
new = "new" ~identifierPart
var = "var" ~identifierPart
catch = "catch" ~identifierPart
finally = "finally" ~identifierPart
return = "return" ~identifierPart
void = "void" ~identifierPart
continue = "continue" ~identifierPart
for = "for" ~identifierPart
switch = "switch" ~identifierPart
while = "while" ~identifierPart
debugger = "debugger" ~identifierPart
function = "function" ~identifierPart
this = "this" ~identifierPart
with = "with" ~identifierPart
default = "default" ~identifierPart
if = "if" ~identifierPart
throw = "throw" ~identifierPart
delete = "delete" ~identifierPart
in = "in" ~identifierPart
try = "try" ~identifierPart
get = "get" ~identifierPart
set = "set" ~identifierPart
class = "class" ~identifierPart
enum = "enum" ~identifierPart
extends = "extends" ~identifierPart
super = "super" ~identifierPart
const = "const" ~identifierPart
export = "export" ~identifierPart
import = "import" ~identifierPart
implements = "implements" ~identifierPart
let = "let" ~identifierPart
private = "private" ~identifierPart
public = "public" ~identifierPart
interface = "interface" ~identifierPart
package = "package" ~identifierPart
protected = "protected" ~identifierPart
static = "static" ~identifierPart
yield = "yield" ~identifierPart
// end of lexical rules
noIn = ~in
withIn =
// §A.3 Expressions -- http://ecma-international.org/ecma-262/5.1/#sec-A.3
PrimaryExpression = this
| identifier
| literal
// ( litToken.type === "regexp"
// ? this.ast(_fromIdx, "RegExpExpr",{body: litToken.value.body
// flags: litToken.value.flags}, [])
// : this.ast(_fromIdx, "LiteralExpr",{type: litToken.type
// value: litToken.value}, []) )
| ArrayLiteral
| ObjectLiteral
| "(" Expression<withIn> ")" -- parenExpr
ArrayLiteral = "[" ListOf<AssignmentExpressionOrElision, ","> "]"
AssignmentExpressionOrElision = AssignmentExpression<withIn>
| -- elision
ObjectLiteral = "{" ListOf<PropertyAssignment, ","> "}" -- noTrailingComma
| "{" NonemptyListOf<PropertyAssignment, ","> "," "}" -- trailingComma
PropertyAssignment = get PropertyName "(" ")" "{" FunctionBody "}" -- getter
| set PropertyName "(" FormalParameter ")" "{" FunctionBody "}" -- setter
| PropertyName ":" AssignmentExpression<withIn> -- simple
PropertyName = identifierName
| stringLiteral
| numericLiteral
MemberExpression = MemberExpression "[" Expression<withIn> "]" -- arrayRefExp
| MemberExpression "." identifierName -- propRefExp
| new MemberExpression Arguments -- newExp
| FunctionExpression
| PrimaryExpression
NewExpression = MemberExpression
| new NewExpression -- newExp
CallExpression = CallExpression "[" Expression<withIn> "]" -- arrayRefExp
| CallExpression "." identifierName -- propRefExp
| CallExpression Arguments -- callExpExp
| MemberExpression Arguments -- memberExpExp
Arguments = "(" ListOf<AssignmentExpression<withIn>, ","> ")"
LeftHandSideExpression = CallExpression
| NewExpression
PostfixExpression = LeftHandSideExpression #(spacesNoNL "++") -- postIncrement
| LeftHandSideExpression #(spacesNoNL "--") -- postDecrement
| LeftHandSideExpression
UnaryExpression = delete UnaryExpression -- deleteExp
| void UnaryExpression -- voidExp
| typeof UnaryExpression -- typeofExp
| "++" UnaryExpression -- preIncrement
| "--" UnaryExpression -- preDecrement
| "+" UnaryExpression -- unaryPlus
| "-" UnaryExpression -- unaryMinus
| "~" UnaryExpression -- bnot
| "!" UnaryExpression -- lnot
| PostfixExpression
MultiplicativeExpression = MultiplicativeExpression "*" UnaryExpression -- mul
| MultiplicativeExpression "/" UnaryExpression -- div
| MultiplicativeExpression "%" UnaryExpression -- mod
| UnaryExpression
AdditiveExpression = AdditiveExpression "+" MultiplicativeExpression -- add
| AdditiveExpression "-" MultiplicativeExpression -- sub
| MultiplicativeExpression
ShiftExpression = ShiftExpression "<<" AdditiveExpression -- lsl
| ShiftExpression ">>>" AdditiveExpression -- lsr
| ShiftExpression ">>" AdditiveExpression -- asr
| AdditiveExpression
RelationalExpression<guardIn>
= RelationalExpression<guardIn> "<" ShiftExpression -- lt
| RelationalExpression<guardIn> ">" ShiftExpression -- gt
| RelationalExpression<guardIn> "<=" ShiftExpression -- le
| RelationalExpression<guardIn> ">=" ShiftExpression -- ge
| RelationalExpression<guardIn> "instanceof" ShiftExpression -- instanceOfExp
| RelationalExpression<guardIn> guardIn "in" ShiftExpression -- inExp
| ShiftExpression
EqualityExpression<guardIn>
= EqualityExpression<guardIn> "==" RelationalExpression<guardIn> -- equal
| EqualityExpression<guardIn> "!=" RelationalExpression<guardIn> -- notEqual
| EqualityExpression<guardIn> "===" RelationalExpression<guardIn> -- eq
| EqualityExpression<guardIn> "!==" RelationalExpression<guardIn> -- notEq
| RelationalExpression<guardIn>
BitwiseANDExpression<guardIn>
= BitwiseANDExpression<guardIn> "&" EqualityExpression<guardIn> -- band
| EqualityExpression<guardIn>
BitwiseXORExpression<guardIn>
= BitwiseXORExpression<guardIn> "^" BitwiseANDExpression<guardIn> -- bxor
| BitwiseANDExpression<guardIn>
BitwiseORExpression<guardIn>
= BitwiseORExpression<guardIn> "|" BitwiseXORExpression<guardIn> -- bor
| BitwiseXORExpression<guardIn>
LogicalANDExpression<guardIn>
= LogicalANDExpression<guardIn> "&&" BitwiseORExpression<guardIn> -- land
| BitwiseORExpression<guardIn>
LogicalORExpression<guardIn>
= LogicalORExpression<guardIn> "||" LogicalANDExpression<guardIn> -- lor
| LogicalANDExpression<guardIn>
ConditionalExpression<guardIn>
= LogicalORExpression<guardIn> "?" AssignmentExpression<withIn> ":" AssignmentExpression<guardIn> -- conditional
| LogicalORExpression<guardIn>
AssignmentExpression<guardIn>
= LeftHandSideExpression AssignmentOperator AssignmentExpression<guardIn> -- assignment
| ConditionalExpression<guardIn>
Expression<guardIn> (an expression)
= Expression<guardIn> "," AssignmentExpression<guardIn> -- commaExp
| AssignmentExpression<guardIn>
AssignmentOperator = "=" | ">>>=" | "<<=" | ">>="
| "*=" | "/=" | "%=" | "+=" | "-=" | "&=" | "^=" | "|="
// §A.4 Statements -- http://ecma-international.org/ecma-262/5.1/#sec-A.4
Statement (a statement)
= Block
| VariableStatement
| EmptyStatement
| ExpressionStatement
| IfStatement
| IterationStatement
| ContinueStatement
| BreakStatement
| ReturnStatement
| WithStatement
| LabelledStatement
| SwitchStatement
| ThrowStatement
| TryStatement
| DebuggerStatement
Block = "{" StatementList "}"
StatementList = Statement*
VariableStatement = var VariableDeclarationList<withIn> #(sc)
VariableDeclarationList<guardIn> = NonemptyListOf<VariableDeclaration<guardIn>, ",">
VariableDeclaration<guardIn> = identifier Initialiser<guardIn>?
Initialiser<guardIn> = "=" AssignmentExpression<guardIn>
EmptyStatement = ";" // note: this semicolon eats newlines
ExpressionStatement = ~("{" | function) Expression<withIn> #(sc)
IfStatement = if "(" Expression<withIn> ")" Statement (else Statement)?
IterationStatement = do Statement while "(" Expression<withIn> ")" #(sc) -- doWhile
| while "(" Expression<withIn> ")" Statement -- whileDo
| for "(" Expression<noIn>? ";"
Expression<withIn>? ";"
Expression<withIn>? ")" Statement -- for3
| for "(" var VariableDeclarationList<noIn> ";"
Expression<withIn>? ";"
Expression<withIn>? ")" Statement -- for3var
| for "(" LeftHandSideExpression in
Expression<withIn> ")" Statement -- forIn
| for "(" var VariableDeclaration<noIn> in
Expression<withIn> ")" Statement -- forInVar
ContinueStatement = continue #((spacesNoNL identifier)? sc)
BreakStatement = break #((spacesNoNL identifier)? sc)
ReturnStatement = return (#(spacesNoNL ~space) Expression<withIn>)? #(sc)
WithStatement = with "(" Expression<withIn> ")" Statement
SwitchStatement = switch "(" Expression<withIn> ")" CaseBlock
CaseBlock = "{" CaseClause* DefaultClause CaseClause* "}" -- withDefault
| "{" CaseClause* "}" -- withoutDefault
CaseClause = case Expression<withIn> ":" Statement*
DefaultClause = default ":" Statement*
LabelledStatement = identifier ":" Statement
ThrowStatement = throw Expression<withIn> #(sc) -- throwExpr
TryStatement = try Block Catch Finally -- tryCatchFinally
| try Block Finally -- tryFinally
| try Block Catch -- tryCatch
Catch = catch "(" FormalParameter ")" Block
Finally = finally Block
DebuggerStatement = #(debugger sc)
// §A.5 Functions and Programs -- http://ecma-international.org/ecma-262/5.1/#sec-A.5
FunctionDeclaration
= function identifier "(" FormalParameterList ")" "{" FunctionBody "}"
FunctionExpression
= function identifier "(" FormalParameterList ")" "{" FunctionBody "}" -- named
| function "(" FormalParameterList ")" "{" FunctionBody "}" -- anonymous
FormalParameterList = ListOf<FormalParameter, ",">
FormalParameter = identifier
FunctionBody = Directive* SourceElement*
SourceElement = Declaration | Statement
// Broken out so es6 can override to include ConstDecl and LetDecl
Declaration = FunctionDeclaration
Directive = stringLiteral #(sc)
}
ES5Lax <: ES5 {
futureReservedWord := futureReservedWordLax
}

38
js/compiler/inbrowser.js Normal file
View File

@ -0,0 +1,38 @@
'use strict';
var compiler = require('./compiler.js');
function getUrlContent(url) {
var req = new XMLHttpRequest();
req.open('GET', url, false);
try {
req.send();
if (req.status === 0 || req.status === 200) {
return req.responseText;
}
} catch (e) {
console.error("Error while loading " + url, e);
}
return false;
}
function translateSyndicateScripts() {
var scriptNodes = document.querySelectorAll('script[type="text/syndicate-js"]');
var allSources = [];
for (var i = 0; i < scriptNodes.length; i++) {
var n = scriptNodes[i];
var srcUrl = n.getAttribute('src');
allSources.push(srcUrl ? getUrlContent(srcUrl) : n.innerHTML);
}
var allSourceText = allSources.join('\n;\n');
var output = compiler.compileSyndicateSource(allSourceText);
var f = new Function(output);
f();
}
document.addEventListener('DOMContentLoaded', translateSyndicateScripts, false);
//---------------------------------------------------------------------------
module.exports = compiler;

View File

@ -15,8 +15,9 @@
"clean": "rm -f dist/*",
"build-debug": "browserify src/main.js -d -s Syndicate -o dist/syndicate.js",
"build-min": "browserify src/main.js -s Syndicate -o dist/_syndicate.js && uglifyjs dist/_syndicate.js -o dist/syndicate.min.js && rm dist/_syndicate.js",
"build-compiler": "browserify compiler/compiler.js -s SyndicateCompiler -o dist/_syndicatecompiler.js && uglifyjs dist/_syndicatecompiler.js -o dist/syndicatecompiler.min.js && rm dist/_syndicatecompiler.js",
"build": "npm run build-debug && npm run build-min && npm run build-compiler",
"build-compiler-debug": "browserify -t brfs compiler/inbrowser.js -s SyndicateCompiler -o dist/syndicatecompiler.js",
"build-compiler": "browserify -t brfs compiler/inbrowser.js -s SyndicateCompiler -o dist/_syndicatecompiler.js && uglifyjs dist/_syndicatecompiler.js -o dist/syndicatecompiler.min.js && rm dist/_syndicatecompiler.js",
"build": "npm run build-debug && npm run build-compiler-debug && npm run build-min && npm run build-compiler",
"watch": "watchify src/main.js -d -s Syndicate -o dist/syndicate.js",
"test": "mocha",
"prepublish": "npm run build"
@ -29,6 +30,7 @@
"mocha": "^2.4.5",
"expect.js": "^0.3.1",
"immutable": "^3.7.6",
"brfs": "^1.4.3",
"ohm-js": "cdglabs/ohm"
}
}