diff options
author | Loïc Hoguin <[email protected]> | 2016-03-28 15:36:42 +0200 |
---|---|---|
committer | Loïc Hoguin <[email protected]> | 2016-03-28 15:36:42 +0200 |
commit | fe3492a98de29942477b061cd02c92246f4bf85a (patch) | |
tree | 2255b796a657e6e4dfb72beec1141258d17f1220 /_build/content/articles/xerl-0.3-atomic-expressions.asciidoc | |
download | ninenines.eu-fe3492a98de29942477b061cd02c92246f4bf85a.tar.gz ninenines.eu-fe3492a98de29942477b061cd02c92246f4bf85a.tar.bz2 ninenines.eu-fe3492a98de29942477b061cd02c92246f4bf85a.zip |
Initial commit, new website system
Diffstat (limited to '_build/content/articles/xerl-0.3-atomic-expressions.asciidoc')
-rw-r--r-- | _build/content/articles/xerl-0.3-atomic-expressions.asciidoc | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/_build/content/articles/xerl-0.3-atomic-expressions.asciidoc b/_build/content/articles/xerl-0.3-atomic-expressions.asciidoc new file mode 100644 index 00000000..dae14906 --- /dev/null +++ b/_build/content/articles/xerl-0.3-atomic-expressions.asciidoc @@ -0,0 +1,135 @@ ++++ +date = "2013-02-18T00:00:00+01:00" +title = "Xerl: atomic expressions" + ++++ + +We will be adding atomic integer expressions to our language. +These look as follow in Erlang: + +[source,erlang] +42. + +And the result of this expression is of course 42. + +We will be running this expression at compile time, since we +don't have the means to run code at runtime yet. This will of +course result in no module being compiled, but that's OK, it will +allow us to discuss a few important things we'll have to plan for +later on. + +First, we must of course accept integers in the tokenizer. + +[source,erlang] +{D}+ : {token, {integer, TokenLine, list_to_integer(TokenChars)}}. + +We must then accept atomic integer expressions in the parser. +This is a simple change. The integer token is terminal so we need +to add it to the list of terminals, and then we only need to add +it as a possible expression. + +[source,erlang] +expr -> integer : '$1'. + +A file containing only the number 42 (with no terminating dot) +will give the following result when parsing it. This is incidentally +the same result as when tokenizing. + +[source,erlang] +---- +[{integer,1,42}] +---- + +We must then evaluate it. We're going to interpret it for now. +Since the result of this expression is not stored in a variable, +we are going to simply print it on the screen and discard it. + +[source,erlang] +---- +execute(Filename, [{integer, _, Int}|Tail], Modules) -> + io:format("integer ~p~n", [Int]), + execute(Filename, Tail, Modules). +---- + +You might think by now that what we've done so far this time +is useless. It brings up many interesting questions though. + +* What happens if a file contains two integers? +* Can we live without expression separators? +* Do we need an interpreter for the compile step? + +This is what happens when we create a file that contains two +integers on two separate lines: + +[source,erlang] +---- +[{integer,1,42},{integer,2,43}] +---- + +And on the same lines: + +[source,erlang] +---- +[{integer,1,42},{integer,1,43}] +---- + +Does this mean we do not need separators between expressions? +Not quite. The `+` and `-` operators are an +example of why we can't have nice things. They are ambiguous. They +have two different meanings: make an atomic integer positive or +negative, or perform an addition or a substraction between two +integers. Without a separator you won't be able to know if the +following snippet is one or two expressions: + +[source,erlang] +42 - 12 + +Can we use the line ending as an expression separator then? +Some languages make whitespace important, often the line +separator becomes the expression separator. I do not think this +is the best idea, it can lead to errors. For example the following +snippet would be two expressions: + +[source,erlang] +---- +Var = some_module:some_function() + some_module:other_function() + + another_module:another_function() +---- + +It is not obvious what would happen unless you are a veteran +of the language, and so we will not go down that road. We will use +an expression separator just like in Erlang: the comma. We will +however allow a trailing comma to make copy pasting code easier, +even if this means some old academics guy will go nuts about it +later on. This trailing comma will be optional and simply discarded +by the parser when encountered. We will implement this next. + +The question as to how we will handle running expressions +remains. We have two choices here: we can write an interpreter, +or we can compile the code and run it. Writing an interpreter +would require us to do twice the work, and we are lazy, so we will +not do that. + +You might already know that Erlang does not use the same code +for compiling and for evaluating commands in the shell. The main +reason for this is that in Erlang everything isn't an expression. +Indeed, the compiler compiles forms which contain expressions, +but you can't have forms in the shell. + +How are we going to compile the code that isn't part of a module +then? What do we need to run at compile-time, anyway? The body of +the file itself, of course. The body of module declarations. That's +about it. + +For the file itself, we can simply compile it as a big function +that will be executed. Then, everytime we encounter a module +declaration, we will run the compiler on its body, making its body +essentially a big function that will be executed. The same mechanism +will be applied when we encounter a module declaration at runtime. + +At runtime there's nothing else for us to do, the result of this +operation will load all the compiled modules. At compile time we +will also want to save them to a file. We'll see later how we can +do that. + +* https://github.com/extend/xerl/blob/0.3/[View the source] |