UNPKG

avg-storyscript

Version:

Build-in Story Script System for AVG.js.

1,529 lines (1,333 loc) 317 kB
/*! * Copyright 2016 Icemic Jia <bingfeng.web@gmail.com> * * 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. */ (function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define([], factory); else { var a = factory(); for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i]; } })(this, function() { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) /******/ return installedModules[moduleId].exports; /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ exports: {}, /******/ id: moduleId, /******/ loaded: false /******/ }; /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ // Flag the module as loaded /******/ module.loaded = true; /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ // Load entry module and return exports /******/ return __webpack_require__(0); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /*! * Copyright 2016 Icemic Jia <bingfeng.web@gmail.com> * * 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. */ var parser = __webpack_require__(1); var variable = __webpack_require__(73); var _require = __webpack_require__(74), IfBlock = _require.IfBlock, WhileBlock = _require.WhileBlock, ForeachBlock = _require.ForeachBlock, InsertedBlock = _require.InsertedBlock; var StoryScript = function () { function StoryScript(onGlobalChanged) { _classCallCheck(this, StoryScript); this.BLOCKSTACK = []; this.CURRENTBLOCK = null; this.onGlobalChanged = onGlobalChanged; } _createClass(StoryScript, [{ key: 'load', value: function load(string) { var result = parser.parse(string); var system = new IfBlock(result); this.CURRENTBLOCK = system; this.BLOCKSTACK = []; // variable.reset(); } }, { key: 'getBlockData', value: function getBlockData() { var blocks = []; var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = [].concat(_toConsumableArray(this.BLOCKSTACK), [this.CURRENTBLOCK]).reverse().entries()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var _step$value = _slicedToArray(_step.value, 2), node = _step$value[0], block = _step$value[1]; var blockData = block.getData(); blockData.scope = variable.getScope(node); blocks.push(blockData); } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } return blocks.reverse(); } }, { key: 'getGlobalScope', value: function getGlobalScope() { return variable.getGlobalScope(); } }, { key: 'getSaveScope', value: function getSaveScope() { return variable.getSaveScope(); } // @deprecated }, { key: 'getData', value: function getData() { console.warn('[Storyscript] getData() has been deprecated!'); return { blocks: this.getBlockData(), globalScope: this.getGlobalScope(), saveScope: this.getSaveScope() }; } }, { key: 'setGlobalScope', value: function setGlobalScope(scope) { variable.setGlobalScope(scope); } }, { key: 'setSaveScope', value: function setSaveScope(scope) { variable.setSaveScope(scope); } }, { key: 'setBlockData', value: function setBlockData(blocks) { var scopes = [blocks[0].scope]; variable.setScopes(scopes); this.CURRENTBLOCK.setCurrentLine(blocks[0].currentLine); if (blocks.length === 1) { return true; } for (var i = 0; i < blocks.length - 1; i++) { var block = blocks[i]; var nextBlock = blocks[i + 1]; var lastLine = block.currentLine - 1; var line = this.CURRENTBLOCK.getLine(lastLine); if (line.name === nextBlock.type) { switch (line.name) { case 'if': var ifBlock = new IfBlock(line.blocks[nextBlock.blockIndex], nextBlock.blockIndex); ifBlock.setCurrentLine(nextBlock.currentLine); variable.pushScope(nextBlock.scope); // variable.popScope(); this.BLOCKSTACK.push(this.CURRENTBLOCK); this.CURRENTBLOCK = ifBlock; break; case 'while': var whileBlock = new WhileBlock(line.block, line.condition); whileBlock.setCurrentLine(nextBlock.currentLine); variable.pushScope(nextBlock.scope); // variable.popScope(); this.BLOCKSTACK.push(this.CURRENTBLOCK); this.CURRENTBLOCK = whileBlock; break; case 'foreach': var foreachBlock = new ForeachBlock(line.block, line.child, line.children); foreachBlock.setCurrentLine(nextBlock.currentLine); variable.pushScope(nextBlock.scope); // variable.popScope(); this.BLOCKSTACK.push(this.CURRENTBLOCK); this.CURRENTBLOCK = foreachBlock; break; default: throw 'Bad savedata'; } } else if (nextBlock.type === 'inserted') { var insertedBlock = new InsertedBlock(nextBlock.data); insertedBlock.setCurrentLine(nextBlock.currentLine); variable.pushScope(nextBlock.scope); // variable.popScope(); this.BLOCKSTACK.push(this.CURRENTBLOCK); this.CURRENTBLOCK = insertedBlock; } else { throw 'Bad savedata'; } } } // @deprecated }, { key: 'setData', value: function setData(object) { console.warn('[Storyscript] setData() has been deprecated!'); this.setGlobalScope(object.globalScope); this.setSaveScope(object.saveScope); this.setBlockData(object.blocks); } }, { key: Symbol.iterator, value: function value() { return this; } }, { key: 'next', value: function next() { var _CURRENTBLOCK$next = this.CURRENTBLOCK.next(), value = _CURRENTBLOCK$next.value, done = _CURRENTBLOCK$next.done; if (done) { var CURRENTBLOCK = this.BLOCKSTACK.pop(); if (CURRENTBLOCK) { this.CURRENTBLOCK = CURRENTBLOCK; variable.popScope(); return this.next(); } else { return { done: true }; } } else { var retValue = this.handleScript(value); if (retValue) { return { value: retValue, done: false }; } else { // handleLogic will return undefined, so should exec next line return this.next(); } } } }, { key: 'handleScript', value: function handleScript(argLine) { // deep copy var line = Object.assign({}, argLine); if (line.type === 'content') { return this.handleContent(line); } else if (line.type === 'logic') { return this.handleLogic(line); } else if (line.type === 'comment') { return null; } else { throw 'Unrecognized type ' + line.type; } } }, { key: 'handleContent', value: function handleContent(line) { var params = line.params; var keys = Object.keys(params); var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = keys[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var key = _step2.value; params[key] = params[key].value; } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } return line; } }, { key: 'handleLogic', value: function handleLogic(line) { switch (line.name) { case 'if': return this.handleLogic_IF(line);break; case 'while': return this.handleLogic_WHILE(line);break; case 'foreach': return this.handleLogic_FOREACH(line);break; case 'let': return this.handleLogic_LET(line);break; default: throw 'Unrecognized name ' + line.name; } } }, { key: 'handleLogic_IF', value: function handleLogic_IF(line) { var blockIndex = 0; var _iteratorNormalCompletion3 = true; var _didIteratorError3 = false; var _iteratorError3 = undefined; try { for (var _iterator3 = line.conditions[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { var condition = _step3.value; if (variable.calc(condition)) { break; } else { blockIndex++; } } } catch (err) { _didIteratorError3 = true; _iteratorError3 = err; } finally { try { if (!_iteratorNormalCompletion3 && _iterator3.return) { _iterator3.return(); } } finally { if (_didIteratorError3) { throw _iteratorError3; } } } this.BLOCKSTACK.push(this.CURRENTBLOCK); var blockData = line.blocks[blockIndex]; var block = new IfBlock(blockData, blockIndex); this.CURRENTBLOCK = block; // variable.pushScope(); } }, { key: 'handleLogic_WHILE', value: function handleLogic_WHILE(line) { var result = variable.calc(line.condition); if (result) { this.BLOCKSTACK.push(this.CURRENTBLOCK); var blockData = line.block; var block = new WhileBlock(blockData, line.condition); this.CURRENTBLOCK = block; } // variable.pushScope(); } }, { key: 'handleLogic_FOREACH', value: function handleLogic_FOREACH(line) { var children = variable.calc(line.children); if (children instanceof Array) { this.BLOCKSTACK.push(this.CURRENTBLOCK); var blockData = line.block; var block = new ForeachBlock(blockData, line.child, line.children); this.CURRENTBLOCK = block; } else { throw '[Foreach] Children must be a array'; } // variable.pushScope(); } }, { key: 'handleLogic_LET', value: function handleLogic_LET(line) { if (line.left.prefix === '$') { this.onGlobalChanged && this.onGlobalChanged(); } variable.assign(line.left.value, line.left.prefix, line.right, line.explicit); } }]); return StoryScript; }(); // module.exports = StoryScript; exports.default = StoryScript; /***/ }, /* 1 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; /** * Copyright 2016 Icemic Jia <bingfeng.web@gmail.com> * * 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. */ var ohm = __webpack_require__(2); // var fs = require('fs'); var actions = __webpack_require__(63); var contents = __webpack_require__(72); var myGrammar = ohm.grammar(contents); var mySemantics = myGrammar.createSemantics(); mySemantics.addOperation('parse', actions); exports.parse = function (string) { var m = myGrammar.match(string); if (m.succeeded()) { return mySemantics(m).parse(); } else { throw m.message; } }; /***/ }, /* 2 */ /***/ function(module, exports, __webpack_require__) { /* global document, XMLHttpRequest */ 'use strict'; // -------------------------------------------------------------------- // Imports // -------------------------------------------------------------------- var Builder = __webpack_require__(3); var Grammar = __webpack_require__(5); var Namespace = __webpack_require__(14); var common = __webpack_require__(8); var errors = __webpack_require__(13); var pexprs = __webpack_require__(38); var util = __webpack_require__(11); var isBuffer = __webpack_require__(57); // -------------------------------------------------------------------- // Private stuff // -------------------------------------------------------------------- // The metagrammar, i.e. the grammar for Ohm grammars. Initialized at the // bottom of this file because loading the grammar requires Ohm itself. var ohmGrammar; // An object which makes it possible to stub out the document API for testing. var documentInterface = { querySelector: function(sel) { return document.querySelector(sel); }, querySelectorAll: function(sel) { return document.querySelectorAll(sel); } }; // Check if `obj` is a DOM element. function isElement(obj) { return !!(obj && obj.nodeType === 1); } function isUndefined(obj) { return obj === void 0; // eslint-disable-line no-void } var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1; function isArrayLike(obj) { if (obj == null) { return false; } var length = obj.length; return typeof length === 'number' && length >= 0 && length <= MAX_ARRAY_INDEX; } // TODO: just use the jQuery thing function load(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) {} throw new Error('unable to load url ' + url); } // Returns a Grammar instance (i.e., an object with a `match` method) for // `tree`, which is the concrete syntax tree of a user-written grammar. // The grammar will be assigned into `namespace` under the name of the grammar // as specified in the source. function buildGrammar(match, namespace, optOhmGrammarForTesting) { var builder = new Builder(); var decl; var currentRuleName; var currentRuleFormals; var overriding = false; var metaGrammar = optOhmGrammarForTesting || ohmGrammar; // A visitor that produces a Grammar instance from the CST. var helpers = metaGrammar.createSemantics().addOperation('visit', { Grammar: function(n, s, open, rs, close) { var grammarName = n.visit(); decl = builder.newGrammar(grammarName, namespace); s.visit(); rs.visit(); var g = decl.build(); g.source = this.source.trimmed(); if (grammarName in namespace) { throw errors.duplicateGrammarDeclaration(g, namespace); } namespace[grammarName] = g; return g; }, SuperGrammar: function(_, n) { var superGrammarName = n.visit(); if (superGrammarName === 'null') { decl.withSuperGrammar(null); } else { if (!namespace || !(superGrammarName in namespace)) { throw errors.undeclaredGrammar(superGrammarName, namespace, n.source); } decl.withSuperGrammar(namespace[superGrammarName]); } }, Rule_define: function(n, fs, d, _, b) { currentRuleName = n.visit(); currentRuleFormals = fs.visit()[0] || []; // If there is no default start rule yet, set it now. This must be done before visiting // the body, because it might contain an inline rule definition. if (!decl.defaultStartRule && decl.ensureSuperGrammar() !== Grammar.ProtoBuiltInRules) { decl.withDefaultStartRule(currentRuleName); } var body = b.visit(); var description = d.visit()[0]; var source = this.source.trimmed(); return decl.define(currentRuleName, currentRuleFormals, body, description, source); }, Rule_override: function(n, fs, _, b) { currentRuleName = n.visit(); currentRuleFormals = fs.visit()[0] || []; overriding = true; var body = b.visit(); var source = this.source.trimmed(); var ans = decl.override(currentRuleName, currentRuleFormals, body, null, source); overriding = false; return ans; }, Rule_extend: function(n, fs, _, b) { currentRuleName = n.visit(); currentRuleFormals = fs.visit()[0] || []; var body = b.visit(); var source = this.source.trimmed(); var ans = decl.extend(currentRuleName, currentRuleFormals, body, null, source); return ans; }, RuleBody: function(_, terms) { var args = terms.visit(); return builder.alt.apply(builder, args).withSource(this.source); }, Formals: function(opointy, fs, cpointy) { return fs.visit(); }, Params: function(opointy, ps, cpointy) { return ps.visit(); }, Alt: function(seqs) { var args = seqs.visit(); return builder.alt.apply(builder, args).withSource(this.source); }, TopLevelTerm_inline: function(b, n) { var inlineRuleName = currentRuleName + '_' + n.visit(); var body = b.visit(); var source = this.source.trimmed(); var isNewRuleDeclaration = !(decl.superGrammar && decl.superGrammar.rules[inlineRuleName]); if (overriding && !isNewRuleDeclaration) { decl.override(inlineRuleName, currentRuleFormals, body, null, source); } else { decl.define(inlineRuleName, currentRuleFormals, body, null, source); } var params = currentRuleFormals.map(function(formal) { return builder.app(formal); }); return builder.app(inlineRuleName, params).withSource(body.source); }, Seq: function(expr) { return builder.seq.apply(builder, expr.visit()).withSource(this.source); }, Iter_star: function(x, _) { return builder.star(x.visit()).withSource(this.source); }, Iter_plus: function(x, _) { return builder.plus(x.visit()).withSource(this.source); }, Iter_opt: function(x, _) { return builder.opt(x.visit()).withSource(this.source); }, Pred_not: function(_, x) { return builder.not(x.visit()).withSource(this.source); }, Pred_lookahead: function(_, x) { return builder.lookahead(x.visit()).withSource(this.source); }, Lex_lex: function(_, x) { return builder.lex(x.visit()).withSource(this.source); }, Base_application: function(rule, ps) { return builder.app(rule.visit(), ps.visit()[0] || []).withSource(this.source); }, Base_range: function(from, _, to) { return builder.range(from.visit(), to.visit()).withSource(this.source); }, Base_terminal: function(expr) { return builder.terminal(expr.visit()).withSource(this.source); }, Base_paren: function(open, x, close) { return x.visit(); }, ruleDescr: function(open, t, close) { return t.visit(); }, ruleDescrText: function(_) { return this.sourceString.trim(); }, caseName: function(_, space1, n, space2, end) { return n.visit(); }, name: function(first, rest) { return this.sourceString; }, nameFirst: function(expr) {}, nameRest: function(expr) {}, terminal: function(open, cs, close) { return cs.visit().map(function(c) { return common.unescapeChar(c); }).join(''); }, terminalChar: function(_) { return this.sourceString; }, escapeChar: function(_) { return this.sourceString; }, NonemptyListOf: function(x, _, xs) { return [x.visit()].concat(xs.visit()); }, EmptyListOf: function() { return []; }, _terminal: function() { return this.primitiveValue; } }); return helpers(match).visit(); } function compileAndLoad(source, namespace) { var m = ohmGrammar.match(source, 'Grammars'); if (m.failed()) { throw errors.grammarSyntaxError(m); } return buildGrammar(m, namespace); } // Return the contents of a script element, fetching it via XHR if necessary. function getScriptElementContents(el) { if (!isElement(el)) { throw new TypeError('Expected a DOM Node, got ' + common.unexpectedObjToString(el)); } if (el.type !== 'text/ohm-js') { throw new Error('Expected a script tag with type="text/ohm-js", got ' + el); } return el.getAttribute('src') ? load(el.getAttribute('src')) : el.innerHTML; } function grammar(source, optNamespace) { var ns = grammars(source, optNamespace); // Ensure that the source contained no more than one grammar definition. var grammarNames = Object.keys(ns); if (grammarNames.length === 0) { throw new Error('Missing grammar definition'); } else if (grammarNames.length > 1) { var secondGrammar = ns[grammarNames[1]]; var interval = secondGrammar.source; throw new Error( util.getLineAndColumnMessage(interval.inputStream.source, interval.startIdx) + 'Found more than one grammar definition -- use ohm.grammars() instead.'); } return ns[grammarNames[0]]; // Return the one and only grammar. } function grammars(source, optNamespace) { var ns = Namespace.extend(Namespace.asNamespace(optNamespace)); if (typeof source !== 'string') { // For convenience, detect Node.js Buffer objects and automatically call toString(). if (isBuffer(source)) { source = source.toString(); } else { throw new TypeError( 'Expected string as first argument, got ' + common.unexpectedObjToString(source)); } } compileAndLoad(source, ns); return ns; } function grammarFromScriptElement(optNode) { var node = optNode; if (isUndefined(node)) { var nodeList = documentInterface.querySelectorAll('script[type="text/ohm-js"]'); if (nodeList.length !== 1) { throw new Error( 'Expected exactly one script tag with type="text/ohm-js", found ' + nodeList.length); } node = nodeList[0]; } return grammar(getScriptElementContents(node)); } function grammarsFromScriptElements(optNodeOrNodeList) { // Simple case: the argument is a DOM node. if (isElement(optNodeOrNodeList)) { return grammars(optNodeOrNodeList); } // Otherwise, it must be either undefined or a NodeList. var nodeList = optNodeOrNodeList; if (isUndefined(nodeList)) { // Find all script elements with type="text/ohm-js". nodeList = documentInterface.querySelectorAll('script[type="text/ohm-js"]'); } else if (typeof nodeList === 'string' || (!isElement(nodeList) && !isArrayLike(nodeList))) { throw new TypeError('Expected a Node, NodeList, or Array, but got ' + nodeList); } var ns = Namespace.createNamespace(); for (var i = 0; i < nodeList.length; ++i) { // Copy the new grammars into `ns` to keep the namespace flat. common.extend(ns, grammars(getScriptElementContents(nodeList[i]), ns)); } return ns; } function makeRecipe(recipe) { if (typeof recipe === 'function') { return recipe.call(new Builder()); } else { if (typeof recipe === 'string') { // stringified JSON recipe recipe = JSON.parse(recipe); } return (new Builder()).fromRecipe(recipe); } } // -------------------------------------------------------------------- // Exports // -------------------------------------------------------------------- // Stuff that users should know about module.exports = { createNamespace: Namespace.createNamespace, grammar: grammar, grammars: grammars, grammarFromScriptElement: grammarFromScriptElement, grammarsFromScriptElements: grammarsFromScriptElements, makeRecipe: makeRecipe, ohmGrammar: null, // Initialized below, after Grammar.BuiltInRules. pexprs: pexprs, util: util, extras: __webpack_require__(58) }; // Stuff for testing, etc. module.exports._buildGrammar = buildGrammar; module.exports._setDocumentInterfaceForTesting = function(doc) { documentInterface = doc; }; // Late initialization for stuff that is bootstrapped. Grammar.BuiltInRules = __webpack_require__(60); var Semantics = __webpack_require__(15); var operationsAndAttributesGrammar = __webpack_require__(61); Semantics.initBuiltInSemantics(Grammar.BuiltInRules); Semantics.initPrototypeParser(operationsAndAttributesGrammar); // requires BuiltInSemantics module.exports.ohmGrammar = ohmGrammar = __webpack_require__(62); Grammar.initApplicationParser(ohmGrammar, buildGrammar); /***/ }, /* 3 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; // -------------------------------------------------------------------- // Imports // -------------------------------------------------------------------- var GrammarDecl = __webpack_require__(4); var pexprs = __webpack_require__(38); // -------------------------------------------------------------------- // Private stuff // -------------------------------------------------------------------- function Builder() {} Builder.prototype = { currentDecl: null, newGrammar: function(name) { return new GrammarDecl(name); }, grammar: function(metaInfo, name, superGrammar, defaultStartRule, rules) { var gDecl = new GrammarDecl(name); if (superGrammar) { gDecl.withSuperGrammar(this.fromRecipe(superGrammar)); } if (defaultStartRule) { gDecl.withDefaultStartRule(defaultStartRule); } if (metaInfo && metaInfo.source) { gDecl.withSource(metaInfo.source); } var self = this; this.currentDecl = gDecl; Object.keys(rules).forEach(function(ruleName) { var ruleRecipe = rules[ruleName]; var action = ruleRecipe[0]; // define/extend/override var metaInfo = ruleRecipe[1]; var description = ruleRecipe[2]; var formals = ruleRecipe[3]; var body = self.fromRecipe(ruleRecipe[4]); var source; if (gDecl.source && metaInfo && metaInfo.sourceInterval) { var inputStream = gDecl.source.inputStream; source = inputStream.interval.apply(inputStream, metaInfo.sourceInterval); } gDecl[action](ruleName, formals, body, description, source); }); this.currentDecl = null; return gDecl.build(); }, terminal: function(x) { return new pexprs.Terminal(x); }, range: function(from, to) { return new pexprs.Range(from, to); }, param: function(index) { return new pexprs.Param(index); }, alt: function(/* term1, term1, ... */) { var terms = []; for (var idx = 0; idx < arguments.length; idx++) { var arg = arguments[idx]; if (!(arg instanceof pexprs.PExpr)) { arg = this.fromRecipe(arg); } if (arg instanceof pexprs.Alt) { terms = terms.concat(arg.terms); } else { terms.push(arg); } } return terms.length === 1 ? terms[0] : new pexprs.Alt(terms); }, seq: function(/* factor1, factor2, ... */) { var factors = []; for (var idx = 0; idx < arguments.length; idx++) { var arg = arguments[idx]; if (!(arg instanceof pexprs.PExpr)) { arg = this.fromRecipe(arg); } if (arg instanceof pexprs.Seq) { factors = factors.concat(arg.factors); } else { factors.push(arg); } } return factors.length === 1 ? factors[0] : new pexprs.Seq(factors); }, star: function(expr) { if (!(expr instanceof pexprs.PExpr)) { expr = this.fromRecipe(expr); } return new pexprs.Star(expr); }, plus: function(expr) { if (!(expr instanceof pexprs.PExpr)) { expr = this.fromRecipe(expr); } return new pexprs.Plus(expr); }, opt: function(expr) { if (!(expr instanceof pexprs.PExpr)) { expr = this.fromRecipe(expr); } return new pexprs.Opt(expr); }, not: function(expr) { if (!(expr instanceof pexprs.PExpr)) { expr = this.fromRecipe(expr); } return new pexprs.Not(expr); }, la: function(expr) { // TODO: temporary to still be able to read old recipes return this.lookahead(expr); }, lookahead: function(expr) { if (!(expr instanceof pexprs.PExpr)) { expr = this.fromRecipe(expr); } return new pexprs.Lookahead(expr); }, lex: function(expr) { if (!(expr instanceof pexprs.PExpr)) { expr = this.fromRecipe(expr); } return new pexprs.Lex(expr); }, app: function(ruleName, optParams) { if (optParams && optParams.length > 0) { optParams = optParams.map(function(param) { return param instanceof pexprs.PExpr ? param : this.fromRecipe(param); }, this); } return new pexprs.Apply(ruleName, optParams); }, fromRecipe: function(recipe) { // the meta-info of 'grammar' is proccessed in Builder.grammar var result = this[recipe[0]].apply(this, recipe[0] === 'grammar' ? recipe.slice(1) : recipe.slice(2)); var metaInfo = recipe[1]; if (metaInfo) { if (metaInfo.sourceInterval && this.currentDecl) { result.withSource( this.currentDecl.sourceInterval.apply(this.currentDecl, metaInfo.sourceInterval) ); } } return result; } }; // -------------------------------------------------------------------- // Exports // -------------------------------------------------------------------- module.exports = Builder; /***/ }, /* 4 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; // -------------------------------------------------------------------- // Imports // -------------------------------------------------------------------- var Grammar = __webpack_require__(5); var InputStream = __webpack_require__(35); var common = __webpack_require__(8); var errors = __webpack_require__(13); var pexprs = __webpack_require__(38); // -------------------------------------------------------------------- // Private Stuff // -------------------------------------------------------------------- // Constructors function GrammarDecl(name) { this.name = name; } // Helpers GrammarDecl.prototype.sourceInterval = function(startIdx, endIdx) { var inputStream = this.source.inputStream; return inputStream.interval(startIdx, endIdx); }; GrammarDecl.prototype.ensureSuperGrammar = function() { if (!this.superGrammar) { this.withSuperGrammar( // TODO: The conditional expression below is an ugly hack. It's kind of ok because // I doubt anyone will ever try to declare a grammar called `BuiltInRules`. Still, // we should try to find a better way to do this. this.name === 'BuiltInRules' ? Grammar.ProtoBuiltInRules : Grammar.BuiltInRules); } return this.superGrammar; }; GrammarDecl.prototype.installOverriddenOrExtendedRule = function(name, formals, body, source) { var duplicateParameterNames = common.getDuplicates(formals); if (duplicateParameterNames.length > 0) { throw errors.duplicateParameterNames(name, duplicateParameterNames, source); } var ruleInfo = this.ensureSuperGrammar().rules[name]; var expectedFormals = ruleInfo.formals; var expectedNumFormals = expectedFormals ? expectedFormals.length : 0; if (formals.length !== expectedNumFormals) { throw errors.wrongNumberOfParameters(name, expectedNumFormals, formals.length, source); } return this.install(name, formals, body, ruleInfo.description, source); }; GrammarDecl.prototype.install = function(name, formals, body, description, source) { this.rules[name] = { body: body.introduceParams(formals), formals: formals, description: description, source: source }; return this; }; // Stuff that you should only do once GrammarDecl.prototype.withSuperGrammar = function(superGrammar) { if (this.superGrammar) { throw new Error('the super grammar of a GrammarDecl cannot be set more than once'); } this.superGrammar = superGrammar; this.rules = Object.create(superGrammar.rules); // Grammars with an explicit supergrammar inherit a default start rule. if (!superGrammar.isBuiltIn()) { this.defaultStartRule = superGrammar.defaultStartRule; } return this; }; GrammarDecl.prototype.withDefaultStartRule = function(ruleName) { this.defaultStartRule = ruleName; return this; }; GrammarDecl.prototype.withSource = function(source) { this.source = new InputStream(source).interval(0, source.length); return this; }; // Creates a Grammar instance, and if it passes the sanity checks, returns it. GrammarDecl.prototype.build = function() { var grammar = new Grammar( this.name, this.ensureSuperGrammar(), this.rules, this.defaultStartRule); // TODO: change the pexpr.prototype.assert... methods to make them add // exceptions to an array that's provided as an arg. Then we'll be able to // show more than one error of the same type at a time. // TODO: include the offending pexpr in the errors, that way we can show // the part of the source that caused it. var grammarErrors = []; var grammarHasInvalidApplications = false; Object.keys(grammar.rules).forEach(function(ruleName) { var body = grammar.rules[ruleName].body; try { body.assertChoicesHaveUniformArity(ruleName); } catch (e) { grammarErrors.push(e); } try { body.assertAllApplicationsAreValid(ruleName, grammar); } catch (e) { grammarErrors.push(e); grammarHasInvalidApplications = true; } }); if (!grammarHasInvalidApplications) { // The following check can only be done if the grammar has no invalid applications. Object.keys(grammar.rules).forEach(function(ruleName) { var body = grammar.rules[ruleName].body; try { body.assertIteratedExprsAreNotNullable(grammar, ruleName); } catch (e) { grammarErrors.push(e); } }); } if (grammarErrors.length > 0) { errors.throwErrors(grammarErrors); } if (this.source) { grammar.source = this.source; } return grammar; }; // Rule declarations GrammarDecl.prototype.define = function(name, formals, body, description, source) { this.ensureSuperGrammar(); if (this.superGrammar.rules[name]) { throw errors.duplicateRuleDeclaration(name, this.name, this.superGrammar.name, source); } else if (this.rules[name]) { throw errors.duplicateRuleDeclaration(name, this.name, this.name, source); } var duplicateParameterNames = common.getDuplicates(formals); if (duplicateParameterNames.length > 0) { throw errors.duplicateParameterNames(name, duplicateParameterNames, source); } return this.install(name, formals, body, description, source); }; GrammarDecl.prototype.override = function(name, formals, body, descIgnored, source) { var ruleInfo = this.ensureSuperGrammar().rules[name]; if (!ruleInfo) { throw errors.cannotOverrideUndeclaredRule(name, this.superGrammar.name, source); } this.installOverriddenOrExtendedRule(name, formals, body, source); return this; }; GrammarDecl.prototype.extend = function(name, formals, fragment, descIgnored, source) { var ruleInfo = this.ensureSuperGrammar().rules[name]; if (!ruleInfo) { throw errors.cannotExtendUndeclaredRule(name, this.superGrammar.name, source); } var body = new pexprs.Extend(this.superGrammar, name, fragment); body.source = fragment.source; this.installOverriddenOrExtendedRule(name, formals, body, source); return this; }; // -------------------------------------------------------------------- // Exports // -------------------------------------------------------------------- module.exports = GrammarDecl; /***/ }, /* 5 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; // -------------------------------------------------------------------- // Imports // -------------------------------------------------------------------- var MatchResult = __webpack_require__(6); var Semantics = __webpack_require__(15); var State = __webpack_require__(34); var common = __webpack_require__(8); var errors = __webpack_require__(13); var pexprs = __webpack_require__(38); // -------------------------------------------------------------------- // Private stuff // -------------------------------------------------------------------- function getSortedRuleValues(grammar) { return Object.keys(grammar.rules).sort().map(function(name) { return grammar.rules[name]; }); } function Grammar( name, superGrammar, rules, optDefaultStartRule) { this.name = name; this.superGrammar = superGrammar; this.rules = rules; if (optDefaultStartRule) { if (!(optDefaultStartRule in rules)) { throw new Error("Invalid start rule: '" + optDefaultStartRule + "' is not a rule in grammar '" + name + "'"); } this.defaultStartRule = optDefaultStartRule; } } var ohmGrammar; var buildGrammar; // This method is called from main.js once Ohm has loaded. Grammar.initApplicationParser = function(grammar, builderFn) { ohmGrammar = grammar; buildGrammar = builderFn; }; Grammar.prototype = { // Return true if the grammar is a built-in grammar, otherwise false. // NOTE: This might give an unexpected result if called before BuiltInRules is defined! isBuiltIn: function() { return this === Grammar.ProtoBuiltInRules || this === Grammar.BuiltInRules; }, equals: function(g) { if (this === g) { return true; } // Do the cheapest comparisons first. if (g == null || this.name !== g.name || this.defaultStartRule !== g.defaultStartRule || !(this.superGrammar === g.superGrammar || this.superGrammar.equals(g.superGrammar))) { return false; } var myRules = getSortedRuleValues(this); var otherRules = getSortedRuleValues(g); return myRules.length === otherRules.length && myRules.every(function(rule, i) { return rule.description === otherRules[i].description && rule.formals.join(',') === otherRules[i].formals.join(',') && rule.body.toString() === otherRules[i].body.toString(); }); }, _match: function(input, opts) { var state = new State(this, input, opts); state.evalFromStart(); return state; }, match: function(input, optStartApplication) { var state = this._match(input, {startApplication: optStartApplication}); return MatchResult.newFor(state); }, trace: function(input, optStartApplication) { var state = this._match(input, {startApplication: optStartApplication, trace: true}); // The trace node for the start rule is always the last entry. If it is a syntactic rule, // the first entry is for an application of 'spaces'. // TODO(pdubroy): Clean this up by introducing a special `Match<startAppl>` rule, which will // ensure that there is always a single root trace node. var rootTrace = state.trace[state.trace.length - 1]; rootTrace.state = state; rootTrace.result = MatchResult.newFor(state); return rootTrace; }, semantics: function() { // TODO: Remove this eventually! Deprecated in v0.12. throw new Error('semantics() is deprecated -- use createSemantics() instead.'); }, createSemantics: function() { return Semantics.createSemantics(this); }, extendSemantics: function(superSemantics) { return Semantics.createSemantics(this, superSemantics._getSemantics()); }, // Check that every key in `actionDict` corresponds to a semantic action, and that it maps to // a function of the correct arity. If not, throw an exception. _checkTopDownActionDict: function(what, name, actionDict) { function isSpecialAction(a) { return a === '_iter' || a === '_terminal' || a === '_nonterminal' || a === '_default'; } var problems = []; for (var k in actionDict) { var v = actionDict[k]; if (!isSpecialAction(k) && !(k in this.rules)) { problems.push("'" + k + "' is not a valid semantic action for '" + this.name + "'"); } else if (typeof v !== 'function') { problems.push( "'" + k + "' must be a function in an action dictionary for '" + this.name + "'"); } else { var actual = v.length; var expected = this._topDownActionArity(k); if (actual !== expected) { problems.push( "Semantic action '" + k + "' has the wrong arity: " + 'expected ' + expected + ', got ' + actual); } } } if (problems.length > 0) { var prettyProblems = problems.map(function(problem) { return '- ' + problem; }); var error = new Error( "Found errors in the action dictionary of the '" + name + "' " + what + ':\n' + prettyProblems.join('\n')); error.problems = problems; throw error; } }, // Return the expected arity for a semantic action named `actionName`, which // is either a rule name or a special action name like '_nonterminal'. _topDownActionArity: function(actionName) { if (actionName === '_iter' || actionName === '_nonterminal' || actionName === '_default') { return 1; } else if (actionName === '_terminal') { return 0; } return this.rules[actionName].body.getArity(); }, _inheritsFrom: function(grammar) { var g = this.superGrammar; while (g) { if (g.equals(grammar, true)) { return true; } g = g.superGrammar; } return false; }, toRecipe: function(optVarName) { var metaInfo = {}; // Include the grammar source if it is available. if (this.source) { metaInfo.source = this.source.contents; } var superGrammar = null; if (this.superGrammar && !this.superGrammar.isBuiltIn()) { superGrammar = JSON.parse(this.superGrammar.toRecipe()); } var startRule = null; if (this.defaultStartRule) { startRule = this.defaultStartRule; } var rules = {}; var self = this; Object.keys(this.rules).forEach(function(ruleName) { var ruleInfo = self.rules[ruleName]; var body = ruleInfo.body; var isDefinition = !self.superGrammar || !self.superGrammar.rules[ruleName]; var operation; if (isDefinition) { operation = 'define'; } else { operation = body instanceof pexprs.Extend ? 'extend' : 'override'; } var metaInfo = {}; if (ruleInfo.source && self.source) { var adjusted = ruleInfo.source.relativeTo(self.source); metaInfo.sourceInterval = [adjusted.startIdx, adjusted.endIdx]; } var description = isDefinition ? ruleInfo.description : null; var bodyRecipe = body.outputRecipe(ruleInfo.formals, self.source); rules[ruleName] = [ operation, // "define"/"extend"/"override" metaInfo, description, ruleInfo.formals, bodyRecipe ]; }); return JSON.stringify([ 'grammar', metaInfo, this.name, superGrammar, startRule, rules ]); }, // TODO: Come up with better names for these methods. // TODO: Write the analog of these methods for inherited attributes. toOperationActionDictionaryTemplate: function() { return this._toOperationOrAttributeActionDictionaryTemplate(); }, toAttributeActionDictionaryTemplate: function() { return this._toOperationOrAttributeActionDictionaryTemplate(); }, _toOperationOrAttributeActionDictionaryTemplate: function() { // TODO: add the super-grammar's templates at the right place, e.g., a case for AddExpr_plus // should appear next to other cases of AddExpr. var sb = new common.StringBuffer(); sb.append('{'); var first = true; for (var ruleName in this.rules) { var body = this.rules[ruleName].body; if (first) { first = false; } else { sb.append(','); } sb.append('\n'); sb.append(' '); this.addSemanticActionTemplate(ruleName, body, sb); } sb.append('\n}'); return sb.contents(); }, addSemanticActionTemplate: function(ruleName, body, sb) { sb.append(ruleName); sb.append(': function('); var arity = this._topDownActionArity(ruleName); sb.append(common.repeat('_', arity).join(', ')); sb.append(') {\n'); sb.append(' }'); }, // Parse a string which expresses a rule application in this grammar, and return the // resulting Apply node. parseApplication: function(str) { var app; if (str.indexOf('<') === -1) { // simple application app = new pexprs.Apply(str); } else { // parameterized application var cst = ohmGrammar.match(str, 'Base_application'); app = buildGrammar(cst, {}); } // Ensure that the application is valid. if (!(app.ruleName in this.rules)) { throw errors.undeclar