implementing the CoffeeScript compiler using interpolation where appropriate.

This commit is contained in:
Jeremy Ashkenas
2010-03-06 13:59:11 -05:00
parent 15b00cb3ca
commit e977967eb5
13 changed files with 44 additions and 38 deletions

View File

@@ -40,7 +40,7 @@
return path.exists('Cakefile', function(exists) {
var _a, _b, _c, _d, arg, args;
if (!(exists)) {
throw new Error('Cakefile not found in ' + process.cwd());
throw new Error("Cakefile not found in " + (process.cwd()));
}
args = process.ARGV.slice(2, process.ARGV.length);
eval(coffee.compile(fs.readFileSync('Cakefile')));
@@ -72,15 +72,15 @@
}
return _b;
}).call(this).join('') : '';
puts("cake " + name + spaces + ' # ' + task.description);
puts("cake " + name + spaces + " # " + (task.description));
}}
if (switches.length) {
return puts('\n' + oparse.help() + '\n');
return puts(oparse.help());
}
};
// Print an error and exit when attempting to all an undefined task.
no_such_task = function no_such_task(task) {
process.stdio.writeError('No such task: "' + task + '"\n');
process.stdio.writeError("No such task: \"" + task + "\"\n");
return process.exit(1);
};
})();

View File

@@ -51,7 +51,7 @@
};
// The "--version" message.
version = function version() {
puts("CoffeeScript version " + CoffeeScript.VERSION);
puts("CoffeeScript version " + (CoffeeScript.VERSION));
return process.exit(0);
};
// Compiles the source CoffeeScript, returning the desired JavaScript, tokens,
@@ -61,7 +61,7 @@
compile = function compile(source) {
return path.exists(source, function(exists) {
if (!(exists)) {
throw new Error('File not found: ' + source);
throw new Error("File not found: " + source);
}
return fs.readFile(source, function(err, code) {
return compile_script(source, code);
@@ -172,12 +172,17 @@
};
// Pretty-print a token stream.
print_tokens = function print_tokens(tokens) {
var _a, _b, _c, _d, strings, token;
var _a, _b, _c, _d, _e, strings, tag, token, value;
strings = (function() {
_a = []; _b = tokens;
for (_c = 0, _d = _b.length; _c < _d; _c++) {
token = _b[_c];
_a.push('[' + token[0] + ' ' + token[1].toString().replace(/\n/, '\\n') + ']');
_a.push((function() {
_e = [token[0], token[1].toString().replace(/\n/, '\\n')];
tag = _e[0];
value = _e[1];
return "[" + tag + " " + value + "]";
}).call(this));
}
return _a;
}).call(this);

View File

@@ -9,8 +9,8 @@
o = function o(pattern_string, func, options) {
var match;
if (func) {
func = (match = (func + "").match(unwrap)) ? match[1] : '(' + func + '())';
return [pattern_string, '$$ = ' + func + ';', options];
func = (match = (func + '').match(unwrap)) ? match[1] : "(" + func + "())";
return [pattern_string, "$$ = " + func + ";", options];
} else {
return [pattern_string, '$$ = $1;', options];
}
@@ -561,7 +561,7 @@
part = _f[_g];
!grammar[part] ? tokens.push(part) : null;
}
name === "Root" ? (option[1] = "return " + option[1]) : null;
name === "Root" ? (option[1] = "return " + (option[1])) : null;
return option;
}).call(this));
}

View File

@@ -45,7 +45,7 @@
var _a, _b, _c, _d, _e, _f, _g, _h, i, let_part, lines, rule, spaces;
lines = ['Available options:'];
if (this.banner) {
lines.unshift(this.banner + '\n');
lines.unshift(this.banner + "\n");
}
_a = this.rules;
for (_b = 0, _c = _a.length; _b < _c; _b++) {
@@ -59,9 +59,9 @@
return _d;
}).call(this).join('') : '';
let_part = rule.letter ? rule.letter + ', ' : ' ';
lines.push(' ' + let_part + rule.flag + spaces + rule.description);
lines.push(" " + let_part + (rule.flag) + spaces + (rule.description));
}
return '\n' + lines.join('\n') + '\n';
return "\n" + (lines.join('\n')) + "\n";
};
return OptionParser;
}).call(this);

View File

@@ -292,7 +292,7 @@
levels[open] -= 1;
}
if (levels[open] < 0) {
throw new Error("too many " + token[1]);
throw new Error("too many " + (token[1]));
}
}
return 1;
@@ -312,7 +312,7 @@
return _l;
}).call(this);
if (unclosed.length) {
throw new Error("unclosed " + unclosed[0]);
throw new Error("unclosed " + (unclosed[0]));
}
};
// We'd like to support syntax like this:

View File

@@ -98,7 +98,7 @@
for (key in _b) { if (__hasProp.call(_b, key)) {
val = _b[key];
if (val.assigned) {
_a.push(key + ' = ' + val.value);
_a.push(key + " = " + (val.value));
}
}}
return _a;

View File

@@ -34,7 +34,7 @@ process.mixin {
# prints them out, with no arguments.
exports.run: ->
path.exists 'Cakefile', (exists) ->
throw new Error('Cakefile not found in ' + process.cwd()) unless exists
throw new Error("Cakefile not found in ${process.cwd()}") unless exists
args: process.ARGV[2...process.ARGV.length]
eval coffee.compile fs.readFileSync 'Cakefile'
oparse: new optparse.OptionParser switches
@@ -48,10 +48,10 @@ print_tasks: ->
for name, task of tasks
spaces: 20 - name.length
spaces: if spaces > 0 then (' ' for i in [0..spaces]).join('') else ''
puts "cake " + name + spaces + ' # ' + task.description
puts '\n' + oparse.help() + '\n' if switches.length
puts "cake $name$spaces # ${task.description}"
puts oparse.help() if switches.length
# Print an error and exit when attempting to all an undefined task.
no_such_task: (task) ->
process.stdio.writeError('No such task: "' + task + '"\n')
process.exit(1)
process.stdio.writeError "No such task: \"$task\"\n"
process.exit 1

View File

@@ -56,7 +56,7 @@ usage: ->
# The "--version" message.
version: ->
puts "CoffeeScript version " + CoffeeScript.VERSION
puts "CoffeeScript version ${CoffeeScript.VERSION}"
process.exit 0
# Compiles the source CoffeeScript, returning the desired JavaScript, tokens,
@@ -64,7 +64,7 @@ version: ->
compile_scripts: ->
compile: (source) ->
path.exists source, (exists) ->
throw new Error 'File not found: ' + source unless exists
throw new Error "File not found: $source" unless exists
fs.readFile source, (err, code) -> compile_script(source, code)
compile(source) for source in sources
@@ -125,7 +125,8 @@ lint: (js) ->
# Pretty-print a token stream.
print_tokens: (tokens) ->
strings: for token in tokens
'[' + token[0] + ' ' + token[1].toString().replace(/\n/, '\\n') + ']'
[tag, value]: [token[0], token[1].toString().replace(/\n/, '\\n')]
"[$tag $value]"
puts strings.join(' ')
# Use OptionParser for all the options.

View File

@@ -8,8 +8,8 @@ unwrap: /function\s*\(\)\s*\{\s*return\s*([\s\S]*);\s*\}/
# Quickie DSL for Jison access.
o: (pattern_string, func, options) ->
if func
func: if match: (func + "").match(unwrap) then match[1] else '(' + func + '())'
[pattern_string, '$$ = ' + func + ';', options]
func: if match: (func + '').match(unwrap) then match[1] else "($func())"
[pattern_string, "$$ = $func;", options]
else
[pattern_string, '$$ = $1;', options]
@@ -464,7 +464,7 @@ for name, non_terminal of grammar
if !grammar[part]
tokens.push(part)
if name == "Root"
option[1] = "return " + option[1]
option[1] = "return ${option[1]}"
option
tokens: tokens.join(" ")
exports.parser: new Parser({tokens: tokens, bnf: bnf, operators: operators.reverse(), startSymbol: 'Root'}, {debug: false})

View File

@@ -19,12 +19,12 @@ exports.compileFile: (path) ->
# Make a factory for the CoffeeScript environment.
exports.makeNarwhalFactory: (path) ->
code: exports.compileFile path
factoryText: "function(require,exports,module,system,print){" + code + "/**/\n}"
factoryText: "function(require,exports,module,system,print){$code/**/\n}"
if system.engine is "rhino"
Packages.org.mozilla.javascript.Context.getCurrentContext().compileFunction(global, factoryText, path, 0, null)
else
# eval requires parentheses, but parentheses break compileFunction.
eval "(" + factoryText + ")"
eval "($factoryText)"
# The Narwhal loader for '.coffee' files.
factories: {}

View File

@@ -21,20 +21,20 @@ exports.OptionParser: class OptionParser
options[rule.name]: if rule.has_argument then args.shift() else true
matched_rule: yes
break
throw new Error "unrecognized option: " + arg if is_option and not matched_rule
throw new Error "unrecognized option: $arg" if is_option and not matched_rule
options.arguments.push arg unless is_option
options
# Return the help text for this OptionParser, for --help and such.
help: ->
lines: ['Available options:']
lines.unshift @banner + '\n' if @banner
lines.unshift "$@banner\n" if @banner
for rule in @rules
spaces: 15 - rule.flag.length
spaces: if spaces > 0 then (' ' for i in [0..spaces]).join('') else ''
let_part: if rule.letter then rule.letter + ', ' else ' '
lines.push ' ' + let_part + rule.flag + spaces + rule.description
'\n' + lines.join('\n') + '\n'
lines.push " $let_part${rule.flag}$spaces${rule.description}"
"\n${ lines.join('\n') }\n"
# Regex matchers for option flags.
LONG_FLAG: /^(--\w[\w\-]+)/

View File

@@ -142,7 +142,7 @@ exports.Rewriter: class Rewriter
if IMPLICIT_END.indexOf(tag) >= 0 or !post?
return 1 if tag is 'INDENT' and prev and IMPLICIT_BLOCK.indexOf(prev[0]) >= 0
if stack[stack.length - 1] > 0 or tag is 'INDENT'
idx: if tag is 'OUTDENT' then i + 1 else i
idx: if tag is 'OUTDENT' then i +1 else i
stack_pointer: if tag is 'INDENT' then 2 else 1
for tmp in [0...stack[stack.length - stack_pointer]]
@tokens.splice(idx, 0, ['CALL_END', ')', token[2]])
@@ -193,10 +193,10 @@ exports.Rewriter: class Rewriter
levels[open] ||= 0
levels[open] += 1 if token[0] is open
levels[open] -= 1 if token[0] is close
throw new Error("too many " + token[1]) if levels[open] < 0
throw new Error("too many ${token[1]}") if levels[open] < 0
return 1
unclosed: key for key, value of levels when value > 0
throw new Error("unclosed " + unclosed[0]) if unclosed.length
throw new Error("unclosed ${unclosed[0]}") if unclosed.length
# We'd like to support syntax like this:
# el.click((event) ->

View File

@@ -65,7 +65,7 @@ exports.Scope: class Scope
# Return the list of variables that are supposed to be assigned at the top
# of scope.
assigned_variables: ->
key + ' = ' + val.value for key, val of @variables when val.assigned
"$key = ${val.value}" for key, val of @variables when val.assigned
# Compile the string representing all of the declared variables for this scope.
compiled_declarations: ->