(********************************************************************)
(*                                                                  *)
(*  progs.s7i     Program handling support library                  *)
(*  Copyright (C) 1991 - 1994, 2004 - 2015, 2020  Thomas Mertes     *)
(*                2021, 2024  Thomas Mertes                         *)
(*                                                                  *)
(*  This file is part of the Seed7 Runtime Library.                 *)
(*                                                                  *)
(*  The Seed7 Runtime Library is free software; you can             *)
(*  redistribute it and/or modify it under the terms of the GNU     *)
(*  Lesser General Public License as published by the Free Software *)
(*  Foundation; either version 2.1 of the License, or (at your      *)
(*  option) any later version.                                      *)
(*                                                                  *)
(*  The Seed7 Runtime Library 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.  See the GNU Lesser General Public License for more    *)
(*  details.                                                        *)
(*                                                                  *)
(*  You should have received a copy of the GNU Lesser General       *)
(*  Public License along with this program; if not, write to the    *)
(*  Free Software Foundation, Inc., 51 Franklin Street,             *)
(*  Fifth Floor, Boston, MA  02110-1301, USA.                       *)
(*                                                                  *)
(********************************************************************)


include "category.s7i";
include "bstring.s7i";
include "bigint.s7i";
include "float.s7i";
include "external_file.s7i";
include "graph.s7i";
include "poll.s7i";
include "process.s7i";


(**
 *  Type to describe a Seed7 program.
 *)
const type: program is subtype object;


IN_PARAM_IS_REFERENCE(program);

const proc: (ref program: dest) ::= (ref program: source)                is action "PRG_CREATE";
const proc: destroy (ref program: aValue)                                is action "PRG_DESTR";
const proc: (inout program: dest) := (ref program: source)               is action "PRG_CPY";

const func program: _GENERATE_EMPTY_PROG                                 is action "PRG_EMPTY";
const program: (attr program) . EMPTY                                    is _GENERATE_EMPTY_PROG;


(**
 *  Default value of ''program'' (program.EMPTY).
 *)
const program: (attr program) . value                                    is program.EMPTY;


(**
 *  Check if two ''program'' values are equal.
 *  @return TRUE if both values are equal, FALSE otherwise.
 *)
const func boolean: (in program: prog1) = (in program: prog2)            is action "PRG_EQ";


(**
 *  Check if two ''program'' values are not equal.
 *  @return FALSE if both values are equal, TRUE otherwise.
 *)
const func boolean: (in program: prog1) <> (in program: prog2)           is action "PRG_NE";


(**
 *  Returns the name of ''aProgram'' without path and extension.
 *  This function does not follow symbolic links.
 *  It determines, with which name a program was called.
 *  If a symbolic link refers to a program, the name of
 *  the symbolic link is returned.
 *  @return the name of the program.
 *)
const func string: name (in program: aProgram)                           is action "PRG_NAME";


(**
 *  Return the absolute path of the program ''aProgram''.
 *  This function does follow symbolic links.
 *  @return the absolute path of the program.
 *)
const func string: path (in program: aProgram)                           is action "PRG_PATH";


const type: singleParseOption is new enum
    TRACE_ACTIONS,         # Trace primitive actions
    TRACE_DO_ACTION_CHECK, # Do action check
    TRACE_DYNAMIC_CALLS,   # Trace dynamic calls
    TRACE_EXCEPTIONS,      # Trace exceptions and handlers
    TRACE_HEAP_SIZE,       # Trace heap size
    TRACE_MATCH,           # Trace matching expressions
    TRACE_EXECUTIL,        # Trace exec utility functions
    WRITE_LIBRARY_NAMES,   # Write a list of include libraries
    WRITE_LINE_NUMBERS,    # Write line numbers, while analyzing
    SHOW_IDENT_TABLE,      # Show the identifier table after the analyzing phase
    SHOW_STATISTICS        # Show compilation statistics
  end enum;

const type: parseOptions is set of singleParseOption;


(**
 *  Parse the file with the given ''fileName'', ''options'', ''libraryDirs'' and ''protFileName''.
 *  @return the parsed program.
 *  @exception RANGE_ERROR ''fileName'' does not use the standard path
 *             representation or ''fileName'' is not representable in
 *             the system path type.
 *  @exception MEMORY_ERROR An out of memory situation occurred.
 *)
const func program: parseFile (in string: fileName, in parseOptions: options,
                               in array string: libraryDirs,
                               in string: protFileName)                  is action "PRG_FIL_PARSE";


(**
 *  Parse the file with the given ''fileName'', ''options'' and ''libraryDirs''.
 *  @return the parsed program.
 *  @exception RANGE_ERROR ''fileName'' does not use the standard path
 *             representation or ''fileName'' is not representable in
 *             the system path type.
 *  @exception MEMORY_ERROR An out of memory situation occurred.
 *)
const func program: parseFile (in string: fileName, in parseOptions: options,
                               in array string: libraryDirs) is
  return parseFile(fileName, options, libraryDirs, "");


(**
 *  Parse the file with the given ''fileName'' and ''options''.
 *  @return the parsed program.
 *  @exception RANGE_ERROR ''fileName'' does not use the standard path
 *             representation or ''fileName'' is not representable in
 *             the system path type.
 *  @exception MEMORY_ERROR An out of memory situation occurred.
 *)
const func program: parseFile (in string: fileName, in parseOptions: options) is
  return parseFile(fileName, options, 0 times "", "");


(**
 *  Parse the file with the given ''fileName''.
 *  @return the parsed program.
 *  @exception RANGE_ERROR ''fileName'' does not use the standard path
 *             representation or ''fileName'' is not representable in
 *             the system path type.
 *  @exception MEMORY_ERROR An out of memory situation occurred.
 *)
const func program: parseFile (in string: fileName) is
  return parseFile(fileName, parseOptions.value, 0 times "", "");


(**
 *  Parse the given ''string'' with ''options', ''libraryDirs'' and ''protFileName''.
 *  @return the parsed program.
 *  @exception MEMORY_ERROR An out of memory situation occurred.
 *)
const func program: parseStri (in string: stri, in parseOptions: options,
                               in array string: libraryDirs,
                               in string: protFileName)                  is action "PRG_STR_PARSE";


(**
 *  Parse the given ''string'' with ''options' and ''libraryDirs''.
 *  @return the parsed program.
 *  @exception MEMORY_ERROR An out of memory situation occurred.
 *)
const func program: parseStri (in string: stri, in parseOptions: options,
                               in array string: libraryDirs) is
  return parseStri(stri, options, libraryDirs, "");


(**
 *  Parse the given ''string'' with ''options'.
 *  @return the parsed program.
 *  @exception MEMORY_ERROR An out of memory situation occurred.
 *)
const func program: parseStri (in string: stri, in parseOptions: options) is
  return parseStri(stri, options, 0 times "", "");


(**
 *  Parse the given ''string''.
 *  @return the parsed program.
 *  @exception MEMORY_ERROR An out of memory situation occurred.
 *)
const func program: parseStri (in string: stri) is
  return parseStri(stri, parseOptions.value, 0 times "", "");


(**
 *  Evaluate ''anExpression'' which is part of ''aProgram''.
 *  @return the result of the evaluation.
 *)
const func reference: evaluate (in program: aProgram,
                                in reference: anExpression)              is action "PRG_EVAL";


(**
 *  Execute ''aProgram'' with the given ''parameters'', ''options'' and ''protFileName''.
 *)
const proc: execute (in program: aProgram, in array string: parameters,
                     in parseOptions: options,
                     in string: protFileName)                            is action "PRG_EXEC";


(**
 *  Execute ''aProgram'' with the given ''parameters'' and ''options''.
 *)
const proc: execute (in program: aProgram, in array string: parameters,
                     in parseOptions: options) is func
  begin
    execute(aProgram, parameters, options, "");
  end func;


(**
 *  Execute ''aProgram'' with the given ''parameters''.
 *)
const proc: execute (in program: aProgram, in array string: parameters) is func
  begin
    execute(aProgram, parameters, parseOptions.value, "");
  end func;


(**
 *  Execute ''aProgram'' with an empty parameter list.
 *)
const proc: execute (in program: aProgram) is func
  begin
    execute(aProgram, 0 times "", parseOptions.value, "");
  end func;


(**
 *  Determine the value of the system variable ''name'' in ''aProgram''.
 *  @return a reference to the value of the system variable or
 *          NIL if no system variable ''name'' exists.
 *)
const func reference: sysVar (in program: aProgram, in string: name)     is action "PRG_SYSVAR";


(**
 *  Determine the number of errors in ''aProgram''.
 *  @return the number of errors.
 *)
const func integer: errorCount (in program: aProgram)                    is action "PRG_ERROR_COUNT";


(**
 *  Determine the list of global defined objects in ''aProgram''.
 *  The returned list contains constant and variable objects
 *  in the same order as the definitions of the source program.
 *  Literal objects and local objects are not part of this list.
 *  @return the list of global defined objects.
 *)
const func ref_list: globalObjects (in program: aProgram)                is action "PRG_GLOBAL_OBJECTS";


(**
 *  Determine object with ''name'' from program ''aProgram''.
 *  @return a reference to the object or NIL if no object ''name'' exists.
 *  @exception MEMORY_ERROR If ''name'' cannot be converted to
 *             the internal representation.
 *)
const func reference: syobject (in program: aProgram, in string: name)   is action "PRG_SYOBJECT";


(**
 *  Determine object from program ''aProgram'' which matches ''expression''.
 *  @return object from program.
 *)
const func reference: match (in program: aProgram, in ref_list: expression) is action "PRG_MATCH";


const func reference: matchExpr (in program: aProgram, in ref_list: expression)  is action "PRG_MATCH_EXPR";
# const func program: get (PROGRAM)                                      is action "PRG_PROG";


(**
 *  Determine if the referenced object is temporary.
 *  @return TRUE if ''aReference'' is temporary, FALSE otherwise.
 *  @exception RANGE_ERROR If ''aReference'' is NIL.
 *)
const func boolean: isTemp (in reference: aReference)                    is action "REF_ISTEMP";


(**
 *  Determine if the referenced object is variable.
 *  @return TRUE if ''aReference'' is a variable, FALSE otherwise.
 *  @exception RANGE_ERROR If ''aReference'' is NIL.
 *)
const func boolean: isVar (in reference: aReference)                     is action "REF_ISVAR";


(**
 *  Set var flag of a referenced object.
 *  @exception RANGE_ERROR If ''aReference'' is NIL.
 *)
const proc: setVar (in reference: aReference, in boolean: isVariable)    is action "REF_SETVAR";


(**
 *  Get the category of a referenced object.
 *  @return the category of the referenced object.
 *  @exception RANGE_ERROR If ''aReference'' is NIL.
 *)
const func category: category (in reference: aReference)                 is action "REF_CATEGORY";


(**
 *  Set the category of ''aReference'' to ''aCategory''.
 *  @exception RANGE_ERROR If ''aReference'' is NIL.
 *)
const proc: setCategory (in reference: aReference,
                         in category: aCategory)                         is action "REF_SETCATEGORY";


(**
 *  Get the formal parameters of the function referenced by ''funcRef''.
 *  For objects without parameters an empty list is returned.
 *  @return the formal parameters as [[ref_list]].
 *  @exception RANGE_ERROR If ''funcRef'' is NIL.
 *  @exception MEMORY_ERROR An out of memory situation occurred.
 *)
const func ref_list: formalParams (in reference: funcRef)                is action "REF_PARAMS";


(**
 *  Set the formal parameters of ''funcRef'' to ''params''.
 *  @exception RANGE_ERROR If ''funcRef'' is NIL.
 *  @exception MEMORY_ERROR An out of memory situation occurred.
 *)
const proc: setFormalParams (in reference: funcRef, in ref_list: params) is action "REF_SETPARAMS";


(**
 *  Gets the result variable of ''funcRef''.
 *  @return a [[reference]] to the result variable.
 *  @exception RANGE_ERROR If ''funcRef'' is NIL or
 *                         category(funcRef) <> BLOCKOBJECT holds.
 *)
const func reference: resultVar (in reference: funcRef)                  is action "REF_RESULT";


(**
 *  Gets the initialization value of the result variable of ''funcRef''.
 *  @return a [[reference]] to the initialization value.
 *  @exception RANGE_ERROR If ''funcRef'' is NIL or
 *                         category(funcRef) <> BLOCKOBJECT holds.
 *)
const func reference: resultInitValue (in reference: funcRef)            is action "REF_RESINI";


(**
 *  Gets the local constants of ''funcRef''.
 *  @return the local constants as [[ref_list]].
 *  @exception RANGE_ERROR If ''funcRef'' is NIL or
 *                         category(funcRef) <> BLOCKOBJECT holds.
 *  @exception MEMORY_ERROR An out of memory situation occurred.
 *)
const func ref_list: localConsts (in reference: funcRef)                 is action "REF_LOCAL_CONSTS";


(**
 *  Gets the local variables of ''funcRef''.
 *  @return the local variables as [[ref_list]].
 *  @exception RANGE_ERROR If ''funcRef'' is NIL or
 *                         category(funcRef) <> BLOCKOBJECT holds.
 *  @exception MEMORY_ERROR An out of memory situation occurred.
 *)
const func ref_list: localVars (in reference: funcRef)                   is action "REF_LOCAL_VARS";


(**
 *  Gets the body of the function referenced by ''funcRef''.
 *  @return the body expression of ''funcRef''.
 *  @exception RANGE_ERROR If ''funcRef'' is NIL or
 *                         category(funcRef) <> BLOCKOBJECT holds.
 *)
const func reference: body (in reference: funcRef)                       is action "REF_BODY";


(**
 *  Obtain the minimum index of the array referenced by 'arrayRef'.
 *  @param arrayRef Reference to an array object.
 *  @return the minimum index of the array.
 *  @exception RANGE_ERROR If 'arrayRef' does not refer to an array.
 *)
const func integer: arrayMinIdx (in reference: arrayRef)                 is action "REF_ARRMINIDX";


(**
 *  Obtain the maximum index of the array referenced by 'arrayRef'.
 *  @param arrayRef Reference to an array object.
 *  @return the maximum index of the array.
 *  @exception RANGE_ERROR If 'arrayRef' does not refer to an array.
 *)
const func integer: arrayMaxIdx (in reference: arrayRef)                 is action "REF_ARRMAXIDX";


(**
 *  Obtain the length of the array referenced by 'arrayRef'.
 *  @param arrayRef Reference to an array object.
 *  @return the length of the array.
 *  @exception RANGE_ERROR If 'arrayRef' does not refer to an array.
 *)
const func integer: arrayLength (in reference: arrayRef) is
    return succ(arrayMaxIdx(arrayRef) - arrayMinIdx(arrayRef));


const func ref_list: arrayToList (in reference: arrayRef)                is action "REF_ARRTOLIST";
const func ref_list: structToList (in reference: structRef)              is action "REF_SCTTOLIST";
const func ref_list: hashDataToList (in reference: hashRef)              is action "REF_HSHDATATOLIST";
const func ref_list: hashKeysToList (in reference: hashRef)              is action "REF_HSHKEYSTOLIST";
const func integer: hashLength (in reference: hashRef)                   is action "REF_HSHLENGTH";
const func reference: interfaceToStruct (in reference: interfaceRef)     is action "REF_ITFTOSCT";


(**
 *  Determine the file name of a referenced object.
 *  @return the file name of the referenced object.
 *  @exception RANGE_ERROR If ''aReference'' is NIL.
 *  @exception MEMORY_ERROR Not enough memory to represent the result.
 *)
const func string: file (in reference: aReference)                     is action "REF_FILE";


(**
 *  Determine the line number of a referenced object.
 *  @return the line number of the referenced object.
 *  @exception RANGE_ERROR If ''aReference'' is NIL.
 *)
const func integer: line (in reference: aReference)                    is action "REF_LINE";


(**
 *  Delivers an unique number for each object
 *  @return a unique object number.
 *  @exception MEMORY_ERROR Not enough memory to maintain the object table.
 *)
const func integer: objNumber (in reference: aReference)               is action "REF_NUM";


const func reference: alloc (in reference: aReference)                 is action "REF_ALLOC";

const func reference: alloc (in boolean: isVar, in type: aType, in integer: number) is action "REF_ALLOC_INT";
const func reference: alloc (in boolean: isVar, in type: aType, in string: stri)    is action "REF_ALLOC_STRI";

const func reference: allocVar (in type: aType, in category: aCategory)      is action "REF_ALLOC_VAR";

const func boolean: getValue (in reference: aReference, attr boolean)        is action "BLN_VALUE";
const func integer: getValue (in reference: aReference, attr integer)        is action "INT_VALUE";
const func char: getValue (in reference: aReference, attr char)              is action "CHR_VALUE";
const func string: getValue (in reference: aReference, attr string)          is action "STR_VALUE";
const func bstring: getValue (in reference: aReference, attr bstring)        is action "BST_VALUE";
const func bitset: getValue (in reference: aReference, attr bitset)          is action "SET_VALUE";
const func pollData: getValue (in reference: aReference, attr pollData)      is action "POL_VALUE";
const func program: getValue (in reference: aReference, attr program)        is action "PRG_VALUE";
const func ACTION: getValue (in reference: aReference, attr ACTION)          is action "ACT_VALUE";
const func clib_file: getValue (in reference: aReference, attr clib_file)    is action "FIL_VALUE";
const func ref_list: getValue (in reference: aReference, attr ref_list)      is action "RFL_VALUE";
const func bigInteger: getValue (in reference: aReference, attr bigInteger)  is action "BIG_VALUE";
const func float: getValue (in reference: aReference, attr float)            is action "FLT_VALUE";
const func reference: getValue (in reference: aReference, attr reference)    is action "REF_VALUE";
const func PRIMITIVE_WINDOW: getValue (in reference: aReference,
                                       attr PRIMITIVE_WINDOW)                is action "DRW_VALUE";
const func pointList: getValue (in reference: aReference, attr pointList)    is action "PLT_VALUE";
const func process: getValue (in reference: aReference, attr process)        is action "PCS_VALUE";
# const func type: getValue (in reference: aReference, attr type)            is action "TYP_VALUE";

const proc: setValue(inout reference: listRef, in ref_list: list)      is action "RFL_SET_VALUE";

const func integer: typeNumber  (in type: aType)                       is action "TYP_NUM";
const func reference: typeObject (in type: aType)                      is action "TYP_MATCHOBJ";