summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Williams <nico@cryptonector.com>2014-08-08 18:00:47 -0500
committerNicolas Williams <nico@cryptonector.com>2014-08-08 19:16:01 -0500
commit32c08d48f32162db1f1b6f3daaecf8f24ed85368 (patch)
tree6c3b10ec4758c86d8a0c4aa752c4a66879b33bf0
parentfc52e78ed407247c0ce22a233647e52d2aa2c4e8 (diff)
Add `def f($arg):` syntax (fix #524)
-rw-r--r--compile.c12
-rw-r--r--compile.h1
-rw-r--r--docs/content/3.manual/manual.yml8
-rw-r--r--opcode_list.h1
-rw-r--r--parser.y86
-rw-r--r--tests/all.test5
6 files changed, 40 insertions, 73 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 <blk> Exp Term MkDict MkDictPair ExpD ElseBody QQString FuncDef FuncDefs String Import Imports
+%type <blk> 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);
- 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);
+Params:
+Param {
+ $$ = $1;
} |
+Params ';' Param {
+ $$ = BLOCK($1, $3);
+}
-"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);
+Param:
+'$' IDENT {
+ $$ = gen_param_regular(jv_string_value($2));
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]