diff --git a/lib/grammar.js b/lib/grammar.js index 3fa3265c..3b9f2d48 100644 --- a/lib/grammar.js +++ b/lib/grammar.js @@ -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 diff --git a/lib/lexer.js b/lib/lexer.js index f5c0c923..072c937f 100644 --- a/lib/lexer.js +++ b/lib/lexer.js @@ -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_@]|[^\\]\$\{.*[^\\]\})/; diff --git a/lib/nodes.js b/lib/nodes.js index 0bf7a630..0f1f157d 100644 --- a/lib/nodes.js +++ b/lib/nodes.js @@ -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); diff --git a/lib/parser.js b/lib/parser.js index 919bd7f8..49a3bc93 100755 --- a/lib/parser.js +++ b/lib/parser.js @@ -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) { diff --git a/lib/rewriter.js b/lib/rewriter.js index 2fcbd77f..66d24d57 100644 --- a/lib/rewriter.js +++ b/lib/rewriter.js @@ -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. diff --git a/src/grammar.coffee b/src/grammar.coffee index f7227190..0c981980 100644 --- a/src/grammar.coffee +++ b/src/grammar.coffee @@ -263,9 +263,9 @@ grammar: { o "NEW Invocation", -> $2.new_instance() o "Super" ] - + 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 diff --git a/src/lexer.coffee b/src/lexer.coffee index 3237bf39..b7711d87 100644 --- a/src/lexer.coffee +++ b/src/lexer.coffee @@ -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 : /^\/[^\/ ]/ diff --git a/src/nodes.coffee b/src/nodes.coffee index b096a19c..f8cbcd80 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -393,22 +393,22 @@ exports.CallNode: class CallNode extends BaseNode # After `Underscore.bind` from [Underscore](http://documentcloud.github.com/underscore/). exports.CurryNode: class CurryNode extends CallNode type: 'Curry' - + constructor: (meth, args) -> @children: flatten [@meth: meth, @context: args[0], @args: (args.slice(1) or [])] - + arguments: (o) -> for arg in @args return @compile_splat_arguments(o) if arg instanceof SplatNode (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 - - + + #### ExtendsNode diff --git a/src/rewriter.coffee b/src/rewriter.coffee index 7002a04e..8fde969b 100644 --- a/src/rewriter.coffee +++ b/src/rewriter.coffee @@ -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', diff --git a/test/test_curry.coffee b/test/test_curry.coffee index 82e4c55f..3f370588 100644 --- a/test/test_curry.coffee +++ b/test/test_curry.coffee @@ -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 \ No newline at end of file +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 \ No newline at end of file