1
0
Fork 0
mirror of https://github.com/jashkenas/coffeescript.git synced 2022-11-09 12:23:24 -05:00

merging in matehat's curry branch. cleaning some loose ends up. adding some tests.

This commit is contained in:
Jeremy Ashkenas 2010-03-18 00:42:26 -04:00
parent 1f87094628
commit 0c6ee52cfc
10 changed files with 33 additions and 49 deletions

View file

@ -272,7 +272,7 @@
return $2.new_instance();
}), o("Super")
],
Curry: [o("Value CURRY Arguments", function() {
Curry: [o("Value <- Arguments", function() {
return new CurryNode($1, $3);
})
],
@ -611,7 +611,7 @@
// 2 + (3 * 4)
// And not:
// (2 + 3) * 4
operators = [["left", '?'], ["nonassoc", 'UMINUS', 'UPLUS', 'NOT', '!', '!!', '~', '++', '--'], ["left", '*', '/', '%'], ["left", '+', '-'], ["left", '<<', '>>', '>>>'], ["left", '&', '|', '^'], ["left", '<=', '<', '>', '>='], ["right", 'DELETE', 'INSTANCEOF', 'TYPEOF'], ["left", '==', '!=', 'IS', 'ISNT'], ["left", '&&', '||', 'AND', 'OR'], ["right", '-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?='], ["left", '.'], ["right", 'INDENT'], ["left", 'OUTDENT'], ["right", 'WHEN', 'LEADING_WHEN', 'IN', 'OF', 'BY', 'THROW'], ["right", 'FOR', 'NEW', 'SUPER', 'CLASS'], ["left", 'EXTENDS'], ["right", 'ASSIGN', 'RETURN'], ["right", '->', '=>', 'UNLESS', 'IF', 'ELSE', 'WHILE']];
operators = [["left", '?'], ["nonassoc", 'UMINUS', 'UPLUS', 'NOT', '!', '!!', '~', '++', '--'], ["left", '*', '/', '%'], ["left", '+', '-'], ["left", '<<', '>>', '>>>'], ["left", '&', '|', '^'], ["left", '<=', '<', '>', '>='], ["right", 'DELETE', 'INSTANCEOF', 'TYPEOF'], ["left", '==', '!=', 'IS', 'ISNT'], ["left", '&&', '||', 'AND', 'OR'], ["right", '-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?='], ["left", '.'], ["right", 'INDENT'], ["left", 'OUTDENT'], ["right", 'WHEN', 'LEADING_WHEN', 'IN', 'OF', 'BY', 'THROW'], ["right", 'FOR', 'NEW', 'SUPER', 'CLASS'], ["left", 'EXTENDS'], ["right", 'ASSIGN', 'RETURN'], ["right", '->', '=>', '<-', 'UNLESS', 'IF', 'ELSE', 'WHILE']];
// Wrapping Up
// -----------
// Finally, now what we have our **grammar** and our **operators**, we can create

View file

@ -1,5 +1,5 @@
(function(){
var ACCESSORS, ASSIGNMENT, BEFORE_WHEN, CALLABLE, CODE, COFFEE_KEYWORDS, COMMENT, COMMENT_CLEANER, CURRY, CURRY_SEPARATOR, HEREDOC, HEREDOC_INDENT, IDENTIFIER, INTERPOLATION, JS_CLEANER, JS_FORBIDDEN, JS_KEYWORDS, KEYWORDS, LAST_DENT, LAST_DENTS, Lexer, MULTILINER, MULTI_DENT, NOT_REGEX, NO_NEWLINE, NUMBER, OPERATOR, REGEX_ESCAPE, REGEX_FLAGS, REGEX_INTERPOLATION, REGEX_START, RESERVED, Rewriter, STRING_NEWLINES, WHITESPACE, balanced_string, compact, count, helpers, include, starts;
var ACCESSORS, ASSIGNMENT, BEFORE_WHEN, CALLABLE, CODE, COFFEE_KEYWORDS, COMMENT, COMMENT_CLEANER, HEREDOC, HEREDOC_INDENT, IDENTIFIER, INTERPOLATION, JS_CLEANER, JS_FORBIDDEN, JS_KEYWORDS, KEYWORDS, LAST_DENT, LAST_DENTS, Lexer, MULTILINER, MULTI_DENT, NOT_REGEX, NO_NEWLINE, NUMBER, OPERATOR, REGEX_ESCAPE, REGEX_FLAGS, REGEX_INTERPOLATION, REGEX_START, RESERVED, Rewriter, STRING_NEWLINES, WHITESPACE, balanced_string, compact, count, helpers, include, starts;
// The CoffeeScript Lexer. Uses a series of token-matching regexes to attempt
// matches against the beginning of the source code. When a match is found,
// a token is produced, we consume the match, and start again. Tokens are in the
@ -95,9 +95,6 @@
if (this.js_token()) {
return null;
}
if (this.curry_token()) {
return null;
}
if (this.string_token()) {
return null;
}
@ -327,15 +324,6 @@
}
return true;
};
// Here we detect the currying operator and change local state in order to
// parse subsequent tokens accordingly.
Lexer.prototype.curry_token = function curry_token() {
if (this.match(CURRY, 1)) {
this.i += 2;
this.token('CURRY', '<-');
return true;
}
};
// We treat all other single characters as a token. Eg.: `( ) , . !`
// Multi-character operators are also literal tokens, so that Jison can assign
// the proper order of operations. There are some symbols that we tag specially
@ -597,8 +585,6 @@
LAST_DENTS = /\n([ \t]*)/g;
LAST_DENT = /\n([ \t]*)/;
ASSIGNMENT = /^(:|=)$/;
CURRY = /^(<-)/;
CURRY_SEPARATOR = /^\,/;
// Regex-matching-regexes.
REGEX_START = /^\/[^\/ ]/;
REGEX_INTERPOLATION = /([^\\]\$[a-zA-Z_@]|[^\\]\$\{.*[^\\]\})/;

View file

@ -525,7 +525,7 @@
};
CurryNode.prototype.compile_node = function compile_node(o) {
var body, curried, curry;
body = Expressions.wrap([literal('func.apply(obj || {}, args.concat(Array.prototype.slice.call(arguments, 0)));')]);
body = Expressions.wrap([literal('func.apply(obj, args.concat(Array.prototype.slice.call(arguments, 0)));')]);
curried = new CodeNode([], body);
curry = new CodeNode([literal('func'), literal('obj'), literal('args')], Expressions.wrap([curried]));
return (new ParentheticalNode(new CallNode(curry, [this.meth, this.context, literal(this.arguments(o))]))).compile(o);

View file

@ -2,8 +2,8 @@
var parser = (function(){
var parser = {trace: function trace() { },
yy: {},
symbols_: {"Root":2,"TERMINATOR":3,"Expressions":4,"Block":5,"Expression":6,"Value":7,"Call":8,"Curry":9,"Code":10,"Operation":11,"Assign":12,"If":13,"Try":14,"Throw":15,"Return":16,"While":17,"For":18,"Switch":19,"Extends":20,"Class":21,"Splat":22,"Existence":23,"Comment":24,"Extension":25,"INDENT":26,"OUTDENT":27,"Identifier":28,"IDENTIFIER":29,"AlphaNumeric":30,"NUMBER":31,"STRING":32,"Literal":33,"JS":34,"REGEX":35,"BREAK":36,"CONTINUE":37,"TRUE":38,"FALSE":39,"YES":40,"NO":41,"ON":42,"OFF":43,"ASSIGN":44,"AssignObj":45,"RETURN":46,"COMMENT":47,"?":48,"PARAM_START":49,"ParamList":50,"PARAM_END":51,"FuncGlyph":52,"->":53,"=>":54,"Param":55,",":56,"PARAM":57,".":58,"Array":59,"Object":60,"Parenthetical":61,"Range":62,"This":63,"Accessor":64,"Invocation":65,"PROPERTY_ACCESS":66,"PROTOTYPE_ACCESS":67,"::":68,"SOAK_ACCESS":69,"Index":70,"Slice":71,"INDEX_START":72,"INDEX_END":73,"SOAKED_INDEX_START":74,"SOAKED_INDEX_END":75,"{":76,"AssignList":77,"}":78,"IndentedAssignList":79,"CLASS":80,"EXTENDS":81,"NEW":82,"Super":83,"CURRY":84,"Arguments":85,"CALL_START":86,"ArgList":87,"CALL_END":88,"SUPER":89,"@":90,"[":91,"]":92,"SimpleArgs":93,"TRY":94,"Catch":95,"FINALLY":96,"CATCH":97,"THROW":98,"(":99,")":100,"EXTENSION":101,"WhileSource":102,"WHILE":103,"WHEN":104,"FOR":105,"ForVariables":106,"ForSource":107,"IN":108,"OF":109,"BY":110,"SWITCH":111,"Whens":112,"ELSE":113,"When":114,"LEADING_WHEN":115,"IfStart":116,"IF":117,"ElsIf":118,"IfBlock":119,"UNLESS":120,"!":121,"!!":122,"-":123,"+":124,"NOT":125,"~":126,"--":127,"++":128,"DELETE":129,"TYPEOF":130,"*":131,"/":132,"%":133,"<<":134,">>":135,">>>":136,"&":137,"|":138,"^":139,"<=":140,"<":141,">":142,">=":143,"==":144,"!=":145,"IS":146,"ISNT":147,"&&":148,"||":149,"AND":150,"OR":151,"-=":152,"+=":153,"/=":154,"*=":155,"%=":156,"||=":157,"&&=":158,"?=":159,"INSTANCEOF":160,"$accept":0,"$end":1},
terminals_: {"3":"TERMINATOR","26":"INDENT","27":"OUTDENT","29":"IDENTIFIER","31":"NUMBER","32":"STRING","34":"JS","35":"REGEX","36":"BREAK","37":"CONTINUE","38":"TRUE","39":"FALSE","40":"YES","41":"NO","42":"ON","43":"OFF","44":"ASSIGN","46":"RETURN","47":"COMMENT","48":"?","49":"PARAM_START","51":"PARAM_END","53":"->","54":"=>","56":",","57":"PARAM","58":".","66":"PROPERTY_ACCESS","67":"PROTOTYPE_ACCESS","68":"::","69":"SOAK_ACCESS","72":"INDEX_START","73":"INDEX_END","74":"SOAKED_INDEX_START","75":"SOAKED_INDEX_END","76":"{","78":"}","80":"CLASS","81":"EXTENDS","82":"NEW","84":"CURRY","86":"CALL_START","88":"CALL_END","89":"SUPER","90":"@","91":"[","92":"]","94":"TRY","96":"FINALLY","97":"CATCH","98":"THROW","99":"(","100":")","101":"EXTENSION","103":"WHILE","104":"WHEN","105":"FOR","108":"IN","109":"OF","110":"BY","111":"SWITCH","113":"ELSE","115":"LEADING_WHEN","117":"IF","120":"UNLESS","121":"!","122":"!!","123":"-","124":"+","125":"NOT","126":"~","127":"--","128":"++","129":"DELETE","130":"TYPEOF","131":"*","132":"/","133":"%","134":"<<","135":">>","136":">>>","137":"&","138":"|","139":"^","140":"<=","141":"<","142":">","143":">=","144":"==","145":"!=","146":"IS","147":"ISNT","148":"&&","149":"||","150":"AND","151":"OR","152":"-=","153":"+=","154":"/=","155":"*=","156":"%=","157":"||=","158":"&&=","159":"?=","160":"INSTANCEOF"},
symbols_: {"Root":2,"TERMINATOR":3,"Expressions":4,"Block":5,"Expression":6,"Value":7,"Call":8,"Curry":9,"Code":10,"Operation":11,"Assign":12,"If":13,"Try":14,"Throw":15,"Return":16,"While":17,"For":18,"Switch":19,"Extends":20,"Class":21,"Splat":22,"Existence":23,"Comment":24,"Extension":25,"INDENT":26,"OUTDENT":27,"Identifier":28,"IDENTIFIER":29,"AlphaNumeric":30,"NUMBER":31,"STRING":32,"Literal":33,"JS":34,"REGEX":35,"BREAK":36,"CONTINUE":37,"TRUE":38,"FALSE":39,"YES":40,"NO":41,"ON":42,"OFF":43,"ASSIGN":44,"AssignObj":45,"RETURN":46,"COMMENT":47,"?":48,"PARAM_START":49,"ParamList":50,"PARAM_END":51,"FuncGlyph":52,"->":53,"=>":54,"Param":55,",":56,"PARAM":57,".":58,"Array":59,"Object":60,"Parenthetical":61,"Range":62,"This":63,"Accessor":64,"Invocation":65,"PROPERTY_ACCESS":66,"PROTOTYPE_ACCESS":67,"::":68,"SOAK_ACCESS":69,"Index":70,"Slice":71,"INDEX_START":72,"INDEX_END":73,"SOAKED_INDEX_START":74,"SOAKED_INDEX_END":75,"{":76,"AssignList":77,"}":78,"IndentedAssignList":79,"CLASS":80,"EXTENDS":81,"NEW":82,"Super":83,"<-":84,"Arguments":85,"CALL_START":86,"ArgList":87,"CALL_END":88,"SUPER":89,"@":90,"[":91,"]":92,"SimpleArgs":93,"TRY":94,"Catch":95,"FINALLY":96,"CATCH":97,"THROW":98,"(":99,")":100,"EXTENSION":101,"WhileSource":102,"WHILE":103,"WHEN":104,"FOR":105,"ForVariables":106,"ForSource":107,"IN":108,"OF":109,"BY":110,"SWITCH":111,"Whens":112,"ELSE":113,"When":114,"LEADING_WHEN":115,"IfStart":116,"IF":117,"ElsIf":118,"IfBlock":119,"UNLESS":120,"!":121,"!!":122,"-":123,"+":124,"NOT":125,"~":126,"--":127,"++":128,"DELETE":129,"TYPEOF":130,"*":131,"/":132,"%":133,"<<":134,">>":135,">>>":136,"&":137,"|":138,"^":139,"<=":140,"<":141,">":142,">=":143,"==":144,"!=":145,"IS":146,"ISNT":147,"&&":148,"||":149,"AND":150,"OR":151,"-=":152,"+=":153,"/=":154,"*=":155,"%=":156,"||=":157,"&&=":158,"?=":159,"INSTANCEOF":160,"$accept":0,"$end":1},
terminals_: {"3":"TERMINATOR","26":"INDENT","27":"OUTDENT","29":"IDENTIFIER","31":"NUMBER","32":"STRING","34":"JS","35":"REGEX","36":"BREAK","37":"CONTINUE","38":"TRUE","39":"FALSE","40":"YES","41":"NO","42":"ON","43":"OFF","44":"ASSIGN","46":"RETURN","47":"COMMENT","48":"?","49":"PARAM_START","51":"PARAM_END","53":"->","54":"=>","56":",","57":"PARAM","58":".","66":"PROPERTY_ACCESS","67":"PROTOTYPE_ACCESS","68":"::","69":"SOAK_ACCESS","72":"INDEX_START","73":"INDEX_END","74":"SOAKED_INDEX_START","75":"SOAKED_INDEX_END","76":"{","78":"}","80":"CLASS","81":"EXTENDS","82":"NEW","84":"<-","86":"CALL_START","88":"CALL_END","89":"SUPER","90":"@","91":"[","92":"]","94":"TRY","96":"FINALLY","97":"CATCH","98":"THROW","99":"(","100":")","101":"EXTENSION","103":"WHILE","104":"WHEN","105":"FOR","108":"IN","109":"OF","110":"BY","111":"SWITCH","113":"ELSE","115":"LEADING_WHEN","117":"IF","120":"UNLESS","121":"!","122":"!!","123":"-","124":"+","125":"NOT","126":"~","127":"--","128":"++","129":"DELETE","130":"TYPEOF","131":"*","132":"/","133":"%","134":"<<","135":">>","136":">>>","137":"&","138":"|","139":"^","140":"<=","141":"<","142":">","143":">=","144":"==","145":"!=","146":"IS","147":"ISNT","148":"&&","149":"||","150":"AND","151":"OR","152":"-=","153":"+=","154":"/=","155":"*=","156":"%=","157":"||=","158":"&&=","159":"?=","160":"INSTANCEOF"},
productions_: [0,[2,0],[2,1],[2,1],[2,2],[4,1],[4,3],[4,2],[6,1],[6,1],[6,1],[6,1],[6,1],[6,1],[6,1],[6,1],[6,1],[6,1],[6,1],[6,1],[6,1],[6,1],[6,1],[6,1],[6,1],[6,1],[6,1],[5,3],[5,2],[5,2],[28,1],[30,1],[30,1],[33,1],[33,1],[33,1],[33,1],[33,1],[33,1],[33,1],[33,1],[33,1],[33,1],[33,1],[12,3],[45,3],[45,3],[45,1],[16,2],[16,1],[24,1],[23,2],[10,5],[10,2],[52,1],[52,1],[50,0],[50,1],[50,3],[55,1],[55,4],[22,4],[7,1],[7,1],[7,1],[7,1],[7,1],[7,1],[7,1],[7,2],[7,2],[64,2],[64,2],[64,1],[64,2],[64,1],[64,1],[70,3],[70,3],[60,3],[60,3],[21,2],[21,4],[21,3],[21,5],[77,0],[77,1],[77,3],[77,3],[77,4],[79,3],[8,1],[8,2],[8,1],[9,3],[20,3],[65,2],[65,2],[85,3],[83,4],[63,1],[63,2],[62,6],[62,7],[71,6],[71,7],[59,3],[87,0],[87,1],[87,2],[87,3],[87,3],[87,4],[87,4],[87,2],[93,1],[93,3],[14,3],[14,4],[14,5],[95,3],[15,2],[61,3],[25,1],[102,2],[102,4],[17,2],[17,2],[18,4],[18,4],[106,1],[106,3],[107,2],[107,2],[107,3],[107,3],[19,5],[19,7],[112,1],[112,2],[114,3],[114,4],[114,3],[116,3],[116,2],[119,1],[119,3],[118,4],[13,1],[13,3],[13,3],[11,2],[11,2],[11,2],[11,2],[11,2],[11,2],[11,2],[11,2],[11,2],[11,2],[11,2],[11,2],[11,3],[11,3],[11,3],[11,3],[11,3],[11,3],[11,3],[11,3],[11,3],[11,3],[11,3],[11,3],[11,3],[11,3],[11,3],[11,3],[11,3],[11,3],[11,3],[11,3],[11,3],[11,3],[11,3],[11,3],[11,3],[11,3],[11,3],[11,3],[11,3],[11,3],[11,3],[11,3],[11,3],[11,3]],
performAction: function anonymous(yytext,yyleng,yylineno,yy) {

View file

@ -384,7 +384,7 @@
// Tokens that indicate the close of a clause of an expression.
EXPRESSION_CLOSE = ['CATCH', 'WHEN', 'ELSE', 'FINALLY'].concat(EXPRESSION_END);
// Tokens that, if followed by an `IMPLICIT_CALL`, indicate a function invocation.
IMPLICIT_FUNC = ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', 'CURRY'];
IMPLICIT_FUNC = ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '<-'];
// If preceded by an `IMPLICIT_FUNC`, indicates a function invocation.
IMPLICIT_CALL = ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'TRY', 'DELETE', 'TYPEOF', 'SWITCH', 'EXTENSION', 'TRUE', 'FALSE', 'YES', 'NO', 'ON', 'OFF', '!', '!!', 'NOT', '@', '->', '=>', '[', '(', '{'];
// Tokens indicating that the implicit call must enclose a block of expressions.

View file

@ -265,7 +265,7 @@ grammar: {
]
Curry: [
o "Value CURRY Arguments", -> new CurryNode $1, $3
o "Value <- Arguments", -> new CurryNode $1, $3
]
# Extending an object by setting its prototype chain to reference a parent
@ -549,7 +549,7 @@ operators: [
["right", 'FOR', 'NEW', 'SUPER', 'CLASS']
["left", 'EXTENDS']
["right", 'ASSIGN', 'RETURN']
["right", '->', '=>', 'UNLESS', 'IF', 'ELSE', 'WHILE']
["right", '->', '=>', '<-', 'UNLESS', 'IF', 'ELSE', 'WHILE']
]
# Wrapping Up

View file

@ -72,7 +72,6 @@ exports.Lexer: class Lexer
return if @line_token()
return if @whitespace_token()
return if @js_token()
return if @curry_token()
return if @string_token()
return @literal_token()
@ -241,14 +240,6 @@ exports.Lexer: class Lexer
@tokens.pop() if @value() is "\\"
true
# Here we detect the currying operator and change local state in order to
# parse subsequent tokens accordingly.
curry_token: ->
if @match(CURRY, 1)
@i += 2
@token 'CURRY', '<-'
true
# We treat all other single characters as a token. Eg.: `( ) , . !`
# Multi-character operators are also literal tokens, so that Jison can assign
# the proper order of operations. There are some symbols that we tag specially
@ -472,8 +463,6 @@ MULTI_DENT : /^((\n([ \t]*))+)(\.)?/
LAST_DENTS : /\n([ \t]*)/g
LAST_DENT : /\n([ \t]*)/
ASSIGNMENT : /^(:|=)$/
CURRY : /^(<-)/
CURRY_SEPARATOR: /^\,/
# Regex-matching-regexes.
REGEX_START : /^\/[^\/ ]/

View file

@ -403,7 +403,7 @@ exports.CurryNode: class CurryNode extends CallNode
(new ArrayNode(@args)).compile o
compile_node: (o) ->
body: Expressions.wrap([literal('func.apply(obj || {}, args.concat(Array.prototype.slice.call(arguments, 0)));')])
body: Expressions.wrap([literal('func.apply(obj, args.concat(Array.prototype.slice.call(arguments, 0)));')])
curried: new CodeNode([], body)
curry: new CodeNode([literal('func'), literal('obj'), literal('args')], Expressions.wrap([curried]))
(new ParentheticalNode(new CallNode(curry, [@meth, @context, literal(@arguments(o))]))).compile o

View file

@ -257,7 +257,7 @@ EXPRESSION_END: pair[1] for pair in BALANCED_PAIRS
EXPRESSION_CLOSE: ['CATCH', 'WHEN', 'ELSE', 'FINALLY'].concat EXPRESSION_END
# Tokens that, if followed by an `IMPLICIT_CALL`, indicate a function invocation.
IMPLICIT_FUNC: ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', 'CURRY']
IMPLICIT_FUNC: ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '<-']
# If preceded by an `IMPLICIT_FUNC`, indicates a function invocation.
IMPLICIT_CALL: ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START',

View file

@ -1,11 +1,20 @@
f: (x,y,z) ->
x*y*z*((@num or 4) + 5)
x * y * z * ((@num or 4) + 5)
obj: {num: 5}
g: f <- obj, 1,1
h: f <- {}, 1,2
i: f <- obj
ok g(2) is 20
ok h(2) is 36
ok i(1,2,3) is 60
func: f <- obj, 1, 1
ok func(2) is 20
func: f <- {}, 1, 2
ok func(2) is 36
func: f <- obj
ok func(1, 2, 3) is 60
in_first_ten: helpers.include <- null, [0...10]
ok in_first_ten 3
ok in_first_ten 9
ok not in_first_ten -1
ok not in_first_ten 12