#charset "us-ascii"
#pragma once

/*
 *   Copyright 2000, 2006 Michael J. Roberts.
 *   
 *   This file is part of TADS 3.
 *   
 *   This module defines the fundamental intrinsic classes, including Object,
 *   String, Collection, List, and Iterator.  
 */


/* ------------------------------------------------------------------------ */
/*
 *   TADS datatype codes.  These values are returned by propType(), etc.  
 */
#define TypeNil         1
#define TypeTrue        2
#define TypeObject      5
#define TypeProp        6
#define TypeInt         7
#define TypeSString     8
#define TypeDString     9
#define TypeList        10
#define TypeCode        11
#define TypeFuncPtr     12
#define TypeNativeCode  14
#define TypeEnum        15
#define TypeBifPtr      16


/* ------------------------------------------------------------------------ */
/*
 *   The root object class.  All objects descend from this class. 
 */
intrinsic class Object 'root-object/030004'
{
    /* 
     *   Determine if I'm an instance or subclass of the given class 'cls'.
     *   Note that x.ofKind(x) returns true - an object is of its own kind.  
     */
    ofKind(cls);

    /* get the list of direct superclasses of this object */
    getSuperclassList();

    /* determine if a property is defined or inherited by this object */
    propDefined(prop, flags?);

    /* get the type of a property defined for this object */
    propType(prop);

    /* 
     *   Get a list of my directly-defined properties.  When called on
     *   intrinsic class objects, this returns a list of properties defined
     *   for instances of the class, as well as static properties of the
     *   class.  
     */
    getPropList();

    /* 
     *   get parameter list information for the given method - returns a
     *   list: [minimumArgc, optionalArgc, varargs], where minimumArgc is
     *   the minimum number of arguments, optionalArgc is the number of
     *   additional optional arguments, and varargs is true if the function
     *   takes a varying number of arguments greater than or equal to the
     *   minimum, nil if not.  
     */
    getPropParams(prop);

    /* 
     *   determine if I'm a "class" object - returns true if the object was
     *   defined with the "class" keyword, nil otherwise 
     */
    isClass();

    /* 
     *   Determine if a property is inherited further from the given object.
     *   definingObj is usually the value of the 'definingobj'
     *   pseudo-variable, and origTargetObj is usually the value of the
     *   'targetobj' pseudo-variable.  
     */
    propInherited(prop, origTargetObj, definingObj, flags?);

    /* determine if this instance is transient */
    isTransient();
}

/*
 *   propDefined() flags 
 */
#define PropDefAny           1
#define PropDefDirectly      2
#define PropDefInherits      3
#define PropDefGetClass      4

/* export the objToString method */
property objToString;
export objToString 'objToString';


/* ------------------------------------------------------------------------ */
/*
 *   The IntrinsicClass intrinsic class.  Objects of this type represent the
 *   intrinsic classes themselves.  
 */
intrinsic class IntrinsicClass 'intrinsic-class/030001': Object
{
    /*
     *   Class method: is the given value an IntrinsicClass object?  This
     *   returns true if so, nil if not.  
     *   
     *   It's not possible to determine if an object is an IntrinsicClass
     *   object using x.ofKind(IntrinsicClass) or via x.getSuperclassList().
     *   This is because those methods traverse the nominal class tree:
     *   [1,2,3] is a List, and List is an Object.  However, List and Object
     *   themselves are represented by IntrinsicClass instances, and it's
     *   occasionally useful to know if you're dealing with such an object.
     *   That's where this method comes in.
     *   
     *   This method returns nil for instances of an intrinsic class.  For
     *   example, isIntrinsicClass([1,2,3]) returns nil, because [1,2,3] is a
     *   List instance.  If you get the superclass list for [1,2,3], though,
     *   that will be [List], and isIntrinsicClass(List) returns true.
     */
    isIntrinsicClass(obj);
}

/*
 *   Intrinsic class modifier object (for internal compiler use only) 
 */
intrinsic class IntrinsicClassModifier 'int-class-mod/030000'
{
}

/* ------------------------------------------------------------------------ */
/*
 *   The native collection type - this is the base class for lists, vectors,
 *   and other objects that represent collections of values.  
 */
intrinsic class Collection 'collection/030000': Object
{
    /* 
     *   Create an iterator for the collection.  This returns a new Iterator
     *   object that can be used to iterate over the values in the
     *   collection.  The Iterator will use a snapshot of the collection that
     *   will never change, even if the collection is changed after the
     *   iterator is created.  
     */
    createIterator();

    /*
     *   Create a "live iterator" for the collection.  This returns a new
     *   Iterator object that refers directly to the original collection; if
     *   the original collection changes, the iterator will reflect the
     *   changes in its iteration.  As a result, the iterator is not
     *   guaranteed to visit all of the elements in the collection if the
     *   collection changes during the course of the iteration.  If
     *   consistent results are required, use createIterator() instead.  
     */
    createLiveIterator();
}

/* ------------------------------------------------------------------------ */
/*
 *   The native iterator type - this is the base class for all iterators.
 *   This class is abstract and is thus never directly instantiated.
 *   
 *   Note that iterators can never be created directly with the 'new'
 *   operator.  Instead, iterators must be obtained from a collection via the
 *   collection's createIterator() method.  
 */
intrinsic class Iterator 'iterator/030001': Object
{
    /*
     *   Get the next item in the collection.  This returns the next item's
     *   value, and advances the internal state in the iterator so that a
     *   subsequent call to getNext() returns the next item after this one.
     *   When the iterator is first created, or after calling
     *   resetIterator(), this returns the first item in the collection.  
     */
    getNext();

    /*
     *   Determine if the collection is out of items.  Returns true if
     *   getNext() will return a valid item, nil if no more items are
     *   available.  
     */
    isNextAvailable();

    /*
     *   Reset to the first item.  After calling this routine, the next call
     *   to getNext() will return the first item in the collection.  
     */
    resetIterator();

    /*
     *   Get the current key.  This returns the value of the key for the
     *   current item in the collection.  For an indexed collection, this
     *   returns the index value; for a keyed collection, this returns the
     *   current key value.  
     */
    getCurKey();

    /*
     *   Get the current value.  This returns the value of the current item
     *   in the collection. 
     */
    getCurVal();
}

/*
 *   Indexed object iterator - this type of iterator is used for lists,
 *   vectors, and other indexed collection objects.  
 */
intrinsic class IndexedIterator 'indexed-iterator/030000': Iterator
{
}


/* ------------------------------------------------------------------------ */
/*
 *   AnonFuncPtr depends on Vector 
 */
#include "vector.h"

/*
 *   Anonymous function pointer intrinsic class 
 */
intrinsic class AnonFuncPtr 'anon-func-ptr': Vector
{
}


/* ------------------------------------------------------------------------ */
/*
 *   The "TADS Object" intrinsic class.  All objects that the program
 *   defines with the "class" or "object" statements descend from this
 *   class.  
 */
intrinsic class TadsObject 'tads-object/030005': Object
{
    /* 
     *   Create an instance of this object: in other words, create a new
     *   object whose superclass is this object.  The arguments provided are
     *   passed to the new object's constructor.  This method returns a
     *   reference to the new object.  
     */
    createInstance(...);

    /*
     *   Create a clone of this object.  This creates an exact copy, with
     *   the same property values, as the original.  This does not call any
     *   constructors; it merely instantiates an exact copy of the original.
     *   
     *   Note that the clone is a "shallow" copy, which means that any
     *   objects it references are not themselves cloned.
     */
    createClone();

    /*
     *   Create a transient instance of this object.  This works just like
     *   createInstance(), but creates a transient instance instead of an
     *   ordinary (persistent) instance.  
     */
    createTransientInstance(...);

    /*
     *   Create an instance of an object based on multiple superclasses.
     *   Each argument gives a superclass, and optionally arguments for
     *   invoking the superclass constructor.  If an argument is given as
     *   simply a class, then we don't invoke that superclass's constructor;
     *   if the argument is given as a list, the first element of the list is
     *   the class, and the remaining elements of the list are arguments for
     *   that superclass's constructor.  The arguments are specified in the
     *   same order they would be to define the object, so the first argument
     *   is the dominant superclass.
     *   
     *   For example, suppose we created a class definition like this:
     *   
     *   class D: A, B, C
     *.    construct(x, y)
     *.    {
     *.      inherited A(x);
     *.      inherited C(y);
     *.    }
     *.  ;
     *   
     *   We could obtain the same effect dynamically like so:
     *   
     *   local d = TadsObject.createInstanceOf([A, x], B, [C, y]);
     *   
     *   Note that only *actual* lists are interpreted as constructor
     *   invokers here.  A list-like object (with operator[] and length()
     *   methods) will be treated as a simple superclass, since otherwise it
     *   wouldn't be possible to specify the no-constructor format for such a
     *   superclass.  
     */
    static createInstanceOf(...);

    /*
     *   Create a transient instance based on multiple superclasses.  This
     *   works just like createInstanceOf(), but creates a transient
     *   instance. 
     */
    static createTransientInstanceOf(...);

    /*
     *   Set the superclass list.  scList is a list giving the new
     *   superclasses.  The superclasses must all be TadsObject objects, with
     *   one exception: the list [TadsObject] may be passed to create an
     *   object based directly on TadsObject.  No other intrinsic classes can
     *   be used in the list, and objects of other types cannot be used in
     *   the list.  
     */
    setSuperclassList(scList);

    /* 
     *   Get a method value.  If the property is a method, this returns a
     *   function pointer to the method; this does NOT evaluate the method.
     *   If the property is not a method, this returns nil.
     *   
     *   The returned function pointer can be called like an ordinary
     *   function, but such a call will have no 'self' value, so the
     *   disembodied method won't be able to refer to properties or methods
     *   of 'self'.  The main use of this method is to get a method of one
     *   object to assign as a method of another object using setMethod().  
     */
    getMethod(prop);

    /*
     *   Set a method value.  Assigns the given function (which must be a
     *   function pointer value) to the given property of 'self'.  This
     *   effectively adds a new method to the object.
     *   
     *   The function can be an ordinary named function, or a method pointer
     *   retrieved from this object or from another object with getMethod().
     *   Anonymous functions are NOT allowed here.  
     */
    setMethod(prop, func);
}


/* ------------------------------------------------------------------------ */
/* 
 *   We need CharacterSet and ByteArray (for String.mapToByteArray).  (But
 *   wait to include these until after we've defined Object, since everything
 *   depends on Object.)  
 */
#include "charset.h"
#include "bytearr.h"

/* ------------------------------------------------------------------------ */
/*
 *   The native string type. 
 */
intrinsic class String 'string/030008': Object
{
    /* get the length of the string */
    length();

    /* extract a substring */
    substr(start, len?);

    /* convert to upper case */
    toUpper();

    /* convert to lower case */
    toLower();

    /* 
     *   Find a substring or pattern within the subject string (self),
     *   searching the string from left to right returning the index of the
     *   first match found.  If 'str' is a string, this searches for an exact
     *   match to the substring.  If 'str' is a RexPattern object, this
     *   searches for a match to the pattern.  Returns the character index of
     *   the start of the match if found (the first character is at index 1),
     *   or nil if no match is found.
     *   
     *   'index' is the optional starting index for the search.  the first
     *   character is at index 1; a negative index specifies an offset from
     *   the end of the string, with -1 indicating the last character, -2 the
     *   second to last, and so on.  If 'index' is omitted, the search starts
     *   at the first character.  Note that the search proceeds from left to
     *   right even if 'index' is negative - a negative starting index is
     *   just a convenience to specify an offset from the end of the string,
     *   but the search still proceeds in the same direction.
     *   
     *   (Note: "left to right" in this context simply means from lower to
     *   higher character index in the string.  We're using the term loosely,
     *   in particular ignoring anything related to the reading order or
     *   display direction for different languages or scripts.)
     */
    find(str, index?);

    /* 
     *   convert to a list of Unicode character codes, or get the Unicode
     *   character code for the single character at the given index 
     */
    toUnicode(idx?);

    /* htmlify a string */
    htmlify(flags?);

    /* determine if we start with the given string */
    startsWith(str);

    /* determine if we end with the given string */
    endsWith(str);

    /* 
     *   Map to a byte array, converting to the given character set.  If
     *   'charset' is provided, it must be an object of intrinsic class
     *   CharacterSet, or a string giving the name of a character set.  The
     *   characters in the string are mapped from the internal Unicode
     *   representation to the appropriate byte representation in the given
     *   character set.  Any unmappable characters are replaced with the
     *   usual default/missing character for the set, as defined by the
     *   mapping.
     *   
     *   If 'charset' is omitted or nil, the byte array is created simply by
     *   treating the Unicode character code of each character in the string
     *   as a byte value.  A byte can only hold values from 0 to 255, so a
     *   numeric overflow error is thrown if any character code in the source
     *   string is outside this range.
     *   
     */
    mapToByteArray(charset?);

    /* 
     *   Replace one occurrence or all occurrences of the given substring
     *   with the given new string.
     *   
     *   'self' is the subject string, which we search for instances of the
     *   replacement.
     *   
     *   'origStr' is the string to search for within 'self'.  This is
     *   treated as a literal text substring to find within 'self'.
     *   'origStr' can alternatively be a RexPattern object, in which case
     *   the regular expression is matched.
     *   
     *   'newStr' is the replacement text, as a string.  'newStr' can
     *   alternatively be a function (regular or anonymous) instead of a
     *   string.  In this case, it's invoked as 'newStr(match, index, orig)'
     *   for each match where 'match' is the matching text, 'index' is the
     *   index within the original subject string of the match, and 'orig' is
     *   the full original subject string.  This function must return a
     *   string value, which is used as the replacement text.  Using a
     *   function allows greater flexibility in specifying the replacement,
     *   since it can vary the replacement according to the actual text
     *   matched and its position in the subject string.
     *   
     *   'flags' is a combination of ReplaceXxx flags specifying the search
     *   options.  It's optional; if omitted, the default is ReplaceAll.
     *   
     *   ReplaceOnce and ReplaceAll are mutually exclusive; they mean,
     *   respectively, that only the first occurrence of the match should be
     *   replaced, or that every occurrence should be replaced.  ReplaceOnce
     *   and ReplaceAll are ignored if a 'limit' value is specified (this is
     *   true even if 'limit' is nil, which means that all occurrences are
     *   replaced).
     *   
     *   'index' is the starting index within 'self' for the search.  If this
     *   is given, we'll ignore any matches that start before the starting
     *   index.  If 'index' is omitted, we start the search at the beginning
     *   of the string.  If 'index' is negative, it's an index from the end
     *   of the string: -1 is the last character, -2 the second to last, etc.
     *   
     *   'origStr' can be given as a list of search strings, rather than a
     *   single string.  In this case, we'll search for each of the strings
     *   in the list, and replace each one with 'newStr'.  If 'newStr' is
     *   also a list, each match to an element of the 'origStr' list is
     *   replaced with the corresponding element (at the same index) of the
     *   'newStr' list.  If there are more 'origStr' elements than 'newStr'
     *   elements, each match to an excess 'origStr' element is replaced with
     *   an empty string.  This allows you to perform several replacements
     *   with a single call.
     *   
     *   'limit', if specified, is an integer indicating the maximum number
     *   of matches to replace, or nil to replace all matches.  If the limit
     *   is reached before all matches have been replaced, no further
     *   replacements are performed.  If this parameter is specified, it
     *   overrides any ReplaceOnce or ReplaceAll flag.
     *   
     *   There are two search modes when 'origStr' is a list.  The default is
     *   "parallel" mode.  In this mode, we search for all of the 'origStr'
     *   elements, and replace the leftmost match.  We then search the
     *   remainder of the string, after this first match, again searching for
     *   all of the 'origStr' elements.  Again we replace the leftmost match.
     *   We repeat this until we run out of matches.
     *   
     *   The other option is "serial" mode, which you select by including
     *   ReplaceSerial in the flags argument.  In serial mode, we start by
     *   searching only for the first 'origStr' element.  We replace each
     *   occurrence throughout the string (unless we're in ReplaceOnce mode,
     *   in which case we stop after the first replacement).  If we're in
     *   ReplaceOnce mode and we did a replacement, we're done.  Otherwise,
     *   we start over with the updated string, containing the replacements
     *   so far, and search it for the second 'origStr' element, replacing
     *   each occurrence (or just the first, in ReplaceOnce mode).  We repeat
     *   this for each 'origStr' element.
     *   
     *   The key difference between the serial and parallel modes is that the
     *   serial mode re-scans the updated string after replacing each
     *   'origStr' element, so replacement text could itself be further
     *   modified.  Parallel mode, in contrast, never re-scans replacement
     *   text.  
     */
    findReplace(origStr, newStr, flags?, index?, limit?);

    /*
     *   Splice: delete 'del' characters starting at 'idx', and insert the
     *   string 'ins' in their place.  'ins' is optional; if omitted, this
     *   simply does the deletion without inserting anything.  
     */
    splice(idx, del, ins?);

    /*
     *   Split the string into substrings at the given delimiter, or of a
     *   given fixed length.
     *   
     *   'delim' is the delimiter.  It can be one of the following:
     *   
     *   - A string or RexPattern, giving the delimiter where we split the
     *   string.  We search 'self' for matches to this string or pattern, and
     *   split it at each instance we find, returning a list of the resulting
     *   substrings.  For example, 'one,two,three'.split(',') returns the
     *   list ['one', 'two', 'three'].  The delimiter separates parts, so
     *   it's not part of the returned substrings.
     *   
     *   - An integer, giving a substring length.  We split the string into
     *   substrings of this exact length (except that the last element will
     *   have whatever's left over).  For example, 'abcdefg'.split(2) returns
     *   ['ab', 'cd', 'ef', 'g'].
     *   
     *   If 'delim' is omitted or nil, the default is 1, so we'll split the
     *   string into one-character substrings.
     *   
     *   If 'limit' is included, it's an integer giving the maximum number of
     *   elements to return in the result list.  If we reach the limit, we'll
     *   stop the search and return the entire rest of the string as the last
     *   element of the result list.  If 'limit' is 1, we simply return a
     *   list consisting of the source string, since a limit of one element
     *   means that we can't make any splits at all.  
     */
    split(delim?, limit?);

    /*
     *   Convert special characters and TADS markups to standard HTML
     *   markups.  Returns a new string with the contents of the 'self'
     *   string processed as described below.
     *   
     *   'stateobj' is an object containing the state of the output stream.
     *   This allows an output stream to process its contents a bit at a
     *   time, by maintaining the state of the stream from one call to the
     *   next.  This object gives the prior state of the stream on entry, and
     *   is updated on return to contain the new state after processing this
     *   string.  If this is omitted or nil, a default initial starting state
     *   is used.  The function uses the following properties of the object:
     *   
     *   stateobj.flags_ is an integer with a collection of flag bits giving
     *   the current line state
     *   
     *   stateobj.tag_ is a string containing the text of the tag currently
     *   in progress.  If the string ends in the middle of a tag, this will
     *   be set on return to the text of the tag up to the end of the string,
     *   so that the next call can resume processing the tag where the last
     *   call left off.
     *   
     *   
     *   The function makes the following conversions:
     *   
     *   \n -> <BR>, or nothing at the start of a line
     *   
     *   \b -> <BR> at the start of a line, or <BR><BR> within a line
     *   
     *   \ (quoted space) -> &nbsp; if followed by a space or another quoted
     *   space, or an ordinary space if followed by a non-space character
     *   
     *   \t -> a sequence of &nbsp; characters followed by a space, padding
     *   to the next 8-character tab stop.  This can't take into account the
     *   font metrics, since that's determined by the browser, so it should
     *   only be used with a monospaced font.
     *   
     *   \^ -> sets an internal flag to capitalize the next character
     *   
     *   \v -> sets an internal flag to lower-case the next character
     *   
     *   <Q> ... </Q> -> &ldquo; ... &rdquo; or &lsquo; ... &rsquo;,
     *   depending on the nesting level
     *   
     *   <BR HEIGHT=N> -> N <BR> tags if at the start of a line, N+1 <BR>
     *   tags if within a line
     *   
     *   
     *   Note that this isn't a general-purpose HTML corrector: it doesn't
     *   correct ill-formed markups or standardize deprecated syntax or
     *   browser-specific syntax.  This function is specifically for
     *   standardizing TADS-specific syntax, so that games can use the
     *   traditional TADS syntax with the Web UI.  
     */
    specialsToHtml(stateobj?);

    /*
     *   Convert special characters and HTML markups to plain text, as it
     *   would appear if written out through the regular console output
     *   writer and displayed on a plain text terminal.  Returns a new string
     *   with the contents of the 'self' string processed as described below.
     *   This works very much like specialsToHtml(), but rather than
     *   generating standard HTML output, we generate plain text output.
     *   
     *   'stateobj' has the same meaning asin specialsToHtml().  
     *   
     *   The function makes the following conversions:
     *   
     *   \n -> \n, or nothing at the start of a line
     *   
     *   \b -> \n at the start of a line, or \n\n within a line
     *   
     *   \ (quoted space) -> regular space
     *   
     *   \^ -> sets an internal flag to capitalize the next character
     *   
     *   \v -> sets an internal flag to lower-case the next character
     *   
     *   <Q> ... </Q> -> "..." or '...' depending on the quote nesting level
     *   
     *   <BR HEIGHT=n> -> N \n characters at the start of a line, N+1 \n
     *   characters within a line
     *   
     *   <P> -> \n at the start of a line, \n\n within a line
     *   
     *   <TAG> -> nothing for all other tags
     *   
     *   &amp; -> &
     *   
     *   &lt; -> <
     *   
     *   &gt; -> >
     *   
     *   &quot; -> "
     *   
     *   &ldquo; and &rdquo; -> "
     *   
     *   &lsquo; and &rsquo; -> '
     *   
     *   &#dddd; -> Unicode character dddd 
     */
    specialsToText(stateobj?);

    /*
     *   Encode a URL parameter string.  Spaces are encoded as "+", and all
     *   other non-alphanumeric characters except - and _ are encoded as
     *   "%xx" sequences.  
     */
    urlEncode();
    
    /*
     *   Decode a URL parameter string.  This reverses the effect of
     *   urlEncode(), returning a string with the encodings translated back
     *   into ordinary characters.  Any sequences that do not form valid
     *   UTF-8 characters are converted to '?'.  
     */
    urlDecode();

    /*
     *   Get the SHA-256 hash of the string.  This calculates the 256-bit
     *   Secure Hash Algorithm 2 hash value, returning the hash as a
     *   64-character string of hex digits.  The hash value is computed on
     *   the UTF-8 representation of the string.  
     */
    sha256();

    /*
     *   Get the MD5 digest of the string.  This calculates the 128-bit RSA
     *   MD5 digest value, returning the digest as a 32-character string of
     *   hex digits.  The hash value is computed on the UTF-8 representation
     *   of the string. 
     */
    digestMD5();

    /*
     *   Pack the arguments into bytes, and create a new string from the byte
     *   values.  The characters of the new string correspond to the packed
     *   byte values, so each character will have a Unicode character number
     *   from 0 to 255.
     *   
     *   'format' is a format string describing the packed formats for the
     *   values, and the rest of the arguments are the values to pack into
     *   the string.  Returns a string containing the packed bytes.
     *   
     *   See Byte Packing in the System Manual for more details.  
     */
    static packBytes(format, ...);

    /*
     *   Unpack this string, interpreting the characters in the string as
     *   byte values, and unpacking the bytes according to the format string.
     *   Each character in the string must have a Unicode character number
     *   from 0 to 255; if any characters are outside this range, an error is
     *   thrown.
     *   
     *   This method can be used to unpack a string created with
     *   String.packBytes().  In most cases, using the same format string
     *   that was used to pack the bytes will re-create the original values.
     *   This method can also be convenient for parsing plain text that's
     *   arranged into fixed-width fields.
     *   
     *   'format' is the format string describing the packed byte format.
     *   Returns a list consisting of the unpacked values.
     *   
     *   See Byte Packing in the System Manual for more details.  
     */
    unpackBytes(format);

    /*
     *   Convert each character in the string to title case, according to the
     *   Unicode character database definitions.  Returns a new string with
     *   the title-case version of this string.
     *   
     *   For most characters, title case is the same as upper case.  It
     *   differs from upper case when a single Unicode character represents
     *   more than one printed letter, such as the German sharp S U+00DF, or
     *   the various "ff" and "fi" ligatures.  In these cases, the title-case
     *   conversion consists of the upper-case version of the first letter of
     *   the ligature followed by the lower-case versions of the remaining
     *   characters.  Unicode doesn't define single-character title-case
     *   equivalents of most of the ligatures, so the result is usually a
     *   sequence of the individual characters making up the ligature.  For
     *   example, title-casing the 'ffi' ligature character (U+FB03) produces
     *   the three-character sequence 'F', 'f', 'i'.
     *   
     *   Note that this routine converts every character in the string to
     *   title case, so it's not by itself a full title formatter - it's
     *   simply a character case converter.
     */
    toTitleCase();

    /*
     *   Convert the string to "folded" case.  Returns a new string with the
     *   case-folded version of this string.
     *   
     *   Folded case is used for eliminating case distinctions in sets of
     *   strings, to allow for case-insensitive comparisons, sorting, etc.
     *   This routine produces the case folding defined in the Unicode
     *   character database; in most cases, the result is the same as
     *   converting each original character to upper case and then converting
     *   the result to lower case.  This process not only removes case
     *   differences but also normalizes some variations in the ways certain
     *   character sequences are rendered, such as converting the German
     *   ess-zed U+00DF to "ss", and converting lower-case accented letters
     *   that don't have single character upper-case equivalents to the
     *   corresponding series of composition characters (e.g., U+01F0, a
     *   small 'j' with a caron, turns into U+006A + U+030C, a regular small
     *   'j' followed by a combining caron character).  Without this
     *   normalization, the upper- and lower-case renderings of such
     *   characters wouldn't match.
     */
    toFoldedCase();

    /*
     *   Compare this string to another string, using Unicode character code
     *   points as the collation order.  Returns an integer less than zero if
     *   this string sorts before the other string, zero if they're
     *   identical, or greater than zero if this string sorts after the
     *   other.  This makes the result suitable for use in a sort() callback,
     *   for example.
     *   
     *   Note that if you use the result for sorting text that includes
     *   accented Roman letters, the result order probably won't match the
     *   dictionary order for your language.  Different languages (and even
     *   different countries/cultures sharing a language) have different
     *   rules for dictionary ordering, so collation is inherently language-
     *   specific.  This routine doesn't take language differences into
     *   account; it simply uses the fixed Unicode code point ordering.  The
     *   Unicode ordering for accented characters is somewhat arbitrary,
     *   because the accented Roman characters are arranged into multiple
     *   disjoint blocks that are all separate from the unaccented
     *   characters.  For example, A-caron sorts after Z-caron, which sorts
     *   after A-breve, which sorts after Y-acute, which sorts after A-acute,
     *   which sorts after plain Z. 
     */
    compareTo(str);

    /*
     *   Compare this string to another string, ignoring case.  The two
     *   strings are compared on the basis of the "case folded" versions of
     *   their characters, using the case folding rules from the Unicode
     *   standard (the case folded version of a string is the value returned
     *   by toFoldedCase()).  The return alue is an integer less than zero if
     *   this string sorts before the other string, zero if they're
     *   identical, or greater than zero if this string sorts after the
     *   other. 
     *   
     *   As with compareTo(), this only produces alphabetically correct
     *   sorting order when comparing ASCII strings.
     */
    compareIgnoreCase(str);

    /*
     *   Find the last instance of a substring or pattern within the string,
     *   searching the subject string (self) from right to left (that is,
     *   from the end of the string towards the beginning).  This works like
     *   find(), but searches in the reverse direction.  Returns the index of
     *   the match, or nil if no match is found.
     *   
     *   'str' can be a string or a RexPattern.  If it's a string, we look
     *   for an exact match to the substring.  If it's a RexPattern, we
     *   search for a match to the pattern.
     *   
     *   The optional 'index' specifies the starting index for the search.
     *   This is the index of the character AFTER the last character that's
     *   allowed to be included in the match.  The first character of the
     *   string is at index 1; a negative index indicates an offset from the
     *   end of the string, so -1 is the last character.  0 has the special
     *   meaning of the end of the string, just past the last character in
     *   the string, so you can use 0 (or, equivalently, self.length()+1) to
     *   search the entire string from the end.  For a repeated search, pass
     *   the index of the previous match, since this will find the next
     *   earlier matching substring that doesn't overlap with the previous
     *   match.
     *   
     *   (Note: "right to left" in this context simply means that the search
     *   runs from higher to lower character index in the string.  We're
     *   using the term loosely, in particular ignoring anything related to
     *   the reading order or display direction for different languages or
     *   scripts.)
     */
    findLast(str, index?);

    /*
     *   Find all occurrences of substring or pattern within a string,
     *   returning a list of the results.
     *   
     *   'str' can be a string or RexPattern object.  If it's a string, we
     *   look for exact matches to the substring.  If it's a RexPattern, we
     *   search for matches to the pattern.
     *   
     *   'func' is an optional function used to process the results.  If this
     *   is provided, the function is called once for each match found in the
     *   string.  The function's return value is then placed into the result
     *   list for the overall findAll() result.  The function is called for
     *   each match found as follows: func(match, idx, g1, g2, ...), where
     *   'match' is a string giving the text of the match, 'idx' is an
     *   integer giving the index in the string (self) of the first character
     *   of the match, and the 'gN' arguments are strings giving the text of
     *   the correspondingly numbered capture groups (the parenthesized
     *   groups in a regular expression match).  All of the 'func' arguments
     *   except 'match' are optional: the function can omit them, in which
     *   case the caller doesn't pass them.  If 'func' specifies more 'gN'
     *   capture group parameters than were actually found in the match, nil
     *   is passed for each extra parameter.
     *   
     *   The return value is a list of the results.  If no occurrences of
     *   'str' are found, the result is an empty list.  If 'func' is
     *   specified, each element in the return list is the return value from
     *   calling 'func' for the corresponding match; if 'func' is omitted,
     *   each element in the return list is a string with the text of that
     *   match.
     */
    findAll(str, func?);

    /*
     *   Match the given string or RexPattern object to this string value,
     *   starting at the start of the string or at the given index, if
     *   specified.  If 'str' is a string, we check for a match to the
     *   literal text of the string; if 'str' is a RexPattern, we try to
     *   match the regular expression.  'idx' is the optional starting
     *   position (1 is the first character; negative values are from the end
     *   of the string, with -1 as the last character, -2 as the second to
     *   last, etc).  If 'idx' is omitted, the default is the start of the
     *   string.
     *   
     *   Returns an integer giving the length of the match found if the
     *   string matches 'str', or nil if there's no match.
     *   
     *   The difference between this method and find() is that this method
     *   only checks for a match at the given starting position, without
     *   searching any further in the string, whereas find() searches for a
     *   match at each subsequent character of the string until a match is
     *   found or the string is exhausted.
     */
    match(str, idx?);
}

/*
 *   Flags for String.htmlify 
 */

/* 
 *   translate spaces - each space in a run of multiple spaces is converted
 *   to an &nbsp; sequence 
 */
#define HtmlifyTranslateSpaces    0x0001

/* translate newlines - converts each \n character to a <br> tag */
#define HtmlifyTranslateNewlines  0x0002

/* translate tabs - converts each \t character to a <tab> tag */
#define HtmlifyTranslateTabs      0x0004

/* 
 *   Translate all whitespace characters - translate all spaces, tabs, and
 *   newlines into their HTML equivalents: each space character becomes an
 *   '&nbsp sequence;', each '\n' character becomes a <br> tag; and each
 *   '\t' character becomes a <tab> tag.  
 */
#define HtmlifyTranslateWhitespace \
    (HtmlifyTranslateSpaces | HtmlifyTranslateNewlines | HtmlifyTranslateTabs)


/*
 *   Flags for String.findReplace 
 */
#define ReplaceAll         0x0001
#define ReplaceIgnoreCase  0x0002
#define ReplaceFollowCase  0x0004
#define ReplaceSerial      0x0008
#define ReplaceOnce        0x0010

/* property exports for specialsToHtml's state object */
property flags_, tag_;
export flags_ 'String.specialsToHtml.flags';
export tag_ 'String.specialsToHtml.tag';


/* ------------------------------------------------------------------------ */
/*
 *   The native list type 
 */
intrinsic class List 'list/030008': Collection
{
    /* 
     *   Select a subset of the list: returns a new list consisting only
     *   of the elements for which the callback function 'func' returns
     *   true.  
     */
    subset(func);

    /*
     *   Apply the callback function to each element of this list, and
     *   return a new list consisting of the results.  Effectively maps
     *   the list to a new list using the given function.  Suppose the
     *   original list is
     *   
     *   [x, y, z]
     *   
     *   Then the result list is
     *   
     *   [func(x), func(y), func(z)] 
     */
    mapAll(func);

    /* get the number of elements in the list */
    length();

    /* extract a sublist */
    sublist(start, len?);

    /* intersect with another list */
    intersect(other);

    /* get the index of the first match for the given value */
    indexOf(val);

    /* car/cdr - head/tail of list */
    car();
    cdr();

    /* 
     *   Find the first element for which the given condition is true, and
     *   return the index of the element.  Applies the callback function
     *   (which encodes the condition to evaluate) to each element in
     *   turn, starting with the first.  For each element, if the callback
     *   returns nil, proceeds to the next element; otherwise, stops and
     *   returns the index of the element.  If the callback never returns
     *   true for any element, we'll return nil.  
     */
    indexWhich(cond);

    /* 
     *   Invoke the callback func(val) on each element, in order from first
     *   to last.  No return value.  
     */
    forEach(func);

    /* 
     *   Find the first element for which the given condition is true, and
     *   return the value of the element.  Returns nil if no item
     *   satisfies the condition.  
     */
    valWhich(cond);

    /* find the last element with the given value, and return its index */
    lastIndexOf(val);

    /* 
     *   Find the last element for which the condition is true, and return
     *   the index of the element.  Applies the callback to each element
     *   in turn, starting with the last element and working backwards.
     *   For each element, if the callback returns nil, proceeds to the
     *   previous element; otherwise, stops and returns the index of the
     *   element.  If the callback never returns true for any element,
     *   we'll return nil.  
     */
    lastIndexWhich(cond);

    /* 
     *   Find the last element for which the condition is true, and return
     *   the value of the element 
     */
    lastValWhich(cond);

    /* count the number of elements with the given value */
    countOf(val);

    /* count the number of elements for which the callback returns true */
    countWhich(cond);

    /* get a new list consisting of the unique elements of this list */
    getUnique();

    /* 
     *   append the elements of the list 'lst' to the elements of this
     *   list, then remove repeated elements in the result; returns a new
     *   list with the unique elements of the combination of the two lists 
     */
    appendUnique(lst);

    /* 
     *   append an element - this works almost exactly like the
     *   concatation operator ('+'), but if the argument is a list, this
     *   simply adds the list as a new element, rather than adding each
     *   element of the list as a separate element 
     */
    append(val);

    /* 
     *   Sort the list, returning a new list.  If the 'descending' flag is
     *   provided and is not nil, we'll sort the list in descending order
     *   rather than ascending order.
     *   
     *   If the 'comparisonFunction' argument is provided, it must be a
     *   callback function; the callback takes two arguments, and returns
     *   an integer less than zero if the first argument value is less
     *   than the second, zero if they're equal, and an integer greater
     *   than zero if the first is greater than the second.  If no
     *   'comparisonFunction' argument is provided, or it's provided and
     *   its value is nil, we'll simply compare the list elements as
     *   ordinary values.  The comparison function can be provided for
     *   caller-defined orderings, such as ordering a set of objects.  
     */
    sort(descending?, comparisonFunction?);

    /*
     *   Prepend an element - this inserts the value before the first
     *   existing element. 
     */
    prepend(val);

    /* 
     *   Insert one or more elements at the given index.  If the starting
     *   index is 1, the elements will be inserted before the first existing
     *   element.  If the index is one higher than the number of elements,
     *   the elements will be inserted after all existing elements.  If the
     *   index is negative, it counts backwards from the end of the list: -1
     *   inserts before the last element, -2 inserts before the second to
     *   last, and so on.  If the index is zero, the new elements are
     *   inserted after the last element.
     *   
     *   Note that a list value argument will simply be inserted as a single
     *   element.
     *   
     *   Returns a new list with the value(s) inserted.  
     */
    insertAt(startingIndex, val, ...);

    /*
     *   Delete the element at the given index, reducing the length of the
     *   list by one element.  If the index is negative, it counts from the
     *   end of the list: -1 is the last element, -2 is the second to last,
     *   etc.  Returns a new list with the given element removed.  
     */
    removeElementAt(index);

    /*
     *   Delete the range of elements starting at startingIndex and ending at
     *   endingIndex.  The elements at the ends of the range are included in
     *   the deletion.  If startingIndex == endingIndex, only one element is
     *   removed.  If either index is negative, it counts from the end of the
     *   list: -1 is the last element, -2 is the second to last, etc.
     *   Returns a new list with the given element range removed.  
     */
    removeRange(startingIndex, endingIndex);

    /*
     *   Invoke the callback func(index, val) on each element, in order from
     *   first to last.  No return value.  
     */
    forEachAssoc(func);

    /*
     *   Class method: Generate a new list.  'func' is a callback function,
     *   which can take zero or one argument.  'n' is the number of elements
     *   for the new list.  For each element, 'func' is invoked as func() if
     *   it takes no arguments, or func(idx) if it takes one argument, where
     *   'idx' is the index of the element being generated.  The return value
     *   of the call to 'func' is stored as the list element.  The method
     *   returns the resulting list.  For example, a list of the first ten
     *   even positive integers: List.generate({i: i*2}, 10).  
     */
    static generate(func, n);

    /*
     *   Splice new values into the list.  Deletes the 'del' list items
     *   starting at 'idx', then inserts the extra arguments in their place.
     *   Returns a new list reflecting the spliced values.  To insert items
     *   without deleting anything, pass 0 for 'del'.  To delete items
     *   without inserting anything, omit any additional arguments.  
     */
    splice(idx, del, ...);

    /*
     *   Combine the list elements into a string.  This converts each element
     *   into a string value using the usual default conversions (or throws
     *   an error if string conversion isn't possible), then concatenates the
     *   values together and returns the result.  If 'separator' is provided,
     *   it's a string that's interposed between elements; if this is
     *   omitted, the elements are concatenated together with no extra
     *   characters in between.  
     */
    join(sep?);

    /*
     *   Get the index of the list item with the minimum value.  If 'func' is
     *   missing, this simply returns the index of the list element with the
     *   smallest value, comparing the element values as though using the '>'
     *   and '<' operators.  If 'func' is specified, it must be a function;
     *   it's called as func(x) for each value in the list, and the result of
     *   the overall call is the index of the element for which func(x)
     *   returns the smallest value.  For example, if you have a list of
     *   strings l, l.indexOfMin({x: x.length()}) returns the index of the
     *   shortest string in the list.  
     */
    indexOfMin(func?);

    /*
     *   Get the minimum value in the list.  If 'func' is missing, this
     *   returns the minimum element value.  If 'func' is specified, it must
     *   be a function; it's called as func(x) for each value in the list,
     *   and the result of the overall method call is the element value x
     *   that minimizes func(x).  For example, if l is a list of strings,
     *   l.minVal({x: x.length()}) returns the shortest string.  
     */
    minVal(func?);

    /*
     *   Get the index of the list item with the maximum value.  If 'func' is
     *   missing, this simply returns the index of the list element with the
     *   largest value, comparing the element values as though using the '>'
     *   and '<' operators.  If 'func' is specified, it must be a function;
     *   it's called as func(x) for each value in the list, and the result of
     *   the overall call is the index of the element for which func(x)
     *   returns the greatest value.  For example, if you have a list of
     *   strings l, l.indexOfMax({x: x.length()}) returns the index of the
     *   longest string in the list.  
     */
    indexOfMax(func?);

    /*
     *   Get the maximum value in the list.  If 'func' is missing, this
     *   returns the largest element value.  If 'func' is specified, it must
     *   be a function; it's called as func(x) for each value in the list,
     *   and the result of the overall method call is the element value x
     *   that maximizes func(x).  For example, if l is a list of strings,
     *   l.maxVal({x: x.length()}) returns the longest string.  
     */
    maxVal(func?);
}

/*
 *   Sorting order flags.  These can be passed in as the first argument to
 *   List.sort() (and Vector.sort() as well) to make the meaning of the
 *   argument clearer.  
 */
#define SortAsc    nil
#define SortDesc   true

/*
 *   Export length() as the element counter method for list-like objects in
 *   general. 
 */
export length 'length';


/* ------------------------------------------------------------------------ */
/*
 *   'RexPattern' intrinsic class.  This class encapsulates a compiled
 *   regular expression pattern.
 *   
 *   A RexPattern object can be passed to the regular expression functions
 *   (rexMatch, rexSearch, rexReplace) in place of a string pattern.  Since
 *   compiling a regular expression takes a non-trivial amount of time, it's
 *   more efficient to compile a pattern to a RexPattern object if the same
 *   pattern will be used in multiple searches.  
 */
intrinsic class RexPattern 'regex-pattern/030000': Object
{
    /*
     *   Constructor:
     *   
     *   new RexPattern(patternString) - returns a RexPattern representing
     *   the compiled pattern string.  
     */

    /* retrieve the original pattern string used to construct the object */
    getPatternString();
}

/* ------------------------------------------------------------------------ */
/*
 *   StackFrameDesc intrinsic class.  This class provides access to a stack
 *   frame.  It lets us retrieve the values of local variables and method
 *   context variables (self, definingobj, targetobj, targetprop).  It also
 *   allows us to assign new values to local variables.
 *   
 *   To get the value of a local variable in the frame, simply use
 *   frame[name], where 'frame' is the StackFrameDesc object for the frame,
 *   and 'name' is a string giving the name of the local variable to
 *   retrieve.  If the frame is active, this retrieves the live value of the
 *   variable from the frame; otherwise it retrieves the value from a
 *   snapshot containing the last value before the routine returned to its
 *   caller.
 *   
 *   To assign a new value to a local in the frame, assign a value to
 *   frame[name] for the desired variable name.  If the frame is active, this
 *   updates the live variable in the stack frame, so when execution returns
 *   to the caller the variable will have the new value.  If the frame is
 *   inactive, it updates the snapshot we made when the routine returned to
 *   its caller.
 *   
 *   This object can't be created with 'new'.  Instead, you obtain these
 *   objects via the t3GetStackTrace() function.  That function retrieves
 *   information on an active stack frame in the current call stack,
 *   including the frame object.  
 */
intrinsic class StackFrameDesc 'stack-frame-desc/030000'
{
    /*
     *   Is the stack frame active?  A stack frame is active until the
     *   function or method it represents returns to its caller.  When the
     *   routine returns, the frame becomes inactive.
     *   
     *   When the routine is about to return (so the frame is about to become
     *   inacive), the StackFrameDesc object makes a private snapshot of the
     *   variables in the frame.  Subsequent access to the locals will
     *   automatically use the snapshot copy, so you can continue to access
     *   the locals as normal without worrying about whether or not the
     *   actual stack frame still exists.  This allows you to continue to
     *   access and modify the values of the variables after the routine has
     *   exited.  
     */
    isActive();

    /*
     *   Get a LookupTable consisting of all of the variables (local
     *   variables and parameters) in the frame.  Each element in the table
     *   is keyed by the name of a variable, and contains the current value
     *   of the variable.
     *   
     *   The returned lookup table is a snapshot copy of the current values
     *   of the variables.  If the underlying variable values in the frame
     *   change, the lookup table won't be affected, since it's just a
     *   separate copy made at the moment this routine is called.  Similarly,
     *   changing the value of an entry in the returned lookup table won't
     *   affect the actual variable in the stack frame.
     *   
     *   To retrieve the current live value of a variable in the actual stack
     *   frame, use frame[name], where 'frame' is the StackFrameDesc object
     *   for the frame, and 'name' is a string giving the variable name.  
     */
    getVars();

    /*
     *   Get the value of 'self' in this frame. 
     */
    getSelf();

    /*
     *   Get the value of 'definingobj' in this frame. 
     */
    getDefiningObj();

    /*
     *   Get the value of 'targetobj' in this frame. 
     */
    getTargetObj();

    /*
     *   Get the value of 'targetprop' in this frame. 
     */
    getTargetProp();

    /*
     *   Get the value of 'invokee' in this frame. 
     */
    getInvokee();
}

/*
 *   A StackFrameRef is an internal object used with StackFrameDesc.  This
 *   type is used internally by the VM; user code can't create an instance of
 *   this class directly with 'new', and the class has no public methods.  
 */
intrinsic class StackFrameRef 'stack-frame-ref/030000'
{
}

