mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-05-03 03:00:14 -04:00
Merge remote-tracking branch 'upstream/master' into sourcemaps
Conflicts: lib/coffee-script/coffee-script.js lib/coffee-script/command.js lib/coffee-script/nodes.js src/coffee-script.coffee src/command.coffee src/nodes.coffee
This commit is contained in:
6
Cakefile
6
Cakefile
@@ -1,8 +1,8 @@
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
{extend} = require './lib/coffee-script/helpers'
|
||||
CoffeeScript = require './lib/coffee-script'
|
||||
{spawn, exec} = require 'child_process'
|
||||
helpers = require './lib/coffee-script/helpers'
|
||||
|
||||
# ANSI Terminal Colors.
|
||||
bold = red = green = reset = ''
|
||||
@@ -79,7 +79,7 @@ task 'build:full', 'rebuild the source twice, and run the tests', ->
|
||||
|
||||
|
||||
task 'build:parser', 'rebuild the Jison parser (run build first)', ->
|
||||
extend global, require('util')
|
||||
helpers.extend global, require('util')
|
||||
require 'jison'
|
||||
parser = require('./lib/coffee-script/grammar').parser
|
||||
fs.writeFile 'lib/coffee-script/parser.js', parser.generate()
|
||||
@@ -225,7 +225,7 @@ runTests = (CoffeeScript) ->
|
||||
# Run every test in the `test` folder, recording failures.
|
||||
files = fs.readdirSync 'test'
|
||||
for file in files when file.match /\.(lit)?coffee$/i
|
||||
literate = path.extname(file) is '.litcoffee'
|
||||
literate = helpers.isLiterate file
|
||||
currentFile = filename = path.join 'test', file
|
||||
code = fs.readFileSync filename
|
||||
try
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Generated by CoffeeScript 1.5.0
|
||||
(function() {
|
||||
var Lexer, baseFileName, compile, count, ext, extend, extensions, fs, lexer, loadFile, parser, path, sourcemap, vm, _i, _len, _ref,
|
||||
__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; },
|
||||
var Lexer, baseFileName, compile, ext, fs, helpers, lexer, loadFile, parser, path, sourcemap, vm, _i, _len, _ref,
|
||||
__hasProp = {}.hasOwnProperty;
|
||||
|
||||
fs = require('fs');
|
||||
@@ -12,26 +11,26 @@
|
||||
|
||||
parser = require('./parser').parser;
|
||||
|
||||
sourcemap = require('./sourcemap');
|
||||
helpers = require('./helpers');
|
||||
|
||||
vm = require('vm');
|
||||
|
||||
_ref = require('./helpers'), count = _ref.count, extend = _ref.extend;
|
||||
|
||||
extensions = ['.coffee', '.litcoffee'];
|
||||
sourcemap = require('./sourcemap');
|
||||
|
||||
loadFile = function(module, filename) {
|
||||
var raw, stripped;
|
||||
raw = fs.readFileSync(filename, 'utf8');
|
||||
stripped = raw.charCodeAt(0) === 0xFEFF ? raw.substring(1) : raw;
|
||||
return module._compile(compile(stripped, {
|
||||
filename: filename
|
||||
filename: filename,
|
||||
literate: helpers.isLiterate(filename)
|
||||
}), filename);
|
||||
};
|
||||
|
||||
if (require.extensions) {
|
||||
for (_i = 0, _len = extensions.length; _i < _len; _i++) {
|
||||
ext = extensions[_i];
|
||||
_ref = ['.coffee', '.litcoffee', '.md', '.coffee.md'];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
ext = _ref[_i];
|
||||
require.extensions[ext] = loadFile;
|
||||
}
|
||||
}
|
||||
@@ -65,7 +64,7 @@
|
||||
noReplace: true
|
||||
});
|
||||
}
|
||||
newLines = count(fragment.code, "\n");
|
||||
newLines = helpers.count(fragment.code, "\n");
|
||||
currentLine += newLines;
|
||||
currentColumn = fragment.code.length - (newLines ? fragment.code.lastIndexOf("\n") : 0);
|
||||
}
|
||||
@@ -91,7 +90,7 @@
|
||||
}
|
||||
merge = exports.helpers.merge;
|
||||
try {
|
||||
options = extend({}, options);
|
||||
options = helpers.extend({}, options);
|
||||
options.sourceMap = new sourcemap.SourceMap();
|
||||
coffeeFile = path.basename(options.filename);
|
||||
jsFile = baseFileName(options.filename) + ".js";
|
||||
@@ -123,7 +122,7 @@
|
||||
};
|
||||
|
||||
exports.run = function(code, options) {
|
||||
var mainModule, _ref1;
|
||||
var mainModule;
|
||||
if (options == null) {
|
||||
options = {};
|
||||
}
|
||||
@@ -131,7 +130,7 @@
|
||||
mainModule.filename = process.argv[1] = options.filename ? fs.realpathSync(options.filename) : '.';
|
||||
mainModule.moduleCache && (mainModule.moduleCache = {});
|
||||
mainModule.paths = require('module')._nodeModulePaths(path.dirname(fs.realpathSync(options.filename)));
|
||||
if ((_ref1 = path.extname(mainModule.filename), __indexOf.call(extensions, _ref1) < 0) || require.extensions) {
|
||||
if (!helpers.isCoffee(mainModule.filename) || require.extensions) {
|
||||
return mainModule._compile(compile(code, options), mainModule.filename);
|
||||
} else {
|
||||
return mainModule._compile(code, mainModule.filename);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Generated by CoffeeScript 1.5.0
|
||||
(function() {
|
||||
var BANNER, CoffeeScript, EventEmitter, SWITCHES, coffee_exts, compileJoin, compileOptions, compilePath, compileScript, compileStdio, exec, exists, forkNode, fs, helpers, hidden, joinTimeout, lint, notSources, optionParser, optparse, opts, outputPath, parseOptions, path, printLine, printTokens, printWarn, removeSource, sourceCode, sources, spawn, timeLog, unwatchDir, usage, version, wait, watch, watchDir, watchers, writeJs, _ref,
|
||||
__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; };
|
||||
var BANNER, CoffeeScript, EventEmitter, SWITCHES, compileJoin, compileOptions, compilePath, compileScript, compileStdio, exec, exists, forkNode, fs, helpers, hidden, joinTimeout, lint, notSources, optionParser, optparse, opts, outputPath, parseOptions, path, printLine, printTokens, printWarn, removeSource, sourceCode, sources, spawn, timeLog, unwatchDir, usage, version, wait, watch, watchDir, watchers, writeJs, _ref;
|
||||
|
||||
fs = require('fs');
|
||||
|
||||
@@ -49,8 +48,6 @@
|
||||
|
||||
optionParser = null;
|
||||
|
||||
coffee_exts = ['.coffee', '.litcoffee'];
|
||||
|
||||
exports.run = function() {
|
||||
var literals, source, _i, _len, _results;
|
||||
parseOptions();
|
||||
@@ -91,7 +88,6 @@
|
||||
|
||||
compilePath = function(source, topLevel, base) {
|
||||
return fs.stat(source, function(err, stats) {
|
||||
var _ref1;
|
||||
if (err && err.code !== 'ENOENT') {
|
||||
throw err;
|
||||
}
|
||||
@@ -131,7 +127,7 @@
|
||||
return compilePath(path.join(source, file), false, base);
|
||||
});
|
||||
});
|
||||
} else if (topLevel || (_ref1 = path.extname(source), __indexOf.call(coffee_exts, _ref1) >= 0)) {
|
||||
} else if (topLevel || helpers.isCoffee(source)) {
|
||||
if (opts.watch) {
|
||||
watch(source, base);
|
||||
}
|
||||
@@ -375,15 +371,15 @@
|
||||
};
|
||||
|
||||
outputPath = function(source, base, extension) {
|
||||
var baseDir, dir, filename, srcDir;
|
||||
var baseDir, basename, dir, srcDir, _ref1;
|
||||
if (extension == null) {
|
||||
extension = ".js";
|
||||
}
|
||||
filename = path.basename(source, path.extname(source)) + extension;
|
||||
basename = path.basename(source, ((_ref1 = source.match(/\.((lit)?coffee|coffee\.md)$/)) != null ? _ref1[0] : void 0) || path.extname(source));
|
||||
srcDir = path.dirname(source);
|
||||
baseDir = base === '.' ? srcDir : srcDir.substring(base.length);
|
||||
dir = opts.output ? path.join(opts.output, baseDir) : srcDir;
|
||||
return path.join(dir, filename);
|
||||
return path.join(dir, basename + extension);
|
||||
};
|
||||
|
||||
writeJs = function(base, sourcePath, js, generatedSourceMap) {
|
||||
@@ -449,7 +445,7 @@
|
||||
};
|
||||
|
||||
printTokens = function(tokens) {
|
||||
var locationData, strings, tag, token, value;
|
||||
var strings, tag, token, value;
|
||||
strings = (function() {
|
||||
var _i, _len, _results;
|
||||
_results = [];
|
||||
@@ -457,8 +453,7 @@
|
||||
token = tokens[_i];
|
||||
tag = token[0];
|
||||
value = token[1].toString().replace(/\n/, '\\n');
|
||||
locationData = helpers.locationDataToString(token[2]);
|
||||
_results.push("[" + tag + " " + value + " " + locationData + "]");
|
||||
_results.push("[" + tag + " " + value + "]");
|
||||
}
|
||||
return _results;
|
||||
})();
|
||||
@@ -480,11 +475,9 @@
|
||||
};
|
||||
|
||||
compileOptions = function(filename) {
|
||||
var literate;
|
||||
literate = path.extname(filename) === '.litcoffee';
|
||||
return {
|
||||
filename: filename,
|
||||
literate: literate,
|
||||
literate: helpers.isLiterate(filename),
|
||||
bare: opts.bare,
|
||||
header: opts.compile
|
||||
};
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
action = (match = unwrap.exec(action)) ? match[1] : "(" + action + "())";
|
||||
action = action.replace(/\bnew /g, '$&yy.');
|
||||
action = action.replace(/\b(?:Block\.wrap|extend)\b/g, 'yy.$&');
|
||||
action = action.replace(/\b(Op|Value\.(create|wrap))\b/g, 'yy.$&');
|
||||
addLocationDataFn = function(first, last) {
|
||||
if (!last) {
|
||||
return "yy.addLocationDataFn(@" + first + ")";
|
||||
@@ -94,12 +93,12 @@
|
||||
],
|
||||
AssignObj: [
|
||||
o('ObjAssignable', function() {
|
||||
return Value.wrap($1);
|
||||
return new Value($1);
|
||||
}), o('ObjAssignable : Expression', function() {
|
||||
return new Assign(LOC(1)(Value.wrap($1)), $3, 'object');
|
||||
return new Assign(LOC(1)(new Value($1)), $3, 'object');
|
||||
}), o('ObjAssignable :\
|
||||
INDENT Expression OUTDENT', function() {
|
||||
return new Assign(LOC(1)(Value.wrap($1)), $4, 'object');
|
||||
return new Assign(LOC(1)(new Value($1)), $4, 'object');
|
||||
}), o('Comment')
|
||||
],
|
||||
ObjAssignable: [o('Identifier'), o('AlphaNumeric'), o('ThisProperty')],
|
||||
@@ -160,27 +159,27 @@
|
||||
],
|
||||
SimpleAssignable: [
|
||||
o('Identifier', function() {
|
||||
return Value.wrap($1);
|
||||
return new Value($1);
|
||||
}), o('Value Accessor', function() {
|
||||
return $1.add($2);
|
||||
}), o('Invocation Accessor', function() {
|
||||
return Value.wrap($1, [].concat($2));
|
||||
return new Value($1, [].concat($2));
|
||||
}), o('ThisProperty')
|
||||
],
|
||||
Assignable: [
|
||||
o('SimpleAssignable'), o('Array', function() {
|
||||
return Value.wrap($1);
|
||||
return new Value($1);
|
||||
}), o('Object', function() {
|
||||
return Value.wrap($1);
|
||||
return new Value($1);
|
||||
})
|
||||
],
|
||||
Value: [
|
||||
o('Assignable'), o('Literal', function() {
|
||||
return Value.wrap($1);
|
||||
return new Value($1);
|
||||
}), o('Parenthetical', function() {
|
||||
return Value.wrap($1);
|
||||
return new Value($1);
|
||||
}), o('Range', function() {
|
||||
return Value.wrap($1);
|
||||
return new Value($1);
|
||||
}), o('This')
|
||||
],
|
||||
Accessor: [
|
||||
@@ -190,6 +189,8 @@
|
||||
return new Access($2, 'soak');
|
||||
}), o(':: Identifier', function() {
|
||||
return [LOC(1)(new Access(new Literal('prototype'))), LOC(2)(new Access($2))];
|
||||
}), o('?:: Identifier', function() {
|
||||
return [LOC(1)(new Access(new Literal('prototype'), 'soak')), LOC(2)(new Access($2))];
|
||||
}), o('::', function() {
|
||||
return new Access(new Literal('prototype'));
|
||||
}), o('Index')
|
||||
@@ -274,14 +275,14 @@
|
||||
],
|
||||
This: [
|
||||
o('THIS', function() {
|
||||
return Value.wrap(new Literal('this'));
|
||||
return new Value(new Literal('this'));
|
||||
}), o('@', function() {
|
||||
return Value.wrap(new Literal('this'));
|
||||
return new Value(new Literal('this'));
|
||||
})
|
||||
],
|
||||
ThisProperty: [
|
||||
o('@ Identifier', function() {
|
||||
return Value.wrap(LOC(1)(new Literal('this')), [LOC(2)(new Access($2))], 'this');
|
||||
return new Value(LOC(1)(new Literal('this')), [LOC(2)(new Access($2))], 'this');
|
||||
})
|
||||
],
|
||||
Array: [
|
||||
@@ -348,7 +349,7 @@
|
||||
o('CATCH Identifier Block', function() {
|
||||
return [$2, $3];
|
||||
}), o('CATCH Object Block', function() {
|
||||
return [LOC(2)(Value.wrap($2)), $3];
|
||||
return [LOC(2)(new Value($2)), $3];
|
||||
})
|
||||
],
|
||||
Throw: [
|
||||
@@ -411,7 +412,7 @@
|
||||
ForBody: [
|
||||
o('FOR Range', function() {
|
||||
return {
|
||||
source: LOC(2)(Value.wrap($2))
|
||||
source: LOC(2)(new Value($2))
|
||||
};
|
||||
}), o('ForStart ForSource', function() {
|
||||
$2.own = $1.own;
|
||||
@@ -430,9 +431,9 @@
|
||||
],
|
||||
ForValue: [
|
||||
o('Identifier'), o('ThisProperty'), o('Array', function() {
|
||||
return Value.wrap($1);
|
||||
return new Value($1);
|
||||
}), o('Object', function() {
|
||||
return Value.wrap($1);
|
||||
return new Value($1);
|
||||
})
|
||||
],
|
||||
ForVariables: [
|
||||
@@ -533,42 +534,42 @@
|
||||
],
|
||||
Operation: [
|
||||
o('UNARY Expression', function() {
|
||||
return Op.create($1, $2);
|
||||
return new Op($1, $2);
|
||||
}), o('- Expression', (function() {
|
||||
return Op.create('-', $2);
|
||||
return new Op('-', $2);
|
||||
}), {
|
||||
prec: 'UNARY'
|
||||
}), o('+ Expression', (function() {
|
||||
return Op.create('+', $2);
|
||||
return new Op('+', $2);
|
||||
}), {
|
||||
prec: 'UNARY'
|
||||
}), o('-- SimpleAssignable', function() {
|
||||
return Op.create('--', $2);
|
||||
return new Op('--', $2);
|
||||
}), o('++ SimpleAssignable', function() {
|
||||
return Op.create('++', $2);
|
||||
return new Op('++', $2);
|
||||
}), o('SimpleAssignable --', function() {
|
||||
return Op.create('--', $1, null, true);
|
||||
return new Op('--', $1, null, true);
|
||||
}), o('SimpleAssignable ++', function() {
|
||||
return Op.create('++', $1, null, true);
|
||||
return new Op('++', $1, null, true);
|
||||
}), o('Expression ?', function() {
|
||||
return new Existence($1);
|
||||
}), o('Expression + Expression', function() {
|
||||
return Op.create('+', $1, $3);
|
||||
return new Op('+', $1, $3);
|
||||
}), o('Expression - Expression', function() {
|
||||
return Op.create('-', $1, $3);
|
||||
return new Op('-', $1, $3);
|
||||
}), o('Expression MATH Expression', function() {
|
||||
return Op.create($2, $1, $3);
|
||||
return new Op($2, $1, $3);
|
||||
}), o('Expression SHIFT Expression', function() {
|
||||
return Op.create($2, $1, $3);
|
||||
return new Op($2, $1, $3);
|
||||
}), o('Expression COMPARE Expression', function() {
|
||||
return Op.create($2, $1, $3);
|
||||
return new Op($2, $1, $3);
|
||||
}), o('Expression LOGIC Expression', function() {
|
||||
return Op.create($2, $1, $3);
|
||||
return new Op($2, $1, $3);
|
||||
}), o('Expression RELATION Expression', function() {
|
||||
if ($2.charAt(0) === '!') {
|
||||
return Op.create($2.slice(1), $1, $3).invert();
|
||||
return new Op($2.slice(1), $1, $3).invert();
|
||||
} else {
|
||||
return Op.create($2, $1, $3);
|
||||
return new Op($2, $1, $3);
|
||||
}
|
||||
}), o('SimpleAssignable COMPOUND_ASSIGN\
|
||||
Expression', function() {
|
||||
@@ -585,7 +586,7 @@
|
||||
]
|
||||
};
|
||||
|
||||
operators = [['left', '.', '?.', '::'], ['left', 'CALL_START', 'CALL_END'], ['nonassoc', '++', '--'], ['left', '?'], ['right', 'UNARY'], ['left', 'MATH'], ['left', '+', '-'], ['left', 'SHIFT'], ['left', 'RELATION'], ['left', 'COMPARE'], ['left', 'LOGIC'], ['nonassoc', 'INDENT', 'OUTDENT'], ['right', '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS'], ['right', 'FORIN', 'FOROF', 'BY', 'WHEN'], ['right', 'IF', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS'], ['right', 'POST_IF']];
|
||||
operators = [['left', '.', '?.', '::', '?::'], ['left', 'CALL_START', 'CALL_END'], ['nonassoc', '++', '--'], ['left', '?'], ['right', 'UNARY'], ['left', 'MATH'], ['left', '+', '-'], ['left', 'SHIFT'], ['left', 'RELATION'], ['left', 'COMPARE'], ['left', 'LOGIC'], ['nonassoc', 'INDENT', 'OUTDENT'], ['right', '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS'], ['right', 'FORIN', 'FOROF', 'BY', 'WHEN'], ['right', 'IF', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS'], ['right', 'POST_IF']];
|
||||
|
||||
tokens = [];
|
||||
|
||||
|
||||
@@ -121,4 +121,12 @@
|
||||
}
|
||||
};
|
||||
|
||||
exports.isCoffee = function(file) {
|
||||
return /\.((lit)?coffee|coffee\.md)$/.test(file);
|
||||
};
|
||||
|
||||
exports.isLiterate = function(file) {
|
||||
return /\.(litcoffee|coffee\.md)$/.test(file);
|
||||
};
|
||||
|
||||
}).call(this);
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
opts = {};
|
||||
}
|
||||
this.literate = opts.literate;
|
||||
code = this.clean(code);
|
||||
this.indent = 0;
|
||||
this.indebt = 0;
|
||||
this.outdebt = 0;
|
||||
@@ -26,6 +25,7 @@
|
||||
this.tokens = [];
|
||||
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.heredocToken() || this.stringToken() || this.numberToken() || this.regexToken() || this.jsToken() || this.literalToken();
|
||||
@@ -47,10 +47,11 @@
|
||||
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--;
|
||||
}
|
||||
code = code.replace(/\r/g, '').replace(TRAILING_SPACES, '');
|
||||
if (this.literate) {
|
||||
lines = (function() {
|
||||
var _i, _len, _ref2, _results;
|
||||
@@ -83,7 +84,7 @@
|
||||
this.token('OWN', id);
|
||||
return id.length;
|
||||
}
|
||||
forcedIdentifier = colon || (prev = last(this.tokens)) && (((_ref2 = prev[0]) === '.' || _ref2 === '?.' || _ref2 === '::') || !prev.spaced && prev[0] === '@');
|
||||
forcedIdentifier = colon || (prev = last(this.tokens)) && (((_ref2 = prev[0]) === '.' || _ref2 === '?.' || _ref2 === '::' || _ref2 === '?::') || !prev.spaced && prev[0] === '@');
|
||||
tag = 'IDENTIFIER';
|
||||
if (!forcedIdentifier && (__indexOf.call(JS_KEYWORDS, id) >= 0 || __indexOf.call(COFFEE_KEYWORDS, id) >= 0)) {
|
||||
tag = id.toUpperCase();
|
||||
@@ -768,7 +769,7 @@
|
||||
|
||||
Lexer.prototype.unfinished = function() {
|
||||
var _ref2;
|
||||
return LINE_CONTINUER.test(this.chunk) || ((_ref2 = this.tag()) === '\\' || _ref2 === '.' || _ref2 === '?.' || _ref2 === 'UNARY' || _ref2 === 'MATH' || _ref2 === '+' || _ref2 === '-' || _ref2 === 'SHIFT' || _ref2 === 'RELATION' || _ref2 === 'COMPARE' || _ref2 === 'LOGIC' || _ref2 === 'THROW' || _ref2 === 'EXTENDS');
|
||||
return LINE_CONTINUER.test(this.chunk) || ((_ref2 = this.tag()) === '\\' || _ref2 === '.' || _ref2 === '?.' || _ref2 === '?::' || _ref2 === 'UNARY' || _ref2 === 'MATH' || _ref2 === '+' || _ref2 === '-' || _ref2 === 'SHIFT' || _ref2 === 'RELATION' || _ref2 === 'COMPARE' || _ref2 === 'LOGIC' || _ref2 === 'THROW' || _ref2 === 'EXTENDS');
|
||||
};
|
||||
|
||||
Lexer.prototype.escapeLines = function(str, heredoc) {
|
||||
@@ -843,7 +844,7 @@
|
||||
|
||||
HEREDOC = /^("""|''')([\s\S]*?)(?:\n[^\n\S]*)?\1/;
|
||||
|
||||
OPERATOR = /^(?:[-=]>|[-+*\/%<>&|^!?=]=|>>>=?|([-+:])\1|([&|<>])\2=?|\?\.|\.{2,3})/;
|
||||
OPERATOR = /^(?:[-=]>|[-+*\/%<>&|^!?=]=|>>>=?|([-+:])\1|([&|<>])\2=?|\?(\.|::)|\.{2,3})/;
|
||||
|
||||
WHITESPACE = /^[^\n\S]+/;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Generated by CoffeeScript 1.5.0
|
||||
(function() {
|
||||
var Access, Arr, Assign, Base, Block, Call, Class, Closure, Code, CodeFragment, Comment, Existence, Extends, For, IDENTIFIER, IDENTIFIER_STR, IS_STRING, If, In, Index, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, Literal, METHOD_DEF, NEGATE, NO, Obj, Op, PARANOID, Param, Parens, RESERVED, Range, Return, SIMPLENUM, STRICT_PROSCRIBED, Scope, Slice, Splat, Switch, TAB, THIS, Throw, Try, UTILITIES, Value, While, YES, addLocationDataFn, checkFragments, compact, del, ends, extend, flatten, fragmentsToText, last, locationDataToString, merge, multident, some, starts, unfoldSoak, utility, _ref, _ref1,
|
||||
var Access, Arr, Assign, Base, Block, Call, Class, Closure, Code, CodeFragment, Comment, Existence, Extends, For, IDENTIFIER, IDENTIFIER_STR, IS_STRING, If, In, Index, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, Literal, METHOD_DEF, NEGATE, NO, Obj, Op, Param, Parens, RESERVED, Range, Return, SIMPLENUM, STRICT_PROSCRIBED, Scope, Slice, Splat, Switch, TAB, THIS, Throw, Try, UTILITIES, Value, While, YES, addLocationDataFn, compact, del, ends, extend, flatten, fragmentsToText, last, locationDataToString, merge, multident, some, starts, unfoldSoak, utility, _ref, _ref1,
|
||||
__hasProp = {}.hasOwnProperty,
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||
__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; },
|
||||
@@ -35,8 +35,6 @@
|
||||
return this;
|
||||
};
|
||||
|
||||
PARANOID = false;
|
||||
|
||||
exports.CodeFragment = CodeFragment = (function() {
|
||||
|
||||
function CodeFragment(parent, code) {
|
||||
@@ -56,7 +54,6 @@
|
||||
|
||||
fragmentsToText = function(fragments) {
|
||||
var fragment;
|
||||
checkFragments(fragments);
|
||||
return ((function() {
|
||||
var _i, _len, _results;
|
||||
_results = [];
|
||||
@@ -68,32 +65,6 @@
|
||||
})()).join('');
|
||||
};
|
||||
|
||||
checkFragments = function(fragments, node) {
|
||||
var fragment, i, inspected, nodeName, nodeStr, _i, _len;
|
||||
if (node == null) {
|
||||
node = null;
|
||||
}
|
||||
if (!PARANOID) {
|
||||
return fragments;
|
||||
}
|
||||
nodeName = node ? " from " + node.constructor.name : "";
|
||||
if (!fragments) {
|
||||
throw new Error("Fragments is null" + nodeName + ": " + fragments + "\n");
|
||||
}
|
||||
if (fragments instanceof CodeFragment) {
|
||||
throw new Error("Expected array of fragments but found fragment" + nodeName + ": " + fragments + "\n");
|
||||
}
|
||||
for (i = _i = 0, _len = fragments.length; _i < _len; i = ++_i) {
|
||||
fragment = fragments[i];
|
||||
if (!(fragment instanceof CodeFragment)) {
|
||||
inspected = (require('util')).inspect(fragments);
|
||||
nodeStr = node ? "node: " + (node.toString()) + "\n" : "";
|
||||
throw new Error("Expected fragment: " + i + " of " + fragments.length + nodeName + ": " + fragment + "\nFragments: " + inspected + "\n" + nodeStr);
|
||||
}
|
||||
}
|
||||
return fragments;
|
||||
};
|
||||
|
||||
exports.Base = Base = (function() {
|
||||
|
||||
function Base() {}
|
||||
@@ -103,7 +74,7 @@
|
||||
};
|
||||
|
||||
Base.prototype.compileToFragments = function(o, lvl) {
|
||||
var fragments, node;
|
||||
var node;
|
||||
o = extend({}, o);
|
||||
if (lvl) {
|
||||
o.level = lvl;
|
||||
@@ -111,12 +82,10 @@
|
||||
node = this.unfoldSoak(o) || this;
|
||||
node.tab = o.indent;
|
||||
if (o.level === LEVEL_TOP || !node.isStatement(o)) {
|
||||
fragments = node.compileNode(o);
|
||||
return node.compileNode(o);
|
||||
} else {
|
||||
fragments = node.compileClosure(o);
|
||||
return node.compileClosure(o);
|
||||
}
|
||||
checkFragments(fragments, node);
|
||||
return fragments;
|
||||
};
|
||||
|
||||
Base.prototype.compileClosure = function(o) {
|
||||
@@ -236,7 +205,7 @@
|
||||
};
|
||||
|
||||
Base.prototype.invert = function() {
|
||||
return Op.create('!', this);
|
||||
return new Op('!', this);
|
||||
};
|
||||
|
||||
Base.prototype.unwrapAll = function() {
|
||||
@@ -289,7 +258,6 @@
|
||||
answer = [];
|
||||
for (i = _i = 0, _len = fragmentsList.length; _i < _len; i = ++_i) {
|
||||
fragments = fragmentsList[i];
|
||||
checkFragments(fragments, this);
|
||||
if (i) {
|
||||
answer.push(this.makeCode(joinStr));
|
||||
}
|
||||
@@ -586,7 +554,7 @@
|
||||
__extends(Undefined, _super);
|
||||
|
||||
function Undefined() {
|
||||
Undefined.__super__.constructor.apply(this, arguments);
|
||||
return Undefined.__super__.constructor.apply(this, arguments);
|
||||
}
|
||||
|
||||
Undefined.prototype.isAssignable = NO;
|
||||
@@ -606,7 +574,7 @@
|
||||
__extends(Null, _super);
|
||||
|
||||
function Null() {
|
||||
Null.__super__.constructor.apply(this, arguments);
|
||||
return Null.__super__.constructor.apply(this, arguments);
|
||||
}
|
||||
|
||||
Null.prototype.isAssignable = NO;
|
||||
@@ -688,21 +656,16 @@
|
||||
|
||||
__extends(Value, _super);
|
||||
|
||||
Value.wrap = function(base, props, tag) {
|
||||
function Value(base, props, tag) {
|
||||
if (!props && base instanceof Value) {
|
||||
return base;
|
||||
} else {
|
||||
return new Value(base, props, tag);
|
||||
}
|
||||
};
|
||||
|
||||
function Value(base, properties, tag) {
|
||||
this.base = base;
|
||||
this.properties = properties;
|
||||
this.properties || (this.properties = []);
|
||||
if (tag === 'this') {
|
||||
this["this"] = true;
|
||||
this.properties = props || [];
|
||||
if (tag) {
|
||||
this[tag] = true;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
Value.prototype.children = ['base', 'properties'];
|
||||
@@ -785,10 +748,10 @@
|
||||
if (this.properties.length < 2 && !this.base.isComplex() && !(name != null ? name.isComplex() : void 0)) {
|
||||
return [this, this];
|
||||
}
|
||||
base = Value.wrap(this.base, this.properties.slice(0, -1));
|
||||
base = new Value(this.base, this.properties.slice(0, -1));
|
||||
if (base.isComplex()) {
|
||||
bref = new Literal(o.scope.freeVariable('base'));
|
||||
base = Value.wrap(new Parens(new Assign(bref, base)));
|
||||
base = new Value(new Parens(new Assign(bref, base)));
|
||||
}
|
||||
if (!name) {
|
||||
return [base, bref];
|
||||
@@ -798,7 +761,7 @@
|
||||
name = new Index(new Assign(nref, name.index));
|
||||
nref = new Index(nref);
|
||||
}
|
||||
return [base.add(name), Value.wrap(bref || base.base, [nref || name])];
|
||||
return [base.add(name), new Value(bref || base.base, [nref || name])];
|
||||
};
|
||||
|
||||
Value.prototype.compileNode = function(o) {
|
||||
@@ -832,8 +795,8 @@
|
||||
continue;
|
||||
}
|
||||
prop.soak = false;
|
||||
fst = Value.wrap(_this.base, _this.properties.slice(0, i));
|
||||
snd = Value.wrap(_this.base, _this.properties.slice(i));
|
||||
fst = new Value(_this.base, _this.properties.slice(0, i));
|
||||
snd = new Value(_this.base, _this.properties.slice(i));
|
||||
if (fst.isComplex()) {
|
||||
ref = new Literal(o.scope.freeVariable('ref'));
|
||||
fst = new Parens(new Assign(ref, fst));
|
||||
@@ -902,24 +865,19 @@
|
||||
};
|
||||
|
||||
Call.prototype.superReference = function(o) {
|
||||
var accesses, method, name;
|
||||
var accesses, method;
|
||||
method = o.scope.namedMethod();
|
||||
if (!method) {
|
||||
throw SyntaxError('cannot call super outside of a function.');
|
||||
}
|
||||
name = method.name;
|
||||
if (name == null) {
|
||||
throw SyntaxError('cannot call super on an anonymous function.');
|
||||
}
|
||||
if (method.klass) {
|
||||
if (method != null ? method.klass : void 0) {
|
||||
accesses = [new Access(new Literal('__super__'))];
|
||||
if (method["static"]) {
|
||||
accesses.push(new Access(new Literal('constructor')));
|
||||
}
|
||||
accesses.push(new Access(new Literal(name)));
|
||||
return (Value.wrap(new Literal(method.klass), accesses)).compile(o);
|
||||
accesses.push(new Access(new Literal(method.name)));
|
||||
return (new Value(new Literal(method.klass), accesses)).compile(o);
|
||||
} else if (method != null ? method.ctor : void 0) {
|
||||
return "" + method.name + ".__super__.constructor";
|
||||
} else {
|
||||
return "" + name + ".__super__.constructor";
|
||||
throw SyntaxError('cannot call super outside of an instance method.');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -936,15 +894,15 @@
|
||||
if (ifn = unfoldSoak(o, this, 'variable')) {
|
||||
return ifn;
|
||||
}
|
||||
_ref2 = Value.wrap(this.variable).cacheReference(o), left = _ref2[0], rite = _ref2[1];
|
||||
_ref2 = new Value(this.variable).cacheReference(o), left = _ref2[0], rite = _ref2[1];
|
||||
} else {
|
||||
left = new Literal(this.superReference(o));
|
||||
rite = Value.wrap(left);
|
||||
rite = new Value(left);
|
||||
}
|
||||
rite = new Call(rite, this.args);
|
||||
rite.isNew = this.isNew;
|
||||
left = new Literal("typeof " + (left.compile(o)) + " === \"function\"");
|
||||
return new If(left, Value.wrap(rite), {
|
||||
return new If(left, new Value(rite), {
|
||||
soak: true
|
||||
});
|
||||
}
|
||||
@@ -1026,7 +984,7 @@
|
||||
return [].concat(this.makeCode("(function(func, args, ctor) {\n" + idt + "ctor.prototype = func.prototype;\n" + idt + "var child = new ctor, result = func.apply(child, args);\n" + idt + "return Object(result) === result ? result : child;\n" + this.tab + "})("), this.variable.compileToFragments(o, LEVEL_LIST), this.makeCode(", "), splatArgs, this.makeCode(", function(){})"));
|
||||
}
|
||||
answer = [];
|
||||
base = Value.wrap(this.variable);
|
||||
base = new Value(this.variable);
|
||||
if ((name = base.properties.pop()) && base.isComplex()) {
|
||||
ref = o.scope.freeVariable('ref');
|
||||
answer = answer.concat(this.makeCode("(" + ref + " = "), base.compileToFragments(o, LEVEL_LIST), this.makeCode(")"), name.compileToFragments(o));
|
||||
@@ -1062,7 +1020,7 @@
|
||||
Extends.prototype.children = ['child', 'parent'];
|
||||
|
||||
Extends.prototype.compileToFragments = function(o) {
|
||||
return new Call(Value.wrap(new Literal(utility('extends'))), [this.child, this.parent]).compileToFragments(o);
|
||||
return new Call(new Value(new Literal(utility('extends'))), [this.child, this.parent]).compileToFragments(o);
|
||||
};
|
||||
|
||||
return Extends;
|
||||
@@ -1432,12 +1390,18 @@
|
||||
};
|
||||
|
||||
Class.prototype.addBoundFunctions = function(o) {
|
||||
var bvar, lhs, _i, _len, _ref2;
|
||||
_ref2 = this.boundFuncs;
|
||||
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
||||
bvar = _ref2[_i];
|
||||
lhs = (Value.wrap(new Literal("this"), [new Access(bvar)])).compile(o);
|
||||
this.ctor.body.unshift(new Literal("" + lhs + " = " + (utility('bind')) + "(" + lhs + ", this)"));
|
||||
var body, bound, func, lhs, name, rhs, _i, _len, _ref2, _ref3;
|
||||
if (this.boundFuncs.length) {
|
||||
o.scope.assign('_this', 'this');
|
||||
_ref2 = this.boundFuncs;
|
||||
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
||||
_ref3 = _ref2[_i], name = _ref3[0], func = _ref3[1];
|
||||
lhs = new Value(new Literal("this"), [new Access(name)]);
|
||||
body = new Block([new Return(new Literal("" + this.ctor.name + ".prototype." + name.value + ".apply(_this, arguments)"))]);
|
||||
rhs = new Code(func.params, body, 'boundfunc');
|
||||
bound = new Assign(lhs, rhs);
|
||||
this.ctor.body.unshift(bound);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1472,9 +1436,9 @@
|
||||
func.context = name;
|
||||
}
|
||||
} else {
|
||||
assign.variable = Value.wrap(new Literal(name), [new Access(new Literal('prototype')), new Access(base)]);
|
||||
assign.variable = new Value(new Literal(name), [new Access(new Literal('prototype')), new Access(base)]);
|
||||
if (func instanceof Code && func.bound) {
|
||||
this.boundFuncs.push(base);
|
||||
this.boundFuncs.push([base, func]);
|
||||
func.bound = false;
|
||||
}
|
||||
}
|
||||
@@ -1490,7 +1454,8 @@
|
||||
Class.prototype.walkBody = function(name, o) {
|
||||
var _this = this;
|
||||
return this.traverseChildren(false, function(child) {
|
||||
var exps, i, node, _i, _len, _ref2;
|
||||
var cont, exps, i, node, _i, _len, _ref2;
|
||||
cont = true;
|
||||
if (child instanceof Class) {
|
||||
return false;
|
||||
}
|
||||
@@ -1499,11 +1464,13 @@
|
||||
for (i = _i = 0, _len = _ref2.length; _i < _len; i = ++_i) {
|
||||
node = _ref2[i];
|
||||
if (node instanceof Value && node.isObject(true)) {
|
||||
cont = false;
|
||||
exps[i] = _this.addProperties(node, name, o);
|
||||
}
|
||||
}
|
||||
return child.expressions = exps = flatten(exps);
|
||||
child.expressions = exps = flatten(exps);
|
||||
}
|
||||
return cont && !(child instanceof Class);
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1517,8 +1484,7 @@
|
||||
return this.directives = expressions.splice(0, index);
|
||||
};
|
||||
|
||||
Class.prototype.ensureConstructor = function(name, o) {
|
||||
var returnExpr;
|
||||
Class.prototype.ensureConstructor = function(name) {
|
||||
if (!this.ctor) {
|
||||
this.ctor = new Code;
|
||||
if (this.parent) {
|
||||
@@ -1527,20 +1493,12 @@
|
||||
if (this.externalCtor) {
|
||||
this.ctor.body.push(new Literal("" + this.externalCtor + ".apply(this, arguments)"));
|
||||
}
|
||||
this.ctor.body.makeReturn();
|
||||
this.body.expressions.unshift(this.ctor);
|
||||
}
|
||||
this.ctor.ctor = this.ctor.name = name;
|
||||
this.ctor.klass = null;
|
||||
this.ctor.noReturn = true;
|
||||
returnExpr = null;
|
||||
this.ctor.body.traverseChildren(false, function(node) {
|
||||
if (node instanceof Return && (returnExpr = node.expression)) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
if (returnExpr) {
|
||||
throw SyntaxError("cannot return a value from a constructor: \"" + (returnExpr.compileNode(o)) + "\" in class " + name);
|
||||
}
|
||||
return this.ctor.noReturn = true;
|
||||
};
|
||||
|
||||
Class.prototype.compileNode = function(o) {
|
||||
@@ -1554,7 +1512,7 @@
|
||||
this.hoistDirectivePrologue();
|
||||
this.setContext(name);
|
||||
this.walkBody(name, o);
|
||||
this.ensureConstructor(name, o);
|
||||
this.ensureConstructor(name);
|
||||
this.body.spaced = true;
|
||||
if (!(this.ctor instanceof Code)) {
|
||||
this.body.expressions.unshift(this.ctor);
|
||||
@@ -1678,7 +1636,7 @@
|
||||
idx = isObject ? obj["this"] ? obj.properties[0].name : obj : new Literal(0);
|
||||
}
|
||||
acc = IDENTIFIER.test(idx.unwrap().value || 0);
|
||||
value = Value.wrap(value);
|
||||
value = new Value(value);
|
||||
value.properties.push(new (acc ? Access : Index)(idx));
|
||||
if (_ref4 = obj.unwrap().value, __indexOf.call(RESERVED, _ref4) >= 0) {
|
||||
throw new SyntaxError("assignment to a reserved word: " + (obj.compile(o)) + " = " + (value.compile(o)));
|
||||
@@ -1704,7 +1662,7 @@
|
||||
_ref5 = obj, (_ref6 = _ref5.variable, idx = _ref6.base), obj = _ref5.value;
|
||||
} else {
|
||||
if (obj.base instanceof Parens) {
|
||||
_ref7 = Value.wrap(obj.unwrapAll()).cacheReference(o), obj = _ref7[0], idx = _ref7[1];
|
||||
_ref7 = new Value(obj.unwrapAll()).cacheReference(o), obj = _ref7[0], idx = _ref7[1];
|
||||
} else {
|
||||
idx = obj["this"] ? obj.properties[0].name : obj;
|
||||
}
|
||||
@@ -1734,7 +1692,7 @@
|
||||
} else {
|
||||
acc = isObject && IDENTIFIER.test(idx.unwrap().value || 0);
|
||||
}
|
||||
val = Value.wrap(new Literal(vvarText), [new (acc ? Access : Index)(idx)]);
|
||||
val = new Value(new Literal(vvarText), [new (acc ? Access : Index)(idx)]);
|
||||
}
|
||||
if ((name != null) && __indexOf.call(RESERVED, name) >= 0) {
|
||||
throw new SyntaxError("assignment to a reserved word: " + (obj.compile(o)) + " = " + (val.compile(o)));
|
||||
@@ -1764,7 +1722,7 @@
|
||||
if (__indexOf.call(this.context, "?") >= 0) {
|
||||
o.isExistentialEquals = true;
|
||||
}
|
||||
return Op.create(this.context.slice(0, -1), left, new Assign(right, this.value, '=')).compileToFragments(o);
|
||||
return new Op(this.context.slice(0, -1), left, new Assign(right, this.value, '=')).compileToFragments(o);
|
||||
};
|
||||
|
||||
Assign.prototype.compileSplice = function(o) {
|
||||
@@ -1857,7 +1815,7 @@
|
||||
o.scope.add(p.value, 'var', true);
|
||||
}
|
||||
}
|
||||
splats = new Assign(Value.wrap(new Arr((function() {
|
||||
splats = new Assign(new Value(new Arr((function() {
|
||||
var _l, _len3, _ref5, _results;
|
||||
_ref5 = this.params;
|
||||
_results = [];
|
||||
@@ -1866,7 +1824,7 @@
|
||||
_results.push(p.asReference(o));
|
||||
}
|
||||
return _results;
|
||||
}).call(this))), Value.wrap(new Literal('arguments')));
|
||||
}).call(this))), new Value(new Literal('arguments')));
|
||||
break;
|
||||
}
|
||||
_ref5 = this.params;
|
||||
@@ -1875,16 +1833,16 @@
|
||||
if (param.isComplex()) {
|
||||
val = ref = param.asReference(o);
|
||||
if (param.value) {
|
||||
val = Op.create('?', ref, param.value);
|
||||
val = new Op('?', ref, param.value);
|
||||
}
|
||||
exprs.push(new Assign(Value.wrap(param.name), val, '=', {
|
||||
exprs.push(new Assign(new Value(param.name), val, '=', {
|
||||
param: true
|
||||
}));
|
||||
} else {
|
||||
ref = param;
|
||||
if (param.value) {
|
||||
lit = new Literal(ref.name.value + ' == null');
|
||||
val = new Assign(Value.wrap(param.name), param.value, '=');
|
||||
val = new Assign(new Value(param.name), param.value, '=');
|
||||
exprs.push(new If(lit, val));
|
||||
}
|
||||
}
|
||||
@@ -2007,7 +1965,7 @@
|
||||
} else if (node.isComplex()) {
|
||||
node = new Literal(o.scope.freeVariable('arg'));
|
||||
}
|
||||
node = Value.wrap(node);
|
||||
node = new Value(node);
|
||||
if (this.splat) {
|
||||
node = new Splat(node);
|
||||
}
|
||||
@@ -2221,7 +2179,7 @@
|
||||
|
||||
__extends(Op, _super);
|
||||
|
||||
Op.create = function(op, first, second, flip) {
|
||||
function Op(op, first, second, flip) {
|
||||
if (op === 'in') {
|
||||
return new In(first, second);
|
||||
}
|
||||
@@ -2236,14 +2194,11 @@
|
||||
first = new Parens(first);
|
||||
}
|
||||
}
|
||||
return new Op(op, first, second, flip);
|
||||
};
|
||||
|
||||
function Op(op, first, second, flip) {
|
||||
this.operator = CONVERSIONS[op] || op;
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
this.operator = CONVERSIONS[op] || op;
|
||||
this.flip = !!flip;
|
||||
return this;
|
||||
}
|
||||
|
||||
CONVERSIONS = {
|
||||
@@ -2305,7 +2260,7 @@
|
||||
} else if (this.operator === '!' && (fst = this.first.unwrap()) instanceof Op && ((_ref2 = fst.operator) === '!' || _ref2 === 'in' || _ref2 === 'instanceof')) {
|
||||
return fst;
|
||||
} else {
|
||||
return Op.create('!', this);
|
||||
return new Op('!', this);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2314,7 +2269,7 @@
|
||||
return ((_ref2 = this.operator) === '++' || _ref2 === '--' || _ref2 === 'delete') && unfoldSoak(o, this, 'first');
|
||||
};
|
||||
|
||||
Op.generateDo = function(exp) {
|
||||
Op.prototype.generateDo = function(exp) {
|
||||
var call, func, param, passedParams, ref, _i, _len, _ref2;
|
||||
passedParams = [];
|
||||
func = exp instanceof Assign && (ref = exp.value.unwrap()) instanceof Code ? ref : exp;
|
||||
@@ -2808,7 +2763,7 @@
|
||||
}
|
||||
fn = ((_ref6 = val.base) != null ? _ref6.unwrapAll() : void 0) || val;
|
||||
ref = new Literal(o.scope.freeVariable('fn'));
|
||||
base = Value.wrap(ref);
|
||||
base = new Value(ref);
|
||||
if (val.base) {
|
||||
_ref7 = [base, val], val.base = _ref7[0], base = _ref7[1];
|
||||
}
|
||||
@@ -2981,7 +2936,7 @@
|
||||
};
|
||||
|
||||
If.prototype.compileStatement = function(o) {
|
||||
var answer, body, child, cond, exeq, ifPart;
|
||||
var answer, body, child, cond, exeq, ifPart, indent;
|
||||
child = del(o, 'chainChild');
|
||||
exeq = del(o, 'isExistentialEquals');
|
||||
if (exeq) {
|
||||
@@ -2989,10 +2944,12 @@
|
||||
type: 'if'
|
||||
}).compileToFragments(o);
|
||||
}
|
||||
indent = o.indent + TAB;
|
||||
body = this.ensureBlock(this.body).compileToFragments(merge(o, {
|
||||
indent: indent
|
||||
}));
|
||||
cond = this.condition.compileToFragments(o, LEVEL_PAREN);
|
||||
o.indent += TAB;
|
||||
body = this.ensureBlock(this.body);
|
||||
ifPart = [].concat(this.makeCode("if ("), cond, this.makeCode(") {\n"), body.compileToFragments(o), this.makeCode("\n" + this.tab + "}"));
|
||||
ifPart = [].concat(this.makeCode("if ("), cond, this.makeCode(") {\n"), body, this.makeCode("\n" + this.tab + "}"));
|
||||
if (!child) {
|
||||
ifPart.unshift(this.makeCode(this.tab));
|
||||
}
|
||||
@@ -3001,19 +2958,20 @@
|
||||
}
|
||||
answer = ifPart.concat(this.makeCode(' else '));
|
||||
if (this.isChain) {
|
||||
o.indent = this.tab;
|
||||
o.chainChild = true;
|
||||
answer = answer.concat(this.elseBody.unwrap().compileToFragments(o, LEVEL_TOP));
|
||||
} else {
|
||||
answer = answer.concat(this.makeCode("{\n"), this.elseBody.compileToFragments(o, LEVEL_TOP), this.makeCode("\n" + this.tab + "}"));
|
||||
answer = answer.concat(this.makeCode("{\n"), this.elseBody.compileToFragments(merge(o, {
|
||||
indent: indent
|
||||
}), LEVEL_TOP), this.makeCode("\n" + this.tab + "}"));
|
||||
}
|
||||
return answer;
|
||||
};
|
||||
|
||||
If.prototype.compileExpression = function(o) {
|
||||
var alt, body, cond, fragments;
|
||||
cond = this.condition.compileToFragments(o, LEVEL_COND);
|
||||
body = this.bodyNode().compileToFragments(o, LEVEL_LIST);
|
||||
cond = this.condition.compileToFragments(o, LEVEL_COND);
|
||||
alt = this.elseBodyNode() ? this.elseBodyNode().compileToFragments(o, LEVEL_LIST) : [this.makeCode('void 0')];
|
||||
fragments = cond.concat(this.makeCode(" ? "), body, this.makeCode(" : "), alt);
|
||||
if (o.level >= LEVEL_COND) {
|
||||
@@ -3048,7 +3006,7 @@
|
||||
if (mentionsArgs) {
|
||||
args.push(new Literal('arguments'));
|
||||
}
|
||||
func = Value.wrap(func, [new Access(meth)]);
|
||||
func = new Value(func, [new Access(meth)]);
|
||||
}
|
||||
func.noReturn = noReturn;
|
||||
call = new Call(func, args);
|
||||
@@ -3072,7 +3030,7 @@
|
||||
return;
|
||||
}
|
||||
parent[name] = ifn.body;
|
||||
ifn.body = Value.wrap(parent);
|
||||
ifn.body = new Value(parent);
|
||||
return ifn;
|
||||
};
|
||||
|
||||
@@ -3080,9 +3038,6 @@
|
||||
"extends": function() {
|
||||
return "function(child, parent) { for (var key in parent) { if (" + (utility('hasProp')) + ".call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }";
|
||||
},
|
||||
bind: function() {
|
||||
return 'function(fn, me){ return function(){ return fn.apply(me, arguments); }; }';
|
||||
},
|
||||
indexOf: function() {
|
||||
return "[].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }";
|
||||
},
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -162,7 +162,7 @@
|
||||
var stack;
|
||||
stack = [];
|
||||
return this.scanTokens(function(token, i, tokens) {
|
||||
var endImplicitCall, endImplicitObject, forward, inImplicit, inImplicitCall, inImplicitControl, inImplicitObject, nextTag, prevTag, s, sameLine, stackIdx, stackTag, stackTop, startIdx, startImplicitCall, startImplicitObject, startsLine, tag, _ref, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6;
|
||||
var endImplicitCall, endImplicitObject, forward, inImplicit, inImplicitCall, inImplicitControl, inImplicitObject, nextTag, offset, prevTag, s, sameLine, stackIdx, stackTag, stackTop, startIdx, startImplicitCall, startImplicitObject, startsLine, tag, _ref, _ref1, _ref2, _ref3, _ref4, _ref5;
|
||||
tag = token[0];
|
||||
prevTag = (i > 0 ? tokens[i - 1] : [])[0];
|
||||
nextTag = (i < tokens.length - 1 ? tokens[i + 1] : [])[0];
|
||||
@@ -225,12 +225,13 @@
|
||||
return i += 1;
|
||||
}
|
||||
};
|
||||
endImplicitObject = function() {
|
||||
endImplicitObject = function(j) {
|
||||
j = j != null ? j : i;
|
||||
stack.pop();
|
||||
tokens.splice(i, 0, generate('}', '}'));
|
||||
tokens.splice(j, 0, generate('}', '}'));
|
||||
return i += 1;
|
||||
};
|
||||
if (inImplicitCall() && (tag === 'IF' || tag === 'TRY' || tag === 'FINALLY' || tag === 'CATCH' || tag === 'CLASS' || tag === 'SWITCH' || tag === 'CATCH')) {
|
||||
if (inImplicitCall() && (tag === 'IF' || tag === 'TRY' || tag === 'FINALLY' || tag === 'CATCH' || tag === 'CLASS' || tag === 'SWITCH')) {
|
||||
stack.push([
|
||||
'CONTROL', i, {
|
||||
ours: true
|
||||
@@ -273,7 +274,7 @@
|
||||
startImplicitCall(i + 1);
|
||||
return forward(2);
|
||||
}
|
||||
if (this.matchTags(i, IMPLICIT_FUNC, 'INDENT') && ((_ref2 = stackTop()) != null ? _ref2[0] : void 0) !== '[' && !this.findTagsBackwards(i, ['CLASS', 'EXTENDS', 'IF', 'CATCH', 'SWITCH', 'LEADING_WHEN', 'FOR', 'WHILE', 'UNTIL'])) {
|
||||
if (this.matchTags(i, IMPLICIT_FUNC, 'INDENT', null, ':') && !this.findTagsBackwards(i, ['CLASS', 'EXTENDS', 'IF', 'CATCH', 'SWITCH', 'LEADING_WHEN', 'FOR', 'WHILE', 'UNTIL'])) {
|
||||
startImplicitCall(i + 1);
|
||||
stack.push(['INDENT', i + 2]);
|
||||
return forward(3);
|
||||
@@ -287,9 +288,9 @@
|
||||
while (this.tag(s - 2) === 'HERECOMMENT') {
|
||||
s -= 2;
|
||||
}
|
||||
startsLine = s === 0 || (_ref3 = this.tag(s - 1), __indexOf.call(LINEBREAKS, _ref3) >= 0) || tokens[s - 1].newLine;
|
||||
startsLine = s === 0 || (_ref2 = this.tag(s - 1), __indexOf.call(LINEBREAKS, _ref2) >= 0) || tokens[s - 1].newLine;
|
||||
if (stackTop()) {
|
||||
_ref4 = stackTop(), stackTag = _ref4[0], stackIdx = _ref4[1];
|
||||
_ref3 = stackTop(), stackTag = _ref3[0], stackIdx = _ref3[1];
|
||||
if ((stackTag === '{' || stackTag === 'INDENT' && this.tag(stackIdx - 1) === '{') && (startsLine || this.tag(s - 1) === ',' || this.tag(s - 1) === '{')) {
|
||||
return forward(1);
|
||||
}
|
||||
@@ -297,7 +298,7 @@
|
||||
startImplicitObject(s, !!startsLine);
|
||||
return forward(2);
|
||||
}
|
||||
if (prevTag === 'OUTDENT' && inImplicitCall() && (tag === '.' || tag === '?.' || tag === '::')) {
|
||||
if (prevTag === 'OUTDENT' && inImplicitCall() && (tag === '.' || tag === '?.' || tag === '::' || tag === '?::')) {
|
||||
endImplicitCall();
|
||||
return forward(1);
|
||||
}
|
||||
@@ -306,7 +307,7 @@
|
||||
}
|
||||
if (__indexOf.call(IMPLICIT_END, tag) >= 0) {
|
||||
while (inImplicit()) {
|
||||
_ref5 = stackTop(), stackTag = _ref5[0], stackIdx = _ref5[1], (_ref6 = _ref5[2], sameLine = _ref6.sameLine, startsLine = _ref6.startsLine);
|
||||
_ref4 = stackTop(), stackTag = _ref4[0], stackIdx = _ref4[1], (_ref5 = _ref4[2], sameLine = _ref5.sameLine, startsLine = _ref5.startsLine);
|
||||
if (inImplicitCall() && prevTag !== ',') {
|
||||
endImplicitCall();
|
||||
} else if (inImplicitObject() && sameLine && !startsLine) {
|
||||
@@ -319,11 +320,9 @@
|
||||
}
|
||||
}
|
||||
if (tag === ',' && !this.looksObjectish(i + 1) && inImplicitObject() && (nextTag !== 'TERMINATOR' || !this.looksObjectish(i + 2))) {
|
||||
if (nextTag === 'OUTDENT') {
|
||||
i += 1;
|
||||
}
|
||||
offset = nextTag === 'OUTDENT' ? 1 : 0;
|
||||
while (inImplicitObject()) {
|
||||
endImplicitObject();
|
||||
endImplicitObject(i + offset);
|
||||
}
|
||||
}
|
||||
return forward(1);
|
||||
|
||||
@@ -39,7 +39,8 @@
|
||||
};
|
||||
|
||||
Scope.prototype.namedMethod = function() {
|
||||
if (this.method.name || !this.parent) {
|
||||
var _ref1;
|
||||
if (((_ref1 = this.method) != null ? _ref1.name : void 0) || !this.parent) {
|
||||
return this.method;
|
||||
}
|
||||
return this.parent.namedMethod();
|
||||
|
||||
@@ -6,25 +6,22 @@
|
||||
# If included on a webpage, it will automatically sniff out, compile, and
|
||||
# execute all scripts present in `text/coffeescript` tags.
|
||||
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
{Lexer} = require './lexer'
|
||||
{parser} = require './parser'
|
||||
fs = require 'fs'
|
||||
path = require 'path'
|
||||
{Lexer} = require './lexer'
|
||||
{parser} = require './parser'
|
||||
helpers = require './helpers'
|
||||
vm = require 'vm'
|
||||
sourcemap = require './sourcemap'
|
||||
vm = require 'vm'
|
||||
{count, extend} = require './helpers'
|
||||
|
||||
# The file extensions that are considered to be CoffeeScript.
|
||||
extensions = ['.coffee', '.litcoffee']
|
||||
|
||||
# Load and run a CoffeeScript file for Node, stripping any `BOM`s.
|
||||
loadFile = (module, filename) ->
|
||||
raw = fs.readFileSync filename, 'utf8'
|
||||
stripped = if raw.charCodeAt(0) is 0xFEFF then raw.substring 1 else raw
|
||||
module._compile compile(stripped, {filename}), filename
|
||||
module._compile compile(stripped, {filename, literate: helpers.isLiterate filename}), filename
|
||||
|
||||
if require.extensions
|
||||
for ext in extensions
|
||||
for ext in ['.coffee', '.litcoffee', '.md', '.coffee.md']
|
||||
require.extensions[ext] = loadFile
|
||||
|
||||
# The current CoffeeScript version number.
|
||||
@@ -55,7 +52,7 @@ exports.compile = compile = (code, options = {}) ->
|
||||
[fragment.locationData.first_line, fragment.locationData.first_column],
|
||||
[currentLine, currentColumn],
|
||||
{noReplace: true})
|
||||
newLines = count fragment.code, "\n"
|
||||
newLines = helpers.count fragment.code, "\n"
|
||||
currentLine += newLines
|
||||
currentColumn = fragment.code.length - (if newLines then fragment.code.lastIndexOf "\n" else 0)
|
||||
|
||||
@@ -76,7 +73,7 @@ exports.compile = compile = (code, options = {}) ->
|
||||
exports.compileWithSourceMap = (code, options={}) ->
|
||||
{merge} = exports.helpers
|
||||
try
|
||||
options = extend {}, options
|
||||
options = helpers.extend {}, options
|
||||
options.sourceMap = new sourcemap.SourceMap()
|
||||
coffeeFile = path.basename options.filename
|
||||
jsFile = baseFileName(options.filename) + ".js"
|
||||
@@ -121,7 +118,7 @@ exports.run = (code, options = {}) ->
|
||||
mainModule.paths = require('module')._nodeModulePaths path.dirname fs.realpathSync options.filename
|
||||
|
||||
# Compile.
|
||||
if (path.extname(mainModule.filename) not in extensions) or require.extensions
|
||||
if not helpers.isCoffee(mainModule.filename) or require.extensions
|
||||
mainModule._compile compile(code, options), mainModule.filename
|
||||
else
|
||||
mainModule._compile code, mainModule.filename
|
||||
|
||||
@@ -57,7 +57,6 @@ sourceCode = []
|
||||
notSources = {}
|
||||
watchers = {}
|
||||
optionParser = null
|
||||
coffee_exts = ['.coffee', '.litcoffee']
|
||||
|
||||
# Run `coffee` by parsing passed options and determining what action to take.
|
||||
# Many flags cause us to divert before compiling anything. Flags passed after
|
||||
@@ -80,8 +79,8 @@ exports.run = ->
|
||||
compilePath source, yes, path.normalize source
|
||||
|
||||
# Compile a path, which could be a script or a directory. If a directory
|
||||
# is passed, recursively compile all '.coffee' and '.litcoffee' extension source
|
||||
# files in it and all subdirectories.
|
||||
# is passed, recursively compile all '.coffee', '.litcoffee', and '.coffee.md'
|
||||
# extension source files in it and all subdirectories.
|
||||
compilePath = (source, topLevel, base) ->
|
||||
fs.stat source, (err, stats) ->
|
||||
throw err if err and err.code isnt 'ENOENT'
|
||||
@@ -99,7 +98,7 @@ compilePath = (source, topLevel, base) ->
|
||||
sourceCode[index..index] = files.map -> null
|
||||
files.forEach (file) ->
|
||||
compilePath (path.join source, file), no, base
|
||||
else if topLevel or path.extname(source) in coffee_exts
|
||||
else if topLevel or helpers.isCoffee source
|
||||
watch source, base if opts.watch
|
||||
fs.readFile source, (err, code) ->
|
||||
throw err if err and err.code isnt 'ENOENT'
|
||||
@@ -251,11 +250,11 @@ removeSource = (source, base, removeJs) ->
|
||||
|
||||
# Get the corresponding output JavaScript path for a source file.
|
||||
outputPath = (source, base, extension=".js") ->
|
||||
filename = path.basename(source, path.extname(source)) + extension
|
||||
basename = path.basename source, source.match(/\.((lit)?coffee|coffee\.md)$/)?[0] or path.extname(source)
|
||||
srcDir = path.dirname source
|
||||
baseDir = if base is '.' then srcDir else srcDir.substring base.length
|
||||
dir = if opts.output then path.join opts.output, baseDir else srcDir
|
||||
path.join dir, filename
|
||||
path.join dir, basename + extension
|
||||
|
||||
# Write out a JavaScript source file with the compiled code. By default, files
|
||||
# are written out in `cwd` as `.js` files with the same name, but the output
|
||||
@@ -301,13 +300,12 @@ lint = (file, js) ->
|
||||
jsl.stdin.write js
|
||||
jsl.stdin.end()
|
||||
|
||||
# Pretty-print a stream of tokens.
|
||||
# Pretty-print a stream of tokens, sans location data.
|
||||
printTokens = (tokens) ->
|
||||
strings = for token in tokens
|
||||
tag = token[0]
|
||||
value = token[1].toString().replace(/\n/, '\\n')
|
||||
locationData = helpers.locationDataToString token[2]
|
||||
"[#{tag} #{value} #{locationData}]"
|
||||
"[#{tag} #{value}]"
|
||||
printLine strings.join(' ')
|
||||
|
||||
# Use the [OptionParser module](optparse.html) to extract all options from
|
||||
@@ -324,8 +322,7 @@ parseOptions = ->
|
||||
|
||||
# The compile-time options to pass to the CoffeeScript compiler.
|
||||
compileOptions = (filename) ->
|
||||
literate = path.extname(filename) is '.litcoffee'
|
||||
{filename, literate, bare: opts.bare, header: opts.compile}
|
||||
{filename, literate: helpers.isLiterate(filename), bare: opts.bare, header: opts.compile}
|
||||
|
||||
# Start up a new Node.js instance with the arguments in `--nodejs` passed to
|
||||
# the `node` binary, preserving the other options.
|
||||
|
||||
@@ -39,7 +39,6 @@ o = (patternString, action, options) ->
|
||||
# All runtime functions we need are defined on "yy"
|
||||
action = action.replace /\bnew /g, '$&yy.'
|
||||
action = action.replace /\b(?:Block\.wrap|extend)\b/g, 'yy.$&'
|
||||
action = action.replace /\b(Op|Value\.(create|wrap))\b/g, 'yy.$&'
|
||||
|
||||
# Returns a function which adds location data to the first parameter passed
|
||||
# in, and returns the parameter. If the parameter is not a node, it will
|
||||
@@ -159,10 +158,10 @@ grammar =
|
||||
# Assignment when it happens within an object literal. The difference from
|
||||
# the ordinary **Assign** is that these allow numbers and strings as keys.
|
||||
AssignObj: [
|
||||
o 'ObjAssignable', -> Value.wrap $1
|
||||
o 'ObjAssignable : Expression', -> new Assign LOC(1)(Value.wrap($1)), $3, 'object'
|
||||
o 'ObjAssignable', -> new Value $1
|
||||
o 'ObjAssignable : Expression', -> new Assign LOC(1)(new Value($1)), $3, 'object'
|
||||
o 'ObjAssignable :
|
||||
INDENT Expression OUTDENT', -> new Assign LOC(1)(Value.wrap($1)), $4, 'object'
|
||||
INDENT Expression OUTDENT', -> new Assign LOC(1)(new Value($1)), $4, 'object'
|
||||
o 'Comment'
|
||||
]
|
||||
|
||||
@@ -236,26 +235,26 @@ grammar =
|
||||
|
||||
# Variables and properties that can be assigned to.
|
||||
SimpleAssignable: [
|
||||
o 'Identifier', -> Value.wrap $1
|
||||
o 'Identifier', -> new Value $1
|
||||
o 'Value Accessor', -> $1.add $2
|
||||
o 'Invocation Accessor', -> Value.wrap $1, [].concat $2
|
||||
o 'Invocation Accessor', -> new Value $1, [].concat $2
|
||||
o 'ThisProperty'
|
||||
]
|
||||
|
||||
# Everything that can be assigned to.
|
||||
Assignable: [
|
||||
o 'SimpleAssignable'
|
||||
o 'Array', -> Value.wrap $1
|
||||
o 'Object', -> Value.wrap $1
|
||||
o 'Array', -> new Value $1
|
||||
o 'Object', -> new Value $1
|
||||
]
|
||||
|
||||
# The types of things that can be treated as values -- assigned to, invoked
|
||||
# as functions, indexed into, named as a class, etc.
|
||||
Value: [
|
||||
o 'Assignable'
|
||||
o 'Literal', -> Value.wrap $1
|
||||
o 'Parenthetical', -> Value.wrap $1
|
||||
o 'Range', -> Value.wrap $1
|
||||
o 'Literal', -> new Value $1
|
||||
o 'Parenthetical', -> new Value $1
|
||||
o 'Range', -> new Value $1
|
||||
o 'This'
|
||||
]
|
||||
|
||||
@@ -264,7 +263,8 @@ grammar =
|
||||
Accessor: [
|
||||
o '. Identifier', -> new Access $2
|
||||
o '?. Identifier', -> new Access $2, 'soak'
|
||||
o ':: Identifier', -> [LOC(1)(new Access new Literal 'prototype'), LOC(2)(new Access $2)]
|
||||
o ':: Identifier', -> [LOC(1)(new Access new Literal('prototype')), LOC(2)(new Access $2)]
|
||||
o '?:: Identifier', -> [LOC(1)(new Access new Literal('prototype'), 'soak'), LOC(2)(new Access $2)]
|
||||
o '::', -> new Access new Literal 'prototype'
|
||||
o 'Index'
|
||||
]
|
||||
@@ -330,13 +330,13 @@ grammar =
|
||||
|
||||
# A reference to the *this* current object.
|
||||
This: [
|
||||
o 'THIS', -> Value.wrap new Literal 'this'
|
||||
o '@', -> Value.wrap new Literal 'this'
|
||||
o 'THIS', -> new Value new Literal 'this'
|
||||
o '@', -> new Value new Literal 'this'
|
||||
]
|
||||
|
||||
# A reference to a property on *this*.
|
||||
ThisProperty: [
|
||||
o '@ Identifier', -> Value.wrap LOC(1)(new Literal('this')), [LOC(2)(new Access($2))], 'this'
|
||||
o '@ Identifier', -> new Value LOC(1)(new Literal('this')), [LOC(2)(new Access($2))], 'this'
|
||||
]
|
||||
|
||||
# The array literal.
|
||||
@@ -400,7 +400,7 @@ grammar =
|
||||
# A catch clause names its error and runs a block of code.
|
||||
Catch: [
|
||||
o 'CATCH Identifier Block', -> [$2, $3]
|
||||
o 'CATCH Object Block', -> [LOC(2)(Value.wrap($2)), $3]
|
||||
o 'CATCH Object Block', -> [LOC(2)(new Value($2)), $3]
|
||||
]
|
||||
|
||||
# Throw an exception object.
|
||||
@@ -449,7 +449,7 @@ grammar =
|
||||
]
|
||||
|
||||
ForBody: [
|
||||
o 'FOR Range', -> source: LOC(2) Value.wrap($2)
|
||||
o 'FOR Range', -> source: LOC(2) new Value($2)
|
||||
o 'ForStart ForSource', -> $2.own = $1.own; $2.name = $1[0]; $2.index = $1[1]; $2
|
||||
]
|
||||
|
||||
@@ -463,8 +463,8 @@ grammar =
|
||||
ForValue: [
|
||||
o 'Identifier'
|
||||
o 'ThisProperty'
|
||||
o 'Array', -> Value.wrap $1
|
||||
o 'Object', -> Value.wrap $1
|
||||
o 'Array', -> new Value $1
|
||||
o 'Object', -> new Value $1
|
||||
]
|
||||
|
||||
# An array or range comprehension has variables for the current element
|
||||
@@ -530,30 +530,30 @@ grammar =
|
||||
# -type rule, but in order to make the precedence binding possible, separate
|
||||
# rules are necessary.
|
||||
Operation: [
|
||||
o 'UNARY Expression', -> Op.create $1 , $2
|
||||
o '- Expression', (-> Op.create '-', $2), prec: 'UNARY'
|
||||
o '+ Expression', (-> Op.create '+', $2), prec: 'UNARY'
|
||||
o 'UNARY Expression', -> new Op $1 , $2
|
||||
o '- Expression', (-> new Op '-', $2), prec: 'UNARY'
|
||||
o '+ Expression', (-> new Op '+', $2), prec: 'UNARY'
|
||||
|
||||
o '-- SimpleAssignable', -> Op.create '--', $2
|
||||
o '++ SimpleAssignable', -> Op.create '++', $2
|
||||
o 'SimpleAssignable --', -> Op.create '--', $1, null, true
|
||||
o 'SimpleAssignable ++', -> Op.create '++', $1, null, true
|
||||
o '-- SimpleAssignable', -> new Op '--', $2
|
||||
o '++ SimpleAssignable', -> new Op '++', $2
|
||||
o 'SimpleAssignable --', -> new Op '--', $1, null, true
|
||||
o 'SimpleAssignable ++', -> new Op '++', $1, null, true
|
||||
|
||||
# [The existential operator](http://jashkenas.github.com/coffee-script/#existence).
|
||||
o 'Expression ?', -> new Existence $1
|
||||
|
||||
o 'Expression + Expression', -> Op.create '+' , $1, $3
|
||||
o 'Expression - Expression', -> Op.create '-' , $1, $3
|
||||
o 'Expression + Expression', -> new Op '+' , $1, $3
|
||||
o 'Expression - Expression', -> new Op '-' , $1, $3
|
||||
|
||||
o 'Expression MATH Expression', -> Op.create $2, $1, $3
|
||||
o 'Expression SHIFT Expression', -> Op.create $2, $1, $3
|
||||
o 'Expression COMPARE Expression', -> Op.create $2, $1, $3
|
||||
o 'Expression LOGIC Expression', -> Op.create $2, $1, $3
|
||||
o 'Expression MATH Expression', -> new Op $2, $1, $3
|
||||
o 'Expression SHIFT Expression', -> new Op $2, $1, $3
|
||||
o 'Expression COMPARE Expression', -> new Op $2, $1, $3
|
||||
o 'Expression LOGIC Expression', -> new Op $2, $1, $3
|
||||
o 'Expression RELATION Expression', ->
|
||||
if $2.charAt(0) is '!'
|
||||
Op.create($2[1..], $1, $3).invert()
|
||||
new Op($2[1..], $1, $3).invert()
|
||||
else
|
||||
Op.create $2, $1, $3
|
||||
new Op $2, $1, $3
|
||||
|
||||
o 'SimpleAssignable COMPOUND_ASSIGN
|
||||
Expression', -> new Assign $1, $3, $2
|
||||
@@ -577,7 +577,7 @@ grammar =
|
||||
#
|
||||
# (2 + 3) * 4
|
||||
operators = [
|
||||
['left', '.', '?.', '::']
|
||||
['left', '.', '?.', '::', '?::']
|
||||
['left', 'CALL_START', 'CALL_END']
|
||||
['nonassoc', '++', '--']
|
||||
['left', '?']
|
||||
|
||||
@@ -92,4 +92,10 @@ exports.locationDataToString = (obj) ->
|
||||
else
|
||||
"No location data"
|
||||
|
||||
# Determine if a filename represents a CoffeeScript file.
|
||||
exports.isCoffee = (file) -> /\.((lit)?coffee|coffee\.md)$/.test file
|
||||
|
||||
# Determine if a filename represents a Literate CoffeeScript file.
|
||||
exports.isLiterate = (file) -> /\.(litcoffee|coffee\.md)$/.test file
|
||||
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@ exports.Lexer = class Lexer
|
||||
# unless explicitly asked not to.
|
||||
tokenize: (code, opts = {}) ->
|
||||
@literate = opts.literate # Are we lexing literate CoffeeScript?
|
||||
code = @clean code # The stripped, cleaned original source code.
|
||||
@indent = 0 # The current indentation level.
|
||||
@indebt = 0 # The over-indentation at the current level.
|
||||
@outdebt = 0 # The under-outdentation at the current level.
|
||||
@@ -47,6 +46,7 @@ exports.Lexer = class Lexer
|
||||
opts.line or 0 # The start line for the current @chunk.
|
||||
@chunkColumn =
|
||||
opts.column or 0 # The start column of the current @chunk.
|
||||
code = @clean code # The stripped, cleaned original source code.
|
||||
|
||||
# At every position, run through this list of attempted matches,
|
||||
# short-circuiting if any of them succeed. Their order determines precedence:
|
||||
@@ -80,8 +80,10 @@ exports.Lexer = class Lexer
|
||||
# by removing all lines that aren't indented by at least four spaces or a tab.
|
||||
clean: (code) ->
|
||||
code = code.slice(1) if code.charCodeAt(0) is BOM
|
||||
code = "\n#{code}" if WHITESPACE.test code
|
||||
code = code.replace(/\r/g, '').replace TRAILING_SPACES, ''
|
||||
if WHITESPACE.test code
|
||||
code = "\n#{code}"
|
||||
@chunkLine--
|
||||
if @literate
|
||||
lines = for line in code.split('\n')
|
||||
if match = LITERATE.exec line
|
||||
@@ -112,7 +114,7 @@ exports.Lexer = class Lexer
|
||||
@token 'OWN', id
|
||||
return id.length
|
||||
forcedIdentifier = colon or
|
||||
(prev = last @tokens) and (prev[0] in ['.', '?.', '::'] or
|
||||
(prev = last @tokens) and (prev[0] in ['.', '?.', '::', '?::'] or
|
||||
not prev.spaced and prev[0] is '@')
|
||||
tag = 'IDENTIFIER'
|
||||
|
||||
@@ -676,7 +678,7 @@ exports.Lexer = class Lexer
|
||||
# Are we in the midst of an unfinished expression?
|
||||
unfinished: ->
|
||||
LINE_CONTINUER.test(@chunk) or
|
||||
@tag() in ['\\', '.', '?.', 'UNARY', 'MATH', '+', '-', 'SHIFT', 'RELATION'
|
||||
@tag() in ['\\', '.', '?.', '?::', 'UNARY', 'MATH', '+', '-', 'SHIFT', 'RELATION'
|
||||
'COMPARE', 'LOGIC', 'THROW', 'EXTENDS']
|
||||
|
||||
# Converts newlines for string literals.
|
||||
@@ -769,7 +771,7 @@ OPERATOR = /// ^ (
|
||||
| >>>=? # zero-fill right shift
|
||||
| ([-+:])\1 # doubles
|
||||
| ([&|<>])\2=? # logic / shift
|
||||
| \?\. # soak access
|
||||
| \?(\.|::) # soak access
|
||||
| \.{2,3} # range or splat
|
||||
) ///
|
||||
|
||||
|
||||
145
src/nodes.coffee
145
src/nodes.coffee
@@ -154,7 +154,7 @@ exports.Base = class Base
|
||||
child.traverseChildren crossScope, func
|
||||
|
||||
invert: ->
|
||||
Op.create '!', this
|
||||
new Op '!', this
|
||||
|
||||
unwrapAll: ->
|
||||
node = this
|
||||
@@ -448,15 +448,12 @@ exports.Return = class Return extends Base
|
||||
# A value, variable or literal or parenthesized, indexed or dotted into,
|
||||
# or vanilla.
|
||||
exports.Value = class Value extends Base
|
||||
@wrap: (base, props, tag) ->
|
||||
if not props and base instanceof Value
|
||||
base
|
||||
else
|
||||
new Value base, props, tag
|
||||
|
||||
constructor: (@base, @properties, tag) ->
|
||||
@properties or= []
|
||||
@this = true if tag is 'this'
|
||||
constructor: (base, props, tag) ->
|
||||
return base if not props and base instanceof Value
|
||||
@base = base
|
||||
@properties = props or []
|
||||
@[tag] = true if tag
|
||||
return this
|
||||
|
||||
children: ['base', 'properties']
|
||||
|
||||
@@ -502,16 +499,16 @@ exports.Value = class Value extends Base
|
||||
name = last @properties
|
||||
if @properties.length < 2 and not @base.isComplex() and not name?.isComplex()
|
||||
return [this, this] # `a` `a.b`
|
||||
base = Value.wrap @base, @properties[...-1]
|
||||
base = new Value @base, @properties[...-1]
|
||||
if base.isComplex() # `a().b`
|
||||
bref = new Literal o.scope.freeVariable 'base'
|
||||
base = Value.wrap new Parens new Assign bref, base
|
||||
base = new Value new Parens new Assign bref, base
|
||||
return [base, bref] unless name # `a()`
|
||||
if name.isComplex() # `a[b()]`
|
||||
nref = new Literal o.scope.freeVariable 'name'
|
||||
name = new Index new Assign nref, name.index
|
||||
nref = new Index nref
|
||||
[base.add(name), Value.wrap(bref or base.base, [nref or name])]
|
||||
[base.add(name), new Value(bref or base.base, [nref or name])]
|
||||
|
||||
# We compile a value to JavaScript by compiling and joining each property.
|
||||
# Things get much more interesting if the chain of properties has *soak*
|
||||
@@ -535,8 +532,8 @@ exports.Value = class Value extends Base
|
||||
return ifn
|
||||
for prop, i in @properties when prop.soak
|
||||
prop.soak = off
|
||||
fst = Value.wrap @base, @properties[...i]
|
||||
snd = Value.wrap @base, @properties[i..]
|
||||
fst = new Value @base, @properties[...i]
|
||||
snd = new Value @base, @properties[i..]
|
||||
if fst.isComplex()
|
||||
ref = new Literal o.scope.freeVariable 'ref'
|
||||
fst = new Parens new Assign ref, fst
|
||||
@@ -584,16 +581,15 @@ exports.Call = class Call extends Base
|
||||
# method.
|
||||
superReference: (o) ->
|
||||
method = o.scope.namedMethod()
|
||||
throw SyntaxError 'cannot call super outside of a function.' unless method
|
||||
{name} = method
|
||||
throw SyntaxError 'cannot call super on an anonymous function.' unless name?
|
||||
if method.klass
|
||||
if method?.klass
|
||||
accesses = [new Access(new Literal '__super__')]
|
||||
accesses.push new Access new Literal 'constructor' if method.static
|
||||
accesses.push new Access new Literal name
|
||||
(Value.wrap (new Literal method.klass), accesses).compile o
|
||||
accesses.push new Access new Literal method.name
|
||||
(new Value (new Literal method.klass), accesses).compile o
|
||||
else if method?.ctor
|
||||
"#{method.name}.__super__.constructor"
|
||||
else
|
||||
"#{name}.__super__.constructor"
|
||||
throw SyntaxError 'cannot call super outside of an instance method.'
|
||||
|
||||
# The appropriate `this` value for a `super` call.
|
||||
superThis : (o) ->
|
||||
@@ -605,14 +601,14 @@ exports.Call = class Call extends Base
|
||||
if @soak
|
||||
if @variable
|
||||
return ifn if ifn = unfoldSoak o, this, 'variable'
|
||||
[left, rite] = Value.wrap(@variable).cacheReference o
|
||||
[left, rite] = new Value(@variable).cacheReference o
|
||||
else
|
||||
left = new Literal @superReference o
|
||||
rite = Value.wrap left
|
||||
rite = new Value left
|
||||
rite = new Call rite, @args
|
||||
rite.isNew = @isNew
|
||||
left = new Literal "typeof #{ left.compile o } === \"function\""
|
||||
return new If left, Value.wrap(rite), soak: yes
|
||||
return new If left, new Value(rite), soak: yes
|
||||
call = this
|
||||
list = []
|
||||
loop
|
||||
@@ -679,7 +675,7 @@ exports.Call = class Call extends Base
|
||||
@makeCode(", "), splatArgs, @makeCode(", function(){})")
|
||||
|
||||
answer = []
|
||||
base = Value.wrap @variable
|
||||
base = new Value @variable
|
||||
if (name = base.properties.pop()) and base.isComplex()
|
||||
ref = o.scope.freeVariable 'ref'
|
||||
answer = answer.concat @makeCode("(#{ref} = "),
|
||||
@@ -709,7 +705,7 @@ exports.Extends = class Extends extends Base
|
||||
|
||||
# Hooks one constructor into another's prototype chain.
|
||||
compileToFragments: (o) ->
|
||||
new Call(Value.wrap(new Literal utility 'extends'), [@child, @parent]).compileToFragments o
|
||||
new Call(new Value(new Literal utility 'extends'), [@child, @parent]).compileToFragments o
|
||||
|
||||
#### Access
|
||||
|
||||
@@ -986,9 +982,22 @@ exports.Class = class Class extends Base
|
||||
# Ensure that all functions bound to the instance are proxied in the
|
||||
# constructor.
|
||||
addBoundFunctions: (o) ->
|
||||
for bvar in @boundFuncs
|
||||
lhs = (Value.wrap (new Literal "this"), [new Access bvar]).compile o
|
||||
@ctor.body.unshift new Literal "#{lhs} = #{utility 'bind'}(#{lhs}, this)"
|
||||
if @boundFuncs.length
|
||||
o.scope.assign '_this', 'this'
|
||||
for [name, func] in @boundFuncs
|
||||
lhs = new Value (new Literal "this"), [new Access name]
|
||||
body = new Block [new Return new Literal "#{@ctor.name}.prototype.#{name.value}.apply(_this, arguments)"]
|
||||
rhs = new Code func.params, body, 'boundfunc'
|
||||
bound = new Assign lhs, rhs
|
||||
|
||||
@ctor.body.unshift bound
|
||||
|
||||
# {base} = assign.variable
|
||||
# lhs = (new Value (new Literal "this"), [new Access base]).compile o
|
||||
# @ctor.body.unshift new Literal """#{lhs} = function() {
|
||||
# #{o.indent} return #{@ctor.name}.prototype.#{base.value}.apply(_this, arguments);
|
||||
# #{o.indent}}\n
|
||||
# """
|
||||
return
|
||||
|
||||
# Merge the properties from a top-level object as prototypal properties
|
||||
@@ -1016,9 +1025,9 @@ exports.Class = class Class extends Base
|
||||
if func.bound
|
||||
func.context = name
|
||||
else
|
||||
assign.variable = Value.wrap(new Literal(name), [(new Access new Literal 'prototype'), new Access base ])
|
||||
assign.variable = new Value(new Literal(name), [(new Access new Literal 'prototype'), new Access base ])
|
||||
if func instanceof Code and func.bound
|
||||
@boundFuncs.push base
|
||||
@boundFuncs.push [base, func]
|
||||
func.bound = no
|
||||
assign
|
||||
compact exprs
|
||||
@@ -1026,12 +1035,15 @@ exports.Class = class Class extends Base
|
||||
# Walk the body of the class, looking for prototype properties to be converted.
|
||||
walkBody: (name, o) ->
|
||||
@traverseChildren false, (child) =>
|
||||
cont = true
|
||||
return false if child instanceof Class
|
||||
if child instanceof Block
|
||||
for node, i in exps = child.expressions
|
||||
if node instanceof Value and node.isObject(true)
|
||||
cont = false
|
||||
exps[i] = @addProperties node, name, o
|
||||
child.expressions = exps = flatten exps
|
||||
cont and child not instanceof Class
|
||||
|
||||
# `use strict` (and other directives) must be the first expression statement(s)
|
||||
# of a function body. This method ensures the prologue is correctly positioned
|
||||
@@ -1045,23 +1057,17 @@ exports.Class = class Class extends Base
|
||||
|
||||
# Make sure that a constructor is defined for the class, and properly
|
||||
# configured.
|
||||
ensureConstructor: (name, o) ->
|
||||
ensureConstructor: (name) ->
|
||||
if not @ctor
|
||||
@ctor = new Code
|
||||
@ctor.body.push new Literal "#{name}.__super__.constructor.apply(this, arguments)" if @parent
|
||||
@ctor.body.push new Literal "#{@externalCtor}.apply(this, arguments)" if @externalCtor
|
||||
@ctor.body.makeReturn()
|
||||
@body.expressions.unshift @ctor
|
||||
@ctor.ctor = @ctor.name = name
|
||||
@ctor.klass = null
|
||||
@ctor.noReturn = yes
|
||||
|
||||
# Prevent constructor from returning a value.
|
||||
returnExpr = null
|
||||
@ctor.body.traverseChildren no, (node) ->
|
||||
return no if node instanceof Return and (returnExpr = node.expression)
|
||||
if returnExpr
|
||||
throw SyntaxError "cannot return a value from a constructor: \"#{returnExpr.compileNode o}\" in class #{name}"
|
||||
|
||||
# Instead of generating the JavaScript string directly, we build up the
|
||||
# equivalent syntax tree and compile that, in pieces. You can see the
|
||||
# constructor, property assignments, and inheritance getting built out below.
|
||||
@@ -1074,7 +1080,7 @@ exports.Class = class Class extends Base
|
||||
@hoistDirectivePrologue()
|
||||
@setContext name
|
||||
@walkBody name, o
|
||||
@ensureConstructor name, o
|
||||
@ensureConstructor name
|
||||
@body.spaced = yes
|
||||
@body.expressions.unshift @ctor unless @ctor instanceof Code
|
||||
@body.expressions.push lname
|
||||
@@ -1166,7 +1172,7 @@ exports.Assign = class Assign extends Base
|
||||
else
|
||||
new Literal 0
|
||||
acc = IDENTIFIER.test idx.unwrap().value or 0
|
||||
value = Value.wrap value
|
||||
value = new Value value
|
||||
value.properties.push new (if acc then Access else Index) idx
|
||||
if obj.unwrap().value in RESERVED
|
||||
throw new SyntaxError "assignment to a reserved word: #{obj.compile o} = #{value.compile o}"
|
||||
@@ -1190,7 +1196,7 @@ exports.Assign = class Assign extends Base
|
||||
else
|
||||
# A shorthand `{a, b, @c} = val` pattern-match.
|
||||
if obj.base instanceof Parens
|
||||
[obj, idx] = Value.wrap(obj.unwrapAll()).cacheReference o
|
||||
[obj, idx] = new Value(obj.unwrapAll()).cacheReference o
|
||||
else
|
||||
idx = if obj.this then obj.properties[0].name else obj
|
||||
if not splat and obj instanceof Splat
|
||||
@@ -1215,7 +1221,7 @@ exports.Assign = class Assign extends Base
|
||||
acc = no
|
||||
else
|
||||
acc = isObject and IDENTIFIER.test idx.unwrap().value or 0
|
||||
val = Value.wrap new Literal(vvarText), [new (if acc then Access else Index) idx]
|
||||
val = new Value new Literal(vvarText), [new (if acc then Access else Index) idx]
|
||||
if name? and name in RESERVED
|
||||
throw new SyntaxError "assignment to a reserved word: #{obj.compile o} = #{val.compile o}"
|
||||
assigns.push new Assign(obj, val, null, param: @param, subpattern: yes).compileToFragments o, LEVEL_LIST
|
||||
@@ -1233,7 +1239,7 @@ exports.Assign = class Assign extends Base
|
||||
left.base.value != "this" and not o.scope.check left.base.value
|
||||
throw new Error "the variable \"#{left.base.value}\" can't be assigned with #{@context} because it has not been defined."
|
||||
if "?" in @context then o.isExistentialEquals = true
|
||||
Op.create(@context[...-1], left, new Assign(right, @value, '=') ).compileToFragments o
|
||||
new Op(@context[...-1], left, new Assign(right, @value, '=') ).compileToFragments o
|
||||
|
||||
# Compile the assignment from an array splice literal, using JavaScript's
|
||||
# `Array#splice` method.
|
||||
@@ -1294,19 +1300,19 @@ exports.Code = class Code extends Base
|
||||
for {name: p} in @params
|
||||
if p.this then p = p.properties[0].name
|
||||
if p.value then o.scope.add p.value, 'var', yes
|
||||
splats = new Assign Value.wrap(new Arr(p.asReference o for p in @params)),
|
||||
Value.wrap new Literal 'arguments'
|
||||
splats = new Assign new Value(new Arr(p.asReference o for p in @params)),
|
||||
new Value new Literal 'arguments'
|
||||
break
|
||||
for param in @params
|
||||
if param.isComplex()
|
||||
val = ref = param.asReference o
|
||||
val = Op.create '?', ref, param.value if param.value
|
||||
exprs.push new Assign Value.wrap(param.name), val, '=', param: yes
|
||||
val = new Op '?', ref, param.value if param.value
|
||||
exprs.push new Assign new Value(param.name), val, '=', param: yes
|
||||
else
|
||||
ref = param
|
||||
if param.value
|
||||
lit = new Literal ref.name.value + ' == null'
|
||||
val = new Assign Value.wrap(param.name), param.value, '='
|
||||
val = new Assign new Value(param.name), param.value, '='
|
||||
exprs.push new If lit, val
|
||||
params.push ref unless splats
|
||||
wasEmpty = @body.isEmpty()
|
||||
@@ -1375,7 +1381,7 @@ exports.Param = class Param extends Base
|
||||
node = new Literal o.scope.freeVariable node.value
|
||||
else if node.isComplex()
|
||||
node = new Literal o.scope.freeVariable 'arg'
|
||||
node = Value.wrap node
|
||||
node = new Value node
|
||||
node = new Splat node if @splat
|
||||
@reference = node
|
||||
|
||||
@@ -1526,19 +1532,18 @@ exports.While = class While extends Base
|
||||
# Simple Arithmetic and logical operations. Performs some conversion from
|
||||
# CoffeeScript operations into their JavaScript equivalents.
|
||||
exports.Op = class Op extends Base
|
||||
@create: (op, first, second, flip) ->
|
||||
if op is 'in'
|
||||
return new In first, second
|
||||
constructor: (op, first, second, flip ) ->
|
||||
return new In first, second if op is 'in'
|
||||
if op is 'do'
|
||||
return @generateDo first
|
||||
if op is 'new'
|
||||
return first.newInstance() if first instanceof Call and not first.do and not first.isNew
|
||||
first = new Parens first if first instanceof Code and first.bound or first.do
|
||||
return new Op op, first, second, flip
|
||||
|
||||
constructor: (op, @first, @second, flip ) ->
|
||||
@operator = CONVERSIONS[op] or op
|
||||
@first = first
|
||||
@second = second
|
||||
@flip = !!flip
|
||||
return this
|
||||
|
||||
# The map of conversions from CoffeeScript to JavaScript symbols.
|
||||
CONVERSIONS =
|
||||
@@ -1591,12 +1596,12 @@ exports.Op = class Op extends Base
|
||||
fst.operator in ['!', 'in', 'instanceof']
|
||||
fst
|
||||
else
|
||||
Op.create '!', this
|
||||
new Op '!', this
|
||||
|
||||
unfoldSoak: (o) ->
|
||||
@operator in ['++', '--', 'delete'] and unfoldSoak o, this, 'first'
|
||||
|
||||
@generateDo: (exp) ->
|
||||
generateDo: (exp) ->
|
||||
passedParams = []
|
||||
func = if exp instanceof Assign and (ref = exp.value.unwrap()) instanceof Code
|
||||
ref
|
||||
@@ -1933,7 +1938,7 @@ exports.For = class For extends While
|
||||
val.properties[0].name?.value in ['call', 'apply'])
|
||||
fn = val.base?.unwrapAll() or val
|
||||
ref = new Literal o.scope.freeVariable 'fn'
|
||||
base = Value.wrap ref
|
||||
base = new Value ref
|
||||
if val.base
|
||||
[val.base, base] = [base, val]
|
||||
body.expressions[idx] = new Call base, expr.args
|
||||
@@ -2038,25 +2043,24 @@ exports.If = class If extends Base
|
||||
if exeq
|
||||
return new If(@condition.invert(), @elseBodyNode(), type: 'if').compileToFragments o
|
||||
|
||||
indent = o.indent + TAB
|
||||
body = @ensureBlock(@body).compileToFragments merge o, {indent}
|
||||
cond = @condition.compileToFragments o, LEVEL_PAREN
|
||||
o.indent += TAB
|
||||
body = @ensureBlock(@body)
|
||||
ifPart = [].concat @makeCode("if ("), cond, @makeCode(") {\n"), body.compileToFragments(o), @makeCode("\n#{@tab}}")
|
||||
ifPart = [].concat @makeCode("if ("), cond, @makeCode(") {\n"), body, @makeCode("\n#{@tab}}")
|
||||
ifPart.unshift @makeCode @tab unless child
|
||||
return ifPart unless @elseBody
|
||||
answer = ifPart.concat @makeCode(' else ')
|
||||
if @isChain
|
||||
o.indent = @tab
|
||||
o.chainChild = yes
|
||||
answer = answer.concat @elseBody.unwrap().compileToFragments o, LEVEL_TOP
|
||||
else
|
||||
answer = answer.concat @makeCode("{\n"), @elseBody.compileToFragments(o, LEVEL_TOP), @makeCode("\n#{@tab}}")
|
||||
answer = answer.concat @makeCode("{\n"), @elseBody.compileToFragments(merge(o, {indent}), LEVEL_TOP), @makeCode("\n#{@tab}}")
|
||||
answer
|
||||
|
||||
# Compile the `If` as a conditional operator.
|
||||
compileExpression: (o) ->
|
||||
cond = @condition.compileToFragments o, LEVEL_COND
|
||||
body = @bodyNode().compileToFragments o, LEVEL_LIST
|
||||
cond = @condition.compileToFragments o, LEVEL_COND
|
||||
alt = if @elseBodyNode() then @elseBodyNode().compileToFragments(o, LEVEL_LIST) else [@makeCode('void 0')]
|
||||
fragments = cond.concat @makeCode(" ? "), body, @makeCode(" : "), alt
|
||||
if o.level >= LEVEL_COND then @wrapInBraces fragments else fragments
|
||||
@@ -2087,7 +2091,7 @@ Closure =
|
||||
meth = new Literal if mentionsArgs then 'apply' else 'call'
|
||||
args = [new Literal 'this']
|
||||
args.push new Literal 'arguments' if mentionsArgs
|
||||
func = Value.wrap func, [new Access meth]
|
||||
func = new Value func, [new Access meth]
|
||||
func.noReturn = noReturn
|
||||
call = new Call func, args
|
||||
if statement then Block.wrap [call] else call
|
||||
@@ -2104,7 +2108,7 @@ Closure =
|
||||
unfoldSoak = (o, parent, name) ->
|
||||
return unless ifn = parent[name].unfoldSoak o
|
||||
parent[name] = ifn.body
|
||||
ifn.body = Value.wrap parent
|
||||
ifn.body = new Value parent
|
||||
ifn
|
||||
|
||||
# Constants
|
||||
@@ -2118,11 +2122,6 @@ UTILITIES =
|
||||
function(child, parent) { for (var key in parent) { if (#{utility 'hasProp'}.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }
|
||||
"""
|
||||
|
||||
# Create a function bound to the current value of "this".
|
||||
bind: -> '''
|
||||
function(fn, me){ return function(){ return fn.apply(me, arguments); }; }
|
||||
'''
|
||||
|
||||
# Discover if an item is in an array.
|
||||
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; }
|
||||
|
||||
@@ -173,14 +173,15 @@ class exports.Rewriter
|
||||
tokens.splice idx, 0, generate '{', generate(new String('{'))
|
||||
i += 1 if not j?
|
||||
|
||||
endImplicitObject = ->
|
||||
endImplicitObject = (j) ->
|
||||
j = j ? i
|
||||
stack.pop()
|
||||
tokens.splice i, 0, generate '}', '}'
|
||||
tokens.splice j, 0, generate '}', '}'
|
||||
i += 1
|
||||
|
||||
# Don't end an implicit call on next indent if any of these are in an argument
|
||||
if inImplicitCall() and tag in ['IF', 'TRY', 'FINALLY', 'CATCH',
|
||||
'CLASS', 'SWITCH', 'CATCH']
|
||||
'CLASS', 'SWITCH']
|
||||
stack.push ['CONTROL', i, ours: true]
|
||||
return forward(1)
|
||||
|
||||
@@ -239,8 +240,7 @@ class exports.Rewriter
|
||||
# which is probably always unintended.
|
||||
# Furthermore don't allow this in literal arrays, as
|
||||
# that creates grammatical ambiguities.
|
||||
if @matchTags(i, IMPLICIT_FUNC, 'INDENT') and
|
||||
stackTop()?[0] isnt '[' and
|
||||
if @matchTags(i, IMPLICIT_FUNC, 'INDENT', null, ':') and
|
||||
not @findTagsBackwards(i, ['CLASS', 'EXTENDS', 'IF', 'CATCH',
|
||||
'SWITCH', 'LEADING_WHEN', 'FOR', 'WHILE', 'UNTIL'])
|
||||
startImplicitCall i + 1
|
||||
@@ -271,7 +271,7 @@ class exports.Rewriter
|
||||
# .g b, ->
|
||||
# c
|
||||
# .h a
|
||||
if prevTag is 'OUTDENT' and inImplicitCall() and tag in ['.', '?.', '::']
|
||||
if prevTag is 'OUTDENT' and inImplicitCall() and tag in ['.', '?.', '::', '?::']
|
||||
endImplicitCall()
|
||||
return forward(1)
|
||||
|
||||
@@ -314,10 +314,10 @@ class exports.Rewriter
|
||||
#
|
||||
# When it isn't the comma go on to play a role in a call or
|
||||
# array further up the stack, so give it a chance.
|
||||
if nextTag is 'OUTDENT'
|
||||
i += 1
|
||||
|
||||
offset = if nextTag is 'OUTDENT' then 1 else 0
|
||||
while inImplicitObject()
|
||||
endImplicitObject()
|
||||
endImplicitObject i + offset
|
||||
return forward(1)
|
||||
|
||||
# Add location data to all tokens generated by the rewriter.
|
||||
|
||||
@@ -41,7 +41,7 @@ can get complicated if super is being called from an inner function.
|
||||
function object that has a name filled in, or bottoms out.
|
||||
|
||||
namedMethod: ->
|
||||
return @method if @method.name or !@parent
|
||||
return @method if @method?.name or !@parent
|
||||
@parent.namedMethod()
|
||||
|
||||
Look up a variable name in lexical scope, and declare it if it does not
|
||||
|
||||
@@ -117,24 +117,23 @@ test "basic classes, again, but in the manual prototype style", ->
|
||||
ok (new ThirdChild)['func-func']('thing') is 'dynamic-thing'
|
||||
|
||||
|
||||
test "super with plain ol' functions as the original constructors", ->
|
||||
test "super with plain ol' prototypes", ->
|
||||
|
||||
TopClass = (arg) ->
|
||||
@prop = 'top-' + arg
|
||||
this
|
||||
TopClass = ->
|
||||
TopClass::func = (arg) ->
|
||||
'top-' + arg
|
||||
|
||||
SuperClass = (arg) ->
|
||||
SuperClass = ->
|
||||
SuperClass extends TopClass
|
||||
SuperClass::func = (arg) ->
|
||||
super 'super-' + arg
|
||||
this
|
||||
|
||||
SubClass = ->
|
||||
super 'sub'
|
||||
this
|
||||
|
||||
SuperClass extends TopClass
|
||||
SubClass extends SuperClass
|
||||
SubClass::func = ->
|
||||
super 'sub'
|
||||
|
||||
ok (new SubClass).prop is 'top-super-sub'
|
||||
eq (new SubClass).func(), 'top-super-sub'
|
||||
|
||||
|
||||
test "'@' referring to the current instance, and not being coerced into a call", ->
|
||||
@@ -313,7 +312,7 @@ test "classes with value'd constructors", ->
|
||||
eq (new Two).value, 2
|
||||
|
||||
|
||||
test "exectuable class bodies", ->
|
||||
test "executable class bodies", ->
|
||||
|
||||
class A
|
||||
if true
|
||||
@@ -327,6 +326,17 @@ test "exectuable class bodies", ->
|
||||
eq a.c, undefined
|
||||
|
||||
|
||||
test "#2502: parenthesizing inner object values", ->
|
||||
|
||||
class A
|
||||
category: (type: 'string')
|
||||
sections: (type: 'number', default: 0)
|
||||
|
||||
eq (new A).category.type, 'string'
|
||||
|
||||
eq (new A).sections.default, 0
|
||||
|
||||
|
||||
test "mild metaprogramming", ->
|
||||
|
||||
class Base
|
||||
@@ -595,6 +605,11 @@ test "#1813: Passing class definitions as expressions", ->
|
||||
|
||||
eq result, B
|
||||
|
||||
test "#1966: external constructors should produce their return value", ->
|
||||
ctor = -> {}
|
||||
class A then constructor: ctor
|
||||
ok (new A) not instanceof A
|
||||
|
||||
test "#1980: regression with an inherited class with static function members", ->
|
||||
|
||||
class A
|
||||
@@ -676,27 +691,6 @@ test "#2630: class bodies can't reference arguments", ->
|
||||
throws ->
|
||||
CoffeeScript.compile('class Test then arguments')
|
||||
|
||||
test "#2359: instanceof should work when extending native objects", ->
|
||||
class MyError extends Error
|
||||
ok new MyError instanceof MyError
|
||||
|
||||
test '#2359: external constructors returning "other typed" objets', ->
|
||||
ctor = -> {}
|
||||
class A then constructor: ctor
|
||||
ok new A instanceof A
|
||||
ok new ctor not instanceof A
|
||||
ok new ctor not instanceof ctor
|
||||
|
||||
test "#2359: constructors should not return an explicit value", ->
|
||||
throws -> CoffeeScript.run "class then constructor: -> return 5"
|
||||
throws -> CoffeeScript.run """
|
||||
class
|
||||
constructor: ->
|
||||
if foo
|
||||
return bar: 7
|
||||
baz()
|
||||
"""
|
||||
|
||||
test "#2319: fn class n extends o.p [INDENT] x = 123", ->
|
||||
first = ->
|
||||
|
||||
@@ -706,4 +700,43 @@ test "#2319: fn class n extends o.p [INDENT] x = 123", ->
|
||||
one = 1
|
||||
one: -> one
|
||||
|
||||
eq new OneKeeper().one(), 1
|
||||
eq new OneKeeper().one(), 1
|
||||
|
||||
|
||||
test "#2599: other typed constructors should be inherited", ->
|
||||
class Base
|
||||
constructor: -> return {}
|
||||
|
||||
class Derived extends Base
|
||||
|
||||
ok (new Derived) not instanceof Derived
|
||||
ok (new Derived) not instanceof Base
|
||||
ok (new Base) not instanceof Base
|
||||
|
||||
test "#2359: extending native objects that use other typed constructors requires defining a constructor", ->
|
||||
class BrokenArray extends Array
|
||||
method: -> 'no one will call me'
|
||||
|
||||
brokenArray = new BrokenArray
|
||||
ok brokenArray not instanceof BrokenArray
|
||||
ok typeof brokenArray.method is 'undefined'
|
||||
|
||||
class WorkingArray extends Array
|
||||
constructor: -> super
|
||||
method: -> 'yes!'
|
||||
|
||||
workingArray = new WorkingArray
|
||||
ok workingArray instanceof WorkingArray
|
||||
eq 'yes!', workingArray.method()
|
||||
|
||||
|
||||
test "#2489: removing __bind", ->
|
||||
|
||||
class Thing
|
||||
foo: (a, b, c) ->
|
||||
bar: (a, b, c) =>
|
||||
|
||||
thing = new Thing
|
||||
|
||||
eq thing.foo.length, 3
|
||||
eq thing.bar.length, 3
|
||||
|
||||
@@ -129,9 +129,3 @@ test "Try catch finally as implicit arguments", ->
|
||||
bar = yes
|
||||
catch e
|
||||
eq bar, yes
|
||||
|
||||
baz = first
|
||||
try iamwhoiam() catch e
|
||||
"bar"
|
||||
try iamwhoiam() catch e
|
||||
eq baz, "bar"
|
||||
@@ -605,15 +605,6 @@ test "#2297, Different behaviors on interpreting literal", ->
|
||||
eq xyzzy.four, 4
|
||||
eq xyzzy.h, 2
|
||||
|
||||
thud = foo
|
||||
1
|
||||
one: 1
|
||||
two: 2
|
||||
three: 3
|
||||
2
|
||||
3
|
||||
eq thud.two, 2
|
||||
|
||||
test "#2715, Chained implicit calls", ->
|
||||
first = (x) -> x
|
||||
second = (x, y) -> y
|
||||
@@ -631,30 +622,6 @@ test "#2715, Chained implicit calls", ->
|
||||
2
|
||||
eq baz, 2
|
||||
|
||||
qux = first second
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
eq qux, 2
|
||||
|
||||
|
||||
test "More implicit calls", ->
|
||||
first = (x) -> x
|
||||
second = (x, y) -> y
|
||||
|
||||
foo = no
|
||||
if (first
|
||||
yes)
|
||||
foo = yes
|
||||
eq foo, yes
|
||||
|
||||
foo = no
|
||||
if not first
|
||||
no
|
||||
foo = yes
|
||||
eq foo, no
|
||||
|
||||
test "Implicit calls and new", ->
|
||||
first = (x) -> x
|
||||
foo = (@x) ->
|
||||
@@ -662,12 +629,23 @@ test "Implicit calls and new", ->
|
||||
eq bar.x, 1
|
||||
|
||||
third = (x, y, z) -> z
|
||||
baz = first new foo
|
||||
new
|
||||
foo third
|
||||
baz = first new foo new foo third
|
||||
one: 1
|
||||
two: 2
|
||||
1
|
||||
three: 3
|
||||
2
|
||||
eq baz.x.x.three, 3
|
||||
eq baz.x.x.three, 3
|
||||
|
||||
test "Loose tokens inside of explicit call lists", ->
|
||||
first = (x) -> x
|
||||
second = (x, y) -> y
|
||||
one = 1
|
||||
|
||||
foo = second( one
|
||||
2)
|
||||
eq foo, 2
|
||||
|
||||
bar = first( first
|
||||
one: 1)
|
||||
eq bar.one, 1
|
||||
|
||||
@@ -38,6 +38,26 @@ test "Verify location of generated tokens", ->
|
||||
eq numberToken[2].last_line, 0
|
||||
eq numberToken[2].last_column, 5
|
||||
|
||||
test "Verify location of generated tokens (with indented first line)", ->
|
||||
tokens = CoffeeScript.tokens " a = 83"
|
||||
|
||||
eq tokens.length, 6
|
||||
[IndentToken, aToken, equalsToken, numberToken] = tokens
|
||||
|
||||
eq aToken[2].first_line, 0
|
||||
eq aToken[2].first_column, 2
|
||||
eq aToken[2].last_line, 0
|
||||
eq aToken[2].last_column, 2
|
||||
|
||||
eq equalsToken[2].first_line, 0
|
||||
eq equalsToken[2].first_column, 4
|
||||
eq equalsToken[2].last_line, 0
|
||||
eq equalsToken[2].last_column, 4
|
||||
|
||||
eq numberToken[2].first_line, 0
|
||||
eq numberToken[2].first_column, 6
|
||||
eq numberToken[2].last_line, 0
|
||||
eq numberToken[2].last_column, 7
|
||||
|
||||
test "Verify all tokens get a location", ->
|
||||
doesNotThrow ->
|
||||
|
||||
@@ -323,6 +323,29 @@ test "#2549, Brace-less Object Literal as a Second Operand on a New Line", ->
|
||||
two: 2
|
||||
eq baz.two, 2
|
||||
|
||||
test "#2757, Nested", ->
|
||||
foo =
|
||||
bar:
|
||||
one: 1,
|
||||
eq foo.bar.one, 1
|
||||
|
||||
baz =
|
||||
qux:
|
||||
one: 1,
|
||||
corge:
|
||||
two: 2,
|
||||
three: three: three: 3,
|
||||
xyzzy:
|
||||
thud:
|
||||
four:
|
||||
four: 4,
|
||||
five: 5,
|
||||
|
||||
eq baz.qux.one, 1
|
||||
eq baz.corge.three.three.three, 3
|
||||
eq baz.xyzzy.thud.four.four, 4
|
||||
eq baz.xyzzy.five, 5
|
||||
|
||||
test "#1865, syntax regression 1.1.3", ->
|
||||
foo = (x, y) -> y
|
||||
|
||||
|
||||
@@ -293,4 +293,6 @@ test "#2567: Optimization of negated existential produces correct result", ->
|
||||
ok !(!a?)
|
||||
ok !b?
|
||||
|
||||
|
||||
test "#2508: Existential access of the prototype", ->
|
||||
eq NonExistent?::nothing, undefined
|
||||
ok Object?::toString
|
||||
|
||||
@@ -23,6 +23,9 @@ test "vlqDecodeValue with offset", ->
|
||||
# Try with an offset, and some cruft at the end.
|
||||
arrayEq (sourcemap.vlqDecodeValue ("abc" + pair[1] + "efg"), 3), [pair[0], pair[1].length]
|
||||
|
||||
eqJson = (a, b) ->
|
||||
eq (JSON.stringify JSON.parse a), (JSON.stringify JSON.parse b)
|
||||
|
||||
test "SourceMap tests", ->
|
||||
map = new sourcemap.SourceMap()
|
||||
map.addMapping [0, 0], [0, 0]
|
||||
@@ -31,8 +34,8 @@ test "SourceMap tests", ->
|
||||
map.addMapping [1, 9], [2, 8]
|
||||
map.addMapping [3, 0], [3, 4]
|
||||
|
||||
eq (sourcemap.generateV3SourceMap map, "source.coffee", "source.js"), '{"version":3,"file":"source.js","sourceRoot":"","sources":["source.coffee"],"names":[],"mappings":"AAAA;;IACK,GAAC,CAAG;IAET"}'
|
||||
eq (sourcemap.generateV3SourceMap map), '{"version":3,"file":null,"sourceRoot":"","sources":[],"names":[],"mappings":"AAAA;;IACK,GAAC,CAAG;IAET"}'
|
||||
eqJson (sourcemap.generateV3SourceMap map, "source.coffee", "source.js"), '{"version":3,"file":"source.js","sourceRoot":"","sources":["source.coffee"],"names":[],"mappings":"AAAA;;IACK,GAAC,CAAG;IAET"}'
|
||||
eqJson (sourcemap.generateV3SourceMap map), '{"version":3,"file":null,"sourceRoot":"","sources":[],"names":[],"mappings":"AAAA;;IACK,GAAC,CAAG;IAET"}'
|
||||
|
||||
# Look up a generated column - should get back the original source position.
|
||||
arrayEq map.getSourcePosition([2,8]), [1,9]
|
||||
|
||||
Reference in New Issue
Block a user