The Atomiser, Part V
The Atomiser can now walk its own Abstract Syntax Tree and pluck lists of valid atoms from its own source code.
Next on the list is to
- Have the Erlang compiler tell us when we use an atom that is not in the valid list.
Sounds easy: let's get to it!
We want to turn our placeholder atom clause in the walk_ast function into something a little more useful:
walk_ast([{atom,Line,Atom}|RestAST], Atoms) ->
walk_ast(RestAST, atom_check(Atom, Line, Atoms));
Our new atom_check function will compare the supplied atom against the given atoms dictionary. If the atom exists in the dictionary then a new dictionary will be returned, with that atom's value updated to 'found' (taking the place of the atom's line-of-definition integer). If the atom does not exist in the dictionary then a warning message will be displayed and the original dictionary will be returned:
atom_check(Atom, Line, Atoms) ->
case dict:find(Atom, Atoms) of
{ok, found} ->
Atoms;
{ok, _LineDefinedOn} ->
dict:store(Atom, found, Atoms);
error ->
io:format(
"Line ~B: Atom ~w unexpected.~n",
[Line, Atom]),
Atoms
end.
...and we are almost done.
A bit of a shock - but a good sign - is the number of unknown atoms that appear when you first run the Atomiser on itself. All of the atoms we use in our walk_ast pattern tuples show up as unknown atoms, so let's add some proper valid atom lists to the top of the file. First, the atoms we use in our patterns:
-atoms([atom, attribute, call, 'case', clause, clauses, compile]).
-atoms([cons, eof, export, file, 'fun', function, match, module]).
-atoms([nil, remote, string, tuple, var]).
And then some other atoms we are use elsewhere in the code:
-atoms([atoms, error, found, ok]).
And... all the function names are showing up as unknown atoms, too?
Executive decision time!
Since internal function-calls are already picked up by the compiler when they do not match a function in the module, I think it should be safe to modify the 'call' line to:
?WALK_AST({call,_Line,_Fun,Args}, [Args]);
This will skip validating the called function name.
And now,
1> c(atomiser), l(atomiser).
{module,atomiser}
2>
Beautiful.
No comments:
Post a Comment