efene & how BEAMs are made

Mariano Guerra

Erlang Basel Meetup

March 2016

Ego Slide

efene

What's This?

{
    "string": "string",
    "integer": 4,
    "float": 12.3,
    "boolean": true,
    "list": [1, null,  "fourteen!"],
}

Answer:

And the remaining ones

Variable
an_atom
`an atom`
()
(1,)
(1, 2)
'a binary string'
[cons :: list]
fn lists.map:2

Some missing?

Nope

Tagged Values

#atom "I'm an atom"

#c "A"

#r.person {name: "bob", lastname: "sponge", age:29}

#i line

#i module

#m PI

#m AUTHOR(bob)

Say IPv4 One More Time!

#b {
    Version:4,
    IHL:4,
    TypeOfService:8,
    TotalLength:16,
    Identification:16,
    FlagX:1,
    FlagD:1,
    FlagM:1,
    FragmentOffset:13,
    TTL:8,
    Protocol:8,
    HeaderCheckSum:16,
    SourceAddress:32,
    DestinationAddress:32,
    Rest: binary
}

Binary Pattern Matching

#b {
    _: _,
    A: _,
    JustSize: 8,
    JustType: binary,
    E: {},
    _: {size: 8},
    _: {type: float},
    _: {sign: unsigned},
    _: {endianness: big},
    _: {unit: 8},
    B: {size: 8, type: float, sign: signed, endianness: little, unit: 16}
}

Top Level Attributes

@export(hello/0, plus/2)

@record(foo) -> (a, b = 12, c = true, d = 12)

@type(f3) -> fun([boolean(), term()], integer())

@import(erlang, [phash2/1])

@on_load(fname/0)

@include("path/to/file.hrl")

Boolean Operations

Op

Description

Erlang Equivalent

or

Short Circuit Or

orelse

and

Short Circuit And

andalso

xor

Xor

xor

orr

Non Short Circuit Or

or

andd

Non Short Circuit And

and

Comparisson Operations

Op

Description

Erlang Equivalent

==

equal to

==

!=

not equal to

/=

is

exactly equal to

=:=

isnt

exactly not equal to

=/=

Comparisson Operations

Op

Description

Erlang Equivalent

<

less than

<

<=

less than or equal to

=<

>

greater than

>

>=

greater than or equal to

>=

Aritmetic Operations

Op

Description

Erlang Equivalent

+

addition

+

-

substraction

-

*

multiplication

*

/

division

/

%

remainder

rem

//

integer division

div

Binary Operations

Op

Description

Erlang Equivalent

|

binary or

bor

&

binary and

band

^

binary xor

bxor

<<

shift left

bsl

>>

shift right

bsr

Unary Operations

Op

Description

Erlang Equivalent

-

integer negative

-

not

boolean not

not

~

binary not

bnot

Expressions

Case Clause in efene

case: <exprs>

case one: <exprs>

case one, two: <exprs>

case one, two when <guard>: <exprs>

else: <exprs>

What's a function?

fn my_function
  case error, Reason: Reason
  case exit, Reason: Reason
  else: other
end

Lambda

fn
  case error, Reason: Reason
  case exit, Reason: Reason
  else: other
end

Receive

receive
  case error, Reason: Reason
  case exit, Reason: Reason
  else: other
end

Try/Catch

try
    <exprs>
catch
  case error, Reason: Reason
  case exit, Reason: Reason
  else: other
end

Match (case)

match A:
  case error, Reason: Reason
  case exit, Reason: Reason
  else: other
end

Where's the if?

There's no if in erlang, just standalone guards:

when  <cond>: <exprs>

else <cond>: <exprs>

else <cond>: <exprs>

else: <exprs>

For comprehensions

for X in lists.seq(1, 10); when X % 2 is 0:
  X + 1
end

Ergonomic syntax

Threading Values

lists.seq(1, 10) ->>
    lists.filter(IsOdd) ->
    MyMap(Increment)

Threading Lambdas

lists.map(R) <<- case X:
  X + 1
end

MapR(R) <- case X:
  X + 1
end

Erlang Integration

efene ecosystem

Next Steps

Help!

I could do a better language than yours!

Great, I can help you!

Start the project

commit 1:

rebar3 new fn_escript name=otl

cd otl

rebar3 escriptize

./_build/default/bin/otl

Implement erl2ast command

Because reading absform is too much work :)

commit 2:

$ ./_build/default/bin/otl erl2ast examples/mymod.erl

{ok,[{attribute,1,file,{"examples/mymod.erl",1}},
     {attribute,1,module,mymod},
     {attribute,2,export,[{main,0}]},
     {function,4,main,0,[{clause,4,[],[],[{atom,4,true}]}]},
     {eof,5}]}

Implement erl2ast2erl

commit 3:

$ ./_build/default/bin/otl erl2ast2erl examples/mymod.erl

-file("examples/mymod.erl", 1).

-module(mymod).

-export([main/0]).

main() -> true.

Implement erl2beam

commit 4:

$ ./_build/default/bin/otl erl2beam examples/mymod.erl .

{ok,[{module_name,mymod},{path,"./mymod.beam"}]}

Implement erl2beam

$ erl

Erlang/OTP 18 [erts-7.0] [source] [64-bit] [smp:4:4] [async-threads:10]
[kernel-poll:false]

Eshell V7.0  (abort with ^G)
1> mymod:main().
true
2> q().
ok

Tokenize true token, skip whites

commit 5:

$ cat examples/trues.otl

true true true


$ ./_build/default/bin/otl lex examples/trues.otl

{ok,[{boolean,1,true},{boolean,1,true},{boolean,1,true}],2}

Parse true token to AST

commit 6:

$ ./_build/default/bin/otl ast examples/trues.otl

{ok,[{atom,1,true},{atom,1,true},{atom,1,true}]}

Build Module with generated AST

commit 7:

$ ./_build/default/bin/otl mod examples/trues.otl mymod myfun

{ok,[{attribute,1,file,{"examples/trues.otl",1}},
     {attribute,1,module,mymod},
     {attribute,2,export,[{myfun,0}]},
     {function,3,myfun,0,
               [{clause,4,[],[],
                        [{atom,1,true},{atom,1,true},{atom,1,true}]}]}]}

Compile to BEAM

commit 8:

$ ./_build/default/bin/otl beam examples/trues.otl . mymod myfun

{ok,[{module_name,mymod},{path,"./mymod.beam"}]}

Compile to Erlang Source

commit 9:

$ ./_build/default/bin/otl erl examples/trues.otl mymod myfun

-file("examples/trues.otl", 1).
-module(mymod).
-export([myfun/0]).

myfun() -> true, true, true.

But I don't like your language!

rebar3 efene compile --format=erl

Add eval

commit 10:

$ ./_build/default/bin/otl eval examples/trues.otl

true

Implement a repl

commit 11:

$ ./otl-shell
Erlang/OTP 18 [erts-7.0] [source] [64-bit] [smp:4:4] [async-threads:10] [kernel-poll:false]

otl shell (Ctrl+g and then q to quit, Ctrl+g for Job Control Mode)

>>> true
true
>>> true true
true
>>>
>>> false
error: {1,otl_lexer,{illegal,"f"}}
>>> ^G
User switch command
 --> q

Parse Numbers Containing 1

commit 12:

$ ./otl-shell
Erlang/OTP 18 [erts-7.0] [source] [64-bit] [smp:4:4] [async-threads:10] [kernel-poll:false]

otl shell (Ctrl+g and then q to quit, Ctrl+g for Job Control Mode)

>>> 1
1
>>> 1 true
true
>>> 1 true 1111
1111
>>> ^G
User switch command
 --> q

Parse Numbers Containing 1

$ ./_build/default/bin/otl erl examples/one_true_language.otl one_true language

-file("examples/one_true_language.otl", 1).

-module(one_true).

-export([language/0]).

language() -> 1, true.

And we are done

We just created the one true language (TM)

gh:marianoguerra/otl to follow each step as a commit