efene programming language

meta programming in efene take II

yesterday I made the first implementation of meta programming in efene, today some changes and some code to show that I wasn’t dreaming too much.

first change: ${ … } expression is now $( … ) to match Template Haskell syntax (and jquery :P)

second change: now meta programming can be made at module level, that means that you can generate any kind of code with meta programming (some examples below)

third change: allow to inject a list of ast nodes at module level, this allows to generate multiple top level expressions from one “meta statement” (I’m inventing names as I go :P)

fourth change: as you will see below, we can generate the so called efene objects using meta programming, this eliminates the need for special syntax for objects, and since core efene attempts to be 100% compatible with erlang I decided to leave the extra features such as objects as a meta library.

fifth change: the $[…] expression was introduced, it’s a shortcut for [| $(…) |]

This will also allow some awesome coder to come with a better implementation of objects using meta programming and replacing it would be a matter of using another library and no change will be needed in the syntax (and no legacy syntax). If the implementation is really awesome I may decide to make it into core efene, but since I’m not 100% sure that my implementation of objects is perfect I will let time (and users) decide.

now some examples:

!$(fn_gen.build_record($line, person, [firstname, lastname, mail]))
!$(fn_object.build($line, request, [time, url, params]))



at top level statements starting with ! and followed by $(…) $[…] or [|…|] are evaluated at compile time and the result of the statement is inserted in the ast tree

if we compile it, it will compile, but you won’t be able to see what is generated, so I will generate erlang from this code so you can see what happens:



-module(test).

-export([request/1, request/3]).

-record(person, {firstname, lastname, mail}).

-record(request, {time, url, params}).

request(#request{time = Time, url = Url,
		 params = Params}) ->
    request(Time, Url, Params).

request(Time, Url, Params) ->
    Obj = #request{time = Time, url = Url, params = Params},
    Wrapper = fun (Self, Request) ->
		      fun (get, time) -> Request#request.time;
			  (get, url) -> Request#request.url;
			  (get, params) -> Request#request.params;
			  (settime, Value) ->
			      Self(Self, Request#request{time = Value});
			  (seturl, Value) ->
			      Self(Self, Request#request{url = Value});
			  (setparams, Value) ->
			      Self(Self, Request#request{params = Value});
			  ({set, time}, Value) ->
			      Self(Self, Request#request{time = Value});
			  ({set, url}, Value) ->
			      Self(Self, Request#request{url = Value});
			  ({set, params}, Value) ->
			      Self(Self, Request#request{params = Value});
			  (to, rec) -> Request;
			  (to, fields) -> {time, url, params};
			  (to, fieldslist) -> [time, url, params];
			  (to, name) -> request;
			  (to, strname) -> "request";
			  (has, time) -> true;
			  (has, url) -> true;
			  (has, params) -> true;
			  (has, "time") -> true;
			  (has, "url") -> true;
			  (has, "params") -> true;
			  (has, _) -> false;
			  (A, B) -> throw({method_not_found, A, B})
		      end
	      end,
    Wrapper(Wrapper, Obj).



that’s a lot of code for two statements. That’s the idea, capture repetitive patterns and put them in meta libraries so we don’t write boilerplate code again.


To Tumblr, Love Metalab