Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

autocb first try

  • Loading branch information...
commit 187abb1d516b3e3d98079677109b7a440180b528 1 parent f2c561e
@maxtaco authored
View
2  TAME.md
@@ -5,7 +5,7 @@ Tame is a system for handling callbacks in event-based code. There
were two existing implementations, one in [the sfslite library for
C++](https://github.com/maxtaco/sfslite), and another in [tamejs
translator for JavaScript](https://github.com/maxtaco/tamejs), and
-this fork of CoffeeScript attempts a third implementation. The code
+this extension to CoffeeScript is a third implementation. The code
and translation techniques are derived from experience with JS, but
with some new Coffee-style flavoring. Also, some of the features in
tamejs are not yet available here.
View
1  TODO-tame.md
@@ -4,3 +4,4 @@ Todos
* continuations must therefore return a value
* tamed `for`, `while` and others return a value
* splats in defer
+ * Autocb?
View
48 lib/coffee-script/nodes.js
@@ -99,7 +99,7 @@
if (res) {
return new Call(new Literal("" + res + ".push"), [me]);
} else {
- return new Return(me);
+ return new Return(me, this.hasAutocb);
}
};
@@ -138,6 +138,7 @@
if (this.tameNodeFlag) extras += "A";
if (this.tameLoopFlag) extras += "L";
if (this.cpsPivotFlag) extras += "P";
+ if (this.hasAutocb) extras += "C";
if (extras.length) extras = " (" + extras + ")";
tree = '\n' + idt + name;
if (this.soak) tree += '?';
@@ -262,6 +263,18 @@
return this.cpsPivotFlag;
};
+ Base.prototype.markAutocbs = function(found) {
+ var child, _i, _len, _ref2, _results;
+ this.hasAutocb = found;
+ _ref2 = this.flattenChildren();
+ _results = [];
+ for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
+ child = _ref2[_i];
+ _results.push(child.markAutocbs(found));
+ }
+ return _results;
+ };
+
Base.prototype.needsDummyContinuation = function() {
var empty, k_id;
if (!this.gotCpsSplit) {
@@ -327,6 +340,8 @@
Base.prototype.cpsPivotFlag = false;
+ Base.prototype.hasAutocb = false;
+
Base.prototype.unwrap = THIS;
Base.prototype.unfoldSoak = NO;
@@ -532,6 +547,7 @@
if (e.tameNodeFlag) child.tameNodeFlag = true;
if (e.tameLoopFlag) child.tameLoopFlag = true;
if (e.cpsPivotFlag) child.cpsPivotFlag = true;
+ if (e.hasAutocb) child.hasAutocb = true;
}
child.cpsRotate();
}
@@ -559,6 +575,7 @@
if (this.needsRuntime() && !this.findTameRequire()) this.addRuntime();
this.walkAstTamedLoop(false);
this.walkCpsPivots();
+ this.markAutocbs();
this.cpsRotate();
return this;
};
@@ -645,7 +662,8 @@
__extends(Return, Base);
- function Return(expr) {
+ function Return(expr, hasAutocb) {
+ this.hasAutocb = hasAutocb;
if (expr && !expr.unwrap().isUndefined) this.expression = expr;
}
@@ -668,7 +686,17 @@
};
Return.prototype.compileNode = function(o) {
- return this.tab + ("return" + [this.expression ? " " + (this.expression.compile(o, LEVEL_PAREN)) : void 0] + ";");
+ var args, block, call, cb, ret;
+ if (this.hasAutocb) {
+ cb = new Value(new Literal(tame["const"].autocb));
+ args = this.expression ? [this.expression] : [];
+ call = new Call(cb, args);
+ ret = new Literal("return");
+ block = new Block([call, ret]);
+ return block.compile(o);
+ } else {
+ return this.tab + ("return" + [this.expression ? " " + (this.expression.compile(o, LEVEL_PAREN)) : void 0] + ";");
+ }
};
return Return;
@@ -1682,6 +1710,20 @@
Code.prototype.jumps = NO;
+ Code.prototype.markAutocbs = function(found) {
+ var p, _i, _len, _ref2;
+ found = false;
+ _ref2 = this.params;
+ for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
+ p = _ref2[_i];
+ if (p.name instanceof Literal && p.name.value === tame["const"].autocb) {
+ found = true;
+ break;
+ }
+ }
+ return Code.__super__.markAutocbs.call(this, found);
+ };
+
Code.prototype.compileNode = function(o) {
var code, exprs, i, idt, lit, p, param, ref, splats, v, val, vars, wasEmpty, _i, _j, _k, _len, _len2, _len3, _len4, _ref2, _ref3, _ref4, _ref5, _ref6;
o.scope = new Scope(o.scope, this.body, this);
View
5 lib/coffee-script/parser.js
@@ -522,7 +522,7 @@ parse: function parse(input) {
token = self.symbols_[token] || token;
}
return token;
- };
+ }
var symbol, preErrorSymbol, state, action, a, r, yyval={},p,len,newState, expected;
while (true) {
@@ -540,6 +540,7 @@ parse: function parse(input) {
}
// handle parse error
+ _handle_error:
if (typeof action === 'undefined' || !action.length || !action[0]) {
if (!recovering) {
@@ -550,7 +551,7 @@ parse: function parse(input) {
}
var errStr = '';
if (this.lexer.showPosition) {
- errStr = 'Parse error on line '+(yylineno+1)+":\n"+this.lexer.showPosition()+'\nExpecting '+expected.join(', ');
+ errStr = 'Parse error on line '+(yylineno+1)+":\n"+this.lexer.showPosition()+"\nExpecting "+expected.join(', ') + ", got '" + this.terminals_[symbol]+ "'";
} else {
errStr = 'Parse error on line '+(yylineno+1)+": Unexpected " +
(symbol == 1 /*EOF*/ ? "end of input" :
View
3  lib/coffee-script/tame.js
@@ -29,7 +29,8 @@
defer_method: "defer",
slot: "__slot",
assign_fn: "assign_fn",
- runtime: "tamerun"
+ runtime: "tamerun",
+ autocb: "autocb"
};
makeDeferReturn = function(obj, defer_args, id) {
View
46 src/nodes.coffee
@@ -95,7 +95,7 @@ exports.Base = class Base
if res
new Call new Literal("#{res}.push"), [me]
else
- new Return me
+ new Return me, @hasAutocb
# Does this node, or any of its children, contain a node of a certain kind?
# Recursively traverses down the *children* of the nodes, yielding to a block
@@ -130,12 +130,10 @@ exports.Base = class Base
#
toString: (idt = '', name = @constructor.name) ->
extras = ""
- if @tameNodeFlag
- extras += "A"
- if @tameLoopFlag
- extras += "L"
- if @cpsPivotFlag
- extras += "P"
+ extras += "A" if @tameNodeFlag
+ extras += "L" if @tameLoopFlag
+ extras += "P" if @cpsPivotFlag
+ extras += "C" if @hasAutocb
if extras.length
extras = " (" + extras + ")"
tree = '\n' + idt + name
@@ -211,7 +209,7 @@ exports.Base = class Base
flood = true if @isLoop() and @tameNodeFlag
@tameLoopFlag = flood
for child in @flattenChildren()
- @tameLoopFlag = true if child.walkAstTamedLoop (flood)
+ @tameLoopFlag = true if child.walkAstTamedLoop flood
@tameLoopFlag
# A node is marked as a "cpsPivot" of it is (a) a 'tamed' node,
@@ -224,6 +222,13 @@ exports.Base = class Base
#
#-----------------------------------------------------------------------
+
+ markAutocbs : (found) ->
+ @hasAutocb = found
+ for child in @flattenChildren()
+ child.markAutocbs(found)
+
+ #-----------------------------------------------------------------------
needsDummyContinuation : ->
if not @gotCpsSplit
@@ -268,6 +273,7 @@ exports.Base = class Base
tameNodeFlag : false
gotCpsSplit : false
cpsPivotFlag : false
+ hasAutocb : false
unwrap : THIS
unfoldSoak : NO
@@ -462,11 +468,12 @@ exports.Block = class Block extends Base
child = new Block rest
pivot.tameNestContinuationBlock child
- # we have to set the taming bit on the new Block
+ # Pass our node bits onto our new children
for e in rest
child.tameNodeFlag = true if e.tameNodeFlag
child.tameLoopFlag = true if e.tameLoopFlag
child.cpsPivotFlag = true if e.cpsPivotFlag
+ child.hasAutocb = true if e.hasAutocb
# now recursive apply the transformation to the new child,
# this being especially import in blocks that have multiple
@@ -510,6 +517,7 @@ exports.Block = class Block extends Base
@addRuntime() if @needsRuntime() and not @findTameRequire()
@walkAstTamedLoop(false)
@walkCpsPivots()
+ @markAutocbs()
@cpsRotate()
this
@@ -570,7 +578,7 @@ exports.Literal = class Literal extends Base
# A `return` is a *pureStatement* -- wrapping it in a closure wouldn't
# make sense.
exports.Return = class Return extends Base
- constructor: (expr) ->
+ constructor: (expr, @hasAutocb) ->
@expression = expr if expr and not expr.unwrap().isUndefined
children: ['expression']
@@ -584,7 +592,15 @@ exports.Return = class Return extends Base
if expr and expr not instanceof Return then expr.compile o, level else super o, level
compileNode: (o) ->
- @tab + "return#{[" #{@expression.compile o, LEVEL_PAREN}" if @expression]};"
+ if @hasAutocb
+ cb = new Value new Literal tame.const.autocb
+ args = if @expression then [ @expression ] else []
+ call = new Call cb, args
+ ret = new Literal "return"
+ block = new Block [ call, ret];
+ block.compile o
+ else
+ @tab + "return#{[" #{@expression.compile o, LEVEL_PAREN}" if @expression]};"
#### Value
@@ -1396,6 +1412,14 @@ exports.Code = class Code extends Base
jumps: NO
+ markAutocbs: (found) ->
+ found = false
+ for p in @params
+ if p.name instanceof Literal and p.name.value == tame.const.autocb
+ found = true
+ break
+ super(found)
+
# Compilation creates a new scope unless explicitly asked to share with the
# outer scope. Handles splat parameters in the parameter list by peeking at
# the JavaScript `arguments` object. If the function is bound with the `=>`
View
1  src/tame.coffee
@@ -20,6 +20,7 @@ exports.const =
slot : "__slot"
assign_fn : "assign_fn"
runtime : "tamerun"
+ autocb : "autocb"
#=======================================================================
# runtime
Please sign in to comment.
Something went wrong with that request. Please try again.