h = {}
h[key] = valueThe equivalent code in Erlang is noisier, thanks to immutable state and single assignment:Dict1 = dict:new(),Since Reia lacks mutable state, it never before had syntax as simple as Ruby's... but now it does!
Dict2 = dict:store(Key, Value, Dict1).
>> m = {}
=> {}
>> (m[:foo], m[:bar], m[:baz]) = (1,2,3)
=> (1,2,3)
>> m
=> {:bar=>2,:baz=>3,:foo=>1}So
what is going on here exactly? Reia is an immutable state language, so
surely I'm not mutating the value that "m" references.>> t = (1,2,3)I plan on eventually exposing this functionality to user-defined types as well, in the form of "bang methods" on immutable objects. Users of Ruby are likely familiar with them:
=> (1,2,3)
>> t[-1] = 42
=> 42
>> t
=> (1,2,42)
>> arr = [1,2,3]Here you can see that calling the "reverse" method on an array (without the !) does not modify the original array in-place. Instead, it returns a new array in reverse order. The complimentary "reverse!" method performs an in-place modification of the array.
=> [1,2,3]
>> arr.reverse; arr
=> [1,2,3]
>> arr.reverse!; arr
=> [3,2,1]
Aside: I notice tuples are entered using parentheses, but I haven't
found how to make a tuple with one entry yet.
Another aside: for anyone who wants to play, here is a patch which
shows the executed code as actual erlang source.
--- a/src/compiler/reia_bytecode.erl
+++ b/src/compiler/reia_bytecode.erl
@@ -30,7 +30,15 @@ compile(Filename, Expressions) ->
compile(Filename, Expressions, #compile_options{}).
compile(Filename, Expressions, Options) ->
- io:format("Output Code: ~p~n", [Expressions]),
+ %% io:format("Output Code: ~p~n", [Expressions]),
+ lists:foreach(fun(Module) ->
+ case Module of
+ {module,_,_,Functions} ->
+ lists:foreach(fun(Form) ->
+ io:put_chars(erl_pp:form(Form)) end, Functions);
+ _ -> 0
+ end
+ end, Expressions),
case compile_expressions(Filename, Expressions, Options) of
{ok, _Module, Bin} ->
Module = #reia_module{filename=Filename, base_module=Bin},
Example:
>> a = 1
Input Code: [{match,1,{identifier,1,a},{integer,1,1}}]
toplevel({}, nil) ->
__reia_eval_return_value_0 = a_0 = 1,
{__reia_eval_return_value_0,[{a,a_0}]}.
=> 1
>> a += 1
Input Code: [{binary_op,1,'+=',{identifier,1,a},{integer,1,1}}]
toplevel({a_0}, nil) ->
__reia_eval_return_value_0 = a_1 = a_0 + 1,
{__reia_eval_return_value_0,[{a,a_1}]}.
=> 2
>> b = a * a
Input Code: [{match,1,
{identifier,1,b},
{binary_op,1,'*',{identifier,1,a},{identifier,
1,a}}}]
toplevel({a_0}, nil) ->
__reia_eval_return_value_0 = b_0 = a_0 * a_0,
{__reia_eval_return_value_0,[{a,a_0},{b,b_0}]}.
=> 4
>> 1 - 2 - 3
Input Code: [{binary_op,1,'-',
{integer,1,1},
{binary_op,1,'-',{integer,1,2},{integer,
1,3}}}]
toplevel({a_0,b_0}, nil) ->
__reia_eval_return_value_0 = 1 - (2 - 3),
{__reia_eval_return_value_0,[{a,a_0},{b,b_0}]}.
=> 2
Awesome... and only a gnats-whisker away from instance variables,
where the 'State' in a gen_server is a dict.
Aside: I notice tuples are entered using parentheses, but I haven't
found how to make a tuple with one entry yet.
Hmm, it looks like the Reia parser treats + and - as right-
associative?
1> io:parse_erl_exprs('. ').
. 1 - 2 - 3.
{ok,[{op,1,'-',
{op,1,'-',{integer,1,1},{integer,1,2}},
{integer,1,3}}],
2}
A := A '+' M
| A '-' M
| M
so that 1 - 2 - 3 is parsed as
A
/ | \
A - M
/ | \ |
A - M 3
| |
M 2
|
1
(and this is what erlang's own parser has, see add_expr).
Whether the grammar is left-recursive or right-recursive is a separate
issue. The grammar I wrote at the top is left-recursive, but you can
transform it mechanically into a right-recursive form, which if I
remember correctly is
A := M A2
A2 := '+' M A2
| '-' M A2
| empty
Since there is no left recursion you could parse this new version with
a top-down recursive parser. But an LALR parser generator like yacc/
yecc is quite happy with left-recursive grammars so there is no need
for you to do this.
These grammars build the same parse tree from 1-2-3, whereas A := M
'-' A builds a different parse tree.
Regards,
Brian.
What you need is:
A := A '+' M
| A '-' M
| M
so that 1 - 2 - 3 is parsed as
A
/ | \
A - M
/ | \ |
A - M 3
| |
M 2
|
1
(and this is what erlang's own parser has, see add_expr).
Aside: I notice tuples are entered using parentheses, but I haven't
found how to make a tuple with one entry yet.
... plus an astonishing amount of other work in the last couple of
days. Keep up the good work!
A couple of minor observations:
(1)
b = 3 < 4
gives a syntax error. However, both
(b = 3) < 4
and
b = (3 < 4)
are accepted.
(2) You appear to have made matches left-associative (commit
cf2e2a5f), but ruby's assignment operator is right-associative, and as
far as I can see from the Erlang grammar, it is in Erlang too:
expr_100 -> expr_150 '=' expr_100 : {match,?line('$2'),'$1','$3'}.
Regards,
Brian.
... plus an astonishing amount of other work in the last couple of
days. Keep up the good work!
A couple of minor observations:
(1)
b = 3 < 4
gives a syntax error. However, both
(b = 3) < 4
and
b = (3 < 4)
are accepted.
(2) You appear to have made matches left-associative (commit
cf2e2a5f), but ruby's assignment operator is right-associative
It's still left associative, but I think it "just works" because of
erlang's match semantics. For example:
a = b = 2
gives
...
{match,1,
{match,1,{var,1,a_0},{var,1,b_0}},
{integer,1,2}}},
That is, (a = b) = 2
But if you make the following change then it's parsed as a = (b = 2)
--- a/src/compiler/reia_parse.yrl
+++ b/src/compiler/reia_parse.yrl
@@ -85,13 +85,13 @@ inline_exprs -> expr : ['$1'].
%% Expressions
expr -> match_expr : '$1'.
-match_expr -> match_expr '=' bool_expr :
+match_expr -> bool_expr '=' match_expr :
#match{
line=?line('$2'),
left='$1',
right='$3'
}.
-match_expr -> match_expr rebind_op bool_expr :
+match_expr -> bool_expr rebind_op match_expr :
#binary_op{
line=?line('$1'),
type=?op('$2'),
It's interesting that even without this patch, an example like
b = 1
a = b += 2
works. Reia is parsing this as
(a = b) = ((a = b) + 2)
which I find rather surprising. With the patch it becomes
a = (b = (b + 2))
Regards,
Brian.
--- a/src/compiler/reia_parse.yrl
+++ b/src/compiler/reia_parse.yrl
@@ -85,13 +85,13 @@ inline_exprs -> expr : ['$1'].
%% Expressions
expr -> match_expr : '$1'.
-match_expr -> match_expr '=' bool_expr :
+match_expr -> bool_expr '=' match_expr :
#match{
line=?line('$2'),
left='$1',
right='$3'
}.
-match_expr -> match_expr rebind_op bool_expr :
+match_expr -> bool_expr rebind_op match_expr :
#binary_op{
line=?line('$1'),
type=?op('$2'),
It's interesting that even without this patch, an example like
b = 1
a = b += 2
works. Reia is parsing this as
(a = b) = ((a = b) + 2)
which I find rather surprising.