[Asterisk-Users] --- AEL 2 --- Try it out!

Steve Murphy murf at e-tools.com
Fri Jan 6 20:47:00 MST 2006


Hello--

I've just written and submitted a new module for asterisk, to the
asterisk bug database.

See     http://bugs.digium.com/view.php?id=6021

There is a file there you can download,  AEL2v0.3.patch.bz2

and I created a wiki page: http://www.voip-info.org/wiki/view/Asterisk+AEL2

Why did I do it? Because I was very impressed with AEL, but the current
AEL compiler isn't real good at pointing out problems. Mostly, it seems
to silently ignore problems.

But I have a better idea. I want the compiler to check the "living
daylights" out of the dialplan code. I want subtle errors that otherwise
would trip up asterisk and hang up a call to be found at load time, not
run-time! I remember all the classes I took long ago, that kept pounding
away at the fact that finding and fixing errors at later stages are
exponentially more expensive than finding and fixing them early in the
design cycle... and I think the same applies to dialplans.

So I wrote AEL2 from the ground up. No newline dependencies, as free-
form as C. After parsing, which will reveal syntax errors, a second pass
is made hunting for semantic errors, like misspelled applications, bad
expressions, etc. I'll tack on a list of the differences and checks at
the end of this message. Code is generated in a third phase, if no
errors are found in the input.

To be as compatible as possible, but separate from, the current pbx_ael
module, my module is called pbx_ael2, and loads the file
"/etc/asterisk/extensions.ael2". Like pbx_ael, it loads this file and
merges it into asterisk, so it is easily possible for you to have a
hybrid dialplan, part in extensions.conf, part in extensions.ael, and
part in extensions.ael2.

Along with the AEL2 module,  some executables are provided in the source dir,
asterisk/utils, called aelparse, and aelparse1, that allow both the
current ael compiler (aelparse1), and my AEL2 compiler (aelparse) to be
standalone executables, so you can test your extensions.ael2 file and
get the syntax/semantic errors output without having to load the file
into asterisk.

AEL2 is made to load the current ael files. But it adds some
functionality, so the reverse (feeding ael2 files to the current ael
compiler)  may not be possible.

I've added the "return" keyword, that will jump to the end of an
extension. I've added the ifTime() statement, which uses GotoIfTime
underneath. I've implemented the #include "filename" directive. The 
AEL2 compiler also causes $[ ] expressions to be checked. 

So I ask you this: how clean are your dialplans? Are you certain?

And I also present you with this thought: to me, the extensions.conf is
very reminiscent of assembly code. I programmed a LOT of assembly code
in my day. But higher level languages made programming more efficient,
and this is what AEL will do for you. So why on earth are you still
writing dialplans in extensions.conf format? (besides the fact that ael
and AEL2 are both in the "experimental" phase right now).

I'm running on my AEL2 dialplan right now. Just loading AEL2 revealed
tons of problems that I wouldn't have spotted until there were problems
in asterisk running on the dialplan, with live calls.

So, step up to the Next Big Thing. Go, fetch, and try this code out,
report the myriad of problems that I'm sure are lurking in there. Now is
the time. Rewrite your spaghetti assembly code into nice structured
code, and see if it is easier to understand, maintain, and update.

For those of you who'd rather use perl, or python, or whatever, the AEL2
parser generates a code tree representing the input code. A pretty
printer and generic traversal routines are provided. If you can generate
your own parse tree from perl/python/etc, you can use the code generator
to enter your dialplan into asterisk. Why re-invent the wheel?

OK, enough blatant marketing.

Here's a chunk from the README.ael2 file:

The BIG differences:

1. It reads in "/etc/asterisk/extensions.ael2", instead of 
   extensions.ael
2. It is more free-form. The newline character means very little, and is
   pulled out of the white-space only for line numbers in error 
   messages.
3. It generates more error messages -- by this I mean that any
   difference between the input and the grammar are reported, by file,
   line number, and column.
4. It checks the contents of $[ ] expressions (or what will end up
   being $[ ] expressions!) for syntax errors. It also does matching
   paren/bracket counts.
5. It runs several semantic checks after the parsing is over, but before
   the compiling begins, and issues these warnings and errors:
   a. (if the application argument analyzer is working: the presence of
       the 'j' option is reported as error.
   b. if options are specified, that are not available in an
      application.
   c. if you specify too many arguments to an application.
   d. a required argument is not present in an application call.
   e. Switch-case using "known" variables that applications set, that
      does not cover all the possible values. (a "default" case will
      solve this problem. Each "unhandled" value is listed.
   f. a Switch construct is used, which is uses a known variable, and
      the application that would set that variable is not called in the
      same extension. This is a warning only...
   g. Macro calls to non-existent macros.
   h. Macro calls to contexts.
   i. Macro calls with argument count not matching the definition.
   j. application call to macro.
   k. application calls to "GotoIf", "GotoIfTime", "while", "endwhile",
      and "execIf", will generate a message to consider converting the 
      call to AEL goto, while, etc. constructs.
   l. Calls to applications not in the "applist" database (installed in 
      /var/lib/asterisk/applist" on most systems).
   m. goto a label in an empty extension.
   n. goto a non-existent label, either a within-extension, within-
      context, or in a different context, or in any included contexts.
   o. All the checks done on the time values in the dial plan, are done
      on the time values in the ifTime() and includes times: the time
      range has to have two times separated by a dash; the times have to
      be in range of 0 to 24 hours. The weekdays have to match the list,
      if provided; the day of the month, if provided, must be in range
      of 1 to 31; the month name or names have to match those in the
      internal list.
6. It handles #include "filepath" directives. -- ALMOST anywhere, in
   fact. You could easily include a file in a context, in an extension,
   or at the root level. Files can be included in files that are
   included in files, down to 50 levels of hierarchy...
7. Local Goto's inside Switch statements automatically have the
   extension of the location of the switch statement appended to them.
8. A pretty printer function is available within pbx_ael2.so.
9. In the utils directory, two standalone programs are supplied for
   debugging AEL files. One is called "aelparse", and it reads in the
   /etc/asterisk/extensions.ael2 file, and shows the results of syntax
   and semantic checking on stdout, and also shows the results of
   compilation to stdout.
   The other is "aelparse1", which uses the original ael compiler to do
   the same work, reading in "/etc/asterisk/extensions.ael", instead.
10. AEL2 supports the "jump" statement, and the "pattern" statement in 
    switch constructs. Hopefully these will be documented in the AEL
    README.
11. Added the "return" keyword, which will jump to the end of an
    extension/Macro.
12. Added the ifTime (<time range>|<days of week>|<days of month>|
    <months> ) {} [else {}]  construct, which executes much like an 
    if () statement, but the decision is based on the current time, and
    the time spec provided in the ifTime. You can use it in this
    fashion:
                ifTime(14:00-25:00|sat-sun|*|*) 
                {
                        BackGround(Hello);
                } 
                else
                        BackGround(Sorry);
    (Note: all the other time-dependent Applications can be used via
     ifTime)

13. Added the optional time spec to the contexts in the includes
    construct.  You can enter the 4 time values like this:

         includes {
                other|16:00-23:59|mon-fri|*|*;
         };
14. There is no restriction about using {}'s in the if or ifTime statements. In
    other words, you can say this:

                ifTime(14:00-25:00|sat-sun|*|*)
                        BackGround(Hello);
                else
                        BackGround(Sorry);

    (you don't have to wrap a single "true" statement in curly braces, as in the
    orignal ael). This creates a conflict in the grammar, but the parser "shifts"
    in this case, and the result is that an "else" is attached to the closest if.
    So, stating something like this:

                ifTime(14:00-23:00|sat-sun|*|*)
                        ifTime(18:00-23:00|sat-sun|*|*)
                            BackGround(Hello);
                        else
                            BackGround(Sorry);

        results in the else being associated with the second "ifTime". As usual, be
        careful about nested if statements! When in doubt, use curlies!

15. Added the syntax [regexten] [hint(channel)] to preceed an extension declaration.
    You can now say things like this:
                                regexten hint(SIP/1) 123 => {
                                                NoOp(hello there);
                                };

    The regexten keyword will cause the priorities in the extension to begin
    with 2 instead of 1. The hint keyword will cause its arguments to be inserted
    in the extension under the hint priority. They are both optional, of course,
    but the order is fixed at the moment-- the regexten must come before the hint.

Sorry for the long letter.

murf






-- 
Steve Murphy <murf at e-tools.com>
Electronic Tools Company




More information about the asterisk-users mailing list