Skip to content

Instantly share code, notes, and snippets.

@tarcieri
Created July 21, 2011 07:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save tarcieri/1096711 to your computer and use it in GitHub Desktop.
Save tarcieri/1096711 to your computer and use it in GitHub Desktop.
Funargs: Ruby-like blocks for Erlang
% Returns [2,4,6,8,10]
% Yes, you could do it with a list comprehension. It's just an example!
lists:map([1,2,3,4,5]) do |N|
N * 2
end.
% Convert an IP address to an integer
lists:foldl(0, [127,0,0,1]) do |Octet, Acc|
Acc bsl 8 bor Octet
end.
% Less ugly Mnesia
mnesia:transaction do
mnesia:write(#thing{foo=1, bar=2, baz=3})
end.
diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl
index bd5d65a..fc9cf70 100644
--- a/lib/stdlib/src/erl_parse.yrl
+++ b/lib/stdlib/src/erl_parse.yrl
@@ -37,7 +37,7 @@ record_expr record_tuple record_field record_fields
if_expr if_clause if_clauses case_expr cr_clause cr_clauses receive_expr
fun_expr fun_clause fun_clauses
try_expr try_catch try_clause try_clauses query_expr
-function_call argument_list
+function_call argument_list funarg funarg_argument_list
exprs guard
atomic strings
prefix_op mult_op add_op list_op comp_op
@@ -54,7 +54,7 @@ char integer float atom string var
'(' ')' ',' '->' ':-' '{' '}' '[' ']' '|' '||' '<-' ';' ':' '#' '.'
'after' 'begin' 'case' 'try' 'catch' 'end' 'fun' 'if' 'of' 'receive' 'when'
-'andalso' 'orelse' 'query'
+'andalso' 'orelse' 'query' 'do'
'bnot' 'not'
'*' '/' 'div' 'rem' 'band' 'and'
'+' '-' 'bor' 'bxor' 'bsl' 'bsr' 'or' 'xor'
@@ -364,7 +364,10 @@ record_field -> atom '=' expr : {record_field,?line('$1'),'
function_call -> expr_800 argument_list :
{call,?line('$1'),'$1',element(1, '$2')}.
-
+function_call -> expr_800 funarg :
+ {call,?line('$1'),'$1',['$2']}.
+function_call -> expr_800 argument_list funarg :
+ {call,?line('$1'),'$1',['$3'|element(1, '$2')]}.
if_expr -> 'if' if_clauses 'end' : {'if',?line('$1'),'$2'}.
@@ -438,6 +441,12 @@ query_expr -> 'query' list_comprehension 'end' :
argument_list -> '(' ')' : {[],?line('$1')}.
argument_list -> '(' exprs ')' : {'$2',?line('$1')}.
+funarg -> 'do' funarg_argument_list exprs 'end' :
+ Clause = {clause,?line('$1'),'fun','$2',[],'$3'},
+ build_fun(?line('$1'), [Clause]).
+
+funarg_argument_list -> '$empty' : [].
+funarg_argument_list -> '|' exprs '|' : '$2'.
exprs -> expr : ['$1'].
exprs -> expr ',' exprs : ['$1' | '$3'].
diff --git a/lib/stdlib/src/erl_scan.erl b/lib/stdlib/src/erl_scan.erl
index 10b2ed2..af29b86 100644
--- a/lib/stdlib/src/erl_scan.erl
+++ b/lib/stdlib/src/erl_scan.erl
@@ -1346,6 +1346,7 @@ reserved_word('if') -> true;
reserved_word('let') -> true;
reserved_word('of') -> true;
reserved_word('query') -> true;
+reserved_word('do') -> true;
reserved_word('receive') -> true;
reserved_word('when') -> true;
reserved_word('bnot') -> true;
@krainboltgreene
Copy link

As a Ruby developer who has written a few Block-style DSLs...Awwww yeah!

I like the look of this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment