UNPKG

rivescript-contrib-coffeescript

Version:

CoffeeScript object macro handler for RiveScript

1,512 lines (1,420 loc) 290 kB
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.RSCoffeeScript = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ /* rivescript-contrib-coffeescript - CoffeeScript object macro handler for RiveScript This code is released under the MIT License. See the "LICENSE" file for more information. https://www.rivescript.com/ */ "use strict"; var coffee = require("coffee-script"); /** * CoffeeHandler (RiveScript master) * * CoffeeScript language support for RiveScript object macros. */ var CoffeeHandler = function(master) { var self = this; self._master = master; self._objects = {}; /** * void load (string name, string[] code) * * Called by the RiveScript instance to load CoffeeScript code. */ self.load = function(name, code) { // Make this a dynamic CoffeeScript function. var source; try { source = "this._objects[\"" + name + "\"] = function(rs, args) {\n" + coffee.compile(code.join("\n"), {bare: true}) + "}\n"; } catch (e) { self._master.warn("Error constructing CoffeeScript source: " + e.message); return; } try { eval(source); } catch (e) { self._master.warn("Error evaluating CoffeeScript object: " + e.message); return; } }; /** * string call (RiveScript rs, string name, string[] fields, scope) * * Called by the RiveScript instance to execute an object macro. */ self.call = function(rs, name, fields, scope) { // Do we have it? if (!self._objects[name]) { return self._master.errors.objectNotFound; } // Call the dynamic method. var func = self._objects[name]; var reply = ""; try { reply = func.call(scope, rs, fields); } catch (e) { reply = "[ERR: Error when executing CoffeeScript object: " + e.message + "]"; } // Allow undefined responses. if (reply === undefined) { reply = ""; } return reply; } } module.exports = CoffeeHandler; },{"coffee-script":2}],2:[function(require,module,exports){ (function (process,global){ // Generated by CoffeeScript 1.10.0 (function() { var Lexer, SourceMap, base, compile, ext, formatSourcePosition, fs, getSourceMap, helpers, i, len, lexer, parser, path, ref, sourceMaps, vm, withPrettyErrors, hasProp = {}.hasOwnProperty, indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; fs = require('fs'); vm = require('vm'); path = require('path'); Lexer = require('./lexer').Lexer; parser = require('./parser').parser; helpers = require('./helpers'); SourceMap = require('./sourcemap'); exports.VERSION = '1.10.0'; exports.FILE_EXTENSIONS = ['.coffee', '.litcoffee', '.coffee.md']; exports.helpers = helpers; withPrettyErrors = function(fn) { return function(code, options) { var err, error; if (options == null) { options = {}; } try { return fn.call(this, code, options); } catch (error) { err = error; if (typeof code !== 'string') { throw err; } throw helpers.updateSyntaxError(err, code, options.filename); } }; }; exports.compile = compile = withPrettyErrors(function(code, options) { var answer, currentColumn, currentLine, extend, fragment, fragments, header, i, js, len, map, merge, newLines, token, tokens; merge = helpers.merge, extend = helpers.extend; options = extend({}, options); if (options.sourceMap) { map = new SourceMap; } tokens = lexer.tokenize(code, options); options.referencedVars = (function() { var i, len, results; results = []; for (i = 0, len = tokens.length; i < len; i++) { token = tokens[i]; if (token.variable) { results.push(token[1]); } } return results; })(); fragments = parser.parse(tokens).compileToFragments(options); currentLine = 0; if (options.header) { currentLine += 1; } if (options.shiftLine) { currentLine += 1; } currentColumn = 0; js = ""; for (i = 0, len = fragments.length; i < len; i++) { fragment = fragments[i]; if (options.sourceMap) { if (fragment.locationData && !/^[;\s]*$/.test(fragment.code)) { map.add([fragment.locationData.first_line, fragment.locationData.first_column], [currentLine, currentColumn], { noReplace: true }); } newLines = helpers.count(fragment.code, "\n"); currentLine += newLines; if (newLines) { currentColumn = fragment.code.length - (fragment.code.lastIndexOf("\n") + 1); } else { currentColumn += fragment.code.length; } } js += fragment.code; } if (options.header) { header = "Generated by CoffeeScript " + this.VERSION; js = "// " + header + "\n" + js; } if (options.sourceMap) { answer = { js: js }; answer.sourceMap = map; answer.v3SourceMap = map.generate(options, code); return answer; } else { return js; } }); exports.tokens = withPrettyErrors(function(code, options) { return lexer.tokenize(code, options); }); exports.nodes = withPrettyErrors(function(source, options) { if (typeof source === 'string') { return parser.parse(lexer.tokenize(source, options)); } else { return parser.parse(source); } }); exports.run = function(code, options) { var answer, dir, mainModule, ref; if (options == null) { options = {}; } mainModule = require.main; mainModule.filename = process.argv[1] = options.filename ? fs.realpathSync(options.filename) : '.'; mainModule.moduleCache && (mainModule.moduleCache = {}); dir = options.filename ? path.dirname(fs.realpathSync(options.filename)) : fs.realpathSync('.'); mainModule.paths = require('module')._nodeModulePaths(dir); if (!helpers.isCoffee(mainModule.filename) || require.extensions) { answer = compile(code, options); code = (ref = answer.js) != null ? ref : answer; } return mainModule._compile(code, mainModule.filename); }; exports["eval"] = function(code, options) { var Module, _module, _require, createContext, i, isContext, js, k, len, o, r, ref, ref1, ref2, ref3, sandbox, v; if (options == null) { options = {}; } if (!(code = code.trim())) { return; } createContext = (ref = vm.Script.createContext) != null ? ref : vm.createContext; isContext = (ref1 = vm.isContext) != null ? ref1 : function(ctx) { return options.sandbox instanceof createContext().constructor; }; if (createContext) { if (options.sandbox != null) { if (isContext(options.sandbox)) { sandbox = options.sandbox; } else { sandbox = createContext(); ref2 = options.sandbox; for (k in ref2) { if (!hasProp.call(ref2, k)) continue; v = ref2[k]; sandbox[k] = v; } } sandbox.global = sandbox.root = sandbox.GLOBAL = sandbox; } else { sandbox = global; } sandbox.__filename = options.filename || 'eval'; sandbox.__dirname = path.dirname(sandbox.__filename); if (!(sandbox !== global || sandbox.module || sandbox.require)) { Module = require('module'); sandbox.module = _module = new Module(options.modulename || 'eval'); sandbox.require = _require = function(path) { return Module._load(path, _module, true); }; _module.filename = sandbox.__filename; ref3 = Object.getOwnPropertyNames(require); for (i = 0, len = ref3.length; i < len; i++) { r = ref3[i]; if (r !== 'paths' && r !== 'arguments' && r !== 'caller') { _require[r] = require[r]; } } _require.paths = _module.paths = Module._nodeModulePaths(process.cwd()); _require.resolve = function(request) { return Module._resolveFilename(request, _module); }; } } o = {}; for (k in options) { if (!hasProp.call(options, k)) continue; v = options[k]; o[k] = v; } o.bare = true; js = compile(code, o); if (sandbox === global) { return vm.runInThisContext(js); } else { return vm.runInContext(js, sandbox); } }; exports.register = function() { return require('./register'); }; if (require.extensions) { ref = this.FILE_EXTENSIONS; for (i = 0, len = ref.length; i < len; i++) { ext = ref[i]; if ((base = require.extensions)[ext] == null) { base[ext] = function() { throw new Error("Use CoffeeScript.register() or require the coffee-script/register module to require " + ext + " files."); }; } } } exports._compileFile = function(filename, sourceMap) { var answer, err, error, raw, stripped; if (sourceMap == null) { sourceMap = false; } raw = fs.readFileSync(filename, 'utf8'); stripped = raw.charCodeAt(0) === 0xFEFF ? raw.substring(1) : raw; try { answer = compile(stripped, { filename: filename, sourceMap: sourceMap, literate: helpers.isLiterate(filename) }); } catch (error) { err = error; throw helpers.updateSyntaxError(err, stripped, filename); } return answer; }; lexer = new Lexer; parser.lexer = { lex: function() { var tag, token; token = parser.tokens[this.pos++]; if (token) { tag = token[0], this.yytext = token[1], this.yylloc = token[2]; parser.errorToken = token.origin || token; this.yylineno = this.yylloc.first_line; } else { tag = ''; } return tag; }, setInput: function(tokens) { parser.tokens = tokens; return this.pos = 0; }, upcomingInput: function() { return ""; } }; parser.yy = require('./nodes'); parser.yy.parseError = function(message, arg) { var errorLoc, errorTag, errorText, errorToken, token, tokens; token = arg.token; errorToken = parser.errorToken, tokens = parser.tokens; errorTag = errorToken[0], errorText = errorToken[1], errorLoc = errorToken[2]; errorText = (function() { switch (false) { case errorToken !== tokens[tokens.length - 1]: return 'end of input'; case errorTag !== 'INDENT' && errorTag !== 'OUTDENT': return 'indentation'; case errorTag !== 'IDENTIFIER' && errorTag !== 'NUMBER' && errorTag !== 'STRING' && errorTag !== 'STRING_START' && errorTag !== 'REGEX' && errorTag !== 'REGEX_START': return errorTag.replace(/_START$/, '').toLowerCase(); default: return helpers.nameWhitespaceCharacter(errorText); } })(); return helpers.throwSyntaxError("unexpected " + errorText, errorLoc); }; formatSourcePosition = function(frame, getSourceMapping) { var as, column, fileLocation, fileName, functionName, isConstructor, isMethodCall, line, methodName, source, tp, typeName; fileName = void 0; fileLocation = ''; if (frame.isNative()) { fileLocation = "native"; } else { if (frame.isEval()) { fileName = frame.getScriptNameOrSourceURL(); if (!fileName) { fileLocation = (frame.getEvalOrigin()) + ", "; } } else { fileName = frame.getFileName(); } fileName || (fileName = "<anonymous>"); line = frame.getLineNumber(); column = frame.getColumnNumber(); source = getSourceMapping(fileName, line, column); fileLocation = source ? fileName + ":" + source[0] + ":" + source[1] : fileName + ":" + line + ":" + column; } functionName = frame.getFunctionName(); isConstructor = frame.isConstructor(); isMethodCall = !(frame.isToplevel() || isConstructor); if (isMethodCall) { methodName = frame.getMethodName(); typeName = frame.getTypeName(); if (functionName) { tp = as = ''; if (typeName && functionName.indexOf(typeName)) { tp = typeName + "."; } if (methodName && functionName.indexOf("." + methodName) !== functionName.length - methodName.length - 1) { as = " [as " + methodName + "]"; } return "" + tp + functionName + as + " (" + fileLocation + ")"; } else { return typeName + "." + (methodName || '<anonymous>') + " (" + fileLocation + ")"; } } else if (isConstructor) { return "new " + (functionName || '<anonymous>') + " (" + fileLocation + ")"; } else if (functionName) { return functionName + " (" + fileLocation + ")"; } else { return fileLocation; } }; sourceMaps = {}; getSourceMap = function(filename) { var answer, ref1; if (sourceMaps[filename]) { return sourceMaps[filename]; } if (ref1 = path != null ? path.extname(filename) : void 0, indexOf.call(exports.FILE_EXTENSIONS, ref1) < 0) { return; } answer = exports._compileFile(filename, true); return sourceMaps[filename] = answer.sourceMap; }; Error.prepareStackTrace = function(err, stack) { var frame, frames, getSourceMapping; getSourceMapping = function(filename, line, column) { var answer, sourceMap; sourceMap = getSourceMap(filename); if (sourceMap) { answer = sourceMap.sourceLocation([line - 1, column - 1]); } if (answer) { return [answer[0] + 1, answer[1] + 1]; } else { return null; } }; frames = (function() { var j, len1, results; results = []; for (j = 0, len1 = stack.length; j < len1; j++) { frame = stack[j]; if (frame.getFunction() === exports.run) { break; } results.push(" at " + (formatSourcePosition(frame, getSourceMapping))); } return results; })(); return (err.toString()) + "\n" + (frames.join('\n')) + "\n"; }; }).call(this); }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"./helpers":3,"./lexer":4,"./nodes":5,"./parser":6,"./register":7,"./sourcemap":10,"_process":13,"fs":11,"module":11,"path":12,"vm":14}],3:[function(require,module,exports){ (function (process){ // Generated by CoffeeScript 1.10.0 (function() { var buildLocationData, extend, flatten, ref, repeat, syntaxErrorToString; exports.starts = function(string, literal, start) { return literal === string.substr(start, literal.length); }; exports.ends = function(string, literal, back) { var len; len = literal.length; return literal === string.substr(string.length - len - (back || 0), len); }; exports.repeat = repeat = function(str, n) { var res; res = ''; while (n > 0) { if (n & 1) { res += str; } n >>>= 1; str += str; } return res; }; exports.compact = function(array) { var i, item, len1, results; results = []; for (i = 0, len1 = array.length; i < len1; i++) { item = array[i]; if (item) { results.push(item); } } return results; }; exports.count = function(string, substr) { var num, pos; num = pos = 0; if (!substr.length) { return 1 / 0; } while (pos = 1 + string.indexOf(substr, pos)) { num++; } return num; }; exports.merge = function(options, overrides) { return extend(extend({}, options), overrides); }; extend = exports.extend = function(object, properties) { var key, val; for (key in properties) { val = properties[key]; object[key] = val; } return object; }; exports.flatten = flatten = function(array) { var element, flattened, i, len1; flattened = []; for (i = 0, len1 = array.length; i < len1; i++) { element = array[i]; if ('[object Array]' === Object.prototype.toString.call(element)) { flattened = flattened.concat(flatten(element)); } else { flattened.push(element); } } return flattened; }; exports.del = function(obj, key) { var val; val = obj[key]; delete obj[key]; return val; }; exports.some = (ref = Array.prototype.some) != null ? ref : function(fn) { var e, i, len1; for (i = 0, len1 = this.length; i < len1; i++) { e = this[i]; if (fn(e)) { return true; } } return false; }; exports.invertLiterate = function(code) { var line, lines, maybe_code; maybe_code = true; lines = (function() { var i, len1, ref1, results; ref1 = code.split('\n'); results = []; for (i = 0, len1 = ref1.length; i < len1; i++) { line = ref1[i]; if (maybe_code && /^([ ]{4}|[ ]{0,3}\t)/.test(line)) { results.push(line); } else if (maybe_code = /^\s*$/.test(line)) { results.push(line); } else { results.push('# ' + line); } } return results; })(); return lines.join('\n'); }; buildLocationData = function(first, last) { if (!last) { return first; } else { return { first_line: first.first_line, first_column: first.first_column, last_line: last.last_line, last_column: last.last_column }; } }; exports.addLocationDataFn = function(first, last) { return function(obj) { if (((typeof obj) === 'object') && (!!obj['updateLocationDataIfMissing'])) { obj.updateLocationDataIfMissing(buildLocationData(first, last)); } return obj; }; }; exports.locationDataToString = function(obj) { var locationData; if (("2" in obj) && ("first_line" in obj[2])) { locationData = obj[2]; } else if ("first_line" in obj) { locationData = obj; } if (locationData) { return ((locationData.first_line + 1) + ":" + (locationData.first_column + 1) + "-") + ((locationData.last_line + 1) + ":" + (locationData.last_column + 1)); } else { return "No location data"; } }; exports.baseFileName = function(file, stripExt, useWinPathSep) { var parts, pathSep; if (stripExt == null) { stripExt = false; } if (useWinPathSep == null) { useWinPathSep = false; } pathSep = useWinPathSep ? /\\|\// : /\//; parts = file.split(pathSep); file = parts[parts.length - 1]; if (!(stripExt && file.indexOf('.') >= 0)) { return file; } parts = file.split('.'); parts.pop(); if (parts[parts.length - 1] === 'coffee' && parts.length > 1) { parts.pop(); } return parts.join('.'); }; exports.isCoffee = function(file) { return /\.((lit)?coffee|coffee\.md)$/.test(file); }; exports.isLiterate = function(file) { return /\.(litcoffee|coffee\.md)$/.test(file); }; exports.throwSyntaxError = function(message, location) { var error; error = new SyntaxError(message); error.location = location; error.toString = syntaxErrorToString; error.stack = error.toString(); throw error; }; exports.updateSyntaxError = function(error, code, filename) { if (error.toString === syntaxErrorToString) { error.code || (error.code = code); error.filename || (error.filename = filename); error.stack = error.toString(); } return error; }; syntaxErrorToString = function() { var codeLine, colorize, colorsEnabled, end, filename, first_column, first_line, last_column, last_line, marker, ref1, ref2, ref3, ref4, start; if (!(this.code && this.location)) { return Error.prototype.toString.call(this); } ref1 = this.location, first_line = ref1.first_line, first_column = ref1.first_column, last_line = ref1.last_line, last_column = ref1.last_column; if (last_line == null) { last_line = first_line; } if (last_column == null) { last_column = first_column; } filename = this.filename || '[stdin]'; codeLine = this.code.split('\n')[first_line]; start = first_column; end = first_line === last_line ? last_column + 1 : codeLine.length; marker = codeLine.slice(0, start).replace(/[^\s]/g, ' ') + repeat('^', end - start); if (typeof process !== "undefined" && process !== null) { colorsEnabled = ((ref2 = process.stdout) != null ? ref2.isTTY : void 0) && !((ref3 = process.env) != null ? ref3.NODE_DISABLE_COLORS : void 0); } if ((ref4 = this.colorful) != null ? ref4 : colorsEnabled) { colorize = function(str) { return "\x1B[1;31m" + str + "\x1B[0m"; }; codeLine = codeLine.slice(0, start) + colorize(codeLine.slice(start, end)) + codeLine.slice(end); marker = colorize(marker); } return filename + ":" + (first_line + 1) + ":" + (first_column + 1) + ": error: " + this.message + "\n" + codeLine + "\n" + marker; }; exports.nameWhitespaceCharacter = function(string) { switch (string) { case ' ': return 'space'; case '\n': return 'newline'; case '\r': return 'carriage return'; case '\t': return 'tab'; default: return string; } }; }).call(this); }).call(this,require('_process')) },{"_process":13}],4:[function(require,module,exports){ // Generated by CoffeeScript 1.10.0 (function() { var BOM, BOOL, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_ALIAS_MAP, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, HERECOMMENT_ILLEGAL, HEREDOC_DOUBLE, HEREDOC_INDENT, HEREDOC_SINGLE, HEREGEX, HEREGEX_OMIT, IDENTIFIER, INDENTABLE_CLOSERS, INDEXABLE, INVALID_ESCAPE, INVERSES, JSTOKEN, JS_FORBIDDEN, JS_KEYWORDS, LEADING_BLANK_LINE, LINE_BREAK, LINE_CONTINUER, LOGIC, Lexer, MATH, MULTI_DENT, NOT_REGEX, NUMBER, OPERATOR, POSSIBLY_DIVISION, REGEX, REGEX_FLAGS, REGEX_ILLEGAL, RELATION, RESERVED, Rewriter, SHIFT, SIMPLE_STRING_OMIT, STRICT_PROSCRIBED, STRING_DOUBLE, STRING_OMIT, STRING_SINGLE, STRING_START, TRAILING_BLANK_LINE, TRAILING_SPACES, UNARY, UNARY_MATH, VALID_FLAGS, WHITESPACE, compact, count, invertLiterate, key, locationDataToString, ref, ref1, repeat, starts, throwSyntaxError, indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; ref = require('./rewriter'), Rewriter = ref.Rewriter, INVERSES = ref.INVERSES; ref1 = require('./helpers'), count = ref1.count, starts = ref1.starts, compact = ref1.compact, repeat = ref1.repeat, invertLiterate = ref1.invertLiterate, locationDataToString = ref1.locationDataToString, throwSyntaxError = ref1.throwSyntaxError; exports.Lexer = Lexer = (function() { function Lexer() {} Lexer.prototype.tokenize = function(code, opts) { var consumed, end, i, ref2; if (opts == null) { opts = {}; } this.literate = opts.literate; this.indent = 0; this.baseIndent = 0; this.indebt = 0; this.outdebt = 0; this.indents = []; this.ends = []; this.tokens = []; this.seenFor = false; this.chunkLine = opts.line || 0; this.chunkColumn = opts.column || 0; code = this.clean(code); i = 0; while (this.chunk = code.slice(i)) { consumed = this.identifierToken() || this.commentToken() || this.whitespaceToken() || this.lineToken() || this.stringToken() || this.numberToken() || this.regexToken() || this.jsToken() || this.literalToken(); ref2 = this.getLineAndColumnFromChunk(consumed), this.chunkLine = ref2[0], this.chunkColumn = ref2[1]; i += consumed; if (opts.untilBalanced && this.ends.length === 0) { return { tokens: this.tokens, index: i }; } } this.closeIndentation(); if (end = this.ends.pop()) { this.error("missing " + end.tag, end.origin[2]); } if (opts.rewrite === false) { return this.tokens; } return (new Rewriter).rewrite(this.tokens); }; Lexer.prototype.clean = function(code) { if (code.charCodeAt(0) === BOM) { code = code.slice(1); } code = code.replace(/\r/g, '').replace(TRAILING_SPACES, ''); if (WHITESPACE.test(code)) { code = "\n" + code; this.chunkLine--; } if (this.literate) { code = invertLiterate(code); } return code; }; Lexer.prototype.identifierToken = function() { var alias, colon, colonOffset, forcedIdentifier, id, idLength, input, match, poppedToken, prev, ref2, ref3, ref4, ref5, tag, tagToken; if (!(match = IDENTIFIER.exec(this.chunk))) { return 0; } input = match[0], id = match[1], colon = match[2]; idLength = id.length; poppedToken = void 0; if (id === 'own' && this.tag() === 'FOR') { this.token('OWN', id); return id.length; } if (id === 'from' && this.tag() === 'YIELD') { this.token('FROM', id); return id.length; } ref2 = this.tokens, prev = ref2[ref2.length - 1]; forcedIdentifier = colon || (prev != null) && (((ref3 = prev[0]) === '.' || ref3 === '?.' || ref3 === '::' || ref3 === '?::') || !prev.spaced && prev[0] === '@'); tag = 'IDENTIFIER'; if (!forcedIdentifier && (indexOf.call(JS_KEYWORDS, id) >= 0 || indexOf.call(COFFEE_KEYWORDS, id) >= 0)) { tag = id.toUpperCase(); if (tag === 'WHEN' && (ref4 = this.tag(), indexOf.call(LINE_BREAK, ref4) >= 0)) { tag = 'LEADING_WHEN'; } else if (tag === 'FOR') { this.seenFor = true; } else if (tag === 'UNLESS') { tag = 'IF'; } else if (indexOf.call(UNARY, tag) >= 0) { tag = 'UNARY'; } else if (indexOf.call(RELATION, tag) >= 0) { if (tag !== 'INSTANCEOF' && this.seenFor) { tag = 'FOR' + tag; this.seenFor = false; } else { tag = 'RELATION'; if (this.value() === '!') { poppedToken = this.tokens.pop(); id = '!' + id; } } } } if (indexOf.call(JS_FORBIDDEN, id) >= 0) { if (forcedIdentifier) { tag = 'IDENTIFIER'; id = new String(id); id.reserved = true; } else if (indexOf.call(RESERVED, id) >= 0) { this.error("reserved word '" + id + "'", { length: id.length }); } } if (!forcedIdentifier) { if (indexOf.call(COFFEE_ALIASES, id) >= 0) { alias = id; id = COFFEE_ALIAS_MAP[id]; } tag = (function() { switch (id) { case '!': return 'UNARY'; case '==': case '!=': return 'COMPARE'; case '&&': case '||': return 'LOGIC'; case 'true': case 'false': return 'BOOL'; case 'break': case 'continue': return 'STATEMENT'; default: return tag; } })(); } tagToken = this.token(tag, id, 0, idLength); if (alias) { tagToken.origin = [tag, alias, tagToken[2]]; } tagToken.variable = !forcedIdentifier; if (poppedToken) { ref5 = [poppedToken[2].first_line, poppedToken[2].first_column], tagToken[2].first_line = ref5[0], tagToken[2].first_column = ref5[1]; } if (colon) { colonOffset = input.lastIndexOf(':'); this.token(':', ':', colonOffset, colon.length); } return input.length; }; Lexer.prototype.numberToken = function() { var binaryLiteral, lexedLength, match, number, octalLiteral; if (!(match = NUMBER.exec(this.chunk))) { return 0; } number = match[0]; lexedLength = number.length; if (/^0[BOX]/.test(number)) { this.error("radix prefix in '" + number + "' must be lowercase", { offset: 1 }); } else if (/E/.test(number) && !/^0x/.test(number)) { this.error("exponential notation in '" + number + "' must be indicated with a lowercase 'e'", { offset: number.indexOf('E') }); } else if (/^0\d*[89]/.test(number)) { this.error("decimal literal '" + number + "' must not be prefixed with '0'", { length: lexedLength }); } else if (/^0\d+/.test(number)) { this.error("octal literal '" + number + "' must be prefixed with '0o'", { length: lexedLength }); } if (octalLiteral = /^0o([0-7]+)/.exec(number)) { number = '0x' + parseInt(octalLiteral[1], 8).toString(16); } if (binaryLiteral = /^0b([01]+)/.exec(number)) { number = '0x' + parseInt(binaryLiteral[1], 2).toString(16); } this.token('NUMBER', number, 0, lexedLength); return lexedLength; }; Lexer.prototype.stringToken = function() { var $, attempt, delimiter, doc, end, heredoc, i, indent, indentRegex, match, quote, ref2, ref3, regex, token, tokens; quote = (STRING_START.exec(this.chunk) || [])[0]; if (!quote) { return 0; } regex = (function() { switch (quote) { case "'": return STRING_SINGLE; case '"': return STRING_DOUBLE; case "'''": return HEREDOC_SINGLE; case '"""': return HEREDOC_DOUBLE; } })(); heredoc = quote.length === 3; ref2 = this.matchWithInterpolations(regex, quote), tokens = ref2.tokens, end = ref2.index; $ = tokens.length - 1; delimiter = quote.charAt(0); if (heredoc) { indent = null; doc = ((function() { var j, len, results; results = []; for (i = j = 0, len = tokens.length; j < len; i = ++j) { token = tokens[i]; if (token[0] === 'NEOSTRING') { results.push(token[1]); } } return results; })()).join('#{}'); while (match = HEREDOC_INDENT.exec(doc)) { attempt = match[1]; if (indent === null || (0 < (ref3 = attempt.length) && ref3 < indent.length)) { indent = attempt; } } if (indent) { indentRegex = RegExp("^" + indent, "gm"); } this.mergeInterpolationTokens(tokens, { delimiter: delimiter }, (function(_this) { return function(value, i) { value = _this.formatString(value); if (i === 0) { value = value.replace(LEADING_BLANK_LINE, ''); } if (i === $) { value = value.replace(TRAILING_BLANK_LINE, ''); } if (indentRegex) { value = value.replace(indentRegex, ''); } return value; }; })(this)); } else { this.mergeInterpolationTokens(tokens, { delimiter: delimiter }, (function(_this) { return function(value, i) { value = _this.formatString(value); value = value.replace(SIMPLE_STRING_OMIT, function(match, offset) { if ((i === 0 && offset === 0) || (i === $ && offset + match.length === value.length)) { return ''; } else { return ' '; } }); return value; }; })(this)); } return end; }; Lexer.prototype.commentToken = function() { var comment, here, match; if (!(match = this.chunk.match(COMMENT))) { return 0; } comment = match[0], here = match[1]; if (here) { if (match = HERECOMMENT_ILLEGAL.exec(comment)) { this.error("block comments cannot contain " + match[0], { offset: match.index, length: match[0].length }); } if (here.indexOf('\n') >= 0) { here = here.replace(RegExp("\\n" + (repeat(' ', this.indent)), "g"), '\n'); } this.token('HERECOMMENT', here, 0, comment.length); } return comment.length; }; Lexer.prototype.jsToken = function() { var match, script; if (!(this.chunk.charAt(0) === '`' && (match = JSTOKEN.exec(this.chunk)))) { return 0; } this.token('JS', (script = match[0]).slice(1, -1), 0, script.length); return script.length; }; Lexer.prototype.regexToken = function() { var body, closed, end, flags, index, match, origin, prev, ref2, ref3, ref4, regex, tokens; switch (false) { case !(match = REGEX_ILLEGAL.exec(this.chunk)): this.error("regular expressions cannot begin with " + match[2], { offset: match.index + match[1].length }); break; case !(match = this.matchWithInterpolations(HEREGEX, '///')): tokens = match.tokens, index = match.index; break; case !(match = REGEX.exec(this.chunk)): regex = match[0], body = match[1], closed = match[2]; this.validateEscapes(body, { isRegex: true, offsetInChunk: 1 }); index = regex.length; ref2 = this.tokens, prev = ref2[ref2.length - 1]; if (prev) { if (prev.spaced && (ref3 = prev[0], indexOf.call(CALLABLE, ref3) >= 0)) { if (!closed || POSSIBLY_DIVISION.test(regex)) { return 0; } } else if (ref4 = prev[0], indexOf.call(NOT_REGEX, ref4) >= 0) { return 0; } } if (!closed) { this.error('missing / (unclosed regex)'); } break; default: return 0; } flags = REGEX_FLAGS.exec(this.chunk.slice(index))[0]; end = index + flags.length; origin = this.makeToken('REGEX', null, 0, end); switch (false) { case !!VALID_FLAGS.test(flags): this.error("invalid regular expression flags " + flags, { offset: index, length: flags.length }); break; case !(regex || tokens.length === 1): if (body == null) { body = this.formatHeregex(tokens[0][1]); } this.token('REGEX', "" + (this.makeDelimitedLiteral(body, { delimiter: '/' })) + flags, 0, end, origin); break; default: this.token('REGEX_START', '(', 0, 0, origin); this.token('IDENTIFIER', 'RegExp', 0, 0); this.token('CALL_START', '(', 0, 0); this.mergeInterpolationTokens(tokens, { delimiter: '"', double: true }, this.formatHeregex); if (flags) { this.token(',', ',', index, 0); this.token('STRING', '"' + flags + '"', index, flags.length); } this.token(')', ')', end, 0); this.token('REGEX_END', ')', end, 0); } return end; }; Lexer.prototype.lineToken = function() { var diff, indent, match, noNewlines, size; if (!(match = MULTI_DENT.exec(this.chunk))) { return 0; } indent = match[0]; this.seenFor = false; size = indent.length - 1 - indent.lastIndexOf('\n'); noNewlines = this.unfinished(); if (size - this.indebt === this.indent) { if (noNewlines) { this.suppressNewlines(); } else { this.newlineToken(0); } return indent.length; } if (size > this.indent) { if (noNewlines) { this.indebt = size - this.indent; this.suppressNewlines(); return indent.length; } if (!this.tokens.length) { this.baseIndent = this.indent = size; return indent.length; } diff = size - this.indent + this.outdebt; this.token('INDENT', diff, indent.length - size, size); this.indents.push(diff); this.ends.push({ tag: 'OUTDENT' }); this.outdebt = this.indebt = 0; this.indent = size; } else if (size < this.baseIndent) { this.error('missing indentation', { offset: indent.length }); } else { this.indebt = 0; this.outdentToken(this.indent - size, noNewlines, indent.length); } return indent.length; }; Lexer.prototype.outdentToken = function(moveOut, noNewlines, outdentLength) { var decreasedIndent, dent, lastIndent, ref2; decreasedIndent = this.indent - moveOut; while (moveOut > 0) { lastIndent = this.indents[this.indents.length - 1]; if (!lastIndent) { moveOut = 0; } else if (lastIndent === this.outdebt) { moveOut -= this.outdebt; this.outdebt = 0; } else if (lastIndent < this.outdebt) { this.outdebt -= lastIndent; moveOut -= lastIndent; } else { dent = this.indents.pop() + this.outdebt; if (outdentLength && (ref2 = this.chunk[outdentLength], indexOf.call(INDENTABLE_CLOSERS, ref2) >= 0)) { decreasedIndent -= dent - moveOut; moveOut = dent; } this.outdebt = 0; this.pair('OUTDENT'); this.token('OUTDENT', moveOut, 0, outdentLength); moveOut -= dent; } } if (dent) { this.outdebt -= moveOut; } while (this.value() === ';') { this.tokens.pop(); } if (!(this.tag() === 'TERMINATOR' || noNewlines)) { this.token('TERMINATOR', '\n', outdentLength, 0); } this.indent = decreasedIndent; return this; }; Lexer.prototype.whitespaceToken = function() { var match, nline, prev, ref2; if (!((match = WHITESPACE.exec(this.chunk)) || (nline = this.chunk.charAt(0) === '\n'))) { return 0; } ref2 = this.tokens, prev = ref2[ref2.length - 1]; if (prev) { prev[match ? 'spaced' : 'newLine'] = true; } if (match) { return match[0].length; } else { return 0; } }; Lexer.prototype.newlineToken = function(offset) { while (this.value() === ';') { this.tokens.pop(); } if (this.tag() !== 'TERMINATOR') { this.token('TERMINATOR', '\n', offset, 0); } return this; }; Lexer.prototype.suppressNewlines = function() { if (this.value() === '\\') { this.tokens.pop(); } return this; }; Lexer.prototype.literalToken = function() { var match, prev, ref2, ref3, ref4, ref5, ref6, tag, token, value; if (match = OPERATOR.exec(this.chunk)) { value = match[0]; if (CODE.test(value)) { this.tagParameters(); } } else { value = this.chunk.charAt(0); } tag = value; ref2 = this.tokens, prev = ref2[ref2.length - 1]; if (value === '=' && prev) { if (!prev[1].reserved && (ref3 = prev[1], indexOf.call(JS_FORBIDDEN, ref3) >= 0)) { if (prev.origin) { prev = prev.origin; } this.error("reserved word '" + prev[1] + "' can't be assigned", prev[2]); } if ((ref4 = prev[1]) === '||' || ref4 === '&&') { prev[0] = 'COMPOUND_ASSIGN'; prev[1] += '='; return value.length; } } if (value === ';') { this.seenFor = false; tag = 'TERMINATOR'; } else if (indexOf.call(MATH, value) >= 0) { tag = 'MATH'; } else if (indexOf.call(COMPARE, value) >= 0) { tag = 'COMPARE'; } else if (indexOf.call(COMPOUND_ASSIGN, value) >= 0) { tag = 'COMPOUND_ASSIGN'; } else if (indexOf.call(UNARY, value) >= 0) { tag = 'UNARY'; } else if (indexOf.call(UNARY_MATH, value) >= 0) { tag = 'UNARY_MATH'; } else if (indexOf.call(SHIFT, value) >= 0) { tag = 'SHIFT'; } else if (indexOf.call(LOGIC, value) >= 0 || value === '?' && (prev != null ? prev.spaced : void 0)) { tag = 'LOGIC'; } else if (prev && !prev.spaced) { if (value === '(' && (ref5 = prev[0], indexOf.call(CALLABLE, ref5) >= 0)) { if (prev[0] === '?') { prev[0] = 'FUNC_EXIST'; } tag = 'CALL_START'; } else if (value === '[' && (ref6 = prev[0], indexOf.call(INDEXABLE, ref6) >= 0)) { tag = 'INDEX_START'; switch (prev[0]) { case '?': prev[0] = 'INDEX_SOAK'; } } } token = this.makeToken(tag, value); switch (value) { case '(': case '{': case '[': this.ends.push({ tag: INVERSES[value], origin: token }); break; case ')': case '}': case ']': this.pair(value); } this.tokens.push(token); return value.length; }; Lexer.prototype.tagParameters = function() { var i, stack, tok, tokens; if (this.tag() !== ')') { return this; } stack = []; tokens = this.tokens; i = tokens.length; tokens[--i][0] = 'PARAM_END'; while (tok = tokens[--i]) { switch (tok[0]) { case ')': stack.push(tok); break; case '(': case 'CALL_START': if (stack.length) { stack.pop(); } else if (tok[0] === '(') { tok[0] = 'PARAM_START'; return this; } else { return this; } } } return this; }; Lexer.prototype.closeIndentation = function() { return this.outdentToken(this.indent); }; Lexer.prototype.matchWithInterpolations = function(regex, delimiter) { var close, column, firstToken, index, lastToken, line, nested, offsetInChunk, open, ref2, ref3, ref4, str, strPart, tokens; tokens = []; offsetInChunk = delimiter.length; if (this.chunk.slice(0, offsetInChunk) !== delimiter) { return null; } str = this.chunk.slice(offsetInChunk); while (true) { strPart = regex.exec(str)[0]; this.validateEscapes(strPart, { isRegex: delimiter.charAt(0) === '/', offsetInChunk: offsetInChunk }); tokens.push(this.makeToken('NEOSTRING', strPart, offsetInChunk)); str = str.slice(strPart.length); offsetInChunk += strPart.length; if (str.slice(0, 2) !== '#{') { break; } ref2 = this.getLineAndColumnFromChunk(offsetInChunk + 1), line = ref2[0], column = ref2[1]; ref3 = new Lexer().tokenize(str.slice(1), { line: line, column: column, untilBalanced: true }), nested = ref3.tokens, index = ref3.index; index += 1; open = nested[0], close = nested[nested.length - 1]; open[0] = open[1] = '('; close[0] = close[1] = ')'; close.origin = ['', 'end of interpolation', close[2]]; if (((ref4 = nested[1]) != null ? ref4[0] : void 0) === 'TERMINATOR') { nested.splice(1, 1); } tokens.push(['TOKENS', nested]); str = str.slice(index); offsetInChunk += index; } if (str.slice(0, delimiter.length) !== delimiter) { this.error("missing " + delimiter, { length: delimiter.length }); } firstToken = tokens[0], lastToken = tokens[tokens.length - 1]; firstToken[2].first_column -= delimiter.length; lastToken[2].last_column += delimiter.length; if (lastToken[1].length === 0) { lastToken[2].last_column -= 1; } return { tokens: tokens, index: offsetInChunk + delimiter.length }; }; Lexer.prototype.mergeInterpolationTokens = function(tokens, options, fn) { var converted, firstEmptyStringIndex, firstIndex, i, j, lastToken, len, locationToken, lparen, plusToken, ref2, rparen, tag, token, tokensToPush, value; if (tokens.length > 1) { lparen = this.token('STRING_START', '(', 0, 0); } firstIndex = this.tokens.length; for (i = j = 0, len = tokens.length; j < len; i = ++j) { token = tokens[i]; tag = token[0], value = token[1]; switch (tag) { case 'TOKENS': if (value.length === 2) { continue; } locationToken = value[0]; tokensToPush = value; break; case 'NEOSTRING': converted = fn(token[1], i); if (converted.length === 0) { if (i === 0) { firstEmptyStringIndex = this.tokens.length; } else { continue; } } if (i === 2 && (firstEmptyStringIndex != null)) { this.tokens.splice(firstEmptyStringIndex, 2); } token[0] = 'STRING'; token[1] = this.makeDelimitedLiteral(converted, options); locationToken = token; tokensToPush = [token]; } if (this.tokens.length > firstIndex) { plusToken = this.token('+', '+'); plusToken[2] = { first_line: locationToken[2].first_line, first_column: locationToken[2].first_column, last_line: locationToken[2].first_line, last_column: locationToken[2].first_column }; } (ref2 = this.tokens).push.apply(ref2, tokensToPush); } if (lparen) { lastToken = tokens[tokens.length - 1]; lparen.origin = [ 'STRING', null, { first_line: lparen[2].first_line, first_column: lparen[2].first_column, last_line: lastToken[2].last_line, last_column: lastToken[2].last_column } ]; rparen = this.token('STRING_END', ')'); return rparen[2] = { first_line: lastToken[2].last_line, first_column: lastToken[2].last_column, last_line: lastToken[2].last_line, last_column: lastToken[2].last_column }; } }; Lexer.prototype.pair = function(tag) { var lastIndent, prev, ref2, ref3, wanted; ref2 = this.ends, prev = ref2[ref2.length - 1]; if (tag !== (wanted = prev != null ? prev.tag : void 0)) { if ('OUTDENT' !== wanted) { this.error("unmatched " + tag); } ref3 = this.indents, lastIndent = ref3[ref3.length - 1]; this.outdentToken(lastIndent, true); return this.pair(tag); } return this.ends.pop(); }; Lexer.prototype.getLineAndColumnFromChunk = function(offset) { var column, lastLine, lineCount, ref2, string; if (offset === 0) { return [this.chunkLine, this.chunkColumn]; } if (offset >= this.chunk.length) { string = this.chunk; } else { string = this.chunk.slice(0, +(offset - 1) + 1 || 9e9); } lineCount = count(string, '\n'); column = this.chunkColumn; if (lineCount > 0) { ref2 = string.split('\n'), lastLine = ref2[ref2.length - 1]; column = lastLine.length; } else { column += string.length; } return [this.chunkLine + lineCount, column]; }; Lexer.prototype.makeToken = function(tag, value, offsetInChunk, length) { var lastCharacter, locationData, ref2, ref3, token; if (offsetInChunk == null) { offsetInChunk = 0; } if (length == null) { length = value.length; } locationData = {}; ref2 = this.getLineAndColumnFromChunk(offsetInChunk), locationData.first_line = ref2[0], locationData.first_column = ref2[1]; lastCharacter = Math.max(0, length - 1); ref3 = this.getLineAndColumnFromChunk(offsetInChunk + lastCharacter), locationData.last_line = ref3[0], locationData.last_column = ref3[1]; token = [tag, value, locationData]; return token; }; Lexer.prototype.token = function(tag, value, offsetInChunk, length, origin) { var token; token = this.makeToken(tag, value, offsetInChunk, length); if (origin) { token.origin = origin; } this.tokens.push(token); return token; }; Lexer.prototype.tag = function() { var ref2, token; ref2 = this.tokens, token = ref2[ref2.length - 1]; return token != null ? token[0] : void 0; }; Lexer.prototype.value = function() { var ref2, token; ref2 = this.tokens, token = ref2[ref2.length - 1]; return token != null ? token[1] : void 0; }; Lexer.prototype.unfinished = function() { var ref2; return LINE_CONTINUER.test(this.chunk) || ((ref2 = this.tag()) === '\\' || ref2 === '.' || ref2 === '?.' || ref2 === '?::' || ref2 === 'UNARY' || ref2 === 'MATH' || ref2 === 'UNARY_MATH' || ref2 === '+' || ref2 === '-' || ref2 === 'YIELD' || ref2 === '*