<?xml version="1.0" encoding="UTF-8"?>

<!-- ====================================================================== -->
<!-- = chapter-5.xml                                                      = -->
<!-- = afnix programmer's guide chapter 5                                 = -->
<!-- ====================================================================== -->
<!-- = This  program  is  free  software; you  can redistribute it and/or = -->
<!-- = modify it provided that this copyright notice is kept intact.      = -->
<!-- = This program is distributed in the hope that it will be useful but = -->
<!-- = without  any  warranty;  without  even  the  implied  warranty  of = -->
<!-- = merchantability or fitness for  a  particular purpose. In no event = -->
<!-- = shall  the  copyright  holder be liable for any  direct, indirect, = -->
<!-- = incidental  or special  damages arising  in any way out of the use = -->
<!-- = of this software.                                                  = -->
<!-- ====================================================================== -->
<!-- = copyright (c) 2005-2007 - amaury darsch                            = -->
<!-- ====================================================================== -->

<chapter volume="1" number="5">
  <title>Advanced concepts</title>

  <p>
  This chapter covers advanced concepts of the <afnix/> programming
  language. The first subject is the exception model. The second
  subject covers some properties of the namesets. Finally, the
  interpreter object is described in details.
  </p>

  <!-- exceptions -->
  <section>
    <title>Exception</title>

    <p>
    An <em>exception</em> is an unexpected change in the execution
    flow. The <afnix/> model for exception is based on a mechanism
    which throws the exception to be caught by a handler. The
    mechanism is also designed to be compatible with the native "C++"
    implementation.
    </p>

    <!-- throwing an exception -->
    <subsect>
      <title>Throwing an exception</title>
      
      <p>
      An exception is thrown with the reserved keyword
      <code>throw</code>. When an exception is thrown, the normal flow
      of execution is interrupted and an object used to carry the
      exception information is created. Such exception object is
      propagated backward in the call stack until an exception handler
      catch it.
      </p>

      <example>
      if (not (number-p n)) 
        (throw "type-error" "invalid object found" n)
      </example>

      <p>
      The example above is the general form to throw an exception. The
      first argument is the <em>the exception id</em>. The second
      argument is the <em>exception reason</em>. The third argument is
      the <em>exception object</em>. The exception id and reason are
      always a string. The exception object can be any object which is
      carried by the exception. The reserved keyword
      <code>throw</code> accepts 0 or more arguments.
      </p>

      <example>
      throw              
      throw "type-error" 
      throw "type-error" "invalid argument"
      </example>

      <p>
      With 0 argument, the exception is thrown with the exception id
      set to "user-exception". With one argument, the argument is the
      exception id. With 2 arguments, the exception id and reason are
      set.
      </p>
    </subsect>

    <!-- exception handler -->
    <subsect>
      <title>Exception handler</title>

      <p>
      The reserved keyword <code>try</code> executes a form and catch
      an exception if one has been thrown. With one argument, the form
      is executed and the result is the result of the form execution
      unless an exception is caught. If an exception is caught, the
      result is the exception object. If the exception is a native
      one, the result is nil.
      </p>

      <example>
      try (+ 1 2)
      try (throw)
      try (throw "hello")
      try (throw "hello" "world")
      try (throw "hello" "world" "folks")
      </example>

      <p>
      In its second form, the <code>try</code> reserved keyword can
      accept a second form which is executed when an exception is
      caught. When an exception is caught, a new nameset is created
      and the special symbol <code>what</code> is bounded with the
      exception object. In such environment, the exception can be
      evaluated. The <code>what:eid</code> qualified name is the
      exception id. The <code>what:reason</code> qualified name is the
      exception reason and <code>what:object</code> is the exception
      object. 
      </p>

      <example>
      try (throw "hello")              
        (eval what:eid)
      try (throw "hello" "world")      
        (eval what:reason)
      try (throw "hello" "world" 2000) 
        (eval what:object)
      </example>

      <p>
      Exceptions are useful to notify abruptly that something went
      wrong. With an untyped language like <afnix/>, it is also a
      convenient mechanism to abort an expression call if some
      arguments do not match the expected types.
      </p>

      <example>
      # protected factorial
      const fact (n) {
        if (not (integer-p n)) 
	  (throw "number-error" "invalid argument in fact")
        if (== n 0) 1 (* n (fact (- n 1)))
      }
      try (fact 5) 0
      try (fact "hello") 0
      </example>
    </subsect>
  </section>

  <!-- nameset -->
  <section>
    <title>Nameset</title>

    <p>
    A nameset is created with the reserved keyword
    <code>nameset</code>. Without argument, the <code>nameset</code>
    reserved keyword creates a nameset without setting its
    parent. With one argument, a nameset is created and the parent set
    with the argument. 
    </p>

    <example>
    const nset (nameset)
    const nset (nameset ...)
    </example>
    
    <!-- default nameset -->
    <subsect>
      <title>Default namesets</title>
      
      <p>
      When a nameset is created, the symbol <code>.</code> is
      automatically created and bound to the newly created nameset. If
      a parent nameset exists, the symbol <code>..</code> is also
      automatically created. The use of the current nameset is a
      useful notation to resolve a particular name given a hierarchy
      of namesets.
      </p>

      <example>
      trans a 1 # 1
      block {
        trans   a (+ a 1) # 2
        println ..:a 1    # 1
      }
      println a           # 1
      </example>
    </subsect>

    <!-- nameset and inheritance -->
    <subsect>
      <title>Nameset and inheritance</title>
      
      <p>
      When a nameset is set as the super object of an instance, some
      interesting results are obtained. Because symbols are resolved
      in the nameset hierarchy, there is no limitation to use a
      nameset to simulate a kind of multiple inheritance. The
      following example illustrates this point.
      </p>

      <example>
      const   cls (class)
      const   ins (cls)
      const   ins:super (nameset)
      const   ins:super:value 2000
      const   ins:super:hello "hello world "
      println ins:hello ins:value # hello world 2000
      </example>
    </subsect>
  </section>

  <!-- delayed evaluation -->
  <section>
    <title>Delayed Evaluation</title>

    <p>
    The <afnix/> engine provides a mechanism called <em>delayed
    evaluation</em>. Such mechanism permits the encapsulation of a
    form to be evaluated inside an object called a <em>promise</em>.
    </p>

    <!-- creating a promise -->
    <subsect>
      <title>Creating a promise</title>
      
      <p>
      The reserved keyword <code>delay</code> creates a
      <em>promise</em>. When the promise is created, the associated
      object is not evaluated. This means that the promise evaluates
      to itself.
      </p>

      <example>
      const a (delay (+ 1 2))
      promise-p a # true
      </example>

      <p>
      The previous example creates a promise and store the argument
      form. The form is not yet evaluated. As a consequence, the symbol
      <code>a</code> evaluates to the promise object.
      </p>
    </subsect>

    <!-- forcing a promise -->
    <subsect>
      <title>Forcing a promise</title>

      <p>
      The reserved keyword <code>force</code> the evaluation of a
      promise. Once the promise has been forced, any further call will
      produce the same result. Note also that, at this stage, the
      promise evaluates to the evaluated form.
      </p>

      <example>
      trans   y 3
      const   l ((lambda (x) (+ x y)) 1)
      assert  4 (force l)
      trans   y 0
      assert  4 (force l)
      </example>
    </subsect>
  </section>

  <!-- enumeration -->
  <section>
    <title>Enumeration</title>
    
    <p>
    Enumeration, that is, named constant bound to an object, can be
    declared with the reserved keyword <code>enum</code>. The
    enumeration is built with a list of literal and evaluated as is.
    </p>

    <example>
    const  e    (enum E1 E2 E3)
    assert true (enum-p e)
    </example>

    <p>
    The complete enumeration evaluates to an <code>Enum</code>
    object. Once built, enumeration item evaluates by literal and
    returns an <code>Item</code> object.
    </p>

    <example>
    assert true   (item-p e:E1)
    assert "Item" (e:E1:repr)
    </example>

    <p>
    Items are comparable objects. Only items can be compared. For a
    given item, the source enumeration can be obtained with the
    <code>get-enum</code> method.
    </p>

    <example>
    # check for item equality
    const i1 e:E1
    const i2 e:E2
    assert true  (i1:== i1)
    assert false (== i1 i2)
    # get back the enumeration
    assert true (enum-p (i1:get-enum))
    </example>
  </section>

  <!-- logger -->
  <section>
    <title>Logger</title>

    <p>
    The Looger class is a message logger that stores messages in a
    buffer with a level. The default level is the level 0. A negative
    level generally indicates a warning or an error message but this
    is just a convention which is not enforced by the class. A high
    level generally indicates a less important message. The messages
    are stored in a circular buffer. When the logger is full, a new
    message replace the oldest one. By default, the logger is
    initialized with a 256 messages capacity that can be resized.
    </p>

    <example>
    const log    (Logger)
    assert true  (logger-p log)
    </example>

    <p>
    When a message is added, the message is stored with a timestamp
    and a level. The timestamp is used later to format a
    message. The <code>length</code> method returns the number of
    logged messages. The <code>get-message</code> method returns a
    message by index. Because the system operates with a circular buffer,
    the <code>get-message</code> method manages the indexes in such way that
    the old messages are accessible with the oldest index. For example,
    even after a buffer circulation, the index 0 will point to the
    oldest message. The <code>get-message-level</code> returns the
    message level and the <code>get-message-time</code> returns the
    message posted time.
    </p>

    <example>
    const mesg (log:get-message 0)
    </example>

    <p>
    In term of usage, the logger facility can be conveniently used
    with other derived classes. The standard i/o module provides
    several classes that permits to manage logging operations in a
    convenient way.
    </p>
  </section>

  <!-- interpreter -->
  <section>
    <title>Interpreter</title>

    <p>
    The <afnix/> interpreter is by itself a special object with
    specialized methods which do not have equivalent using the
    standard <afnix/> notation. The interpreter is always referred
    with the special symbol <code>interp</code>. The following table
    is a summary of the symbols and methods bound to the interpreter.
    </p>

    <table>
     <title>Interpreter builtin symbols</title>
     <thead>
      <tr>
        <td>Symbol</td><td>Description</td>
      </tr>
     </thead>
     <tbody>
      <tr><td>argv</td>          <td>Command arguments vector</td></tr>
      <tr><td>os-name</td>       <td>Operating system name</td></tr>
      <tr><td>os-type</td>       <td>Operating system type</td></tr>
      <tr><td>version</td>       <td>Full afnix version</td></tr>
      <tr><td>program-name</td>  <td>Interpreter program name</td></tr>
      <tr><td>major-version</td> <td>Major version number</td></tr>
      <tr><td>minor-version</td> <td>Minor version number</td></tr>
      <tr><td>patch-version</td> <td>Patch version number</td></tr>
      <tr><td>afnix-url </td>    <td>Official url name</td></tr>
      <tr><td>load</td>          <td>Load a file and execute it</td></tr>
      <tr><td>launch</td>        <td>Launch a normal thread</td></tr>
      <tr><td>daemon</td>        <td>Launch a daemon thread</td></tr>
      <tr><td>library</td>       <td>Load and initialize a library</td></tr>
      <tr><td>set-epsilon</td>   <td>Set real number precision</td></tr>
      <tr><td>get-epsilon</td>   <td>Set real number precision</td></tr>
     </tbody>
    </table>

    <!-- arguments vector -->
    <subsect>
      <title>Arguments vector</title>

      <p>
      The <code>interp:argv</code> qualified name evaluates to a
      vector of strings. Each argument is stored in the vector during
      the interpreter initialization.
      </p>

      <example>
      zsh&gt; axi hello world
      afnix&gt; println (interp:argv:length) # 2
      afnix&gt; println (interp:argv:get 0)  # hello
      </example>
    </subsect>

    <!-- interpreter version-->
    <subsect>
      <title>Interpreter version</title>

      <p>
      Several symbols can be used to track the interpreter version and the
      operating system. The full version is bound to the
      <code>interp:version</code> qualified name. The full version is
      composed of the <em>major</em>, <em>minor</em> and
      <em>patch</em> number. The operating system name is bound to the
      qualified name <code>interp:os-name</code>. The operating system
      type is bound to the <code>interp:os-type</code>.
      </p>

      <example>
      println "major version number   : " interp:major-version
      println "minor version number   : " interp:minor-version
      println "patch version number   : " interp:patch-version
      println "interpreter version    : " interp:version
      println "operating system name  : " interp:os-name
      println "operating system type  : " interp:os-type
      println "afnix official url     : " interp:afnix-url
      </example>
    </subsect>

    <!-- file loading -->
    <subsect>
      <title>File loading</title>

      <p>
      The <code>interp:load</code> method loads and execute a
      file. The interpreter interactive command session is suspended
      during the execution of the file. In case of error or if an
      exception is raised, the file execution is terminated. The
      process used to load a file is governed by the <em>file
      resolver</em>. Without extension, a compiled  file is searched
      first and if not found a source file is searched.
      </p>
    </subsect>

    <!-- library loading -->
    <subsect>
      <title>Library loading</title>

      <p>
      The <code>interp:library</code> method loads and initializes a
      library. The interpreter maintains a list of opened
      library. Multiple execution of this method for the same library
      does nothing. The method returns the library object.
      </p>

      <example>
      interp:library "afnix-sys"
      println "random number: " (afnix:sys:get-random)
      </example>
    </subsect>

    <!-- interpreter duplication -->
    <subsect>
      <title>Interpreter duplication</title>

      <p>
      The interpreter can be duplicated with the help of the
      <code>dup</code> method. Without argument, a clone of the
      current interpreter is made and a terminal object is attached to
      it. When used in conjunction with the <code>roll</code> method,
      this approach permits to create an interactive interpreter. The
      <code>dup</code> method also accepts a terminal object.
      </p>

      <example>
      # duplicate the interpreter
      const si (interp:dup)
      # change the primary prompt
      si:set-primary-prompt "(si)"
      </example>
    </subsect>

    <!-- interpreter loop -->
    <subsect>
      <title>Interpreter loop</title>

      <p>
      The interpreter loop can be run with the <code>roll</code>. The
      loop operates by reading the interpreter input stream. If the
      interpreter has been cloned with the help of the
      <code>dup</code> method, this method provides a convenient way
      to operate in interactive mode. The method is not called
      <em>loop</em> because it is a reserved keyword and starting a
      loop is like having the ball rolling.
      </p>

      <example>
      # duplicate the interpreter
      const si (interp:dup)
      # loop with this interpreter
      si:loop
      </example>
    </subsect>
  </section>
</chapter>
