FPLIL: A Little Interpreted Language (Free Pascal port)
=======================================================

0. Contents
-----------
  1. About
  2. Free Pascal API
     2.1. TLILValue
     2.2. TLILVariable
     2.3. TLILEnvironment
     2.4. TLILList
     2.5. TLILFunction
     2.6. TLIL
  3. Integrating FPLIL in Free Pascal programs
  4. Contact


1. About
--------
   LIL (Little Interpreted Language) is a small C library in just a pair of
 .c and .h files which provide a compact yet very dynamic scripting language
 inspired by Tcl and the UNIX shell.  LIL can be used in a wide range of
 situations, from simple configuration files to full extendability via
 scripting.

   FPLIL is a Free Pascal port of LIL in the OBJFPC compiler mode.  The source
 code consists of a single .pas file (the fplil unit) which is written against
 the latest version of Free Pascal at the moment of the port (2.4.2).  No
 other Free Pascal versions or Pascal compilers have been tested.  However the
 code might compile under Delphi with some modifications.

   This readme file does not describe the LIL syntax or the C API (which is
 also used by the Free Pascal bindings to the C library with the unit provided
 by the Import LIL project).  You need to read the C LIL's readme.txt file
 for that.  This readme file describes the Free Pascal API which uses a
 slightly more object-oriented approach. 
 
   Note that any difference between the C LIL and the Free Pascal LIL should
 be considered as a bug in the Free Pascal LIL.  The C LIL is the "canonical"
 version of LIL.


2. Free Pascal API
------------------
   The Free Pascal version of LIL uses a more FreePascal-ish object oriented API
 than the pure procedural C version.  The API is accessed mainly via the TLIL
 class, which represents a LIL runtime and the TLILValue, TLILVariable,
 TLILEnvironment and TLILFunction classes.  The classes that a FPLIL user will
 concern himself most commonly are TLIL and TLILValue.  The public interface
 for each class is documented below.

2.1. TLILValue
     ---------
   This class represents a value in the LIL runtime.  Internally the value is
 stored as a string (at least in the current implementation), but can be
 accessed as a string, integer, floating point number or boolean.  The public
 functions and properties are:

      procedure AppendChar(Ch: Char);
      Appends the character Ch to the end of the value

      procedure AppendString(Str: string);
      Appends the string Str to the end of the value

      procedure AppendValue(AValue: TLILValue);
      Appends the value AValue to the end of the value

      function Clone: TLILValue;
      Creates a clone of this value

      function Equals(StrVal: string): Boolean;
      Returns True if the value equals to the string StrVal

      function Equals(IntVal: Int64): Boolean;
      Returns True if the value equals to the integer IntVal

      function Equals(FloatVal: Extended): Boolean;
      Returns True if the value equals to the floating point number FloatVal

      function Equals(LILVal: TLILValue): Boolean;
      Returns True if the value equals to the LIL value LILVal

      property StringValue: string (read only)
      Returns the value as a string

      property IntegerValue: Int64 (read only)
      Returns the value as an integer

      property FloatValue: Extended (read only)
      Returns the value as a floating point number

      property BooleanValue: Boolean (read only)
      Returns the value as a boolean value (using LIL's boolean logic)

      property Length: Integer (read only)
      Returns the length of the value in characters (assuming 8bits per char)

2.2. TLILVariable
     ------------
   This class represents a variable in LIL.  The public functions and
 properties are:

      procedure AddWatch(const AWatch: TNotifyEvent);
      Add a watch for variable modifications

      procedure RemoveWatch(const AWatch: TNotifyEvent);
      Remove a watch added with AddWatch

      property Name: string (read only)
      Returns the variable's name

      property Environment: TLILEnvironment (read only)
      Returns the variable's enviroment

      property Value: TLILValue (read write)
      Returns or sets the variable's value.  Note that setting this property
      will actually create a clone of the value so it is safe to use temporary
      values here

   Note that it is recommended to use TLIL's SetVar and GetVar methods to
 set/modify/access variables instead of using TLILVariable instances directly.
 Keep in mind that local variable instances do not outlive their envrionments.

2.3. TLILEnvironment
     ---------------
   This class represents an execution environment (which mostly contains a
 list with the variables in the current scope) and should be treated as an
 opaque object.  It provides only a single property:

      property LIL: TLIL (read only)
      The LIL instance that owns this environment


2.4. TLILList
     --------
   This class is used to hold a list of LIL values and to encode such lists to
 LIL values (a TLILValue cannot hold a TLILList and must be encoded to one to
 use it).  The public functions and properties are:

      procedure Add(AValue: TLILValue);
      Add the LIL value AValue to the end of the list

      procedure AddString(AString: string);
      Add the string AString to the end of the list

      procedure AddFloat(AFloat: Extended);
      Add the floating point number AFloat to the end of the list

      procedure AddBoolean(ABoolean: Boolean);
      Add the boolean ABoolean to the end of the list

      function IndexOf(AValue: TLILValue): Integer;
      Returns the index of a value in the list that equals (using the Equals
      method) to the given value or -1 if the value was not found

      function IndexOfString(AString: string): Integer;
      Returns the index of a value in the list that equals to the given string
      value or -1 if the value was not found

      function IndexOfInteger(AInteger: Int64): Integer;
      Returns the index of a value in the list that equals to the given integer
      value or -1 if the value was not found

      function IndexOfFloat(AFloat: Extended): Integer;
      Returns the index of a value in the list that equals to the given
      floating point number or -1 if the value was not found

      function IndexOfBoolean(ABoolean: Boolean): Integer;
      Returns the index of a value in the list that equals to the given boolean
      value or -1 if the value was not found

      function Has(AValue: TLILValue): Boolean;
      Returns True if any of the values in the list is equal (using the Equals
      method) to the given value

      function HasString(AString: string): Boolean;
      Returns True if any of the values in the list is equal to the given
      string value

      function HasInteger(AInteger: Int64): Boolean;
      Returns True if any of the values in the list is equal to the given
      integer value

      function HasFloat(AFloat: Extended): Boolean;
      Returns True if any of the values in the list is equal to the given
      floating point number value

      function HasBoolean(ABoolean: Boolean): Boolean;
      Returns True if any of the values in the list is equal to the given
      boolean value

      function ToValue(DoEscape: Boolean=True): TLILValue;
      Encode the list to a LIL value.  If DoEscape is True (the default),
      proper escaping will be added for LIL symbols

      property Count: Integer (read only)
      Returns the number of values in the list

      property Values[AIndex: Integer]: TLILValue (read only, default)
      Returns the value at AIndex

   To create a list from a LIL value you can use TLIL's SubstituteToList
 method.

2.5. TLILFunction
     ------------
   This class represents a LIL function (both native functions and functions
 defined by the script).  The public functions and properties are:

      property Name: string (read only)
      Returns the function's name

      property Body: string (read only)
      Returns the function's body (the code, if a script defined function)

      property Native: Boolean (read only)
      Returns True if the function is a native function or False if it is a
      script defined function

      property FunctionProc: TLILFunctionProc (read only)
      Returns the function procedure if the function is a native function

      property Arguments: Integer (read only)
      Returns the number of arguments this function accepts (for script
      defined functions only)

      property Argument[AIndex: Integer]: string (ready only)
      Returns the argument name at AIndex (for script defined functions only)

2.6. TLIL
     ----
   This class is the most important class for FPLIL and the "entry" to using
 LIL in a Free Pascal program.  It represent a LIL runtime and it is a
 TComponent descendant so it can be used as a FCL/LCL component.  The public
 functions and properties are:

      class function AllocString(Str: string): TLILValue;
      Allocate a string value

      class function AllocInteger(Int: Int64): TLILValue;
      Allocate an integer value

      class function AllocFloat(Float: Extended): TLILValue;
      Allocate a floating point number value

      class function AllocBoolean(Bool: Boolean): TLILValue;
      Allocate a boolean value

      class function ToString(AValue: TLILValue): string;
      Returns the value as a string or an empty string if the value is nil

      class function ToInteger(AValue: TLILValue): Int64;
      Returns the value as an integer or 0 if the value is nil

      class function ToFloat(AValue: TLILValue): Extended;
      Returns the value as a floating point number or 0 if the value is nil

      class function ToBoolean(AValue: TLILValue): Boolean;
      Returns the value as a boolean or False if the value is nil

      procedure SetError(AErrorMessage: string);
      Set an error message (it will be captured by 'try' later, if it is set)

      procedure Register(AName: string; AProc: TLILFunctionProc);
      Register a native LIL function with the given name and function
      procedure.  The related TLILFunctionProc and TLILFunctionProcTypes are
      defined as:
        TLILFunctionProcArgs = array of TLILValue;
        TLILFunctionProc = function(LIL: TLIL; Args: TLILFunctionProcArgs):
                           TLILValue;
      The native function will be called with the passed arguments in Args and
      will have to return a LIL value (allocated with one of the TLIL.Alloc???
      functions above) or nil if the function is not to return a value (or
      returns an empty/False value)

      function GetFunction(AName: string): TLILFunction;
      Returns the function object for the function with the given name or nil
      if no such function exists

      function SetVar(AName: string; AValue: TLILValue; Locality:
                      Locality: TLILSetVarLocality): TLILVariable;
      Sets the given variable to the given value.  The Locality parameter is
      used to decide the scope of the variable and can be one of:
        lsvlGlobal   - If the variable does not exist, create a global one
        lsvlLocal    - If the variable does not exist, create a local one
        lsvlLocalNew - Always create a new local variable even if it exists
      The function returns the variable's object

      function GetVar(AName: string; DefaultValue: TLILValue=nil): TLILValue;
      Returns the value of the given variable at the current scope or the given
      default value if no variable with the given name is found

      function FindVar(AName: string): TLILVariable;
      Returns the variable object for the variable with the given name or nil if
      there is no variable with that given name.  This may return both global and
      local variables

      function FindGlobal(AName: string): TLILVariable;
      Similar to FindVar, but only looks for global variables

      function UnusedName(Part: string): string;
      Returns an unused name (both in functions and variables).  The Part
      parameter is used as part of the name

      function PushEnv;
      Push the current environment down the environment stack and create a new
      one at the top.  Use this before calling LIL code from a LIL native
      function to cause any local variable defined in the code be lost in the
      next call to PopEnv

      function PopEnv;
      Pop the environment from the environment stack and delete it.  PushEnv
      and PopEnv must always match each other

      function SubstituteToList(ACode: TLILValue): TLILList;
      Perform a single substitution pass on the given code and return the words
      that make up the code in the given LIL list.  See the C LIL documentation
      for how substitution is done

      function SubstituteToValue(ACode: TLILValue): TLILValue;
      Like SubstituteToList but encodes the list to a value

      function EvaluateExpression(ACode: string): TLILValue;
      Evaluate the expression in the given string like the expr function does

      function EvaluateExpressionValue(AValue: TLILValue): TLILValue;
      Evaluate the epxression in the given value like the expr function does

      function Parse(ACommand: string; FuncLevel: Boolean=False): TLILValue;
      Parse and execute the LIL code in ACommand and return it's result.  The
      FuncLevel determines what the "result" is supposed to be: if True, the
      result is set using the return function (like in a script defined
      function), otherwise it is the result of the last command.  The value
      must be freed (if not nil)

      function ParseValue(ACmdValue: TLILValue; FuncLevel: Boolean=False):
               TLILValue;
      Like Parse, but uses a lil value for the command

      procedure WriteString(Chars: string);
      Calls OnWrite with the given string, if set, otherwise it writes it to
      the standard output.  The #10 character is parsed as a newline character
      for compatibility with C LIL.

      function ToString: string;
      Simply returns '<LIL Runtime>'

      property FuncName: string (read only)
      Returns the currently executed native function name.  This should be
      used only from within native function procedures.

      property Error: Boolean (read only)
      Returns True if there was an error in the last call to Parse/ParseValue

      property ErrorHead: Integer (read only)
      Returns the character where the error occured.  The character is in the
      string passed to Parse/ParseValue

      property ErrorMessage: string (read only)
      Returns the error message

      property Data: Pointer (read write)
      Custom data pointer

      property EvaluatedCode: string (published read only)
      The code that is currently being evaluated (this can be used in error
      reporting alongside the reported position)

   The class also defines the following events:

      OnExit(LIL: TLIL; Arg: TLILValue)
      Called when the exit function is called.  If this is not set, the Halt
      function will be called.  The Arg parameter is the first argument passed
      to the exit function

      OnWrite(LIL: TLIL; Chars: string)
      Called when the write or print LIL function or TLIL.WriteString method
      is called.  The #10 character is used for newline by print.  If this
      is not set, the Write/WriteLn functions are used

      OnRead(LIL: TLIL; AFileName: string; out AContent: string)
      Called when the read or source (when the OnSource is not set) function
      is called to read the text from the given file in the AContent parameter
      (it is expected that if the read fails, the AContent will be set to an
      empty string).  If this is not set, the Assign/Reset/Close functions are
      used

      OnStore(LIL: TLIL; AFileName, AContent: string)
      Called when the store function is called to store the given content to
      the given filename.  If not set, the Assign/Rewrite/Close functions are
      used

      OnSource(LIL: TLIL; AFileName: string; out AContent: string)
      Like OnRead, but called only when the source function is called.  If not
      set, the OnRead handler is called and if that isn't set either, then the
      Assign/Reset/Close functions are used

      OnError(LIL: TLIL; APosition: Integer; AMessage: string)
      Called when an error occurs at the passed position with the passed
      message

      OnSetVar(LIL: TLIL; AName: string; const AValue: TLILValue;
               var AReplacement: TLILValue;
               var ASetVarAction: TLILOnSetVarAction)
      Called each time before a variable is set for the host program to
      inspect the variable's name and value and decide what to do with it using
      the ASetVarAction parameter.  The parameter can take one of the following
      values:
        losaDefault - default action (store the value to the variable normally)
        losaReplace - store the AReplacement value to the variable
        losaIgnore  - do nothing (if the variable isn't set it won't be made)

      OnGetVar(LIL: TLIL; AName: string; const AValue: TLILValue;
               var AReplacement: TLILValue;
               var AGetVarAction: TLILOnGetVarAction)
      Called each time a variable is about to be read for the host program to
      inspect the variable's name and value and decide what to do with it using
      the AGetVarAction parameter.  The parameter can take one of the following
      values:
        logaDefault - default action (return the variable's value)
        logaReplace - return the AReplacement value
      

3. Integrating FPLIL in Free Pascal programs
--------------------------------------------
   To use FPLIL simply create a TLIL instance like

      var LIL: TLIL;

      LIL:=TLIL.Create(nil);
   
   To register a custom function, use LIL.Register, like

      function FncMul(LIL: TLIL; Args: TLILFunctionProcArgs): TLILValue;
      begin
        if Length(Args) < 2 then exit(nil);
        Result:=TLIL.AllocFloat(TLIL.ToFloat(Args[0])*TLIL.ToFloat(Args[1]));
      end;

      LIL.Register('mul', @FncMul);

   To execute some LIL code, use LIL.Parse, like

      LIL.Parse('print [mul 3 4]').Free;

   See the example.pas for a complete example with the above.


4. Contact
----------
  Kostas Michalopoulos
  badsector@runtimeterror.com
  badsectoracula@gmail.com

  also see http://runtimeterror.com/rep/lil
