From 32c08d48f32162db1f1b6f3daaecf8f24ed85368 Mon Sep 17 00:00:00 2001 From: Nicolas Williams Date: Fri, 8 Aug 2014 18:00:47 -0500 Subject: [PATCH] Add `def f($arg):` syntax (fix #524) --- compile.c | 12 +++- compile.h | 1 + docs/content/3.manual/manual.yml | 8 ++- opcode_list.h | 1 + parser.y | 94 +++++++------------------------- tests/all.test | 5 ++ 6 files changed, 44 insertions(+), 77 deletions(-) diff --git a/compile.c b/compile.c index cc5a8d09..92c7d2c5 100644 --- a/compile.c +++ b/compile.c @@ -451,8 +451,14 @@ block gen_import(const char* name, const char* as, const char* search) { } block gen_function(const char* name, block formals, block body) { - block_bind_each(formals, body, OP_IS_CALL_PSEUDO); inst* i = inst_new(CLOSURE_CREATE); + for (inst* i = formals.last; i; i = i->prev) { + if (i->op == CLOSURE_PARAM_REGULAR) { + i->op = CLOSURE_PARAM; + body = gen_var_binding(gen_call(i->symbol, gen_noop()), i->symbol, body); + } + block_bind_subblock(inst_block(i), body, OP_IS_CALL_PSEUDO | OP_HAS_BINDING); + } i->subfn = body; i->symbol = strdup(name); i->arglist = formals; @@ -461,6 +467,10 @@ block gen_function(const char* name, block formals, block body) { return b; } +block gen_param_regular(const char* name) { + return gen_op_unbound(CLOSURE_PARAM_REGULAR, name); +} + block gen_param(const char* name) { return gen_op_unbound(CLOSURE_PARAM, name); } diff --git a/compile.h b/compile.h index a487c14c..ff8b8972 100644 --- a/compile.h +++ b/compile.h @@ -30,6 +30,7 @@ block gen_op_var_fresh(opcode op, const char* name); block gen_import(const char* name, const char *as, const char *search); block gen_function(const char* name, block formals, block body); +block gen_param_regular(const char* name); block gen_param(const char* name); block gen_lambda(block body); block gen_call(const char* name, block body); diff --git a/docs/content/3.manual/manual.yml b/docs/content/3.manual/manual.yml index bd3c82bb..c9e3ce09 100644 --- a/docs/content/3.manual/manual.yml +++ b/docs/content/3.manual/manual.yml @@ -1931,9 +1931,13 @@ sections: If you want the value-argument behaviour for defining simple functions, you can just use a variable: - def addvalue(f): f as $value | map(. + $value); + def addvalue(f): f as $f | map(. + $f); - With that definition, `addvalue(.foo)` will add the current + Or use the short-hand: + + def addvalue($f): ...; + + With either definition, `addvalue(.foo)` will add the current input's `.foo` field to each element of the array. Multiple definitions using the same function name are allowed. diff --git a/opcode_list.h b/opcode_list.h index 5ecf57e3..119a70d3 100644 --- a/opcode_list.h +++ b/opcode_list.h @@ -36,4 +36,5 @@ OP(CLOSURE_CREATE, DEFINITION, 0, 0) OP(CLOSURE_CREATE_C, DEFINITION, 0, 0) OP(TOP, NONE, 0, 0) +OP(CLOSURE_PARAM_REGULAR, DEFINITION, 0, 0) OP(DEPS, CONSTANT, 0, 0) diff --git a/parser.y b/parser.y index 7117b4ca..1246483d 100644 --- a/parser.y +++ b/parser.y @@ -102,7 +102,7 @@ struct lexer_param; %precedence "catch" -%type Exp Term MkDict MkDictPair ExpD ElseBody QQString FuncDef FuncDefs String Import Imports +%type Exp Term MkDict MkDictPair ExpD ElseBody QQString FuncDef FuncDefs String Import Imports Param Params %{ #include "lexer.h" struct lexer_param { @@ -471,82 +471,28 @@ FuncDef: jv_free($2); } | -"def" IDENT '(' IDENT ')' ':' Exp ';' { - $$ = gen_function(jv_string_value($2), - gen_param(jv_string_value($4)), - $7); +"def" IDENT '(' Params ')' ':' Exp ';' { + $$ = gen_function(jv_string_value($2), $4, $7); + jv_free($2); +} + +Params: +Param { + $$ = $1; +} | +Params ';' Param { + $$ = BLOCK($1, $3); +} + +Param: +'$' IDENT { + $$ = gen_param_regular(jv_string_value($2)); jv_free($2); - jv_free($4); } | -"def" IDENT '(' IDENT ';' IDENT ')' ':' Exp ';' { - $$ = gen_function(jv_string_value($2), - BLOCK(gen_param(jv_string_value($4)), - gen_param(jv_string_value($6))), - $9); - jv_free($2); - jv_free($4); - jv_free($6); -} | - -"def" IDENT '(' IDENT ';' IDENT ';' IDENT ')' ':' Exp ';' { - $$ = gen_function(jv_string_value($2), - BLOCK(gen_param(jv_string_value($4)), - gen_param(jv_string_value($6)), - gen_param(jv_string_value($8))), - $11); - jv_free($2); - jv_free($4); - jv_free($6); - jv_free($8); -} | - -"def" IDENT '(' IDENT ';' IDENT ';' IDENT ';' IDENT ')' ':' Exp ';' { - $$ = gen_function(jv_string_value($2), - BLOCK(gen_param(jv_string_value($4)), - gen_param(jv_string_value($6)), - gen_param(jv_string_value($8)), - gen_param(jv_string_value($10))), - $13); - jv_free($2); - jv_free($4); - jv_free($6); - jv_free($8); - jv_free($10); -} | - -"def" IDENT '(' IDENT ';' IDENT ';' IDENT ';' IDENT ';' IDENT ')' ':' Exp ';' { - $$ = gen_function(jv_string_value($2), - BLOCK(gen_param(jv_string_value($4)), - gen_param(jv_string_value($6)), - gen_param(jv_string_value($8)), - gen_param(jv_string_value($10)), - gen_param(jv_string_value($12))), - $15); - jv_free($2); - jv_free($4); - jv_free($6); - jv_free($8); - jv_free($10); - jv_free($12); -} | - -"def" IDENT '(' IDENT ';' IDENT ';' IDENT ';' IDENT ';' IDENT ';' IDENT ')' ':' Exp ';' { - $$ = gen_function(jv_string_value($2), - BLOCK(gen_param(jv_string_value($4)), - gen_param(jv_string_value($6)), - gen_param(jv_string_value($8)), - gen_param(jv_string_value($10)), - gen_param(jv_string_value($12)), - gen_param(jv_string_value($14))), - $17); - jv_free($2); - jv_free($4); - jv_free($6); - jv_free($8); - jv_free($10); - jv_free($12); - jv_free($14); +IDENT { + $$ = gen_param(jv_string_value($1)); + jv_free($1); } diff --git a/tests/all.test b/tests/all.test index c73e27a3..2e14afb0 100644 --- a/tests/all.test +++ b/tests/all.test @@ -538,6 +538,11 @@ def id(x):x; 2000 as $x | def f(x):1 as $x | id([$x, x, x]); def g(x): 100 as $x "more testing" [1,100,2100.0,100,2100.0] +# test def f($a) syntax +def x(a;b): a as $a | b as $b | $a + $b; def y($a;$b): $a + $b; def check(a;b): [x(a;b)] == [y(a;b)]; check(.[];.[]*2) +[1,2,3] +true + # test backtracking through function calls and returns # this test is *evil* [[20,10][1,0] as $x | def f: (100,200) as $y | def g: [$x + $y, .]; . + $x | g; f[0] | [f][0][1] | f]