diff --git a/doomsday/libdeng2/include/de/core/commandline.h b/doomsday/libdeng2/include/de/core/commandline.h index 2a9a8752dc..61f3a5f747 100644 --- a/doomsday/libdeng2/include/de/core/commandline.h +++ b/doomsday/libdeng2/include/de/core/commandline.h @@ -30,184 +30,185 @@ #include "../String" #include "../NativePath" -namespace de +namespace de { + +/** + * Stores and provides access to the command line arguments passed + * to an application at launch. + * + * @ingroup core + */ +class DENG2_PUBLIC CommandLine { +public: + /// Tried to access an argument that does not exist. @ingroup errors + DENG2_ERROR(OutOfRangeError); + + /// Execution of the command line failed. @ingroup errors + DENG2_ERROR(ExecuteError); + +public: + CommandLine(); + /** - * Stores and provides access to the command line arguments passed - * to an application at launch. - * - * @ingroup core - */ - class DENG2_PUBLIC CommandLine - { - public: - /// Tried to access an argument that does not exist. @ingroup errors - DENG2_ERROR(OutOfRangeError); - - /// Execution of the command line failed. @ingroup errors - DENG2_ERROR(ExecuteError); - - public: - CommandLine(); - - /** - * Constructs a CommandLine out of a list of strings. The argument - * strings that begin with a @@ character are parsed as response files - * the rest are used without modification. - * - * @param args Arguments to use. - */ - CommandLine(QStringList const &args); - - CommandLine(CommandLine const &other); - - virtual ~CommandLine(); - - /** - * Returns the native path where the command line was started in. - * @return Native startup location. - */ - NativePath startupPath(); - - /** - * Returns the number of arguments. This includes the program name, which - * is the first argument in the list. - */ - dint count() const; - - void clear(); - - /** - * Appends a new argument to the list of arguments. - * - * @param arg Argument to append. - */ - void append(String const &arg); - - /** - * Inserts a new argument to the list of arguments at index @a pos. - * - * @param pos Index at which the new argument will be at. - * @param arg Argument to insert. - */ - void insert(duint pos, String const &arg); - - /** - * Removes an argument by index. - * - * @param pos Index of argument to remove. - */ - void remove(duint pos); - - /** - * Checks whether @a arg is in the arguments. Since the first argument is - * the program name, it is not included in the search. - * - * @param arg Argument to look for. Don't use aliases here. - * @param count Number of parameters (non-option arguments) that follow - * the located argument. - * - * @see isOption() - * - * @return Index of the argument, if found. Otherwise zero. - */ - dint check(String const &arg, dint count = 0) const; - - /** - * Gets the parameter for an argument. - * - * @param arg Argument to look for. Don't use aliases here. Defines - * aliases will be checked for matches. - * @param param The parameter is returned here, if found. - * - * @return @c true, if parameter was successfully returned. - * Otherwise @c false, in which case @a param is not modified. - */ - bool getParameter(String const &arg, String ¶m) const; - - /** - * Determines whether @a arg exists in the list of arguments. - * - * @param arg Argument to look for. Don't use aliases here. - * - * @return Number of times @a arg is found in the arguments. - */ - dint has(String const &arg) const; - - /** - * Determines whether an argument is an option, i.e., it begins with a hyphen. - */ - bool isOption(duint pos) const; - - /** - * Determines whether an argument is an option, i.e., it begins with a hyphen. - */ - static bool isOption(String const &arg); - - String at(duint pos) const; - - /** - * Returns a list of pointers to the arguments. The list contains - * count() strings and is NULL-terminated. - */ - char const *const *argv() const; - - /** - * Converts the argument at position @a pos into an absolute native path. - * Relative paths are converted relative to the directory that was - * current at the time the CommandLine was created. - * - * @param pos Argument index. - */ - void makeAbsolutePath(duint pos); - - /** - * Reads a native file and parses its contents using parse(). - * - * @param nativePath File to parse. - */ - void parseResponseFile(NativePath const &nativePath); - - /** - * Breaks down a single string containing arguments. - * - * Examples of behavior: - * - -cmd "echo ""this is a command""" => [-cmd] [echo "this is a command"] - * - Hello" My"Friend => [Hello MyFriend] - * - @@test.rsp [reads contents of test.rsp] - * - @@\\"Program Files"\\test.rsp [reads contents of "\Program Files\test.rsp"] - * - * @param cmdLine String containing the arguments. - */ - void parse(String const &cmdLine); - - /** - * Defines a new alias for a full argument. - * - * @param full The full argument, e.g., "--help" - * @param alias Alias for the full argument, e.g., "-h" - */ - void alias(String const &full, String const &alias); - - /** - * @return @c true, iff the two parameters are equivalent according to - * the abbreviations. - */ - bool matches(String const &full, String const &fullOrAlias) const; - - /** - * Spawns a new process using the command line. The first argument - * specifies the file name of the executable. Returns immediately - * after the process has been started. - * - * @return @c true if successful, otherwise @c false. - */ - bool execute() const; - - private: - struct Instance; - Instance *d; - }; -} + * Constructs a CommandLine out of a list of strings. The argument + * strings that begin with a @@ character are parsed as response files + * the rest are used without modification. + * + * @param args Arguments to use. + */ + CommandLine(QStringList const &args); + + CommandLine(CommandLine const &other); + + virtual ~CommandLine(); + + /** + * Returns the native path where the command line was started in. + * @return Native startup location. + */ + NativePath startupPath(); + + /** + * Returns the number of arguments. This includes the program name, which + * is the first argument in the list. + */ + dint count() const; + + void clear(); + + /** + * Appends a new argument to the list of arguments. + * + * @param arg Argument to append. + */ + void append(String const &arg); + + /** + * Inserts a new argument to the list of arguments at index @a pos. + * + * @param pos Index at which the new argument will be at. + * @param arg Argument to insert. + */ + void insert(duint pos, String const &arg); + + /** + * Removes an argument by index. + * + * @param pos Index of argument to remove. + */ + void remove(duint pos); + + /** + * Checks whether @a arg is in the arguments. Since the first argument is + * the program name, it is not included in the search. + * + * @param arg Argument to look for. Don't use aliases here. + * @param count Number of parameters (non-option arguments) that follow + * the located argument. + * + * @see isOption() + * + * @return Index of the argument, if found. Otherwise zero. + */ + dint check(String const &arg, dint count = 0) const; + + /** + * Gets the parameter for an argument. + * + * @param arg Argument to look for. Don't use aliases here. Defines + * aliases will be checked for matches. + * @param param The parameter is returned here, if found. + * + * @return @c true, if parameter was successfully returned. + * Otherwise @c false, in which case @a param is not modified. + */ + bool getParameter(String const &arg, String ¶m) const; + + /** + * Determines whether @a arg exists in the list of arguments. + * + * @param arg Argument to look for. Don't use aliases here. + * + * @return Number of times @a arg is found in the arguments. + */ + dint has(String const &arg) const; + + /** + * Determines whether an argument is an option, i.e., it begins with a hyphen. + */ + bool isOption(duint pos) const; + + /** + * Determines whether an argument is an option, i.e., it begins with a hyphen. + */ + static bool isOption(String const &arg); + + String at(duint pos) const; + + /** + * Returns a list of pointers to the arguments. The list contains + * count() strings and is NULL-terminated. + */ + char const *const *argv() const; + + /** + * Converts the argument at position @a pos into an absolute native path. + * Relative paths are converted relative to the directory that was + * current at the time the CommandLine was created. + * + * @param pos Argument index. + */ + void makeAbsolutePath(duint pos); + + /** + * Reads a native file and parses its contents using parse(). + * + * @param nativePath File to parse. + */ + void parseResponseFile(NativePath const &nativePath); + + /** + * Breaks down a single string containing arguments. + * + * Examples of behavior: + * - -cmd "echo ""this is a command""" => [-cmd] [echo "this is a command"] + * - Hello" My"Friend => [Hello MyFriend] + * - @@test.rsp [reads contents of test.rsp] + * - @@\\"Program Files"\\test.rsp [reads contents of "\Program Files\test.rsp"] + * + * @param cmdLine String containing the arguments. + */ + void parse(String const &cmdLine); + + /** + * Defines a new alias for a full argument. + * + * @param full The full argument, e.g., "--help" + * @param alias Alias for the full argument, e.g., "-h" + */ + void alias(String const &full, String const &alias); + + /** + * @return @c true, iff the two parameters are equivalent according to + * the abbreviations. + */ + bool matches(String const &full, String const &fullOrAlias) const; + + /** + * Spawns a new process using the command line. The first argument + * specifies the file name of the executable. Returns immediately + * after the process has been started. + * + * @return @c true if successful, otherwise @c false. + */ + bool execute() const; + +private: + struct Instance; + Instance *d; +}; + +} // namespace de #endif /* LIBDENG2_COMMANDLINE_H */ diff --git a/doomsday/libdeng2/include/de/core/config.h b/doomsday/libdeng2/include/de/core/config.h index 3d827825c0..a9978bc30d 100644 --- a/doomsday/libdeng2/include/de/core/config.h +++ b/doomsday/libdeng2/include/de/core/config.h @@ -24,88 +24,89 @@ #include "../String" #include "../Path" -namespace de +namespace de { + +class ArrayValue; + +/** + * Stores the configuration of everything. The application owns a Config. + * The default configuration is produced by executing the .de scripts + * in the config directories. The resulting namespace is serialized for + * storage, and is restored from the serialized version directly before the + * config scripts are run. + * + * The version of the engine is stored in the serialized config namespace. + * This is for actions needed when upgrading: the config script can check + * the previous version and apply changes accordingly. + */ +class DENG2_PUBLIC Config { - class ArrayValue; +public: + /// Attempted to get the value of a variable while expecting the wrong type. @ingroup errors + DENG2_ERROR(ValueTypeError); +public: /** - * Stores the configuration of everything. The application owns a Config. - * The default configuration is produced by executing the .de scripts - * in the config directories. The resulting namespace is serialized for - * storage, and is restored from the serialized version directly before the - * config scripts are run. + * Constructs a new configuration. * - * The version of the engine is stored in the serialized config namespace. - * This is for actions needed when upgrading: the config script can check - * the previous version and apply changes accordingly. + * @param path Name of the configuration file to read. */ - class DENG2_PUBLIC Config - { - public: - /// Attempted to get the value of a variable while expecting the wrong type. @ingroup errors - DENG2_ERROR(ValueTypeError); - - public: - /** - * Constructs a new configuration. - * - * @param path Name of the configuration file to read. - */ - Config(Path const &path); - - /** - * Destructor. The configuration is automatically saved. - */ - virtual ~Config(); - - /// Read configuration from files. - void read(); - - /// Writes the configuration to /home. - void write(); - - /// Returns the value of @a name as a Value. - Value &get(String const &name); - - /// Returns the value of @a name as an integer. - dint geti(String const &name); - - /// Returns the value of @a name as a boolean. - bool getb(String const &name); - - /// Returns the value of @a name as an unsigned integer. - duint getui(String const &name); - - /// Returns the value of @a name as a double-precision floating point number. - ddouble getd(String const &name); - - /// Returns the value of @a name as a string. - String gets(String const &name); - - /// Returns the value of @a name as an array value. An exception is thrown - /// if the variable does not have an array value. - ArrayValue &geta(String const &name); - - template - ValueType &getAs(String const &name) { - ValueType *v = dynamic_cast(&get(name)); - if(!v) - { - throw ValueTypeError("Config::getAs", String("Cannot cast to expected type (") + - DENG2_TYPE_NAME(ValueType) + ")"); - } - return *v; + Config(Path const &path); + + /** + * Destructor. The configuration is automatically saved. + */ + virtual ~Config(); + + /// Read configuration from files. + void read(); + + /// Writes the configuration to /home. + void write(); + + /// Returns the value of @a name as a Value. + Value &get(String const &name); + + /// Returns the value of @a name as an integer. + dint geti(String const &name); + + /// Returns the value of @a name as a boolean. + bool getb(String const &name); + + /// Returns the value of @a name as an unsigned integer. + duint getui(String const &name); + + /// Returns the value of @a name as a double-precision floating point number. + ddouble getd(String const &name); + + /// Returns the value of @a name as a string. + String gets(String const &name); + + /// Returns the value of @a name as an array value. An exception is thrown + /// if the variable does not have an array value. + ArrayValue &geta(String const &name); + + template + ValueType &getAs(String const &name) { + ValueType *v = dynamic_cast(&get(name)); + if(!v) + { + throw ValueTypeError("Config::getAs", String("Cannot cast to expected type (") + + DENG2_TYPE_NAME(ValueType) + ")"); } - - /** - * Returns the configuration namespace. - */ - Record &names(); - - private: - struct Instance; - Instance *d; - }; -} + return *v; + } + + /** + * Returns the configuration namespace. + */ + Record &names(); + +private: + struct Instance; + Instance *d; +}; + +} // namespace de #endif /* LIBDENG2_CONFIG_H */ diff --git a/doomsday/libdeng2/include/de/core/library.h b/doomsday/libdeng2/include/de/core/library.h index cc54852c53..2a22c1f0f1 100644 --- a/doomsday/libdeng2/include/de/core/library.h +++ b/doomsday/libdeng2/include/de/core/library.h @@ -32,188 +32,189 @@ */ #define DENG2_SYMBOL(Name) symbol(#Name) -namespace de +namespace de { + +class Audio; +class Map; +class Object; +class User; +class World; + +/** + * The Library class allows loading shared library files + * (DLL/so/bundle/dylib) and looks up exported symbols in the libraries. + * + * Library type identifiers; + * - library/generic: A shared library with no special function. + * - deng-plugin/generic: Generic libdeng2 plugin. Loaded always. + * - deng-plugin/game: The game plugin. Only one of these can be loaded. + * - deng-plugin/audio: Audio driver. Optional. Loaded on demand by + * the audio subsystem. + * + * @ingroup core + */ +class DENG2_PUBLIC Library { - class Audio; - class Map; - class Object; - class User; - class World; - - /** - * The Library class allows loading shared library files - * (DLL/so/bundle/dylib) and looks up exported symbols in the libraries. +public: + /// Loading the shared library failed. @ingroup errors + DENG2_ERROR(LoadError); + + /// A symbol was not found. @ingroup errors + DENG2_ERROR(SymbolMissingError); + + /// Default type identifier. + static char const *DEFAULT_TYPE; + + // Common function profiles. + /** + * Queries the plugin for a type identifier string. If this function is not + * defined, the identifier defaults to DEFAULT_TYPE. * - * Library type identifiers; - * - library/generic: A shared library with no special function. - * - deng-plugin/generic: Generic libdeng2 plugin. Loaded always. - * - deng-plugin/game: The game plugin. Only one of these can be loaded. - * - deng-plugin/audio: Audio driver. Optional. Loaded on demand by - * the audio subsystem. + * @return Type identifier string. + */ + typedef char const *(*deng_LibraryType)(void); + + /** + * Passes Doomsda'ys public APIs to the library. Called automatically by + * the engine when loading libraries. + */ + typedef void (*deng_API)(int, void *); + + /** + * Performs any one-time initialization necessary for the usage of the plugin. + * If this symbol is exported from a shared library, it gets called automatically + * when the library is loaded. Note that this is called before deng_API(), so it + * should be used exclusively for setting up the plugin's internal state. + */ + typedef void (*deng_InitializePlugin)(void); + + /** + * Frees resources reserved by the plugin. If this symbol is exported from a + * shared library, it gets called automatically when the library is unloaded. + */ + typedef void (*deng_ShutdownPlugin)(void); + + /** + * Constructs a new instance of an audio subsystem. * - * @ingroup core - */ - class DENG2_PUBLIC Library - { - public: - /// Loading the shared library failed. @ingroup errors - DENG2_ERROR(LoadError); - - /// A symbol was not found. @ingroup errors - DENG2_ERROR(SymbolMissingError); - - /// Default type identifier. - static char const *DEFAULT_TYPE; - - // Common function profiles. - /** - * Queries the plugin for a type identifier string. If this function is not - * defined, the identifier defaults to DEFAULT_TYPE. - * - * @return Type identifier string. - */ - typedef char const *(*deng_LibraryType)(void); + * @return Audio subsystem. + */ + typedef Audio *(*deng_NewAudio)(void); - /** - * Passes Doomsda'ys public APIs to the library. Called automatically by - * the engine when loading libraries. - */ - typedef void (*deng_API)(int, void *); - - /** - * Performs any one-time initialization necessary for the usage of the plugin. - * If this symbol is exported from a shared library, it gets called automatically - * when the library is loaded. Note that this is called before deng_API(), so it - * should be used exclusively for setting up the plugin's internal state. - */ - typedef void (*deng_InitializePlugin)(void); - - /** - * Frees resources reserved by the plugin. If this symbol is exported from a - * shared library, it gets called automatically when the library is unloaded. - */ - typedef void (*deng_ShutdownPlugin)(void); - - /** - * Constructs a new instance of an audio subsystem. - * - * @return Audio subsystem. - */ - typedef Audio *(*deng_NewAudio)(void); - - /** - * Constructs a new game world. - */ - typedef World *(*deng_NewWorld)(void); - - /** - * Constructs a new game map. - */ - typedef Map *(*deng_NewMap)(); - - /** - * Constructs a new object. - */ - typedef Object *(*deng_NewObject)(void); - - /** - * Constructs a new user. - */ - typedef User *(*deng_NewUser)(void); - - typedef dint (*deng_GetInteger)(dint id); - typedef char const *(*deng_GetString)(dint id); - typedef void *(*deng_GetAddress)(dint id); - typedef void (*deng_Ticker)(ddouble tickLength); - - public: - /** - * Constructs a new Library by loading a native shared library. - * - * @param nativePath Path of the shared library to load. - */ - Library(NativePath const &nativePath); - - /** - * Unloads the shared library. - */ - virtual ~Library(); + /** + * Constructs a new game world. + */ + typedef World *(*deng_NewWorld)(void); - /** - * Returns the type identifier of the library. This affects how - * libdeng2 will treat the library. The type is determined - * automatically when the library is first loaded, and can then be - * queried at any time even after the library has been unloaded. - */ - String const &type() const; + /** + * Constructs a new game map. + */ + typedef Map *(*deng_NewMap)(); - enum SymbolLookupMode { - RequiredSymbol, ///< Symbol must be exported. - OptionalSymbol ///< Symbol can be missing. - }; + /** + * Constructs a new object. + */ + typedef Object *(*deng_NewObject)(void); - /** - * Gets the address of an exported symbol. Throws an exception if a required - * symbol is not found. - * - * @param name Name of the exported symbol. - * @param lookup Lookup mode (required or optional). - * - * @return A pointer to the symbol. Returns @c NULL if an optional symbol is - * not found. - */ - void *address(String const &name, SymbolLookupMode lookup = RequiredSymbol); + /** + * Constructs a new user. + */ + typedef User *(*deng_NewUser)(void); - /** - * Checks if the library exports a specific symbol. - * @param name Name of the exported symbol. - * @return @c true if the symbol is exported, @c false if not. - */ - bool hasSymbol(String const &name) const; + typedef dint (*deng_GetInteger)(dint id); + typedef char const *(*deng_GetString)(dint id); + typedef void *(*deng_GetAddress)(dint id); + typedef void (*deng_Ticker)(ddouble tickLength); - /** - * Gets the address of a symbol. Throws an exception if a required symbol - * is not found. - * - * @param name Name of the symbol. - * @param lookup Symbol lookup mode (required or optional). - * - * @return Pointer to the symbol as type @a Type. - */ - template - Type symbol(String const &name, SymbolLookupMode lookup = RequiredSymbol) { - /** - * @note Casting to a pointer-to-function type: see - * http://www.trilithium.com/johan/2004/12/problem-with-dlsym/ - */ - // This is not 100% portable to all possible memory architectures; thus: - DENG2_ASSERT(sizeof(void *) == sizeof(Type)); - - union { void *original; Type target; } forcedCast; - forcedCast.original = address(name, lookup); - return forcedCast.target; - } +public: + /** + * Constructs a new Library by loading a native shared library. + * + * @param nativePath Path of the shared library to load. + */ + Library(NativePath const &nativePath); + + /** + * Unloads the shared library. + */ + virtual ~Library(); + + /** + * Returns the type identifier of the library. This affects how + * libdeng2 will treat the library. The type is determined + * automatically when the library is first loaded, and can then be + * queried at any time even after the library has been unloaded. + */ + String const &type() const; + enum SymbolLookupMode { + RequiredSymbol, ///< Symbol must be exported. + OptionalSymbol ///< Symbol can be missing. + }; + + /** + * Gets the address of an exported symbol. Throws an exception if a required + * symbol is not found. + * + * @param name Name of the exported symbol. + * @param lookup Lookup mode (required or optional). + * + * @return A pointer to the symbol. Returns @c NULL if an optional symbol is + * not found. + */ + void *address(String const &name, SymbolLookupMode lookup = RequiredSymbol); + + /** + * Checks if the library exports a specific symbol. + * @param name Name of the exported symbol. + * @return @c true if the symbol is exported, @c false if not. + */ + bool hasSymbol(String const &name) const; + + /** + * Gets the address of a symbol. Throws an exception if a required symbol + * is not found. + * + * @param name Name of the symbol. + * @param lookup Symbol lookup mode (required or optional). + * + * @return Pointer to the symbol as type @a Type. + */ + template + Type symbol(String const &name, SymbolLookupMode lookup = RequiredSymbol) { /** - * Utility template for acquiring pointers to symbols. Throws an exception - * if a required symbol is not found. - * - * @param ptr Pointer that will be set to point to the symbol's address. - * @param name Name of the symbol whose address to get. - * @param lookup Symbol lookup mode (required or optional). - * - * @return @c true, if the symbol was found. Otherwise @c false. + * @note Casting to a pointer-to-function type: see + * http://www.trilithium.com/johan/2004/12/problem-with-dlsym/ */ - template - bool setSymbolPtr(Type &ptr, String const &name, SymbolLookupMode lookup = RequiredSymbol) { - ptr = symbol(name, lookup); - return ptr != 0; - } - - private: - struct Instance; - Instance *d; - }; -} + // This is not 100% portable to all possible memory architectures; thus: + DENG2_ASSERT(sizeof(void *) == sizeof(Type)); + + union { void *original; Type target; } forcedCast; + forcedCast.original = address(name, lookup); + return forcedCast.target; + } + + /** + * Utility template for acquiring pointers to symbols. Throws an exception + * if a required symbol is not found. + * + * @param ptr Pointer that will be set to point to the symbol's address. + * @param name Name of the symbol whose address to get. + * @param lookup Symbol lookup mode (required or optional). + * + * @return @c true, if the symbol was found. Otherwise @c false. + */ + template + bool setSymbolPtr(Type &ptr, String const &name, SymbolLookupMode lookup = RequiredSymbol) { + ptr = symbol(name, lookup); + return ptr != 0; + } + +private: + struct Instance; + Instance *d; +}; + +} // namespace de #endif /* LIBDENG2_LIBRARY_H */ diff --git a/doomsday/libdeng2/include/de/data/archive.h b/doomsday/libdeng2/include/de/data/archive.h index 0036b68687..706603e788 100644 --- a/doomsday/libdeng2/include/de/data/archive.h +++ b/doomsday/libdeng2/include/de/data/archive.h @@ -30,297 +30,298 @@ #include -namespace de +namespace de { + +class IBlock; +class Block; + +/** + * Collection of named memory blocks stored inside a byte array. + * + * An archive consists of a collection of Block instances that are + * identified using a path tree structure. Blocks can be added and removed + * at any time. + * + * Archive is merely IWritable instead of ISerializable because of its + * memory management model. The basic assumption is that even though the + * archive is kept in serialized form, individual entries can still be + * accessed without processing the entire serialization. Therefore, Archive + * only operates on existing, serialized archives that live in externally + * owned byte arrays; Archive does not take ownership of the source data. + * This also means that read-only access to very large byte arrays can be + * done without loading all the source data into memory (e.g., Archive + * that reads from a large NativeFile). + * + * It is also assumed that accessing the source data and extracting a + * particular entry is potentially a slow operation: when individual + * entries are read from the source, the entries are cached in memory so + * that subsequent access is fast. + * + * An Archive instance expects that the source byte array is never changed + * by third parties while it is the source of the Archive. + * + * It is possible to detach an Archive instance from its source byte array + * by calling @c cache(DetachFromSource). This forces all entries to be + * copied to Archive-owned memory (in original serialized form). + * + * @see ArchiveFeed, ArchiveEntryFile + * + * @ingroup data + */ +class DENG2_PUBLIC Archive : public IWritable { - class IBlock; - class Block; - +public: + /// Base class for format-related errors. @ingroup errors + DENG2_ERROR(FormatError); + + /// Provided path was not valid. @ingroup errors + DENG2_ERROR(InvalidPathError); + + /// The requested entry does not exist in the archive. @ingroup errors + DENG2_ERROR(NotFoundError); + + /// There is an error related to content processing. @ingroup errors + DENG2_ERROR(ContentError); + + typedef std::set Names; // alphabetical order + +public: + /** + * Constructs an empty Archive. + */ + Archive(); + + /** + * Constructs a new Archive instance. The content index contained in + * @a data is read during construction. + * + * @param data Data of the source archive. No copy of the + * data is made, so the caller must make sure the + * byte array remains in existence for the lifetime + * of the Archive instance. + */ + Archive(IByteArray const &data); + + virtual ~Archive(); + + /** + * Returns the source byte array. @c NULL, if the archive was + * constructed without a source (as empty) or has been detached from + * its original source. + */ + IByteArray const *source() const; + + enum CacheAttachment { + RemainAttachedToSource = 0, + DetachFromSource = 1 + }; + + /** + * Loads a copy of the serialized data into memory for all the entries that + * don't already have deserialized data stored. + * + * @param attach If DetachFromSource, the archive becomes a standalone + * archive that no longer needs the source byte array to + * remain in existence. + */ + void cache(CacheAttachment attach = DetachFromSource); + + /** + * Determines whether the archive contains an entry (not a folder). + * + * @param path Path of the entry. + * + * @return @c true or @c false. + */ + bool hasEntry(Path const &path) const; + + /** + * List the files in a specific folder of the archive. + * + * @param folder Folder path to look in. By default looks in the root. + * @param names Entry names collected in a set. The names are relative to a + * @a folder and are in alphabetical order. + * + * @return Number of names returned in @a names. + */ + dint listFiles(Names &names, Path const &folder = Path()) const; + + /** + * List the folders in a specific folder of the archive. + * + * @param folder Folder path to look in. By default looks in the root. + * @param names Folder entry names collected in a set. The names are + * relative to @a folder and are in alphabetical order. + * + * @return Number of names returned in @a names. + */ + dint listFolders(Names &names, Path const &folder = Path()) const; + + /** + * Returns information about the specified path. + * + * @param path Path of the entry within the archive. + * + * @return Type, size, and other metadata about the entry. + */ + File::Status entryStatus(Path const &path) const; + /** - * Collection of named memory blocks stored inside a byte array. + * Returns the deserialized data of an entry for read-only access. The + * data is deserialized and cached if a cached copy doesn't already + * exist. * - * An archive consists of a collection of Block instances that are - * identified using a path tree structure. Blocks can be added and removed - * at any time. + * This method operates on the Archive in immutable mode: the user is + * not expected to modify the contents of the returned Block, and the + * existing serialized data of the entry can be used as-is when the + * archive is written. * - * Archive is merely IWritable instead of ISerializable because of its - * memory management model. The basic assumption is that even though the - * archive is kept in serialized form, individual entries can still be - * accessed without processing the entire serialization. Therefore, Archive - * only operates on existing, serialized archives that live in externally - * owned byte arrays; Archive does not take ownership of the source data. - * This also means that read-only access to very large byte arrays can be - * done without loading all the source data into memory (e.g., Archive - * that reads from a large NativeFile). + * @param path Entry path. The entry must already exist in the archive. * - * It is also assumed that accessing the source data and extracting a - * particular entry is potentially a slow operation: when individual - * entries are read from the source, the entries are cached in memory so - * that subsequent access is fast. + * @return Immutable contents of the entry. + */ + Block const &entryBlock(Path const &path) const; + + inline Block const &constEntryBlock(Path const &path) const { + return entryBlock(path); + } + + /** + * Returns the deserialized data of an entry for read and write access. + * The data is deserialized and cached if a cached copy doesn't already + * exist. * - * An Archive instance expects that the source byte array is never changed - * by third parties while it is the source of the Archive. + * The user is allowed to make changes to the returned block. The + * entry's data is automatically marked for re-serialization in case + * the archive is written. * - * It is possible to detach an Archive instance from its source byte array - * by calling @c cache(DetachFromSource). This forces all entries to be - * copied to Archive-owned memory (in original serialized form). + * @param path Entry path. If doesn't exist, a new entry will be added. * - * @see ArchiveFeed, ArchiveEntryFile + * @return Modifiable contents of the entry. + */ + Block &entryBlock(Path const &path); + + /** + * Adds an entry to the archive. The entry will not be committed to the + * source, but instead remains as-is in memory. + * + * @param path Path of the entry within the archive. + * @param data Data of the entry. + */ + void add(Path const &path, IByteArray const &data); + + /** + * Removes an entry from the archive. If there is deserialized data for + * the entry in memory, it will be deleted. * - * @ingroup data + * @param path Path of the entry. + */ + void remove(Path const &path); + + /** + * Clears the index of the archive. All entries are deleted. + */ + void clear(); + + /** + * Determines if the archive has been modified. + */ + bool modified() const; + + /** + * Writes the archive to a Writer. Deserialized entries are + * re-serialized just-in-time before writing if they have been + * modified. + * + * @note If overwriting the source array, be sure to either first write + * to a temporary array and then replace the source, or alternatively + * detach the source from the archive beforehand. Otherwise the + * unchanged entries may become corrupted as they are reused from their + * old location in the source, which may have been already overwritten. + * + * @param to Where to write. + */ + virtual void operator >> (Writer &to) const = 0; + +protected: + /* + * Interface for derived classes: */ - class DENG2_PUBLIC Archive : public IWritable + /// Base class for archive entries. + struct Entry : public PathTree::Node { - public: - /// Base class for format-related errors. @ingroup errors - DENG2_ERROR(FormatError); - - /// Provided path was not valid. @ingroup errors - DENG2_ERROR(InvalidPathError); - - /// The requested entry does not exist in the archive. @ingroup errors - DENG2_ERROR(NotFoundError); - - /// There is an error related to content processing. @ingroup errors - DENG2_ERROR(ContentError); - - typedef std::set Names; // alphabetical order - - public: - /** - * Constructs an empty Archive. - */ - Archive(); - - /** - * Constructs a new Archive instance. The content index contained in - * @a data is read during construction. - * - * @param data Data of the source archive. No copy of the - * data is made, so the caller must make sure the - * byte array remains in existence for the lifetime - * of the Archive instance. - */ - Archive(IByteArray const &data); - - virtual ~Archive(); - - /** - * Returns the source byte array. @c NULL, if the archive was - * constructed without a source (as empty) or has been detached from - * its original source. - */ - IByteArray const *source() const; - - enum CacheAttachment { - RemainAttachedToSource = 0, - DetachFromSource = 1 - }; - - /** - * Loads a copy of the serialized data into memory for all the entries that - * don't already have deserialized data stored. - * - * @param attach If DetachFromSource, the archive becomes a standalone - * archive that no longer needs the source byte array to - * remain in existence. - */ - void cache(CacheAttachment attach = DetachFromSource); - - /** - * Determines whether the archive contains an entry (not a folder). - * - * @param path Path of the entry. - * - * @return @c true or @c false. - */ - bool hasEntry(Path const &path) const; - - /** - * List the files in a specific folder of the archive. - * - * @param folder Folder path to look in. By default looks in the root. - * @param names Entry names collected in a set. The names are relative to a - * @a folder and are in alphabetical order. - * - * @return Number of names returned in @a names. - */ - dint listFiles(Names &names, Path const &folder = Path()) const; - - /** - * List the folders in a specific folder of the archive. - * - * @param folder Folder path to look in. By default looks in the root. - * @param names Folder entry names collected in a set. The names are - * relative to @a folder and are in alphabetical order. - * - * @return Number of names returned in @a names. - */ - dint listFolders(Names &names, Path const &folder = Path()) const; - - /** - * Returns information about the specified path. - * - * @param path Path of the entry within the archive. - * - * @return Type, size, and other metadata about the entry. - */ - File::Status entryStatus(Path const &path) const; - - /** - * Returns the deserialized data of an entry for read-only access. The - * data is deserialized and cached if a cached copy doesn't already - * exist. - * - * This method operates on the Archive in immutable mode: the user is - * not expected to modify the contents of the returned Block, and the - * existing serialized data of the entry can be used as-is when the - * archive is written. - * - * @param path Entry path. The entry must already exist in the archive. - * - * @return Immutable contents of the entry. - */ - Block const &entryBlock(Path const &path) const; - - inline Block const &constEntryBlock(Path const &path) const { - return entryBlock(path); - } + dsize offset; ///< Offset from the start of the source array. + dsize size; ///< Deserialized size. + dsize sizeInArchive; ///< Size within the archive (serialized). + Time modifiedAt; ///< Latest modification timestamp. + bool maybeChanged; ///< @c true, if the data must be re-serialized when writing. + + /// Deserialized data. Can be @c NULL. Entry has ownership. + Block *data; + + /// Cached copy of the serialized data. Can be @c NULL. Entry has ownership. + Block mutable *dataInArchive; - /** - * Returns the deserialized data of an entry for read and write access. - * The data is deserialized and cached if a cached copy doesn't already - * exist. - * - * The user is allowed to make changes to the returned block. The - * entry's data is automatically marked for re-serialization in case - * the archive is written. - * - * @param path Entry path. If doesn't exist, a new entry will be added. - * - * @return Modifiable contents of the entry. - */ - Block &entryBlock(Path const &path); - - /** - * Adds an entry to the archive. The entry will not be committed to the - * source, but instead remains as-is in memory. - * - * @param path Path of the entry within the archive. - * @param data Data of the entry. - */ - void add(Path const &path, IByteArray const &data); - - /** - * Removes an entry from the archive. If there is deserialized data for - * the entry in memory, it will be deleted. - * - * @param path Path of the entry. - */ - void remove(Path const &path); - - /** - * Clears the index of the archive. All entries are deleted. - */ - void clear(); - - /** - * Determines if the archive has been modified. - */ - bool modified() const; - - /** - * Writes the archive to a Writer. Deserialized entries are - * re-serialized just-in-time before writing if they have been - * modified. - * - * @note If overwriting the source array, be sure to either first write - * to a temporary array and then replace the source, or alternatively - * detach the source from the archive beforehand. Otherwise the - * unchanged entries may become corrupted as they are reused from their - * old location in the source, which may have been already overwritten. - * - * @param to Where to write. - */ - virtual void operator >> (Writer &to) const = 0; - - protected: - /* - * Interface for derived classes: - */ - /// Base class for archive entries. - struct Entry : public PathTree::Node + Entry(PathTree::NodeArgs const &args) : Node(args), + offset(0), + size(0), + sizeInArchive(0), + maybeChanged(false), + data(0), + dataInArchive(0) + {} + + virtual ~Entry() { - dsize offset; ///< Offset from the start of the source array. - dsize size; ///< Deserialized size. - dsize sizeInArchive; ///< Size within the archive (serialized). - Time modifiedAt; ///< Latest modification timestamp. - bool maybeChanged; ///< @c true, if the data must be re-serialized when writing. - - /// Deserialized data. Can be @c NULL. Entry has ownership. - Block *data; - - /// Cached copy of the serialized data. Can be @c NULL. Entry has ownership. - Block mutable *dataInArchive; - - Entry(PathTree::NodeArgs const &args) : Node(args), - offset(0), - size(0), - sizeInArchive(0), - maybeChanged(false), - data(0), - dataInArchive(0) - {} - - virtual ~Entry() - { - // Entry has ownership of the cached data. - delete data; - delete dataInArchive; - } - }; - - /** - * Sets the index used by the Archive. A concrete subclass must call - * this in their constructor; Archive does not create an index on its - * own. - * - * @param tree PathTree with entries of suitable type. Ownership given to Archive. - */ - void setIndex(PathTree *tree); - - /** - * Reads an entry from the source archive. The implementation of this - * method is expected to cache the read data of the entry in its - * original, serialized format in Entry::dataInArchive. - * - * @param entry Entry that is being read. - * @param path Path of the entry within the archive. - * @param data Data is written here. - */ - virtual void readFromSource(Entry const &entry, Path const &path, IBlock &data) const = 0; - - /** - * Inserts an entry into the archive's index. If the path already - * exists in the index, the old entry is deleted first. - * - * @param path Path of the entry. - * - * @return Inserted entry. - */ - Entry &insertEntry(Path const &path); - - /** - * Returns the full entry index so that derived classes can iterate the - * entries. - * - * @return Entry index. - */ - PathTree const &index() const; - - private: - struct Instance; - Instance *d; + // Entry has ownership of the cached data. + delete data; + delete dataInArchive; + } }; -} + + /** + * Sets the index used by the Archive. A concrete subclass must call + * this in their constructor; Archive does not create an index on its + * own. + * + * @param tree PathTree with entries of suitable type. Ownership given to Archive. + */ + void setIndex(PathTree *tree); + + /** + * Reads an entry from the source archive. The implementation of this + * method is expected to cache the read data of the entry in its + * original, serialized format in Entry::dataInArchive. + * + * @param entry Entry that is being read. + * @param path Path of the entry within the archive. + * @param data Data is written here. + */ + virtual void readFromSource(Entry const &entry, Path const &path, IBlock &data) const = 0; + + /** + * Inserts an entry into the archive's index. If the path already + * exists in the index, the old entry is deleted first. + * + * @param path Path of the entry. + * + * @return Inserted entry. + */ + Entry &insertEntry(Path const &path); + + /** + * Returns the full entry index so that derived classes can iterate the + * entries. + * + * @return Entry index. + */ + PathTree const &index() const; + +private: + struct Instance; + Instance *d; +}; + +} // namespace de #endif /* LIBDENG2_ARCHIVE_H */ diff --git a/doomsday/libdeng2/include/de/data/counted.h b/doomsday/libdeng2/include/de/data/counted.h index 74edd71183..c607bf9174 100644 --- a/doomsday/libdeng2/include/de/data/counted.h +++ b/doomsday/libdeng2/include/de/data/counted.h @@ -22,64 +22,64 @@ #include "../libdeng2.h" -namespace de +namespace de { +/** + * Reference-counted object. Gets destroyed when its reference counter + * hits zero. + * + * @ingroup data + */ +class DENG2_PUBLIC Counted { +public: /** - * Reference-counted object. Gets destroyed when its reference counter - * hits zero. + * New counted objects have a reference count of 1 -- it is assumed + * that whoever constructs the object holds on to one reference. + */ + Counted(); + + /** + * Acquires a reference to the reference-counted object. Use the + * template to get the correct type of pointer from a derived class. + */ + template + Type *ref() { + addRef(); + return static_cast(this); + } + + /** + * Releases a reference that was acquired earlier with ref(). The + * object destroys itself when the reference counter hits zero. + */ + void release(); + +protected: + /** + * Modifies the reference counter. If the reference count is reduced to + * zero, the caller is responsible for making sure the object gets + * deleted. * - * @ingroup data + * @param count Added to the reference counter. */ - class DENG2_PUBLIC Counted - { - public: - /** - * New counted objects have a reference count of 1 -- it is assumed - * that whoever constructs the object holds on to one reference. - */ - Counted(); - - /** - * Acquires a reference to the reference-counted object. Use the - * template to get the correct type of pointer from a derived class. - */ - template - Type *ref() { - addRef(); - return static_cast(this); - } - - /** - * Releases a reference that was acquired earlier with ref(). The - * object destroys itself when the reference counter hits zero. - */ - void release(); + void addRef(dint count = 1) { + _refCount += count; + DENG2_ASSERT(_refCount >= 0); + } - protected: - /** - * Modifies the reference counter. If the reference count is reduced to - * zero, the caller is responsible for making sure the object gets - * deleted. - * - * @param count Added to the reference counter. - */ - void addRef(dint count = 1) { - _refCount += count; - DENG2_ASSERT(_refCount >= 0); - } + /** + * When a counted object is destroyed, its reference counter must be + * zero. Note that this is only called from release() when all + * references have been released. + */ + virtual ~Counted(); - /** - * When a counted object is destroyed, its reference counter must be - * zero. Note that this is only called from release() when all - * references have been released. - */ - virtual ~Counted(); +private: + /// Number of other things that refer to this object, i.e. have + /// a pointer to it. + dint _refCount; +}; - private: - /// Number of other things that refer to this object, i.e. have - /// a pointer to it. - dint _refCount; - }; -} +} // namespace de #endif /* LIBDENG2_COUNTED_H */ diff --git a/doomsday/libdeng2/include/de/data/record.h b/doomsday/libdeng2/include/de/data/record.h index 494f9d6411..133ba31aa7 100644 --- a/doomsday/libdeng2/include/de/data/record.h +++ b/doomsday/libdeng2/include/de/data/record.h @@ -30,302 +30,303 @@ #include #include -namespace de +namespace de { + +class ArrayValue; +class Function; + +/** + * A set of variables. A record may have any number of subrecords. Note + * that the members of a record do not have an order. + * + * A @em subrecord is a record that is owned by one of the members of the + * main record. The ownership chain is as follows: Record -> Variable -> + * RecordValue -> Record. + * + * @see http://en.wikipedia.org/wiki/Record_(computer_science) + * + * @ingroup data + */ +class DENG2_PUBLIC Record : public ISerializable, public LogEntry::Arg::Base, + DENG2_OBSERVES(Variable, Deletion) { - class ArrayValue; - class Function; - +public: + /// Unknown variable name was given. @ingroup errors + DENG2_ERROR(NotFoundError); + + /// All variables and subrecords in the record must have a name. @ingroup errors + DENG2_ERROR(UnnamedError); + + typedef std::map Members; + typedef std::map Subrecords; + typedef std::pair KeyValue; + typedef std::list List; + + DENG2_DEFINE_AUDIENCE(Deletion, void recordBeingDeleted(Record &record)) + +public: + Record(); + + /** + * Constructs a copy of another record. + * + * @param other Record to copy. + */ + Record(Record const &other); + + virtual ~Record(); + + /** + * Deletes all the variables in the record. + */ + void clear(); + + /** + * Determines if the record contains a variable or a subrecord named @a variableName. + */ + bool has(String const &name) const; + + /** + * Determines if the record contains a variable named @a variableName. + */ + bool hasMember(String const &variableName) const; + + /** + * Determines if the record contains a subrecord named @a subrecordName. + */ + bool hasSubrecord(String const &subrecordName) const; + + /** + * Adds a new variable to the record. + * + * @param variable Variable to add. Record gets ownership. + * The variable must have a name. + * + * @return @a variable, for convenience. + */ + Variable &add(Variable *variable); + + /** + * Removes a variable from the record. + * + * @param variable Variable owned by the record. + * + * @return Caller gets ownership of the removed variable. + */ + Variable *remove(Variable &variable); + + /** + * Adds a number variable to the record. The variable is set up to only accept + * number values. + * + * @param variableName Name of the variable. + * @param number Value of the variable. + * + * @return The number variable. + */ + Variable &addNumber(String const &variableName, Value::Number const &number); + + /** + * Adds a number variable to the record with a Boolean semantic hint. + * The variable is set up to only accept number values. + * + * @param variableName Name of the variable. + * @param booleanValue Value of the variable (@c true or @c false). + * + * @return The number variable. + */ + Variable &addBoolean(String const &variableName, bool booleanValue); + + /** + * Adds a text variable to the record. The variable is set up to only accept + * text values. + * + * @param variableName Name of the variable. + * @param text Value of the variable. + * + * @return The text variable. + */ + Variable &addText(String const &variableName, Value::Text const &text); + + Variable &addTime(String const &variableName, Time const &time); + + /** + * Adds an array variable to the record. The variable is set up to only accept + * array values. + * + * @param variableName Name of the variable. + * @param array Value for the new variable (ownership taken). If not + * provided, an empty array will be created for the variable. + * + * @return The array variable. + */ + Variable &addArray(String const &variableName, ArrayValue *array = 0); + + /** + * Adds a dictionary variable to the record. The variable is set up to only accept + * dictionary values. + * + * @param variableName Name of the variable. + * + * @return The dictionary variable. + */ + Variable &addDictionary(String const &variableName); + + /** + * Adds a block variable to the record. The variable is set up to only accept + * block values. + * + * @param variableName Name of the variable. + * + * @return The block variable. + */ + Variable &addBlock(String const &variableName); + + /** + * Adds a function variable to the record. The variable is set up to only + * accept function values. + * + * @param variableName Name of the variable. + * @param func Function. The variable's value will hold a + * reference to the Function; the caller may release + * its reference afterwards. + * + * @return The function variable. + */ + Variable &addFunction(String const &variableName, Function *func); + /** - * A set of variables. A record may have any number of subrecords. Note - * that the members of a record do not have an order. + * Adds a new subrecord to the record. Adds a variable named @a name + * and gives ownership of @a subrecord to it. * - * A @em subrecord is a record that is owned by one of the members of the - * main record. The ownership chain is as follows: Record -> Variable -> - * RecordValue -> Record. + * @param name Name to use for the subrecord. This must be a valid variable name. + * @param subrecord Record to add. This record gets ownership + * of the subrecord. + * + * @return @a subrecord, for convenience. + */ + Record &add(String const &name, Record *subrecord); + + /** + * Adds a new empty subrecord to the record. Adds a variable named @a + * name and creates a new record owned by it. + * + * @param name Name to use for the subrecord. This must be a valid variable name. + * + * @return The new subrecord. + */ + Record &addRecord(String const &name); + + /** + * Removes a subrecord from the record. + * + * @param name Name of subrecord owned by this record. + * + * @return Caller gets ownership of the removed record. + */ + Record *remove(String const &name); + + /** + * Looks up a variable in the record. Variables in subrecords can be accessed + * using the member notation: subrecord-name.variable-name + * + * @param name Variable name. + * + * @return Variable. + */ + Variable &operator [] (String const &name); + + /** + * Looks up a variable in the record. Variables in subrecords can be accessed + * using the member notation: subrecord-name.variable-name + * + * @param name Variable name. + * + * @return Variable (non-modifiable). + */ + Variable const &operator [] (String const &name) const; + + /** + * Looks up a subrecord in the record. * - * @see http://en.wikipedia.org/wiki/Record_(computer_science) + * @param name Name of the subrecord. * - * @ingroup data + * @return Subrecord. */ - class DENG2_PUBLIC Record : public ISerializable, public LogEntry::Arg::Base, - DENG2_OBSERVES(Variable, Deletion) - { - public: - /// Unknown variable name was given. @ingroup errors - DENG2_ERROR(NotFoundError); - - /// All variables and subrecords in the record must have a name. @ingroup errors - DENG2_ERROR(UnnamedError); - - typedef std::map Members; - typedef std::map Subrecords; - typedef std::pair KeyValue; - typedef std::list List; - - DENG2_DEFINE_AUDIENCE(Deletion, void recordBeingDeleted(Record &record)) - - public: - Record(); - - /** - * Constructs a copy of another record. - * - * @param other Record to copy. - */ - Record(Record const &other); - - virtual ~Record(); - - /** - * Deletes all the variables in the record. - */ - void clear(); - - /** - * Determines if the record contains a variable or a subrecord named @a variableName. - */ - bool has(String const &name) const; - - /** - * Determines if the record contains a variable named @a variableName. - */ - bool hasMember(String const &variableName) const; - - /** - * Determines if the record contains a subrecord named @a subrecordName. - */ - bool hasSubrecord(String const &subrecordName) const; - - /** - * Adds a new variable to the record. - * - * @param variable Variable to add. Record gets ownership. - * The variable must have a name. - * - * @return @a variable, for convenience. - */ - Variable &add(Variable *variable); - - /** - * Removes a variable from the record. - * - * @param variable Variable owned by the record. - * - * @return Caller gets ownership of the removed variable. - */ - Variable *remove(Variable &variable); - - /** - * Adds a number variable to the record. The variable is set up to only accept - * number values. - * - * @param variableName Name of the variable. - * @param number Value of the variable. - * - * @return The number variable. - */ - Variable &addNumber(String const &variableName, Value::Number const &number); - - /** - * Adds a number variable to the record with a Boolean semantic hint. - * The variable is set up to only accept number values. - * - * @param variableName Name of the variable. - * @param booleanValue Value of the variable (@c true or @c false). - * - * @return The number variable. - */ - Variable &addBoolean(String const &variableName, bool booleanValue); - - /** - * Adds a text variable to the record. The variable is set up to only accept - * text values. - * - * @param variableName Name of the variable. - * @param text Value of the variable. - * - * @return The text variable. - */ - Variable &addText(String const &variableName, Value::Text const &text); - - Variable &addTime(String const &variableName, Time const &time); - - /** - * Adds an array variable to the record. The variable is set up to only accept - * array values. - * - * @param variableName Name of the variable. - * @param array Value for the new variable (ownership taken). If not - * provided, an empty array will be created for the variable. - * - * @return The array variable. - */ - Variable &addArray(String const &variableName, ArrayValue *array = 0); - - /** - * Adds a dictionary variable to the record. The variable is set up to only accept - * dictionary values. - * - * @param variableName Name of the variable. - * - * @return The dictionary variable. - */ - Variable &addDictionary(String const &variableName); - - /** - * Adds a block variable to the record. The variable is set up to only accept - * block values. - * - * @param variableName Name of the variable. - * - * @return The block variable. - */ - Variable &addBlock(String const &variableName); - - /** - * Adds a function variable to the record. The variable is set up to only - * accept function values. - * - * @param variableName Name of the variable. - * @param func Function. The variable's value will hold a - * reference to the Function; the caller may release - * its reference afterwards. - * - * @return The function variable. - */ - Variable &addFunction(String const &variableName, Function *func); - - /** - * Adds a new subrecord to the record. Adds a variable named @a name - * and gives ownership of @a subrecord to it. - * - * @param name Name to use for the subrecord. This must be a valid variable name. - * @param subrecord Record to add. This record gets ownership - * of the subrecord. - * - * @return @a subrecord, for convenience. - */ - Record &add(String const &name, Record *subrecord); - - /** - * Adds a new empty subrecord to the record. Adds a variable named @a - * name and creates a new record owned by it. - * - * @param name Name to use for the subrecord. This must be a valid variable name. - * - * @return The new subrecord. - */ - Record &addRecord(String const &name); - - /** - * Removes a subrecord from the record. - * - * @param name Name of subrecord owned by this record. - * - * @return Caller gets ownership of the removed record. - */ - Record *remove(String const &name); - - /** - * Looks up a variable in the record. Variables in subrecords can be accessed - * using the member notation: subrecord-name.variable-name - * - * @param name Variable name. - * - * @return Variable. - */ - Variable &operator [] (String const &name); - - /** - * Looks up a variable in the record. Variables in subrecords can be accessed - * using the member notation: subrecord-name.variable-name - * - * @param name Variable name. - * - * @return Variable (non-modifiable). - */ - Variable const &operator [] (String const &name) const; - - /** - * Looks up a subrecord in the record. - * - * @param name Name of the subrecord. - * - * @return Subrecord. - */ - Record &subrecord(String const &name); - - /** - * Looks up a subrecord in the record. - * - * @param name Name of the subrecord. - * - * @return Subrecord (non-modifiable). - */ - Record const &subrecord(String const &name) const; - - /** - * Returns a non-modifiable map of the members. - */ - Members const &members() const; - - /** - * Collects a map of all the subrecords present in the record. - */ - Subrecords subrecords() const; - - /** - * Creates a text representation of the record. Each variable name is - * prefixed with @a prefix. - * - * @param prefix Prefix for each variable name. - * @param lines NULL (used for recursion into subrecords). - * - * @return Text representation. - */ - String asText(String const &prefix, List *lines) const; - - /** - * Convenience template for getting the value of a variable in a - * specific type. - * - * @param name Name of variable. - * - * @return Value cast to a specific value type. - */ - template - ValueType const &value(String const &name) const { - return (*this)[name].value(); - } - - /** - * Convenience method for finding the Function referenced by a member. - * - * @param name Name of member. - * - * @return The function, or @c NULL if the member does not exist or - * has some other value than FunctionValue. - */ - Function const *function(String const &name) const; - - // Implements ISerializable. - void operator >> (Writer &to) const; - void operator << (Reader &from); - - // Implements LogEntry::Arg::Base. - LogEntry::Arg::Type logEntryArgType() const { return LogEntry::Arg::STRING; } - String asText() const { return asText("", 0); } - - // Observes Variable deletion. - void variableBeingDeleted(Variable &variable); - - private: - struct Instance; - Instance * d; - }; - - /// Converts the record into a human-readable text representation. - DENG2_PUBLIC QTextStream &operator << (QTextStream &os, Record const &record); -} + Record &subrecord(String const &name); + + /** + * Looks up a subrecord in the record. + * + * @param name Name of the subrecord. + * + * @return Subrecord (non-modifiable). + */ + Record const &subrecord(String const &name) const; + + /** + * Returns a non-modifiable map of the members. + */ + Members const &members() const; + + /** + * Collects a map of all the subrecords present in the record. + */ + Subrecords subrecords() const; + + /** + * Creates a text representation of the record. Each variable name is + * prefixed with @a prefix. + * + * @param prefix Prefix for each variable name. + * @param lines NULL (used for recursion into subrecords). + * + * @return Text representation. + */ + String asText(String const &prefix, List *lines) const; + + /** + * Convenience template for getting the value of a variable in a + * specific type. + * + * @param name Name of variable. + * + * @return Value cast to a specific value type. + */ + template + ValueType const &value(String const &name) const { + return (*this)[name].value(); + } + + /** + * Convenience method for finding the Function referenced by a member. + * + * @param name Name of member. + * + * @return The function, or @c NULL if the member does not exist or + * has some other value than FunctionValue. + */ + Function const *function(String const &name) const; + + // Implements ISerializable. + void operator >> (Writer &to) const; + void operator << (Reader &from); + + // Implements LogEntry::Arg::Base. + LogEntry::Arg::Type logEntryArgType() const { return LogEntry::Arg::STRING; } + String asText() const { return asText("", 0); } + + // Observes Variable deletion. + void variableBeingDeleted(Variable &variable); + +private: + struct Instance; + Instance * d; +}; + +/// Converts the record into a human-readable text representation. +DENG2_PUBLIC QTextStream &operator << (QTextStream &os, Record const &record); + +} // namespace de #endif /* LIBDENG2_RECORD_H */ diff --git a/doomsday/libdeng2/include/de/data/stringpool.h b/doomsday/libdeng2/include/de/data/stringpool.h index affae9a340..223206a8ae 100644 --- a/doomsday/libdeng2/include/de/data/stringpool.h +++ b/doomsday/libdeng2/include/de/data/stringpool.h @@ -27,223 +27,223 @@ #include "../ISerializable" #include "../String" -namespace de +namespace de { + +/** + * Container data structure for a set of unique case-insensitive strings. + * Comparable to a @c std::set with unique IDs assigned to each contained string. + * + * The term "intern" is used here to refer to the act of inserting a string to + * the pool. As a result of interning a string, a new internal copy of the + * string may be created in the pool. + * + * Each string that actually gets added to the pool is assigned a unique + * identifier. If one tries to intern a string that already exists in the pool + * (case insensitively speaking), no new internal copy is created and no new + * identifier is assigned. Instead, the existing id of the previously interned + * string is returned. The string identifiers are not unique over the lifetime + * of the container: if a string is removed from the pool, its id is free to be + * reassigned to the next new string. Zero is not a valid id. + * + * Each string can also have an associated, custom user-defined uint32 value + * and/or void *data pointer. + * + * The implementation has, at worst, O(log n) complexity for addition, removal, + * string lookup, and user value/pointer set/get. + * + * @todo Add case-sensitive mode. + * + * @ingroup data + */ +class DENG2_PUBLIC StringPool : public ISerializable { +public: + /// String identifier was invalid. @ingroup errors + DENG2_ERROR(InvalidIdError); + + /// The pool does not have any available identifiers. @ingroup errors + DENG2_ERROR(FullError); + + /// String identifier. Each string is assigned its own Id. Because this is + /// 32-bit, there can be approximately 4.2 billion unique strings in the pool. + typedef duint32 Id; + +public: + /** + * Constructs an empty StringPool. + */ + StringPool(); + + /** + * Constructs an empty StringPool and interns a number of strings. + * + * @param strings Array of strings to be interned (must contain at least @a count strings). + * @param count Number of strings to be interned. + */ + StringPool(String *strings, uint count); + + /** + * Destroys the stringpool. + */ + ~StringPool(); + + /** + * Clear the string pool. All strings in the pool will be destroyed. + */ + void clear(); + + /** + * Is the pool empty? + * @return @c true if there are no strings present in the pool. + */ + bool empty() const; + + /** + * Determines the number of strings in the pool. + * @return Number of strings in the pool. + */ + dsize size() const; + /** - * Container data structure for a set of unique case-insensitive strings. - * Comparable to a @c std::set with unique IDs assigned to each contained string. - * - * The term "intern" is used here to refer to the act of inserting a string to - * the pool. As a result of interning a string, a new internal copy of the - * string may be created in the pool. - * - * Each string that actually gets added to the pool is assigned a unique - * identifier. If one tries to intern a string that already exists in the pool - * (case insensitively speaking), no new internal copy is created and no new - * identifier is assigned. Instead, the existing id of the previously interned - * string is returned. The string identifiers are not unique over the lifetime - * of the container: if a string is removed from the pool, its id is free to be - * reassigned to the next new string. Zero is not a valid id. - * - * Each string can also have an associated, custom user-defined uint32 value - * and/or void *data pointer. - * - * The implementation has, at worst, O(log n) complexity for addition, removal, - * string lookup, and user value/pointer set/get. - * - * @todo Add case-sensitive mode. - * - * @ingroup data - */ - class DENG2_PUBLIC StringPool : public ISerializable - { - public: - /// String identifier was invalid. @ingroup errors - DENG2_ERROR(InvalidIdError); - - /// The pool does not have any available identifiers. @ingroup errors - DENG2_ERROR(FullError); - - /// String identifier. Each string is assigned its own Id. Because this is - /// 32-bit, there can be approximately 4.2 billion unique strings in the pool. - typedef duint32 Id; - - public: - /** - * Constructs an empty StringPool. - */ - StringPool(); - - /** - * Constructs an empty StringPool and interns a number of strings. - * - * @param strings Array of strings to be interned (must contain at least @a count strings). - * @param count Number of strings to be interned. - */ - StringPool(String *strings, uint count); - - /** - * Destroys the stringpool. - */ - ~StringPool(); - - /** - * Clear the string pool. All strings in the pool will be destroyed. - */ - void clear(); - - /** - * Is the pool empty? - * @return @c true if there are no strings present in the pool. - */ - bool empty() const; - - /** - * Determines the number of strings in the pool. - * @return Number of strings in the pool. - */ - dsize size() const; - - /** - * Interns string @a str. If this string is not already in the pool, a new - * internal copy is created; otherwise, the existing internal copy is returned. - * New internal copies will be assigned new identifiers. - * - * @param str String to be added (must not be of zero-length). - * A copy of this is made if the string is interned. - * - * @return Unique Id associated with the internal copy of @a str. - */ - Id intern(String str); - - /** - * Interns string @a str. If this string is not already in the pool, a new - * internal copy is created; otherwise, the existing internal copy is returned. - * New internal copies will be assigned new identifiers. - * - * @param str String to be added (must not be of zero-length). - * A copy of this is made if the string is interned. - * - * @return The interned copy of the string owned by the pool. - */ - String internAndRetrieve(String str); - - /** - * Sets the user-specified custom value associated with the string @a id. - * The default user value is zero. - * - * @param id Id of a string. - * @param value User value. - */ - void setUserValue(Id id, uint value); - - /** - * Retrieves the user-specified custom value associated with the string @a id. - * The default user value is zero. - * - * @param id Id of a string. - * - * @return User value. - */ - uint userValue(Id id) const; - - /** - * Sets the user-specified custom pointer associated with the string @a id. - * By default the pointer is NULL. - * - * @note User pointer values are @em not serialized. - * - * @param id Id of a string. - * @param ptr User pointer. - */ - void setUserPointer(Id id, void *ptr); - - /** - * Retrieves the user-specified custom pointer associated with the string @a id. - * - * @param id Id of a string. - * - * @return User pointer. - */ - void *userPointer(Id id) const; - - /** - * Is @a str considered to be in the pool? - * - * @param str String to look for. - * - * @return Id of the matching string; else @c 0. - */ - Id isInterned(String str) const; - - /** - * Retrieve an immutable copy of the interned string associated with the - * string @a id. - * - * @param id Id of the string to retrieve. - * - * @return Interned string associated with @a internId. - */ - String string(Id id) const; - - /** - * Returns a reference to an interned string. Only use this when the - * pool is being accessed as a const object -- the returned references - * may become invalid when the pool is changed. - * - * @param id Id of the string to retrieve. - * - * @return Reference to interned string. Do not change the contents of - * the pool while retaining the returned reference. - */ - String const &stringRef(Id id) const; - - /** - * Removes a string from the pool. - * - * @param str String to be removed. - * - * @return @c true iff a string was removed. - */ - bool remove(String str); - - /** - * Removes a string from the pool. - * - * @param id Id of the string to remove. - * - * @return @c true iff a string was removed. - */ - bool removeById(Id id); - - /** - * Iterate over all strings in the pool making a callback for each. Iteration - * ends when all strings have been processed or a callback returns non-zero. - * - * @param callback Callback to make for each iteration. - * @param data User data to be passed to the callback. - * - * @return @c 0 iff iteration completed wholly. Otherwise the non-zero value - * returned by @a callback. - */ - int iterate(int (*callback)(Id, void *), void *data) const; - - // Implements ISerializable. - void operator >> (Writer &to) const; - void operator << (Reader &from); + * Interns string @a str. If this string is not already in the pool, a new + * internal copy is created; otherwise, the existing internal copy is returned. + * New internal copies will be assigned new identifiers. + * + * @param str String to be added (must not be of zero-length). + * A copy of this is made if the string is interned. + * + * @return Unique Id associated with the internal copy of @a str. + */ + Id intern(String str); + + /** + * Interns string @a str. If this string is not already in the pool, a new + * internal copy is created; otherwise, the existing internal copy is returned. + * New internal copies will be assigned new identifiers. + * + * @param str String to be added (must not be of zero-length). + * A copy of this is made if the string is interned. + * + * @return The interned copy of the string owned by the pool. + */ + String internAndRetrieve(String str); + + /** + * Sets the user-specified custom value associated with the string @a id. + * The default user value is zero. + * + * @param id Id of a string. + * @param value User value. + */ + void setUserValue(Id id, uint value); + + /** + * Retrieves the user-specified custom value associated with the string @a id. + * The default user value is zero. + * + * @param id Id of a string. + * + * @return User value. + */ + uint userValue(Id id) const; + + /** + * Sets the user-specified custom pointer associated with the string @a id. + * By default the pointer is NULL. + * + * @note User pointer values are @em not serialized. + * + * @param id Id of a string. + * @param ptr User pointer. + */ + void setUserPointer(Id id, void *ptr); + + /** + * Retrieves the user-specified custom pointer associated with the string @a id. + * + * @param id Id of a string. + * + * @return User pointer. + */ + void *userPointer(Id id) const; + + /** + * Is @a str considered to be in the pool? + * + * @param str String to look for. + * + * @return Id of the matching string; else @c 0. + */ + Id isInterned(String str) const; + + /** + * Retrieve an immutable copy of the interned string associated with the + * string @a id. + * + * @param id Id of the string to retrieve. + * + * @return Interned string associated with @a internId. + */ + String string(Id id) const; + + /** + * Returns a reference to an interned string. Only use this when the + * pool is being accessed as a const object -- the returned references + * may become invalid when the pool is changed. + * + * @param id Id of the string to retrieve. + * + * @return Reference to interned string. Do not change the contents of + * the pool while retaining the returned reference. + */ + String const &stringRef(Id id) const; + + /** + * Removes a string from the pool. + * + * @param str String to be removed. + * + * @return @c true iff a string was removed. + */ + bool remove(String str); + + /** + * Removes a string from the pool. + * + * @param id Id of the string to remove. + * + * @return @c true iff a string was removed. + */ + bool removeById(Id id); + + /** + * Iterate over all strings in the pool making a callback for each. Iteration + * ends when all strings have been processed or a callback returns non-zero. + * + * @param callback Callback to make for each iteration. + * @param data User data to be passed to the callback. + * + * @return @c 0 iff iteration completed wholly. Otherwise the non-zero value + * returned by @a callback. + */ + int iterate(int (*callback)(Id, void *), void *data) const; + + // Implements ISerializable. + void operator >> (Writer &to) const; + void operator << (Reader &from); #if _DEBUG - /** - * Print contents of the pool. For debug. - * @param pool StringPool instance. - */ - void print() const; + /** + * Print contents of the pool. For debug. + * @param pool StringPool instance. + */ + void print() const; #endif - private: - struct Instance; - Instance *d; - }; +private: + struct Instance; + Instance *d; +}; } // namespace de diff --git a/doomsday/libdeng2/include/de/data/variable.h b/doomsday/libdeng2/include/de/data/variable.h index d2a3b74f85..f0c8080848 100644 --- a/doomsday/libdeng2/include/de/data/variable.h +++ b/doomsday/libdeng2/include/de/data/variable.h @@ -26,247 +26,248 @@ #include -namespace de -{ - class Value; +namespace de { + +class Value; +/** + * Stores a value and name identifier. Variables are typically stored in a Record. + * A variable's behavior is defined by its mode flags. + * + * @ingroup data + */ +class DENG2_PUBLIC Variable : public ISerializable +{ +public: + /// There was an attempt to change the value of a read-only variable. @ingroup errors + DENG2_ERROR(ReadOnlyError); + + /// An invalid value type was used. The mode flags denied using a value of the + /// given type with the variable. @ingroup errors + DENG2_ERROR(InvalidError); + + /// Variable name contains invalid characters. @ingroup errors + DENG2_ERROR(NameError); + + /// Value could not be converted to the attempted type. @ingroup errors + DENG2_ERROR(TypeError); + + /** @name Mode Flags */ + //@{ + enum Flag + { + /// Variable's value cannot change. + ReadOnly = 0x1, + + /// Variable cannot be serialized. + NoSerialize = 0x2, + + /// NoneValue allowed as value. + AllowNone = 0x4, + + /// NumberValue allowed as value. + AllowNumber = 0x8, + + /// TextValue allowed as value. + AllowText = 0x10, + + /// ArrayValue allowed as value. + AllowArray = 0x20, + + /// DictionaryValue allowed as value. + AllowDictionary = 0x40, + + /// BlockValue allowed as value. + AllowBlock = 0x80, + + /// FunctionValue allowed as value. + AllowFunction = 0x100, + + /// RecordValue allowed as value. + AllowRecord = 0x200, + + /// RefValue allowed as value. + AllowRef = 0x400, + + /// TimeValue allowed as value. + AllowTime = 0x800, + + /// The default mode allows reading and writing all types of values, + /// including NoneValue. + DefaultMode = AllowNone | AllowNumber | AllowText | AllowArray | + AllowDictionary | AllowBlock | AllowFunction | AllowRecord | + AllowRef | AllowTime + }; + //@} + Q_DECLARE_FLAGS(Flags, Flag) + +public: /** - * Stores a value and name identifier. Variables are typically stored in a Record. - * A variable's behavior is defined by its mode flags. + * Constructs a new variable. * - * @ingroup data + * @param name Name for the variable. Any periods (.) are not allowed. + * @param initial Initial value. Variable gets ownership. If no value is given here, + * a NoneValue will be created for the variable. + * @param varMode Mode flags. */ - class DENG2_PUBLIC Variable : public ISerializable - { - public: - /// There was an attempt to change the value of a read-only variable. @ingroup errors - DENG2_ERROR(ReadOnlyError); - - /// An invalid value type was used. The mode flags denied using a value of the - /// given type with the variable. @ingroup errors - DENG2_ERROR(InvalidError); - - /// Variable name contains invalid characters. @ingroup errors - DENG2_ERROR(NameError); - - /// Value could not be converted to the attempted type. @ingroup errors - DENG2_ERROR(TypeError); - - /** @name Mode Flags */ - //@{ - enum Flag - { - /// Variable's value cannot change. - ReadOnly = 0x1, - - /// Variable cannot be serialized. - NoSerialize = 0x2, - - /// NoneValue allowed as value. - AllowNone = 0x4, - - /// NumberValue allowed as value. - AllowNumber = 0x8, - - /// TextValue allowed as value. - AllowText = 0x10, - - /// ArrayValue allowed as value. - AllowArray = 0x20, - - /// DictionaryValue allowed as value. - AllowDictionary = 0x40, - - /// BlockValue allowed as value. - AllowBlock = 0x80, - - /// FunctionValue allowed as value. - AllowFunction = 0x100, - - /// RecordValue allowed as value. - AllowRecord = 0x200, - - /// RefValue allowed as value. - AllowRef = 0x400, - - /// TimeValue allowed as value. - AllowTime = 0x800, - - /// The default mode allows reading and writing all types of values, - /// including NoneValue. - DefaultMode = AllowNone | AllowNumber | AllowText | AllowArray | - AllowDictionary | AllowBlock | AllowFunction | AllowRecord | - AllowRef | AllowTime - }; - //@} - Q_DECLARE_FLAGS(Flags, Flag) - - public: - /** - * Constructs a new variable. - * - * @param name Name for the variable. Any periods (.) are not allowed. - * @param initial Initial value. Variable gets ownership. If no value is given here, - * a NoneValue will be created for the variable. - * @param varMode Mode flags. - */ - Variable(String const &name = "", Value *initial = 0, - Flags const &varMode = DefaultMode); - - /** - * Constructs a copy of another variable. - * - * @param other Variable to copy. - */ - Variable(Variable const &other); - - virtual ~Variable(); - - /** - * Returns the name of the variable. - */ - String const &name() const { return _name; } - - /** - * Sets the value of the variable. - * - * @param v New value. Variable gets ownership. - */ - void set(Value *v); - - /** - * Sets the value of the variable. - * - * @param v New value. Variable gets ownership. - */ - Variable &operator = (Value *v); - - /** - * Sets the value of the variable. - * - * @param v New value. Variable takes a copy of this. - */ - void set(Value const &v); - - /** - * Returns the value of the variable (non-modifiable). - */ - Value const &value() const; - - /** - * Returns the value of the variable. - */ - Value &value(); - - /** - * Returns the value of the variable. - */ - template - Type &value() { - Type *v = dynamic_cast(_value); - if(!v) { - /// @throw TypeError Casting to Type failed. - throw TypeError("Variable::value", "Illegal type conversion"); - } - return *v; + Variable(String const &name = "", Value *initial = 0, + Flags const &varMode = DefaultMode); + + /** + * Constructs a copy of another variable. + * + * @param other Variable to copy. + */ + Variable(Variable const &other); + + virtual ~Variable(); + + /** + * Returns the name of the variable. + */ + String const &name() const { return _name; } + + /** + * Sets the value of the variable. + * + * @param v New value. Variable gets ownership. + */ + void set(Value *v); + + /** + * Sets the value of the variable. + * + * @param v New value. Variable gets ownership. + */ + Variable &operator = (Value *v); + + /** + * Sets the value of the variable. + * + * @param v New value. Variable takes a copy of this. + */ + void set(Value const &v); + + /** + * Returns the value of the variable (non-modifiable). + */ + Value const &value() const; + + /** + * Returns the value of the variable. + */ + Value &value(); + + /** + * Returns the value of the variable. + */ + template + Type &value() { + Type *v = dynamic_cast(_value); + if(!v) { + /// @throw TypeError Casting to Type failed. + throw TypeError("Variable::value", "Illegal type conversion"); } + return *v; + } - /** - * Returns the value of the variable. - */ - template - Type const &value() const { - Type const *v = dynamic_cast(_value); - if(!v) { - /// @throw TypeError Casting to Type failed. - throw TypeError("Variable::value", "Illegal type conversion"); - } - return *v; + /** + * Returns the value of the variable. + */ + template + Type const &value() const { + Type const *v = dynamic_cast(_value); + if(!v) { + /// @throw TypeError Casting to Type failed. + throw TypeError("Variable::value", "Illegal type conversion"); } - - /** - * Returns the current mode flags of the variable. - */ - Flags mode() const; - - /** - * Sets the mode flags of the variable. - * - * @param flags New mode flags that will replace the current ones. - */ - void setMode(Flags const &flags); - - /** - * Makes the variable read-only. - * - * @return Reference to this variable. - */ - Variable &setReadOnly(); - - /** - * Checks that a value is valid, checking what is allowed in the mode - * flags. - * - * @param v Value to check. - * - * @return @c true, if the value is valid. @c false otherwise. - */ - bool isValid(Value const &v) const; - - /** - * Verifies that a value is valid, checking against what is allowed in the - * mode flags. If not, an exception is thrown. - * - * @param v Value to test. - */ - void verifyValid(Value const &v) const; - - /** - * Verifies that the variable can be assigned a new value. - * - * @param attemptedNewValue The new value that is being assigned. - */ - void verifyWritable(Value const &attemptedNewValue); - - /** - * Verifies that a string is a valid name for the variable. If not, - * an exception is thrown. - * - * @param s Name to test. - */ - static void verifyName(String const &s); - - // Implements ISerializable. - void operator >> (Writer &to) const; - void operator << (Reader &from); - - public: - /** - * The variable is about to be deleted. - * - * @param variable Variable. - */ - DENG2_DEFINE_AUDIENCE(Deletion, void variableBeingDeleted(Variable &variable)) - - /** - * The value of the variable has changed. - * - * @param variable Variable. - * @param newValue New value of the variable. - */ - DENG2_DEFINE_AUDIENCE(Change, void variableValueChanged(Variable &variable, Value const &newValue)) - - private: - String _name; - - /// Value of the variable. - Value *_value; - - /// Mode flags. - Flags _mode; - }; + return *v; + } + + /** + * Returns the current mode flags of the variable. + */ + Flags mode() const; + + /** + * Sets the mode flags of the variable. + * + * @param flags New mode flags that will replace the current ones. + */ + void setMode(Flags const &flags); + + /** + * Makes the variable read-only. + * + * @return Reference to this variable. + */ + Variable &setReadOnly(); + + /** + * Checks that a value is valid, checking what is allowed in the mode + * flags. + * + * @param v Value to check. + * + * @return @c true, if the value is valid. @c false otherwise. + */ + bool isValid(Value const &v) const; + + /** + * Verifies that a value is valid, checking against what is allowed in the + * mode flags. If not, an exception is thrown. + * + * @param v Value to test. + */ + void verifyValid(Value const &v) const; + + /** + * Verifies that the variable can be assigned a new value. + * + * @param attemptedNewValue The new value that is being assigned. + */ + void verifyWritable(Value const &attemptedNewValue); + + /** + * Verifies that a string is a valid name for the variable. If not, + * an exception is thrown. + * + * @param s Name to test. + */ + static void verifyName(String const &s); + + // Implements ISerializable. + void operator >> (Writer &to) const; + void operator << (Reader &from); + +public: + /** + * The variable is about to be deleted. + * + * @param variable Variable. + */ + DENG2_DEFINE_AUDIENCE(Deletion, void variableBeingDeleted(Variable &variable)) + + /** + * The value of the variable has changed. + * + * @param variable Variable. + * @param newValue New value of the variable. + */ + DENG2_DEFINE_AUDIENCE(Change, void variableValueChanged(Variable &variable, Value const &newValue)) + +private: + String _name; + + /// Value of the variable. + Value *_value; + + /// Mode flags. + Flags _mode; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(Variable::Flags) - Q_DECLARE_OPERATORS_FOR_FLAGS(Variable::Flags) -} +} // namespace de #endif /* LIBDENG2_VARIABLE_H */ diff --git a/doomsday/libdeng2/include/de/data/waitable.h b/doomsday/libdeng2/include/de/data/waitable.h index aeb62fce55..386dbeb26c 100644 --- a/doomsday/libdeng2/include/de/data/waitable.h +++ b/doomsday/libdeng2/include/de/data/waitable.h @@ -25,41 +25,42 @@ #include -namespace de +namespace de { + +/** + * Semaphore that allows objects to be waited on. + * + * @ingroup data + */ +class DENG2_PUBLIC Waitable { - /** - * Semaphore that allows objects to be waited on. - * - * @ingroup data - */ - class DENG2_PUBLIC Waitable - { - public: - /// wait() failed due to timing out before the resource is secured. @ingroup errors - DENG2_ERROR(TimeOutError); - - /// wait() or waitTime() failed to secure the resource. @ingroup errors - DENG2_ERROR(WaitError); - - public: - Waitable(duint initialValue = 0); - virtual ~Waitable(); +public: + /// wait() failed due to timing out before the resource is secured. @ingroup errors + DENG2_ERROR(TimeOutError); + + /// wait() or waitTime() failed to secure the resource. @ingroup errors + DENG2_ERROR(WaitError); + +public: + Waitable(duint initialValue = 0); + virtual ~Waitable(); + + /// Wait until the resource becomes available. + void wait(); + + /// Wait for the specified period of time to secure the + /// resource. If timeout occurs, an exception is thrown. + void wait(Time::Delta const &timeOut); + + /// Mark the resource as available by incrementing the + /// semaphore value. + void post(); - /// Wait until the resource becomes available. - void wait(); +private: + /// Pointer to the internal semaphore data. + QSemaphore _semaphore; +}; - /// Wait for the specified period of time to secure the - /// resource. If timeout occurs, an exception is thrown. - void wait(Time::Delta const &timeOut); - - /// Mark the resource as available by incrementing the - /// semaphore value. - void post(); - - private: - /// Pointer to the internal semaphore data. - QSemaphore _semaphore; - }; } #endif /* LIBDENG2_WAITABLE_H */ diff --git a/doomsday/libdeng2/include/de/data/waitablefifo.h b/doomsday/libdeng2/include/de/data/waitablefifo.h index 981836ed0e..f1c678a03d 100644 --- a/doomsday/libdeng2/include/de/data/waitablefifo.h +++ b/doomsday/libdeng2/include/de/data/waitablefifo.h @@ -23,20 +23,21 @@ #include "../FIFO" #include "../Waitable" -namespace de +namespace de { + +/** + * FIFO with a semaphore that allows threads to wait until there are objects in + * the buffer. + * + * @ingroup data + */ +template +class WaitableFIFO : public FIFO, public Waitable { - /** - * FIFO with a semaphore that allows threads to wait until there are objects in - * the buffer. - * - * @ingroup data - */ - template - class WaitableFIFO : public FIFO, public Waitable - { - public: - WaitableFIFO() {} - }; -} +public: + WaitableFIFO() {} +}; + +} // namespace de #endif /* LIBDENG2_WAITABLEFIFO_H */ diff --git a/doomsday/libdeng2/include/de/data/zeroed.h b/doomsday/libdeng2/include/de/data/zeroed.h index fce4e844d4..dc7f5d6209 100644 --- a/doomsday/libdeng2/include/de/data/zeroed.h +++ b/doomsday/libdeng2/include/de/data/zeroed.h @@ -22,35 +22,36 @@ #include "../libdeng2.h" -namespace de +namespace de { + +/** + * Template for primitive types that are automatically initialized to zero. + */ +template +class Zeroed { - /** - * Template for primitive types that are automatically initialized to zero. - */ - template - class Zeroed - { - public: - Zeroed(Type const &v = 0) : value(v) {} - operator Type const &() const { return value; } - operator Type &() { return value; } - Zeroed &operator = (Type const &v) { - value = v; - return *this; - } - - public: - Type value; - }; - - typedef Zeroed Int8; - typedef Zeroed Int16; - typedef Zeroed Int32; - typedef Zeroed Int64; - typedef Zeroed Uint8; - typedef Zeroed Uint16; - typedef Zeroed Uint32; - typedef Zeroed Uint64; -} +public: + Zeroed(Type const &v = 0) : value(v) {} + operator Type const &() const { return value; } + operator Type &() { return value; } + Zeroed &operator = (Type const &v) { + value = v; + return *this; + } + +public: + Type value; +}; + +typedef Zeroed Int8; +typedef Zeroed Int16; +typedef Zeroed Int32; +typedef Zeroed Int64; +typedef Zeroed Uint8; +typedef Zeroed Uint16; +typedef Zeroed Uint32; +typedef Zeroed Uint64; + +} // namespace de #endif /* LIBDENG2_ZEROED_H */ diff --git a/doomsday/libdeng2/include/de/data/ziparchive.h b/doomsday/libdeng2/include/de/data/ziparchive.h index 46396f2d9e..132fd7c694 100644 --- a/doomsday/libdeng2/include/de/data/ziparchive.h +++ b/doomsday/libdeng2/include/de/data/ziparchive.h @@ -22,93 +22,94 @@ #include "../Archive" -namespace de +namespace de { + +/** + * Archive whose serialization uses the ZIP file format. + * @ingroup data + * + * All the features of the ZIP format are not supported: + * - Deflate is the only supported compression method. + * - Multipart ZIP files are not supported. + * + * @see http://en.wikipedia.org/wiki/Zip_(file_format) + */ +class DENG2_PUBLIC ZipArchive : public Archive { +public: + /// The central directory of the ZIP archive cannot be located. Maybe it's not + /// a ZIP archive after all? @ingroup errors + DENG2_SUB_ERROR(FormatError, MissingCentralDirectoryError); + + /// The source archive belongs to a multipart archive. @ingroup errors + DENG2_SUB_ERROR(FormatError, MultiPartError); + + /// An entry in the archive uses a compression algorithm not supported by the + /// implementation. @ingroup errors + DENG2_SUB_ERROR(FormatError, UnknownCompressionError); + + /// An entry is encrypted. Decrypting is not supported. @ingroup errors + DENG2_SUB_ERROR(FormatError, EncryptionError); + + /// There is an error during decompression. @ingroup errors + DENG2_SUB_ERROR(ContentError, InflateError); + + /// There is an error during compression. @ingroup errors + DENG2_SUB_ERROR(ContentError, DeflateError); + +public: + /** + * Constructs an empty ZIP archive. + */ + ZipArchive(); + /** - * Archive whose serialization uses the ZIP file format. - * @ingroup data + * Constructs a new ZIP archive instance. The content index contained + * in @a data is read during construction. * - * All the features of the ZIP format are not supported: - * - Deflate is the only supported compression method. - * - Multipart ZIP files are not supported. + * @param data Data of the source archive. No copy of the + * data is made, so the caller must make sure the + * byte array remains in existence for the lifetime + * of the Archive instance. + */ + ZipArchive(IByteArray const &data); + + virtual ~ZipArchive(); + + void operator >> (Writer &to) const; + +public: + /** + * Determines whether a File looks like it could be accessed using + * ZipArchive. + * + * @param file File to check. * - * @see http://en.wikipedia.org/wiki/Zip_(file_format) + * @return @c true, if the file looks like an archive. */ - class DENG2_PUBLIC ZipArchive : public Archive + static bool recognize(File const &file); + +protected: + void readFromSource(Entry const &entry, Path const &path, IBlock &uncompressedData) const; + + struct ZipEntry : public Entry { - public: - /// The central directory of the ZIP archive cannot be located. Maybe it's not - /// a ZIP archive after all? @ingroup errors - DENG2_SUB_ERROR(FormatError, MissingCentralDirectoryError); - - /// The source archive belongs to a multipart archive. @ingroup errors - DENG2_SUB_ERROR(FormatError, MultiPartError); - - /// An entry in the archive uses a compression algorithm not supported by the - /// implementation. @ingroup errors - DENG2_SUB_ERROR(FormatError, UnknownCompressionError); - - /// An entry is encrypted. Decrypting is not supported. @ingroup errors - DENG2_SUB_ERROR(FormatError, EncryptionError); - - /// There is an error during decompression. @ingroup errors - DENG2_SUB_ERROR(ContentError, InflateError); - - /// There is an error during compression. @ingroup errors - DENG2_SUB_ERROR(ContentError, DeflateError); - - public: - /** - * Constructs an empty ZIP archive. - */ - ZipArchive(); - - /** - * Constructs a new ZIP archive instance. The content index contained - * in @a data is read during construction. - * - * @param data Data of the source archive. No copy of the - * data is made, so the caller must make sure the - * byte array remains in existence for the lifetime - * of the Archive instance. - */ - ZipArchive(IByteArray const &data); - - virtual ~ZipArchive(); - - void operator >> (Writer &to) const; - - public: - /** - * Determines whether a File looks like it could be accessed using - * ZipArchive. - * - * @param file File to check. - * - * @return @c true, if the file looks like an archive. - */ - static bool recognize(File const &file); - - protected: - void readFromSource(Entry const &entry, Path const &path, IBlock &uncompressedData) const; - - struct ZipEntry : public Entry - { - duint16 compression; ///< Type of compression employed by the entry. - duint32 crc32; ///< CRC32 checksum. - dsize localHeaderOffset; ///< Offset of the local file header. - - ZipEntry(PathTree::NodeArgs const &args) : Entry(args), - compression(0), crc32(0), localHeaderOffset(0) {} - - /// Recalculates CRC32 of the entry. - void update(); - }; - - typedef PathTreeT Index; - - Index const &index() const; + duint16 compression; ///< Type of compression employed by the entry. + duint32 crc32; ///< CRC32 checksum. + dsize localHeaderOffset; ///< Offset of the local file header. + + ZipEntry(PathTree::NodeArgs const &args) : Entry(args), + compression(0), crc32(0), localHeaderOffset(0) {} + + /// Recalculates CRC32 of the entry. + void update(); }; -} + + typedef PathTreeT Index; + + Index const &index() const; +}; + +} // namespace de #endif // LIBDENG2_ZIPARCHIVE_H diff --git a/doomsday/libdeng2/include/de/filesys/archiveentryfile.h b/doomsday/libdeng2/include/de/filesys/archiveentryfile.h index 18282fc693..f2a74640db 100644 --- a/doomsday/libdeng2/include/de/filesys/archiveentryfile.h +++ b/doomsday/libdeng2/include/de/filesys/archiveentryfile.h @@ -22,50 +22,51 @@ #include "../ByteArrayFile" -namespace de +namespace de { + +class Archive; + +/** + * Accesses data of an entry within an archive. + * + * @ingroup fs + */ +class ArchiveEntryFile : public ByteArrayFile { - class Archive; - +public: /** - * Accesses data of an entry within an archive. + * Constructs an archive file. * - * @ingroup fs + * @param name Name of the file. + * @param archive Archive where the contents of the file are located. + * @param entryPath Path of the file's entry within the archive. */ - class ArchiveEntryFile : public ByteArrayFile - { - public: - /** - * Constructs an archive file. - * - * @param name Name of the file. - * @param archive Archive where the contents of the file are located. - * @param entryPath Path of the file's entry within the archive. - */ - ArchiveEntryFile(String const &name, Archive &archive, String const &entryPath); - - ~ArchiveEntryFile(); + ArchiveEntryFile(String const &name, Archive &archive, String const &entryPath); + + ~ArchiveEntryFile(); + + String describe() const; + + void clear(); + + /// Returns the archive of the file. + Archive &archive() { return _archive; } - String describe() const; + /// Returns the archive of the file (non-modifiable). + Archive const &archive() const { return _archive; } - void clear(); + // Implements IByteArray. + Size size() const; + void get(Offset at, Byte *values, Size count) const; + void set(Offset at, Byte const *values, Size count); - /// Returns the archive of the file. - Archive &archive() { return _archive; } +private: + Archive &_archive; - /// Returns the archive of the file (non-modifiable). - Archive const &archive() const { return _archive; } + /// Path of the entry within the archive. + String _entryPath; +}; - // Implements IByteArray. - Size size() const; - void get(Offset at, Byte *values, Size count) const; - void set(Offset at, Byte const *values, Size count); - - private: - Archive &_archive; - - /// Path of the entry within the archive. - String _entryPath; - }; -} +} // namespace de #endif /* LIBDENG2_ARCHIVEENTRYFILE_H */ diff --git a/doomsday/libdeng2/include/de/filesys/archivefeed.h b/doomsday/libdeng2/include/de/filesys/archivefeed.h index 9a4aaa4e13..18fbf53a0b 100644 --- a/doomsday/libdeng2/include/de/filesys/archivefeed.h +++ b/doomsday/libdeng2/include/de/filesys/archivefeed.h @@ -24,61 +24,62 @@ #include "../ByteArrayFile" #include "../String" -namespace de +namespace de { + +class Archive; + +/** + * Produces files and folders that represent the contents of an Archive. + * + * @ingroup fs + */ +class ArchiveFeed : public Feed { - class Archive; - +public: + /// Provided source file cannot be used as a feed source. @ingroup errors + DENG2_ERROR(InvalidSourceError); + +public: /** - * Produces files and folders that represent the contents of an Archive. + * Constructs a new archive feed. * - * @ingroup fs + * @param archiveFile File where the data comes from. */ - class ArchiveFeed : public Feed - { - public: - /// Provided source file cannot be used as a feed source. @ingroup errors - DENG2_ERROR(InvalidSourceError); + ArchiveFeed(File &archiveFile); - public: - /** - * Constructs a new archive feed. - * - * @param archiveFile File where the data comes from. - */ - ArchiveFeed(File &archiveFile); - - /** - * Constructs an archive feed that populates the contents of a folder - * in another feed's archive. - * - * @param parentFeed Feed whose archive will be used. - * @param basePath Path within the archive for the new feed. - */ - ArchiveFeed(ArchiveFeed &parentFeed, String const &basePath); + /** + * Constructs an archive feed that populates the contents of a folder + * in another feed's archive. + * + * @param parentFeed Feed whose archive will be used. + * @param basePath Path within the archive for the new feed. + */ + ArchiveFeed(ArchiveFeed &parentFeed, String const &basePath); - virtual ~ArchiveFeed(); + virtual ~ArchiveFeed(); - String description() const; + String description() const; + + void populate(Folder &folder); + bool prune(File &file) const; + File *newFile(String const &name); + void removeFile(String const &name); + + /** + * Returns the archive that the feed accesses. + */ + Archive &archive(); + + /** + * Returns the base path within the archive. + */ + String const &basePath() const; - void populate(Folder &folder); - bool prune(File &file) const; - File *newFile(String const &name); - void removeFile(String const &name); +private: + struct Instance; + Instance *d; +}; - /** - * Returns the archive that the feed accesses. - */ - Archive &archive(); - - /** - * Returns the base path within the archive. - */ - String const &basePath() const; - - private: - struct Instance; - Instance *d; - }; -} +} // namespace de #endif /* LIBDENG2_ARCHIVEFEED_H */ diff --git a/doomsday/libdeng2/include/de/filesys/bytearrayfile.h b/doomsday/libdeng2/include/de/filesys/bytearrayfile.h index 40249bebb8..ff3babf1bb 100644 --- a/doomsday/libdeng2/include/de/filesys/bytearrayfile.h +++ b/doomsday/libdeng2/include/de/filesys/bytearrayfile.h @@ -24,32 +24,33 @@ #include "../File" #include "../IByteArray" -namespace de +namespace de { + +/** + * Reads from and writes to files that contain a random-access byte array + * of data. This is an abstract base class for files that have this + * property. + * + * When used as an I/O stream: reading from the stream outputs the entire + * contents of the file, and writing to the stream appends new content to + * the end of the file. Byte array files must be used is immutable mode; + * the bytes are not removed from the stream by readers (i.e., when, say, a + * native file is read, the bytes aren't removed from the file). + * + * @ingroup fs + */ +class DENG2_PUBLIC ByteArrayFile : public File, public IByteArray { - /** - * Reads from and writes to files that contain a random-access byte array - * of data. This is an abstract base class for files that have this - * property. - * - * When used as an I/O stream: reading from the stream outputs the entire - * contents of the file, and writing to the stream appends new content to - * the end of the file. Byte array files must be used is immutable mode; - * the bytes are not removed from the stream by readers (i.e., when, say, a - * native file is read, the bytes aren't removed from the file). - * - * @ingroup fs - */ - class DENG2_PUBLIC ByteArrayFile : public File, public IByteArray - { - protected: - ByteArrayFile(String const &name = "") : File(name) {} +protected: + ByteArrayFile(String const &name = "") : File(name) {} + +public: + // Implements IIOStream. + IOStream &operator << (IByteArray const &bytes); + IIStream &operator >> (IByteArray &bytes); + IIStream const &operator >> (IByteArray &bytes) const; +}; - public: - // Implements IIOStream. - IOStream &operator << (IByteArray const &bytes); - IIStream &operator >> (IByteArray &bytes); - IIStream const &operator >> (IByteArray &bytes) const; - }; -} +} // namespace de #endif // LIBDENG2_BYTEARRAYFILE_H diff --git a/doomsday/libdeng2/include/de/filesys/directoryfeed.h b/doomsday/libdeng2/include/de/filesys/directoryfeed.h index 30c2f1fa07..99c296c4b4 100644 --- a/doomsday/libdeng2/include/de/filesys/directoryfeed.h +++ b/doomsday/libdeng2/include/de/filesys/directoryfeed.h @@ -26,101 +26,102 @@ #include -namespace de +namespace de { + +/** + * Reads from and writes to directories in the native file system. + * + * @ingroup fs + */ +class DENG2_PUBLIC DirectoryFeed : public Feed { +public: + /// The native directory was not found. @ingroup errors + DENG2_ERROR(NotFoundError); + + /// Failed attempt to find out the status of a file. @ingroup errors + DENG2_ERROR(StatusError); + + /// An error occurred changing the working directory. @ingroup errors + DENG2_ERROR(WorkingDirError); + + /// Creating a directory failed. @ingroup errors + DENG2_ERROR(CreateDirError); + + enum Flag + { + /// Opens all files and folders in write mode. + AllowWrite = 0x1, + + /// Creates the native directory if not does not exist. + CreateIfMissing = 0x2 + }; + Q_DECLARE_FLAGS(Flags, Flag) + +public: /** - * Reads from and writes to directories in the native file system. + * Constructs a DirectoryFeed that accesses a directory in the native file system. * - * @ingroup fs + * @param nativePath Path of the native directory. + * @param mode Feed mode. */ - class DENG2_PUBLIC DirectoryFeed : public Feed - { - public: - /// The native directory was not found. @ingroup errors - DENG2_ERROR(NotFoundError); - - /// Failed attempt to find out the status of a file. @ingroup errors - DENG2_ERROR(StatusError); - - /// An error occurred changing the working directory. @ingroup errors - DENG2_ERROR(WorkingDirError); - - /// Creating a directory failed. @ingroup errors - DENG2_ERROR(CreateDirError); - - enum Flag - { - /// Opens all files and folders in write mode. - AllowWrite = 0x1, - - /// Creates the native directory if not does not exist. - CreateIfMissing = 0x2 - }; - Q_DECLARE_FLAGS(Flags, Flag) - - public: - /** - * Constructs a DirectoryFeed that accesses a directory in the native file system. - * - * @param nativePath Path of the native directory. - * @param mode Feed mode. - */ - DirectoryFeed(NativePath const &nativePath, Flags const &mode = 0); - - virtual ~DirectoryFeed(); - - String description() const; - - void populate(Folder &folder); - bool prune(File &file) const; - File *newFile(String const &name); - void removeFile(String const &name); - - public: - /** - * Changes the native working directory. - * - * @param nativePath New path to use as the working directory. - */ - static void changeWorkingDir(NativePath const &nativePath); - - /** - * Creates a native directory relative to the current working directory. - * - * @param nativePath Native directory to create. - */ - static void createDir(NativePath const &nativePath); - - /** - * Determines whether a native path exists. - * - * @param nativePath Path to check. - * - * @return @c true if the path exists, @c false otherwise. - */ - static bool exists(NativePath const &nativePath); - - /** - * Determines the status of a file in the directory. - * StatusError is thrown if the file status cannot be determined - * due to any reason. - * - * @param nativePath Path of the file. - * - * @return Status of the file. - */ - static File::Status fileStatus(NativePath const &nativePath); - - protected: - void populateSubFolder(Folder &folder, String const &entryName); - void populateFile(Folder &folder, String const &entryName); - - private: - NativePath const _nativePath; - Flags _mode; - }; + DirectoryFeed(NativePath const &nativePath, Flags const &mode = 0); + + virtual ~DirectoryFeed(); + + String description() const; + + void populate(Folder &folder); + bool prune(File &file) const; + File *newFile(String const &name); + void removeFile(String const &name); + +public: + /** + * Changes the native working directory. + * + * @param nativePath New path to use as the working directory. + */ + static void changeWorkingDir(NativePath const &nativePath); + + /** + * Creates a native directory relative to the current working directory. + * + * @param nativePath Native directory to create. + */ + static void createDir(NativePath const &nativePath); + + /** + * Determines whether a native path exists. + * + * @param nativePath Path to check. + * + * @return @c true if the path exists, @c false otherwise. + */ + static bool exists(NativePath const &nativePath); + + /** + * Determines the status of a file in the directory. + * StatusError is thrown if the file status cannot be determined + * due to any reason. + * + * @param nativePath Path of the file. + * + * @return Status of the file. + */ + static File::Status fileStatus(NativePath const &nativePath); + +protected: + void populateSubFolder(Folder &folder, String const &entryName); + void populateFile(Folder &folder, String const &entryName); + +private: + NativePath const _nativePath; + Flags _mode; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(DirectoryFeed::Flags) - Q_DECLARE_OPERATORS_FOR_FLAGS(DirectoryFeed::Flags) -} +} // namespace de #endif /* LIBDENG2_DIRECTORYFEED_H */ diff --git a/doomsday/libdeng2/include/de/filesys/feed.h b/doomsday/libdeng2/include/de/filesys/feed.h index 931ea581ef..72dcd92606 100644 --- a/doomsday/libdeng2/include/de/filesys/feed.h +++ b/doomsday/libdeng2/include/de/filesys/feed.h @@ -24,89 +24,90 @@ #include -namespace de +namespace de { + +class File; +class Folder; +class String; + +/** + * Base class for feeds that generate File and Folder instances. + * + * While File and Folder instances are responsible for the organization of + * the data, and provide access to the content bytes, it is up to the Feed + * instances to interpret the contents of files and folders and generate + * the appropriate File/Folder instances. + * + * When it comes time to repopulate the file system, feeds are responsible + * for determining whether a given File or Folder needs to be destroyed + * (pruned). For instance, pruning a NativeFile is necessary if the + * corresponding native file has been deleted from the hard drive since the + * latest population was done. + * + * @ingroup fs + */ +class DENG2_PUBLIC Feed { - class File; - class Folder; - class String; - +public: + /// Tried to create a new file that already exists in the native file + /// system. @ingroup errors + DENG2_ERROR(AlreadyExistsError); + + /// Failed to remove a file. @ingroup errors + DENG2_ERROR(RemoveError); + +public: + Feed(); + + virtual ~Feed(); + + /** + * Returns a textual description of the feed, intended only for humans. + * + * @return Human-friendly description of the feed. + */ + virtual String description() const = 0; + /** - * Base class for feeds that generate File and Folder instances. + * Populates a folder with File instances. Subclasses implement this to + * produce the appropriate instances for the data they handle. * - * While File and Folder instances are responsible for the organization of - * the data, and provide access to the content bytes, it is up to the Feed - * instances to interpret the contents of files and folders and generate - * the appropriate File/Folder instances. + * @param folder Folder where the File instances are placed. * - * When it comes time to repopulate the file system, feeds are responsible - * for determining whether a given File or Folder needs to be destroyed - * (pruned). For instance, pruning a NativeFile is necessary if the - * corresponding native file has been deleted from the hard drive since the - * latest population was done. + * @see Folder::populate() + */ + virtual void populate(Folder &folder) = 0; + + /** + * Determines whether a file has become obsolete and needs to be pruned. + * The file should be deleted if it needs to be pruned. If the Feed cannot + * make a decision on whether pruning is needed, @c false should be returned. + * + * @param file File to check for pruning. + * + * @return @c true, if the file should be pruned and deleted, otherwise + * @c false. + */ + virtual bool prune(File &file) const = 0; + + /** + * Creates a new file with a given name and sets the new file's origin feed + * to this feed. + * + * @param name Name of the new file. * - * @ingroup fs + * @return The new file. Caller gets ownership. */ - class DENG2_PUBLIC Feed - { - public: - /// Tried to create a new file that already exists in the native file - /// system. @ingroup errors - DENG2_ERROR(AlreadyExistsError); - - /// Failed to remove a file. @ingroup errors - DENG2_ERROR(RemoveError); - - public: - Feed(); - - virtual ~Feed(); - - /** - * Returns a textual description of the feed, intended only for humans. - * - * @return Human-friendly description of the feed. - */ - virtual String description() const = 0; - - /** - * Populates a folder with File instances. Subclasses implement this to - * produce the appropriate instances for the data they handle. - * - * @param folder Folder where the File instances are placed. - * - * @see Folder::populate() - */ - virtual void populate(Folder &folder) = 0; - - /** - * Determines whether a file has become obsolete and needs to be pruned. - * The file should be deleted if it needs to be pruned. If the Feed cannot - * make a decision on whether pruning is needed, @c false should be returned. - * - * @param file File to check for pruning. - * - * @return @c true, if the file should be pruned and deleted, otherwise - * @c false. - */ - virtual bool prune(File &file) const = 0; - - /** - * Creates a new file with a given name and sets the new file's origin feed - * to this feed. - * - * @param name Name of the new file. - * - * @return The new file. Caller gets ownership. - */ - virtual File *newFile(String const &name); - - /** - * Removes a file with the given name. - * - * @param name Name of the removed file. - */ - virtual void removeFile(String const &name); - }; -} + virtual File *newFile(String const &name); + + /** + * Removes a file with the given name. + * + * @param name Name of the removed file. + */ + virtual void removeFile(String const &name); +}; + +} // namespace de #endif /* LIBDENG2_FEED_H */ diff --git a/doomsday/libdeng2/include/de/filesys/file.h b/doomsday/libdeng2/include/de/filesys/file.h index 532f97d7ed..f62938d791 100644 --- a/doomsday/libdeng2/include/de/filesys/file.h +++ b/doomsday/libdeng2/include/de/filesys/file.h @@ -30,329 +30,330 @@ #include -namespace de +namespace de { + +class FS; +class Folder; +class Feed; + +/** + * Base class for all files stored in the file system. + * + * All files are Lockable so that multiple threads can use them + * simultaneously. As a general rule, the user of a file does not need to + * lock the file manually; files will lock themselves as appropriate. A + * user may lock the file manually if long-term exclusive access is + * required. + * + * Implements the IIOStream interface to allow files to receive and send + * out a stream of bytes. The default implementation only throws an + * exception -- it is up to subclasses to implement the stream in the + * context of the concrete file class. + * + * Note that the constructor of File is protected: only subclasses can be + * instantiated. + * + * Subclasses have some special requirements for their destructors: + * - deindex() must be called in all subclass destructors so that the + * instances indexed under the subclasses' type are removed from the + * file system's index also. + * - The file must be automatically flushed before it gets destroyed + * (see flush()). + * - The deletion audience must be notified and @c audienceForDeletion + * must be cleared afterwards. + * + * @ingroup fs + */ +class DENG2_PUBLIC File : public Lockable, public IIOStream { - class FS; - class Folder; - class Feed; - +public: + // Mode flags. + enum Flag + { + Write = 0x1, + Truncate = 0x2 + }; + Q_DECLARE_FLAGS(Flags, Flag) + /** - * Base class for all files stored in the file system. - * - * All files are Lockable so that multiple threads can use them - * simultaneously. As a general rule, the user of a file does not need to - * lock the file manually; files will lock themselves as appropriate. A - * user may lock the file manually if long-term exclusive access is - * required. - * - * Implements the IIOStream interface to allow files to receive and send - * out a stream of bytes. The default implementation only throws an - * exception -- it is up to subclasses to implement the stream in the - * context of the concrete file class. - * - * Note that the constructor of File is protected: only subclasses can be - * instantiated. + * The file object is about to be deleted. This may be, e.g., due to pruning or + * because the parent is being deleted. * - * Subclasses have some special requirements for their destructors: - * - deindex() must be called in all subclass destructors so that the - * instances indexed under the subclasses' type are removed from the - * file system's index also. - * - The file must be automatically flushed before it gets destroyed - * (see flush()). - * - The deletion audience must be notified and @c audienceForDeletion - * must be cleared afterwards. + * @param file The file object being deleted. + */ + DENG2_DEFINE_AUDIENCE(Deletion, void fileBeingDeleted(File const &file)) + + /** + * Stores the status of a file (size, time of last modification). + */ + class Status + { + public: + /// Type of file. + enum Type { + FILE = 0, + FOLDER = 1 + }; + + public: + Status(dsize s = 0, Time const &modTime = Time()) + : size(s), modifiedAt(modTime), _type(FILE) {} + + Status(Type t, dsize s = 0, Time const &modTime = Time()) + : size(s), modifiedAt(modTime), _type(t) {} + + Type type() const { return _type; } + + bool operator == (Status const &s) const { + return size == s.size && modifiedAt == s.modifiedAt; + } + + bool operator != (Status const &s) const { return !(*this == s); } + + public: + dsize size; + Time modifiedAt; + + private: + Type _type; + }; + + /** + * Accesses the properties of a File. Allows using properties of a file + * (like its name, path or size) as a Value, for instance in script + * expressions. * * @ingroup fs */ - class DENG2_PUBLIC File : public Lockable, public IIOStream + class Accessor : public AccessorValue { - public: - // Mode flags. - enum Flag - { - Write = 0x1, - Truncate = 0x2 - }; - Q_DECLARE_FLAGS(Flags, Flag) - - /** - * The file object is about to be deleted. This may be, e.g., due to pruning or - * because the parent is being deleted. - * - * @param file The file object being deleted. - */ - DENG2_DEFINE_AUDIENCE(Deletion, void fileBeingDeleted(File const &file)) - - /** - * Stores the status of a file (size, time of last modification). - */ - class Status - { - public: - /// Type of file. - enum Type { - FILE = 0, - FOLDER = 1 - }; - - public: - Status(dsize s = 0, Time const &modTime = Time()) - : size(s), modifiedAt(modTime), _type(FILE) {} - - Status(Type t, dsize s = 0, Time const &modTime = Time()) - : size(s), modifiedAt(modTime), _type(t) {} - - Type type() const { return _type; } - - bool operator == (Status const &s) const { - return size == s.size && modifiedAt == s.modifiedAt; - } - - bool operator != (Status const &s) const { return !(*this == s); } - - public: - dsize size; - Time modifiedAt; - - private: - Type _type; - }; - - /** - * Accesses the properties of a File. Allows using properties of a file - * (like its name, path or size) as a Value, for instance in script - * expressions. - * - * @ingroup fs - */ - class Accessor : public AccessorValue - { - public: - /// Property of the file to access. - enum Property { - NAME, - PATH, - TYPE, - SIZE, - MODIFIED_AT - }; - - public: - Accessor(File &owner, Property prop); - - /// Update the text content of the accessor. - void update() const; - - /// Returns a TextValue with the text content of the accessor, - /// except for the SIZE property, which is duplicated as a NumberValue. - Value *duplicateContent() const; - - private: - File &_owner; - Property _prop; + public: + /// Property of the file to access. + enum Property { + NAME, + PATH, + TYPE, + SIZE, + MODIFIED_AT }; public: - /** - * When destroyed, a file is automatically removed from its parent folder - * and deindexed from the file system. - * - * The source file of this file will be destroyed also. - * - * @note Subclasses must call deindex() in their destructors so that - * the instances indexed under the subclasses' type are removed - * from the index also. Flushing should also be done automatically - * as necessary in the subclass. - */ - virtual ~File(); - - /** - * Remove this file from its file system's index. - */ - virtual void deindex(); - - /** - * Commits any buffered changes to the content of the file. All subclasses - * of File must make sure they flush themselves right before they get deleted. - */ - virtual void flush(); - - /** - * Empties the contents of the file. - */ - virtual void clear(); - - /// Returns a reference to the application's file system. - static FS &fileSystem(); - - /// Returns the name of the file. - String const &name() const { return _name; } - - /** - * Returns a textual description of the file, intended only for humans. - * This attempts to fully describe the file, taking into consideration - * the file's type and possible source. - * - * @return Full human-friendly description of the file. - */ - String description() const; - - /** - * Returns a textual description of this file only. Subclasses must - * override this method to provide a description relevant to the - * subclass. - * - * @return Human-friendly description of this file only. - */ - virtual String describe() const; - - /** - * Sets the parent folder of this file. - */ - void setParent(Folder *parent) { _parent = parent; } - - /** - * Returns the parent folder. May be NULL. - */ - Folder *parent() const { return _parent; } - - /** - * Sets the origin Feed of the File. The origin feed is the feed that is able - * to singlehandedly decide whether the File needs to be pruned. Typically - * this is the Feed that generated the File. - * - * @note Folder instances should not have an origin feed as the folder may - * be shared by many feeds. - * - * @param feed The origin feed. - */ - void setOriginFeed(Feed *feed); - - /** - * Returns the origin Feed of the File. - * @see setOriginFeed() - */ - Feed *originFeed() const { return _originFeed; } - - /** - * Sets the source file of this file. The source is where this file is - * getting its data from. File interpreters use this to access their - * uninterpreted data. By default all files use themselves as the - * source, so there is always a valid source for every file. If another - * file is being used as the source, the source is not typically - * indexed to the file system. - * - * @param source Source file. The file takes ownership of @a source. - */ - void setSource(File *source); - - /** - * Returns the source file. - * - * @return Source file. Always returns a valid pointer. - * @see setSource() - */ - File const *source() const; - - /** - * Returns the source file. - * - * @return Source file. Always returns a valid pointer. - * @see setSource() - */ - File *source(); - - /** - * Updates the status of the file. - * - * @param status New status. - */ - virtual void setStatus(Status const &status); - - /** - * Returns the status of the file. - */ - Status const &status() const; - - /** - * Returns the size of the file. - * - * @return Size in bytes. If the file does not have a size (purely - * stream-based file), the size is zero. - */ - dsize size() const; - - /** - * Forms the complete path of this file object. - * - * @return Path of the object. This is not a native path, but instead - * intended for de::FS. - */ - String const path() const; - - /** - * Returns the mode of the file. - */ - Flags const &mode() const; - - /** - * Changes the mode of the file. For example, using - * WRITE|TRUNCATE as the mode would empty the contents of - * the file and open it in writing mode. - * - * @param newMode Mode. - */ - virtual void setMode(Flags const &newMode); - - /// Returns the file information (const). - Record const &info() const { return _info; } - - /// Returns the file information. - Record &info() { return _info; } - - /** - * Makes sure that the file has write access. - */ - void verifyWriteAccess(); - - // Implements IIOStream. - IOStream &operator << (IByteArray const &bytes); - IIStream &operator >> (IByteArray &bytes); - IIStream const &operator >> (IByteArray &bytes) const; - - protected: - /** - * Constructs a new file. By default files are in read-only mode. - * - * @param name Name of the file. - */ - File(String const &name = ""); - + Accessor(File &owner, Property prop); + + /// Update the text content of the accessor. + void update() const; + + /// Returns a TextValue with the text content of the accessor, + /// except for the SIZE property, which is duplicated as a NumberValue. + Value *duplicateContent() const; + private: - /// The parent folder. - Folder *_parent; - - /// The source file (NULL for non-interpreted files). - File *_source; - - /// Feed that generated the file. This feed is called upon when the file needs - /// to be pruned. May also be NULL. - Feed *_originFeed; - - /// Name of the file. - String _name; - - /// Status of the file. - Status _status; - - /// Mode flags. - Flags _mode; - - /// File information. - Record _info; - }; - - Q_DECLARE_OPERATORS_FOR_FLAGS(File::Flags) -} + File &_owner; + Property _prop; + }; + +public: + /** + * When destroyed, a file is automatically removed from its parent folder + * and deindexed from the file system. + * + * The source file of this file will be destroyed also. + * + * @note Subclasses must call deindex() in their destructors so that + * the instances indexed under the subclasses' type are removed + * from the index also. Flushing should also be done automatically + * as necessary in the subclass. + */ + virtual ~File(); + + /** + * Remove this file from its file system's index. + */ + virtual void deindex(); + + /** + * Commits any buffered changes to the content of the file. All subclasses + * of File must make sure they flush themselves right before they get deleted. + */ + virtual void flush(); + + /** + * Empties the contents of the file. + */ + virtual void clear(); + + /// Returns a reference to the application's file system. + static FS &fileSystem(); + + /// Returns the name of the file. + String const &name() const { return _name; } + + /** + * Returns a textual description of the file, intended only for humans. + * This attempts to fully describe the file, taking into consideration + * the file's type and possible source. + * + * @return Full human-friendly description of the file. + */ + String description() const; + + /** + * Returns a textual description of this file only. Subclasses must + * override this method to provide a description relevant to the + * subclass. + * + * @return Human-friendly description of this file only. + */ + virtual String describe() const; + + /** + * Sets the parent folder of this file. + */ + void setParent(Folder *parent) { _parent = parent; } + + /** + * Returns the parent folder. May be NULL. + */ + Folder *parent() const { return _parent; } + + /** + * Sets the origin Feed of the File. The origin feed is the feed that is able + * to singlehandedly decide whether the File needs to be pruned. Typically + * this is the Feed that generated the File. + * + * @note Folder instances should not have an origin feed as the folder may + * be shared by many feeds. + * + * @param feed The origin feed. + */ + void setOriginFeed(Feed *feed); + + /** + * Returns the origin Feed of the File. + * @see setOriginFeed() + */ + Feed *originFeed() const { return _originFeed; } + + /** + * Sets the source file of this file. The source is where this file is + * getting its data from. File interpreters use this to access their + * uninterpreted data. By default all files use themselves as the + * source, so there is always a valid source for every file. If another + * file is being used as the source, the source is not typically + * indexed to the file system. + * + * @param source Source file. The file takes ownership of @a source. + */ + void setSource(File *source); + + /** + * Returns the source file. + * + * @return Source file. Always returns a valid pointer. + * @see setSource() + */ + File const *source() const; + + /** + * Returns the source file. + * + * @return Source file. Always returns a valid pointer. + * @see setSource() + */ + File *source(); + + /** + * Updates the status of the file. + * + * @param status New status. + */ + virtual void setStatus(Status const &status); + + /** + * Returns the status of the file. + */ + Status const &status() const; + + /** + * Returns the size of the file. + * + * @return Size in bytes. If the file does not have a size (purely + * stream-based file), the size is zero. + */ + dsize size() const; + + /** + * Forms the complete path of this file object. + * + * @return Path of the object. This is not a native path, but instead + * intended for de::FS. + */ + String const path() const; + + /** + * Returns the mode of the file. + */ + Flags const &mode() const; + + /** + * Changes the mode of the file. For example, using + * WRITE|TRUNCATE as the mode would empty the contents of + * the file and open it in writing mode. + * + * @param newMode Mode. + */ + virtual void setMode(Flags const &newMode); + + /// Returns the file information (const). + Record const &info() const { return _info; } + + /// Returns the file information. + Record &info() { return _info; } + + /** + * Makes sure that the file has write access. + */ + void verifyWriteAccess(); + + // Implements IIOStream. + IOStream &operator << (IByteArray const &bytes); + IIStream &operator >> (IByteArray &bytes); + IIStream const &operator >> (IByteArray &bytes) const; + +protected: + /** + * Constructs a new file. By default files are in read-only mode. + * + * @param name Name of the file. + */ + File(String const &name = ""); + +private: + /// The parent folder. + Folder *_parent; + + /// The source file (NULL for non-interpreted files). + File *_source; + + /// Feed that generated the file. This feed is called upon when the file needs + /// to be pruned. May also be NULL. + Feed *_originFeed; + + /// Name of the file. + String _name; + + /// Status of the file. + Status _status; + + /// Mode flags. + Flags _mode; + + /// File information. + Record _info; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(File::Flags) + +} // namespace de #endif /* LIBDENG2_FILE_H */ diff --git a/doomsday/libdeng2/include/de/filesys/folder.h b/doomsday/libdeng2/include/de/filesys/folder.h index 46f01ffdc6..8a5523026f 100644 --- a/doomsday/libdeng2/include/de/filesys/folder.h +++ b/doomsday/libdeng2/include/de/filesys/folder.h @@ -26,243 +26,244 @@ #include #include -namespace de +namespace de { + +class Feed; + +/** + * A folder contains a set of files. It is used for building a tree of files + * in the file system (de::FS). This is the base class for all types of folders. + * + * @see Feed + * + * @ingroup fs + */ +class DENG2_PUBLIC Folder : public File { - class Feed; - +public: + /// A folder cannot contain two or more files with the same name. @ingroup errors + DENG2_ERROR(DuplicateNameError); + + /// File path did not point to a file. @ingroup errors + DENG2_ERROR(NotFoundError); + + /// Creating a new file was unsuccessful. @ingroup errors + DENG2_ERROR(NewFileError); + /** - * A folder contains a set of files. It is used for building a tree of files - * in the file system (de::FS). This is the base class for all types of folders. - * - * @see Feed + * Accesses the properties of a Folder. Allows using properties of a + * folder (like how many items it contains) as a Value, for instance in + * script expressions. * * @ingroup fs */ - class DENG2_PUBLIC Folder : public File + class Accessor : public AccessorValue { public: - /// A folder cannot contain two or more files with the same name. @ingroup errors - DENG2_ERROR(DuplicateNameError); - - /// File path did not point to a file. @ingroup errors - DENG2_ERROR(NotFoundError); - - /// Creating a new file was unsuccessful. @ingroup errors - DENG2_ERROR(NewFileError); - - /** - * Accesses the properties of a Folder. Allows using properties of a - * folder (like how many items it contains) as a Value, for instance in - * script expressions. - * - * @ingroup fs - */ - class Accessor : public AccessorValue - { - public: - /// Property of the file to access. - enum Property { - CONTENT_SIZE - }; - - public: - Accessor(Folder &owner, Property prop); - void update() const; - Value *duplicateContent() const; - - private: - Folder &_owner; - Property _prop; + /// Property of the file to access. + enum Property { + CONTENT_SIZE }; - - typedef std::list Feeds; - typedef std::map Contents; - enum PopulationBehavior { - PopulateFullTree = 0, ///< The full tree is populated. - PopulateJustThisFolder = 0x1 ///< Do not descend into subfolders while populating. - }; - public: - Folder(String const &name = ""); - - virtual ~Folder(); - - String describe() const; - - /** - * Populates the folder with a set of File instances. Each feed - * attached to the folder will contribute. Every populated file will - * also be added to the file system's main index. - * - * Repopulation is nondestructive as long as the source data has not - * changed. Population may be performed more than once during the - * lifetime of the folder, for example when it's necessary to - * synchronize it with the contents of a native hard drive directory. - * - * @param behavior Behavior of the population operation, see - * Folder::PopulationBehavior. - */ - virtual void populate(PopulationBehavior behavior = PopulateFullTree); - - /** - * Provides direct read-only access to the content of the folder. - */ - Contents const &contents() const; - - /** - * Destroys the contents of the folder. All contained file objects are deleted. - */ - void clear(); - - /** - * Creates a new file in the folder. The feeds attached to the folder will - * decide what kind of file is actually created. The new file is added to - * the file system's index. - * - * @param name Name or path of the new file, relative to this folder. - * @param replaceExisting Replacing existing file with the same name. - * - * @return The created file (write mode enabled). - */ - File &newFile(String const &name, bool replaceExisting = false); - - /** - * Creates a new file in the folder, replacing an existing file with the - * same name. Same as calling newFile(name, true). - * - * @param name Name or path of the new file, relative to this folder. - */ - File &replaceFile(String const &name); - - /** - * Removes a file from a folder. If it has an origin feed, the feed will be - * asked to remove the file as well. - * - * @param name Name or path of file to remove, relative to this folder. - */ - void removeFile(String const &name); - - /** - * Checks whether the folder contains a file. - * - * @param name File to check for. The name is not case sensitive. - */ - bool has(String const &name) const; - - /** - * Adds an object to the folder. The object must be an instance of a class - * derived from File. - * - * @param fileObject Object to add to the folder. The folder takes - * ownership of this object. Cannot be NULL. - * - * @return Reference to @a fileObject, for convenience. - */ - template - Type &add(Type *fileObject) { - DENG2_ASSERT(fileObject != 0); - add(static_cast(fileObject)); - return *fileObject; - } - - /** - * Adds a file instance to the contents of the folder. - * - * @param file File to add. The folder takes ownership of this instance. - * - * @return Reference to the file, for convenience. - */ - virtual File &add(File *file); - - /** - * Removes a file from the folder, by name. The file is not deleted. The - * ownership of the file is given to the caller. - * - * @return The removed file object. Ownership of the object is given to - * the caller. - */ - File *remove(String const &name); - - template - Type *remove(Type *fileObject) { - DENG2_ASSERT(fileObject != 0); - remove(*static_cast(fileObject)); - return fileObject; - } + Accessor(Folder &owner, Property prop); + void update() const; + Value *duplicateContent() const; - /** - * Removes a file from the folder. The file is not deleted. The ownership - * of the file is given to the caller. - * - * @return The removed file object. Ownership of the object is given to - * the caller. - */ - virtual File *remove(File &file); - - /** - * Locates a file in this folder or in one of its subfolders. Looks recursively - * through subfolders. - * - * @param path Path to look for. Relative to this folder. - * - * @return The located file, or @c NULL if the path was not found. - */ - virtual File *tryLocateFile(String const &path) const; - - template - Type *tryLocate(String const &path) const { - return dynamic_cast(tryLocateFile(path)); - } + private: + Folder &_owner; + Property _prop; + }; - /** - * Locates a file in this folder or in one of its subfolders. Looks recusively - * through subfolders. - * - * @param path Path to look for. Relative to this folder. - * - * @return The found file. - */ - template - Type &locate(String const &path) const { - Type *found = tryLocate(path); - if(!found) { - /// @throw NotFoundError Path didn't exist, or the located file had - /// an incompatible type. - throw NotFoundError("Folder::locate", path +": path was not found or had incompatible type"); - } - return *found; - } + typedef std::list Feeds; + typedef std::map Contents; - /** - * Attach a feed to the folder. The feed will provide content for the folder. - * - * @param feed Feed to attach to the folder. The folder gets ownership of the feed. - */ - void attach(Feed *feed); - - /** - * Detaches a feed from the folder. The feed object is not deleted. - * - * @param feed Feed to detach from the folder. - * - * @return The Feed object. Ownership is returned to the caller. - */ - Feed *detach(Feed &feed); - - /** - * Provides access to the list of Feeds for this folder. The feeds are responsible - * for creating File and Folder instances in the folder. - */ - Feeds const &feeds() const { return _feeds; } - - private: - /// A map of file names to file instances. - Contents _contents; - - /// Feeds provide content for the folder. - Feeds _feeds; + enum PopulationBehavior { + PopulateFullTree = 0, ///< The full tree is populated. + PopulateJustThisFolder = 0x1 ///< Do not descend into subfolders while populating. }; -} + +public: + Folder(String const &name = ""); + + virtual ~Folder(); + + String describe() const; + + /** + * Populates the folder with a set of File instances. Each feed + * attached to the folder will contribute. Every populated file will + * also be added to the file system's main index. + * + * Repopulation is nondestructive as long as the source data has not + * changed. Population may be performed more than once during the + * lifetime of the folder, for example when it's necessary to + * synchronize it with the contents of a native hard drive directory. + * + * @param behavior Behavior of the population operation, see + * Folder::PopulationBehavior. + */ + virtual void populate(PopulationBehavior behavior = PopulateFullTree); + + /** + * Provides direct read-only access to the content of the folder. + */ + Contents const &contents() const; + + /** + * Destroys the contents of the folder. All contained file objects are deleted. + */ + void clear(); + + /** + * Creates a new file in the folder. The feeds attached to the folder will + * decide what kind of file is actually created. The new file is added to + * the file system's index. + * + * @param name Name or path of the new file, relative to this folder. + * @param replaceExisting Replacing existing file with the same name. + * + * @return The created file (write mode enabled). + */ + File &newFile(String const &name, bool replaceExisting = false); + + /** + * Creates a new file in the folder, replacing an existing file with the + * same name. Same as calling newFile(name, true). + * + * @param name Name or path of the new file, relative to this folder. + */ + File &replaceFile(String const &name); + + /** + * Removes a file from a folder. If it has an origin feed, the feed will be + * asked to remove the file as well. + * + * @param name Name or path of file to remove, relative to this folder. + */ + void removeFile(String const &name); + + /** + * Checks whether the folder contains a file. + * + * @param name File to check for. The name is not case sensitive. + */ + bool has(String const &name) const; + + /** + * Adds an object to the folder. The object must be an instance of a class + * derived from File. + * + * @param fileObject Object to add to the folder. The folder takes + * ownership of this object. Cannot be NULL. + * + * @return Reference to @a fileObject, for convenience. + */ + template + Type &add(Type *fileObject) { + DENG2_ASSERT(fileObject != 0); + add(static_cast(fileObject)); + return *fileObject; + } + + /** + * Adds a file instance to the contents of the folder. + * + * @param file File to add. The folder takes ownership of this instance. + * + * @return Reference to the file, for convenience. + */ + virtual File &add(File *file); + + /** + * Removes a file from the folder, by name. The file is not deleted. The + * ownership of the file is given to the caller. + * + * @return The removed file object. Ownership of the object is given to + * the caller. + */ + File *remove(String const &name); + + template + Type *remove(Type *fileObject) { + DENG2_ASSERT(fileObject != 0); + remove(*static_cast(fileObject)); + return fileObject; + } + + /** + * Removes a file from the folder. The file is not deleted. The ownership + * of the file is given to the caller. + * + * @return The removed file object. Ownership of the object is given to + * the caller. + */ + virtual File *remove(File &file); + + /** + * Locates a file in this folder or in one of its subfolders. Looks recursively + * through subfolders. + * + * @param path Path to look for. Relative to this folder. + * + * @return The located file, or @c NULL if the path was not found. + */ + virtual File *tryLocateFile(String const &path) const; + + template + Type *tryLocate(String const &path) const { + return dynamic_cast(tryLocateFile(path)); + } + + /** + * Locates a file in this folder or in one of its subfolders. Looks recusively + * through subfolders. + * + * @param path Path to look for. Relative to this folder. + * + * @return The found file. + */ + template + Type &locate(String const &path) const { + Type *found = tryLocate(path); + if(!found) { + /// @throw NotFoundError Path didn't exist, or the located file had + /// an incompatible type. + throw NotFoundError("Folder::locate", path +": path was not found or had incompatible type"); + } + return *found; + } + + /** + * Attach a feed to the folder. The feed will provide content for the folder. + * + * @param feed Feed to attach to the folder. The folder gets ownership of the feed. + */ + void attach(Feed *feed); + + /** + * Detaches a feed from the folder. The feed object is not deleted. + * + * @param feed Feed to detach from the folder. + * + * @return The Feed object. Ownership is returned to the caller. + */ + Feed *detach(Feed &feed); + + /** + * Provides access to the list of Feeds for this folder. The feeds are responsible + * for creating File and Folder instances in the folder. + */ + Feeds const &feeds() const { return _feeds; } + +private: + /// A map of file names to file instances. + Contents _contents; + + /// Feeds provide content for the folder. + Feeds _feeds; +}; + +} // namespace de #endif /* LIBDENG2_FOLDER_H */ diff --git a/doomsday/libdeng2/include/de/filesys/fs.h b/doomsday/libdeng2/include/de/filesys/fs.h index 4579784028..1dc56225f3 100644 --- a/doomsday/libdeng2/include/de/filesys/fs.h +++ b/doomsday/libdeng2/include/de/filesys/fs.h @@ -55,193 +55,194 @@ * @see de::ArchiveEntryFile, de::ArchiveFeed, and de::FS::interpret() */ -namespace de +namespace de { + +namespace internal { + template + inline bool cannotCastFileTo(File *file) { + return dynamic_cast(file) == NULL; + } +} + +/** + * The file system maintains a tree of files and folders. It provides a way + * to quickly and efficiently locate files anywhere in the tree. It also + * maintains semantic information about the structure and content of the + * file tree, allowing others to know how to treat the files and folders. + * + * In practice, the file system consists of a tree of File and Folder + * instances. These instances are generated by the Feed objects attached to + * the folders. For instance, a DirectoryFeed will generate the appropriate + * File and Folder instances for a directory in the native file system. + * + * Wildcard searches are discouraged as implementing them is potentially + * inefficient. Instead, suitable indices should be built beforehand if + * there is a need to look up lots of files matching a specific criteria + * from unknown locations in the tree. + * + * The file system can be repopulated at any time to resynchronize it with + * the source data. Repopulation is nondestructive as long as the source + * data has not changed. Repopulation is needed for instance when native + * files get deleted in the directory a folder is feeding on. The feeds are + * responsible for deciding when instances get out-of-date and need to be + * deleted (pruning). Pruning occurs when a folder that is already + * populated with files is repopulated. + * + * @ingroup fs + */ +class DENG2_PUBLIC FS { - namespace internal { - template - inline bool cannotCastFileTo(File *file) { - return dynamic_cast(file) == NULL; +public: + /// No index is found for the specified type. @ingroup errors + DENG2_ERROR(UnknownTypeError); + + /// No files found. @ingroup errors + DENG2_ERROR(NotFoundError); + + /// More than one file found and there is not enough information to choose + /// between them. @ingroup errors + DENG2_ERROR(AmbiguousError); + + typedef std::multimap Index; + typedef std::pair IndexRange; + typedef std::pair ConstIndexRange; + typedef std::pair IndexEntry; + typedef std::list FoundFiles; + +public: + /** + * Constructs a new file system. The file system needs to be manually + * refreshed; initially it is empty. + */ + FS(); + + virtual ~FS(); + + void printIndex(); + + Folder &root(); + + /** + * Refresh the file system. Populates all folders with files from the feeds. + */ + void refresh(); + + /** + * Retrieves a folder in the file system. The folder gets created if it + * does not exist. Any missing parent folders will also be created. + * + * @param path Path of the folder. Relative to the root folder. + */ + Folder &makeFolder(String const &path); + + /** + * Finds all files matching a full or partial path. The search is done + * using the file system's index; no recursive descent into folders is + * done. + * + * @param path Path or file name to look for. + * @param found Set of files that match the result. + * + * @return Number of files found. + */ + int findAll(String const &path, FoundFiles &found) const; + + /** + * Finds a single file matching a full or partial path. The search is + * done using the file system's index; no recursive descent into + * folders is done. + * + * @param path Path or file name to look for. + * + * @return The found file. + */ + File &find(String const &path) const; + + /** + * Finds a file of a specific type. The search is done using the file + * system's index; no recursive descent into folders is done. Only + * files that can be represented as @a Type are included in the + * results. + * + * @param path Full/partial path or file name to look for. + * + * @see indexFor() returns the full index for a particular type of file + * for manual searches. + */ + template + Type &find(String const &path) const { + FoundFiles found; + findAll(path, found); + // Filter out the wrong types. + found.remove_if(internal::cannotCastFileTo); + if(found.size() > 1) { + /// @throw AmbiguousError More than one file matches the conditions. + throw AmbiguousError("FS::find", "More than one file found matching '" + path + "'"); + } + if(found.empty()) { + /// @throw NotFoundError No files found matching the condition. + throw NotFoundError("FS::find", "No files found matching '" + path + "'"); } + return *dynamic_cast(found.front()); } - + /** - * The file system maintains a tree of files and folders. It provides a way - * to quickly and efficiently locate files anywhere in the tree. It also - * maintains semantic information about the structure and content of the - * file tree, allowing others to know how to treat the files and folders. + * Creates an interpreter for the data in a file. * - * In practice, the file system consists of a tree of File and Folder - * instances. These instances are generated by the Feed objects attached to - * the folders. For instance, a DirectoryFeed will generate the appropriate - * File and Folder instances for a directory in the native file system. + * @param sourceData File with the source data. While interpreting, + * ownership of the file is given to de::FS. * - * Wildcard searches are discouraged as implementing them is potentially - * inefficient. Instead, suitable indices should be built beforehand if - * there is a need to look up lots of files matching a specific criteria - * from unknown locations in the tree. + * @return If the format of the source data was recognized, returns a + * new File (or Folder) that can be used for accessing the data. + * Ownership of the @a sourceData will be transferred to the new + * interpreter File instance. If the format was not recognized, @a + * sourceData is returned as-is and ownership is returned to the + * caller. + */ + File *interpret(File *sourceData); + + /** + * Provides access to the main index of the file system. This can be + * used for efficiently looking up files based on name. * - * The file system can be repopulated at any time to resynchronize it with - * the source data. Repopulation is nondestructive as long as the source - * data has not changed. Repopulation is needed for instance when native - * files get deleted in the directory a folder is feeding on. The feeds are - * responsible for deciding when instances get out-of-date and need to be - * deleted (pruning). Pruning occurs when a folder that is already - * populated with files is repopulated. + * @note The file names are indexed in lower case. + */ + Index const &nameIndex() const; + + /** + * Retrieves the index of files of a particular type. + * + * @param typeIdentifier Type identifier to look for. Use the TYPE_NAME() macro. * - * @ingroup fs + * @return A subset of the main index containing only the entries of + * the given type. + * + * For example, to look up the index for NativeFile instances: + * @code + * FS::Index &nativeFileIndex = App::fileSystem().indexFor(TYPE_NAME(NativeFile)); + * @endcode */ - class DENG2_PUBLIC FS - { - public: - /// No index is found for the specified type. @ingroup errors - DENG2_ERROR(UnknownTypeError); - - /// No files found. @ingroup errors - DENG2_ERROR(NotFoundError); - - /// More than one file found and there is not enough information to choose - /// between them. @ingroup errors - DENG2_ERROR(AmbiguousError); - - typedef std::multimap Index; - typedef std::pair IndexRange; - typedef std::pair ConstIndexRange; - typedef std::pair IndexEntry; - typedef std::list FoundFiles; - - public: - /** - * Constructs a new file system. The file system needs to be manually - * refreshed; initially it is empty. - */ - FS(); - - virtual ~FS(); - - void printIndex(); - - Folder &root(); - - /** - * Refresh the file system. Populates all folders with files from the feeds. - */ - void refresh(); - - /** - * Retrieves a folder in the file system. The folder gets created if it - * does not exist. Any missing parent folders will also be created. - * - * @param path Path of the folder. Relative to the root folder. - */ - Folder &makeFolder(String const &path); - - /** - * Finds all files matching a full or partial path. The search is done - * using the file system's index; no recursive descent into folders is - * done. - * - * @param path Path or file name to look for. - * @param found Set of files that match the result. - * - * @return Number of files found. - */ - int findAll(String const &path, FoundFiles &found) const; - - /** - * Finds a single file matching a full or partial path. The search is - * done using the file system's index; no recursive descent into - * folders is done. - * - * @param path Path or file name to look for. - * - * @return The found file. - */ - File &find(String const &path) const; - - /** - * Finds a file of a specific type. The search is done using the file - * system's index; no recursive descent into folders is done. Only - * files that can be represented as @a Type are included in the - * results. - * - * @param path Full/partial path or file name to look for. - * - * @see indexFor() returns the full index for a particular type of file - * for manual searches. - */ - template - Type &find(String const &path) const { - FoundFiles found; - findAll(path, found); - // Filter out the wrong types. - found.remove_if(internal::cannotCastFileTo); - if(found.size() > 1) { - /// @throw AmbiguousError More than one file matches the conditions. - throw AmbiguousError("FS::find", "More than one file found matching '" + path + "'"); - } - if(found.empty()) { - /// @throw NotFoundError No files found matching the condition. - throw NotFoundError("FS::find", "No files found matching '" + path + "'"); - } - return *dynamic_cast(found.front()); - } - - /** - * Creates an interpreter for the data in a file. - * - * @param sourceData File with the source data. While interpreting, - * ownership of the file is given to de::FS. - * - * @return If the format of the source data was recognized, returns a - * new File (or Folder) that can be used for accessing the data. - * Ownership of the @a sourceData will be transferred to the new - * interpreter File instance. If the format was not recognized, @a - * sourceData is returned as-is and ownership is returned to the - * caller. - */ - File *interpret(File *sourceData); - - /** - * Provides access to the main index of the file system. This can be - * used for efficiently looking up files based on name. - * - * @note The file names are indexed in lower case. - */ - Index const &nameIndex() const; - - /** - * Retrieves the index of files of a particular type. - * - * @param typeIdentifier Type identifier to look for. Use the TYPE_NAME() macro. - * - * @return A subset of the main index containing only the entries of - * the given type. - * - * For example, to look up the index for NativeFile instances: - * @code - * FS::Index &nativeFileIndex = App::fileSystem().indexFor(TYPE_NAME(NativeFile)); - * @endcode - */ - Index const &indexFor(String const &typeIdentifier) const; - - /** - * Adds a file to the main index. - * - * @param file File to index. - */ - void index(File &file); - - /** - * Removes a file from the main index. - * - * @param file File to remove from the index. - */ - void deindex(File &file); - - private: - struct Instance; - Instance *d; - }; -} + Index const &indexFor(String const &typeIdentifier) const; + + /** + * Adds a file to the main index. + * + * @param file File to index. + */ + void index(File &file); + + /** + * Removes a file from the main index. + * + * @param file File to remove from the index. + */ + void deindex(File &file); + +private: + struct Instance; + Instance *d; +}; + +} // namespace de #endif /* LIBDENG2_FS_H */ diff --git a/doomsday/libdeng2/include/de/filesys/libraryfile.h b/doomsday/libdeng2/include/de/filesys/libraryfile.h index e03f14d7eb..d2a52237bb 100644 --- a/doomsday/libdeng2/include/de/filesys/libraryfile.h +++ b/doomsday/libdeng2/include/de/filesys/libraryfile.h @@ -22,95 +22,96 @@ #include "../File" -namespace de -{ - class Library; +namespace de { + +class Library; +/** + * Provides a way to load and unload a shared library. The Library will be + * loaded automatically when someone attempts to use it. Unloading the + * library occurs when the LibraryFile instance is deleted, or when + * unload() is called. + * + * @see Library + * + * @ingroup fs + */ +class DENG2_PUBLIC LibraryFile : public File +{ +public: + /// Attempted to load a shared library from a source file with unsupported type. + /// @ingroup errors + DENG2_ERROR(UnsupportedSourceError); + + /// Attempted an operation that requires the library to be loaded (and it + /// couldn't be loaded automatically). @ingroup errors + DENG2_ERROR(NotLoadedError); + +public: + /** + * Constructs a new LibraryFile instance. + * + * @param source Library file. Ownership transferred to LibraryFile. + */ + LibraryFile(File *source); + + /** + * When the LibraryFile is deleted the library is gets unloaded. + */ + virtual ~LibraryFile(); + + String describe() const; + + /** + * Determines whether the library is loaded and ready for use. + * + * @return @c true, if the library has been loaded. + */ + bool loaded() const { return _library != 0; } + + /** + * Provides access to the library. Automatically attempts to load the + * library if it hasn't been loaded yet. + * + * @return The library. + */ + Library &library(); + + /** + * Provides access to the library without trying to load it. Throws + * an exception if the library is not loaded. + * + * @return The library. + */ + Library const &library() const; + /** - * Provides a way to load and unload a shared library. The Library will be - * loaded automatically when someone attempts to use it. Unloading the - * library occurs when the LibraryFile instance is deleted, or when - * unload() is called. + * Unloads the library. + */ + void clear(); + + /** + * Checks whether the name of the library file matches. An "underscore + * name" is a convention used for some plugins where the name of the + * plugin is prefixed by, e.g., "audio_". The "underscore name" is the + * part of the file that follows the underscore. * - * @see Library + * @param nameAfterUnderscore Part of the name following underscore. + */ + bool hasUnderscoreName(String const &nameAfterUnderscore) const; + +public: + /** + * Determines whether a file appears suitable for use with LibraryFile. * - * @ingroup fs + * @param file File whose content to recognize. */ - class DENG2_PUBLIC LibraryFile : public File - { - public: - /// Attempted to load a shared library from a source file with unsupported type. - /// @ingroup errors - DENG2_ERROR(UnsupportedSourceError); - - /// Attempted an operation that requires the library to be loaded (and it - /// couldn't be loaded automatically). @ingroup errors - DENG2_ERROR(NotLoadedError); - - public: - /** - * Constructs a new LibraryFile instance. - * - * @param source Library file. Ownership transferred to LibraryFile. - */ - LibraryFile(File *source); - - /** - * When the LibraryFile is deleted the library is gets unloaded. - */ - virtual ~LibraryFile(); - - String describe() const; - - /** - * Determines whether the library is loaded and ready for use. - * - * @return @c true, if the library has been loaded. - */ - bool loaded() const { return _library != 0; } - - /** - * Provides access to the library. Automatically attempts to load the - * library if it hasn't been loaded yet. - * - * @return The library. - */ - Library &library(); - - /** - * Provides access to the library without trying to load it. Throws - * an exception if the library is not loaded. - * - * @return The library. - */ - Library const &library() const; - - /** - * Unloads the library. - */ - void clear(); - - /** - * Checks whether the name of the library file matches. An "underscore - * name" is a convention used for some plugins where the name of the - * plugin is prefixed by, e.g., "audio_". The "underscore name" is the - * part of the file that follows the underscore. - * - * @param nameAfterUnderscore Part of the name following underscore. - */ - bool hasUnderscoreName(String const &nameAfterUnderscore) const; - - public: - /** - * Determines whether a file appears suitable for use with LibraryFile. - * - * @param file File whose content to recognize. - */ - static bool recognize(File const &file); - - private: - Library *_library; - }; -} + static bool recognize(File const &file); + +private: + Library *_library; +}; + +} // namespace de #endif /* LIBDENG2_LIBRARYFILE_H */ diff --git a/doomsday/libdeng2/include/de/filesys/nativefile.h b/doomsday/libdeng2/include/de/filesys/nativefile.h index 7f8919fe5c..9f3e8b632c 100644 --- a/doomsday/libdeng2/include/de/filesys/nativefile.h +++ b/doomsday/libdeng2/include/de/filesys/nativefile.h @@ -26,66 +26,67 @@ #include -namespace de +namespace de { + +/** + * Reads from and writes to files in the native file system. The contents + * of the native file are available as a byte array. + * + * @ingroup fs + */ +class DENG2_PUBLIC NativeFile : public ByteArrayFile { +public: /** - * Reads from and writes to files in the native file system. The contents - * of the native file are available as a byte array. + * Constructs a NativeFile that accesses a file in the native file system + * in read-only mode. * - * @ingroup fs + * @param name Name of the file object. + * @param nativePath Path in the native file system to access. Relative + * to the current working directory. + */ + NativeFile(String const &name, NativePath const &nativePath); + + virtual ~NativeFile(); + + String describe() const; + + void clear(); + void flush(); + + /** + * Returns the native path of the file. */ - class DENG2_PUBLIC NativeFile : public ByteArrayFile - { - public: - /** - * Constructs a NativeFile that accesses a file in the native file system - * in read-only mode. - * - * @param name Name of the file object. - * @param nativePath Path in the native file system to access. Relative - * to the current working directory. - */ - NativeFile(String const &name, NativePath const &nativePath); - - virtual ~NativeFile(); - - String describe() const; - - void clear(); - void flush(); - - /** - * Returns the native path of the file. - */ - NativePath const &nativePath() const { return _nativePath; } - - void setMode(Flags const &newMode); - - // Implements IByteArray. - Size size() const; - void get(Offset at, Byte *values, Size count) const; - void set(Offset at, Byte const *values, Size count); - - protected: - /// Returns the input stream. - QFile &input() const; - - /// Returns the output stream. - QFile &output(); - - /// Close any open streams. - void close(); - - private: - /// Path of the native file in the OS file system. - NativePath _nativePath; - - /// Input stream. - mutable QFile *_in; - - /// Output stream. - QFile *_out; - }; -} + NativePath const &nativePath() const { return _nativePath; } + + void setMode(Flags const &newMode); + + // Implements IByteArray. + Size size() const; + void get(Offset at, Byte *values, Size count) const; + void set(Offset at, Byte const *values, Size count); + +protected: + /// Returns the input stream. + QFile &input() const; + + /// Returns the output stream. + QFile &output(); + + /// Close any open streams. + void close(); + +private: + /// Path of the native file in the OS file system. + NativePath _nativePath; + + /// Input stream. + mutable QFile *_in; + + /// Output stream. + QFile *_out; +}; + +} // namespace de #endif /* LIBDENG2_NATIVEFILE_H */ diff --git a/doomsday/libdeng2/include/de/math.h b/doomsday/libdeng2/include/de/math.h index e145340b94..46fc2cf467 100644 --- a/doomsday/libdeng2/include/de/math.h +++ b/doomsday/libdeng2/include/de/math.h @@ -30,56 +30,57 @@ # undef max #endif -namespace de -{ +namespace de { + #undef PI - ddouble const PI = 3.14159265358979323846; - ddouble const EPSILON = 1.0e-7; +ddouble const PI = 3.14159265358979323846; +ddouble const EPSILON = 1.0e-7; - /// Absolute value. - template - inline Type abs(Type const &a) { - if(a < 0.0) { - return -a; - } - return a; +/// Absolute value. +template +inline Type abs(Type const &a) { + if(a < 0.0) { + return -a; } + return a; +} - // Special case, this is never negative. - inline duint abs(duint const &a) { - return a; - } +// Special case, this is never negative. +inline duint abs(duint const &a) { + return a; +} - /// Minimum of two values. - template - inline Type const &min(Type const &a, Type const &b) { - return (a < b? a : b); - } +/// Minimum of two values. +template +inline Type const &min(Type const &a, Type const &b) { + return (a < b? a : b); +} - /// Maximum of two values. - template - inline Type const &max(Type const &a, Type const &b) { - return (a > b? a : b); - } - - /// Clamp value within range. - template - inline Type clamp(Type const &low, Type const &value, Type const &high) { - return min(max(value, low), high); - } - - /// Compare two floating-point values for equality, with the precision of EPSILON. - inline ddouble fequal(ddouble a, ddouble b) { - return abs(a - b) < EPSILON; - } +/// Maximum of two values. +template +inline Type const &max(Type const &a, Type const &b) { + return (a > b? a : b); +} - /// General comparison function. - template - inline dint cmp(Type const &a, Type const &b) { - if(a < b) return -1; - if(a > b) return 1; - return 0; - } +/// Clamp value within range. +template +inline Type clamp(Type const &low, Type const &value, Type const &high) { + return min(max(value, low), high); +} + +/// Compare two floating-point values for equality, with the precision of EPSILON. +inline ddouble fequal(ddouble a, ddouble b) { + return abs(a - b) < EPSILON; } +/// General comparison function. +template +inline dint cmp(Type const &a, Type const &b) { + if(a < b) return -1; + if(a > b) return 1; + return 0; +} + +} // namespace de + #endif /* LIBDENG2_MATH_H */ diff --git a/doomsday/libdeng2/include/de/scriptsys/arrayexpression.h b/doomsday/libdeng2/include/de/scriptsys/arrayexpression.h index c769041ba0..c8ee6ae9c4 100644 --- a/doomsday/libdeng2/include/de/scriptsys/arrayexpression.h +++ b/doomsday/libdeng2/include/de/scriptsys/arrayexpression.h @@ -24,65 +24,66 @@ #include -namespace de +namespace de { + +class Evaluator; +class Value; + +/** + * Evaluates into an ArrayValue. + * + * @ingroup script + */ +class ArrayExpression : public Expression { - class Evaluator; - class Value; - +public: + ArrayExpression(); + ~ArrayExpression(); + + void clear(); + + dsize size() const { return _arguments.size(); } + + /** + * Adds an argument expression to the array expression. + * + * @param arg Argument expression to add. Ownership transferred + * to the array expression. + */ + void add(Expression *arg); + + void push(Evaluator &evaluator, Record *names = 0) const; + /** - * Evaluates into an ArrayValue. + * Returns one of the expressions in the array. + * + * @param pos Index. * - * @ingroup script + * @return Expression. */ - class ArrayExpression : public Expression - { - public: - ArrayExpression(); - ~ArrayExpression(); - - void clear(); - - dsize size() const { return _arguments.size(); } - - /** - * Adds an argument expression to the array expression. - * - * @param arg Argument expression to add. Ownership transferred - * to the array expression. - */ - void add(Expression *arg); - - void push(Evaluator &evaluator, Record *names = 0) const; - - /** - * Returns one of the expressions in the array. - * - * @param pos Index. - * - * @return Expression. - */ - Expression const &at(dint pos) const; - - Expression const &front() const { return at(0); } - - Expression const &back() const { return at(size() - 1); } - - /** - * Collects the result values of the arguments and puts them - * into an array. - * - * @return ArrayValue with the results of the argument evaluations. - */ - Value *evaluate(Evaluator &evaluator) const; - - // Implements ISerializable. - void operator >> (Writer &to) const; - void operator << (Reader &from); - - private: - typedef std::vector Arguments; - Arguments _arguments; - }; -} + Expression const &at(dint pos) const; + + Expression const &front() const { return at(0); } + + Expression const &back() const { return at(size() - 1); } + + /** + * Collects the result values of the arguments and puts them + * into an array. + * + * @return ArrayValue with the results of the argument evaluations. + */ + Value *evaluate(Evaluator &evaluator) const; + + // Implements ISerializable. + void operator >> (Writer &to) const; + void operator << (Reader &from); + +private: + typedef std::vector Arguments; + Arguments _arguments; +}; + +} // namespace de #endif /* LIBDENG2_ARRAYEXPRESSION_H */ diff --git a/doomsday/libdeng2/include/de/scriptsys/assignstatement.h b/doomsday/libdeng2/include/de/scriptsys/assignstatement.h index b801e139eb..733518a47e 100644 --- a/doomsday/libdeng2/include/de/scriptsys/assignstatement.h +++ b/doomsday/libdeng2/include/de/scriptsys/assignstatement.h @@ -26,48 +26,49 @@ #include #include -namespace de +namespace de { + +/** + * Assigns a value to a variable. + * + * @ingroup script + */ +class AssignStatement : public Statement { +public: + /// Trying to assign into something other than a reference (RefValue). @ingroup errors + DENG2_ERROR(LeftValueError); + + typedef std::vector Indices; + +public: + AssignStatement(); + /** - * Assigns a value to a variable. + * Constructor. Statement takes ownership of the expressions + * @c target and @c value. * - * @ingroup script + * @param target Expression that resolves to a reference (RefValue). + * @param indices Expressions that determine element indices into existing + * element-based values. Empty, if there is no indices for + * the assignment. + * @param value Expression that determines the value of the variable. */ - class AssignStatement : public Statement - { - public: - /// Trying to assign into something other than a reference (RefValue). @ingroup errors - DENG2_ERROR(LeftValueError); - - typedef std::vector Indices; - - public: - AssignStatement(); - - /** - * Constructor. Statement takes ownership of the expressions - * @c target and @c value. - * - * @param target Expression that resolves to a reference (RefValue). - * @param indices Expressions that determine element indices into existing - * element-based values. Empty, if there is no indices for - * the assignment. - * @param value Expression that determines the value of the variable. - */ - AssignStatement(Expression *target, Indices const &indices, Expression *value); - - ~AssignStatement(); - - void execute(Context &context) const; - - // Implements ISerializable. - void operator >> (Writer &to) const; - void operator << (Reader &from); - - private: - ArrayExpression _args; - dint _indexCount; - }; -} + AssignStatement(Expression *target, Indices const &indices, Expression *value); + + ~AssignStatement(); + + void execute(Context &context) const; + + // Implements ISerializable. + void operator >> (Writer &to) const; + void operator << (Reader &from); + +private: + ArrayExpression _args; + dint _indexCount; +}; + +} // namespace de #endif /* LIBDENG2_ASSIGNSTATEMENT_H */ diff --git a/doomsday/libdeng2/include/de/scriptsys/builtinexpression.h b/doomsday/libdeng2/include/de/scriptsys/builtinexpression.h index ba96c19e88..1eeb93a962 100644 --- a/doomsday/libdeng2/include/de/scriptsys/builtinexpression.h +++ b/doomsday/libdeng2/include/de/scriptsys/builtinexpression.h @@ -24,63 +24,64 @@ #include "../Expression" #include "../String" -namespace de +namespace de { + +/** + * Evaluates a built-in function on the argument(s). + * + * @ingroup script + */ +class BuiltInExpression : public Expression { +public: + /// A wrong number of arguments is given to one of the built-in methods. @ingroup errors + DENG2_ERROR(WrongArgumentsError); + + /// Type of the built-in expression. + /// @note These are serialied as is, so do not change the existing values. + enum Type { + NONE = 0, + LENGTH = 1, ///< Evaluate the length of an value (by calling size()). + DICTIONARY_KEYS = 2, + DICTIONARY_VALUES = 3, + RECORD_MEMBERS = 4, + RECORD_SUBRECORDS = 5, + AS_TEXT = 6, + AS_NUMBER = 7, + LOCAL_NAMESPACE = 8, + SERIALIZE = 9, + DESERIALIZE = 10, + AS_TIME = 11, + TIME_DELTA = 12, + AS_RECORD = 13 + }; + +public: + BuiltInExpression(); + + BuiltInExpression(Type type, Expression *argument); + + ~BuiltInExpression(); + + void push(Evaluator &evaluator, Record *names = 0) const; + + Value *evaluate(Evaluator &evaluator) const; + + // Implements ISerializable. + void operator >> (Writer &to) const; + void operator << (Reader &from); + +public: /** - * Evaluates a built-in function on the argument(s). - * - * @ingroup script + * Checks if the identifier is one of the built-in functions. */ - class BuiltInExpression : public Expression - { - public: - /// A wrong number of arguments is given to one of the built-in methods. @ingroup errors - DENG2_ERROR(WrongArgumentsError); - - /// Type of the built-in expression. - /// @note These are serialied as is, so do not change the existing values. - enum Type { - NONE = 0, - LENGTH = 1, ///< Evaluate the length of an value (by calling size()). - DICTIONARY_KEYS = 2, - DICTIONARY_VALUES = 3, - RECORD_MEMBERS = 4, - RECORD_SUBRECORDS = 5, - AS_TEXT = 6, - AS_NUMBER = 7, - LOCAL_NAMESPACE = 8, - SERIALIZE = 9, - DESERIALIZE = 10, - AS_TIME = 11, - TIME_DELTA = 12, - AS_RECORD = 13 - }; - - public: - BuiltInExpression(); - - BuiltInExpression(Type type, Expression *argument); - - ~BuiltInExpression(); - - void push(Evaluator &evaluator, Record *names = 0) const; - - Value *evaluate(Evaluator &evaluator) const; + static Type findType(String const &identifier); - // Implements ISerializable. - void operator >> (Writer &to) const; - void operator << (Reader &from); +private: + Type _type; + Expression *_arg; +}; - public: - /** - * Checks if the identifier is one of the built-in functions. - */ - static Type findType(String const &identifier); - - private: - Type _type; - Expression *_arg; - }; -} +} // namespace de #endif /* LIBDENG2_BUILTINEXPRESSION_H */ diff --git a/doomsday/libdeng2/include/de/scriptsys/catchstatement.h b/doomsday/libdeng2/include/de/scriptsys/catchstatement.h index e9f8c2ed9c..c8a0a23106 100644 --- a/doomsday/libdeng2/include/de/scriptsys/catchstatement.h +++ b/doomsday/libdeng2/include/de/scriptsys/catchstatement.h @@ -26,62 +26,63 @@ #include -namespace de +namespace de { + +/** + * Catches an exception that occurs within a try compound. + */ +class CatchStatement : public Statement { - /** - * Catches an exception that occurs within a try compound. - */ - class CatchStatement : public Statement +public: + enum Flag { - public: - enum Flag - { - /// The final catch compound in a sequence of catch compounds. - FinalCompound = 0x1 - }; - Q_DECLARE_FLAGS(Flags, Flag) - - /// Flags. - Flags flags; - - public: - CatchStatement(ArrayExpression *args = 0); - ~CatchStatement(); - - Compound &compound() { return _compound; } - - /// Skips the catch compound (called only during normal execution). - void execute(Context &context) const; - - bool isFinal() const; - - /** - * Determines whether the catch statement will catch an error. - * - * @param err Error to check. - * - * @return @c true, if the error is caught and catch compound should be executed. - */ - bool matches(Error const &err) const; - - /** - * Assigns the exception to the specified variable and begins the catch compound. - * - * @param context Execution context. - * @param err Error. - */ - void executeCatch(Context &context, Error const &err) const; - - // Implements ISerializable. - void operator >> (Writer &to) const; - void operator << (Reader &from); - - private: - ArrayExpression *_args; - Compound _compound; + /// The final catch compound in a sequence of catch compounds. + FinalCompound = 0x1 }; + Q_DECLARE_FLAGS(Flags, Flag) + + /// Flags. + Flags flags; + +public: + CatchStatement(ArrayExpression *args = 0); + ~CatchStatement(); + + Compound &compound() { return _compound; } + + /// Skips the catch compound (called only during normal execution). + void execute(Context &context) const; + + bool isFinal() const; + + /** + * Determines whether the catch statement will catch an error. + * + * @param err Error to check. + * + * @return @c true, if the error is caught and catch compound should be executed. + */ + bool matches(Error const &err) const; + + /** + * Assigns the exception to the specified variable and begins the catch compound. + * + * @param context Execution context. + * @param err Error. + */ + void executeCatch(Context &context, Error const &err) const; + + // Implements ISerializable. + void operator >> (Writer &to) const; + void operator << (Reader &from); + +private: + ArrayExpression *_args; + Compound _compound; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(CatchStatement::Flags) - Q_DECLARE_OPERATORS_FOR_FLAGS(CatchStatement::Flags) -} +} // namespace de #endif /* LIBDENG2_CATCHSTATEMENT_H */ diff --git a/doomsday/libdeng2/include/de/scriptsys/compound.h b/doomsday/libdeng2/include/de/scriptsys/compound.h index a3fae4ffd7..2ee5986685 100644 --- a/doomsday/libdeng2/include/de/scriptsys/compound.h +++ b/doomsday/libdeng2/include/de/scriptsys/compound.h @@ -26,54 +26,55 @@ #include -namespace de +namespace de { + +class Statement; + +/** + * A series of statements. + * + * @ingroup script + */ +class Compound : public ISerializable { - class Statement; - +public: + Compound(); + + virtual ~Compound(); + + Statement const *firstStatement() const; + + /// Determines the size of the compound. + /// @return Number of statements in the compound. + duint size() const { + return _statements.size(); + } + /** - * A series of statements. + * Adds a new statement to the end of the compound. The previous + * final statement is updated to use this statement as its + * successor. * - * @ingroup script + * @param statement Statement object. The Compound takes ownership + * of the object. + */ + void add(Statement *statement); + + /** + * Deletes all statements. */ - class Compound : public ISerializable - { - public: - Compound(); + void clear(); + + // Implements ISerializable. + void operator >> (Writer &to) const; + void operator << (Reader &from); - virtual ~Compound(); +private: + typedef std::list Statements; + Statements _statements; +}; - Statement const *firstStatement() const; - - /// Determines the size of the compound. - /// @return Number of statements in the compound. - duint size() const { - return _statements.size(); - } - - /** - * Adds a new statement to the end of the compound. The previous - * final statement is updated to use this statement as its - * successor. - * - * @param statement Statement object. The Compound takes ownership - * of the object. - */ - void add(Statement *statement); - - /** - * Deletes all statements. - */ - void clear(); - - // Implements ISerializable. - void operator >> (Writer &to) const; - void operator << (Reader &from); - - private: - typedef std::list Statements; - Statements _statements; - }; -} +} // namespace de #endif /* LIBDENG2_COMPOUND_H */ diff --git a/doomsday/libdeng2/include/de/scriptsys/constantexpression.h b/doomsday/libdeng2/include/de/scriptsys/constantexpression.h index 9118f93e56..3a37aff8a4 100644 --- a/doomsday/libdeng2/include/de/scriptsys/constantexpression.h +++ b/doomsday/libdeng2/include/de/scriptsys/constantexpression.h @@ -23,44 +23,45 @@ #include "../Expression" #include "../Value" -namespace de +namespace de { + +/** + * An expression that always evaluates to a constant value. It is used for + * storing constants in scripts. + * + * @ingroup script + */ +class ConstantExpression : public Expression { +public: + ConstantExpression(); + /** - * An expression that always evaluates to a constant value. It is used for - * storing constants in scripts. + * Constructor. * - * @ingroup script + * @param value Value of the expression. The expression takes + * ownership of the value object. */ - class ConstantExpression : public Expression - { - public: - ConstantExpression(); - - /** - * Constructor. - * - * @param value Value of the expression. The expression takes - * ownership of the value object. - */ - ConstantExpression(Value *value); - - ~ConstantExpression(); - - Value *evaluate(Evaluator &evaluator) const; + ConstantExpression(Value *value); + + ~ConstantExpression(); + + Value *evaluate(Evaluator &evaluator) const; + + // Implements ISerializable. + void operator >> (Writer &to) const; + void operator << (Reader &from); + +public: + static ConstantExpression *None(); + static ConstantExpression *True(); + static ConstantExpression *False(); + static ConstantExpression *Pi(); - // Implements ISerializable. - void operator >> (Writer &to) const; - void operator << (Reader &from); - - public: - static ConstantExpression *None(); - static ConstantExpression *True(); - static ConstantExpression *False(); - static ConstantExpression *Pi(); +private: + Value *_value; +}; - private: - Value *_value; - }; -} +} // namespace de #endif /* LIBDENG2_CONSTANTEXPRESSION_H */ diff --git a/doomsday/libdeng2/include/de/scriptsys/context.h b/doomsday/libdeng2/include/de/scriptsys/context.h index eaccdc337d..6ca54b0da4 100644 --- a/doomsday/libdeng2/include/de/scriptsys/context.h +++ b/doomsday/libdeng2/include/de/scriptsys/context.h @@ -23,197 +23,198 @@ #include "../Evaluator" #include "../Record" -namespace de +namespace de { + +class Statement; +class Process; + +/** + * Entry in the process's call stack. + * + * @ingroup script + */ +class DENG2_PUBLIC Context { - class Statement; - class Process; - +public: + /// Attempting a jump when there is no suitable target (continue or break). @ingroup errors + DENG2_ERROR(JumpError); + + enum Type { + PROCESS, + GLOBAL_NAMESPACE, + FUNCTION_CALL + }; + +public: /** - * Entry in the process's call stack. + * Constructor. * - * @ingroup script + * @param type Type of the execution context. + * @param owner Process that owns the context. + * @param globals Optionally a global namespace. Lookups will stop here. */ - class DENG2_PUBLIC Context - { - public: - /// Attempting a jump when there is no suitable target (continue or break). @ingroup errors - DENG2_ERROR(JumpError); - - enum Type { - PROCESS, - GLOBAL_NAMESPACE, - FUNCTION_CALL - }; + Context(Type type, Process *owner, Record *globals = 0); - public: - /** - * Constructor. - * - * @param type Type of the execution context. - * @param owner Process that owns the context. - * @param globals Optionally a global namespace. Lookups will stop here. - */ - Context(Type type, Process *owner, Record *globals = 0); - - virtual ~Context(); + virtual ~Context(); - /// Determines the type of the execution context. - Type type() { return _type; } + /// Determines the type of the execution context. + Type type() { return _type; } - /// Returns the process that owns this context. - Process &process() { return *_owner; } + /// Returns the process that owns this context. + Process &process() { return *_owner; } - /// Returns the namespace of the context. - Record &names(); + /// Returns the namespace of the context. + Record &names(); - /// Returns the expression evaluator of the context. - Evaluator &evaluator(); + /// Returns the expression evaluator of the context. + Evaluator &evaluator(); - /** - * Start the execution of a series of statements. - * - * @param statement The first statement to execute. - * @param flow The statement to continue program flow when no more - * statements follow the current one. - * @param jumpContinue The statement to jump to when a "continue" - * statement is encountered. - * @param jumpBreak The statement to jump to when a "break" statement - * is encountered. - */ - void start(Statement const *statement, - Statement const *flow = NULL, - Statement const *jumpContinue = NULL, - Statement const *jumpBreak = NULL); + /** + * Start the execution of a series of statements. + * + * @param statement The first statement to execute. + * @param flow The statement to continue program flow when no more + * statements follow the current one. + * @param jumpContinue The statement to jump to when a "continue" + * statement is encountered. + * @param jumpBreak The statement to jump to when a "break" statement + * is encountered. + */ + void start(Statement const *statement, + Statement const *flow = NULL, + Statement const *jumpContinue = NULL, + Statement const *jumpBreak = NULL); - /** - * Clears the evaluator and control flow. Does not empty the namespace. - * This needs to be called if the process is aborted. - */ - void reset(); + /** + * Clears the evaluator and control flow. Does not empty the namespace. + * This needs to be called if the process is aborted. + */ + void reset(); - /// Returns the currently executed statement. - /// @return Statement, or @c NULL if no control flow information exists. - Statement const *current(); + /// Returns the currently executed statement. + /// @return Statement, or @c NULL if no control flow information exists. + Statement const *current(); - /** - * Execute the current statement. - * - * @return @c false if there are no more statements to execute. - */ - bool execute(); - - /** - * Proceed to the next statement as dictated by the control flow. - */ - void proceed(); - - /** - * Jump to the topmost continue target in the control flow stack. - * If there are no continue targets available, an error will be - * thrown. - */ - void jumpContinue(); - - /** - * Jump to the topmost break target in the control flow stack. - * If there are no break targets available, an error will be - * thrown. - * - * @param count Number of times to break out. Allows breaking - * out of nested loops. - */ - void jumpBreak(duint count = 1); + /** + * Execute the current statement. + * + * @return @c false if there are no more statements to execute. + */ + bool execute(); - /// Returns the current iteration value of the context. - Value *iterationValue(); + /** + * Proceed to the next statement as dictated by the control flow. + */ + void proceed(); + /** + * Jump to the topmost continue target in the control flow stack. + * If there are no continue targets available, an error will be + * thrown. + */ + void jumpContinue(); + + /** + * Jump to the topmost break target in the control flow stack. + * If there are no break targets available, an error will be + * thrown. + * + * @param count Number of times to break out. Allows breaking + * out of nested loops. + */ + void jumpBreak(duint count = 1); + + /// Returns the current iteration value of the context. + Value *iterationValue(); + + /** + * Sets the iteration value of the context. + * + * @param value Value to be iterated within the context. + */ + void setIterationValue(Value *value); + + /** + * Returns the throwaway variable. This can be used for dumping + * values that are not needed. For instance, the weak assignment operator + * will use this when the identifier already exists. + */ + Variable &throwaway() { return _throwaway; } + +private: + /** + * Information about the control flow is stored within a stack of + * ControlFlow instances. + */ + class ControlFlow { + public: /** - * Sets the iteration value of the context. + * Constructor. * - * @param value Value to be iterated within the context. + * @param current Current statement being executed. + * @param f Statement where normal flow continues. + * @param c Statement where to jump on "continue". + * @c NULL if continuing is not allowed. + * @param b Statement where to jump to and flow from on "break". + * @c NULL if breaking is not allowed. */ - void setIterationValue(Value *value); - - /** - * Returns the throwaway variable. This can be used for dumping - * values that are not needed. For instance, the weak assignment operator - * will use this when the identifier already exists. - */ - Variable &throwaway() { return _throwaway; } - - private: - /** - * Information about the control flow is stored within a stack of - * ControlFlow instances. - */ - class ControlFlow { - public: - /** - * Constructor. - * - * @param current Current statement being executed. - * @param f Statement where normal flow continues. - * @param c Statement where to jump on "continue". - * @c NULL if continuing is not allowed. - * @param b Statement where to jump to and flow from on "break". - * @c NULL if breaking is not allowed. - */ - ControlFlow(Statement const *current, - Statement const *f = 0, - Statement const *c = 0, - Statement const *b = 0) - : flow(f), jumpContinue(c), jumpBreak(b), iteration(0), _current(current) {} - - /// Returns the currently executed statement. - Statement const *current() const { return _current; } - - /// Sets the currently executed statement. When the statement - /// changes, the phase is reset back to zero. - void setCurrent(Statement const *s) { _current = s; } - - public: - Statement const *flow; - Statement const *jumpContinue; - Statement const *jumpBreak; - Value *iteration; - - private: - Statement const *_current; - }; - + ControlFlow(Statement const *current, + Statement const *f = 0, + Statement const *c = 0, + Statement const *b = 0) + : flow(f), jumpContinue(c), jumpBreak(b), iteration(0), _current(current) {} + + /// Returns the currently executed statement. + Statement const *current() const { return _current; } + + /// Sets the currently executed statement. When the statement + /// changes, the phase is reset back to zero. + void setCurrent(Statement const *s) { _current = s; } + + public: + Statement const *flow; + Statement const *jumpContinue; + Statement const *jumpBreak; + Value *iteration; + private: - /// Returns the topmost control flow information. - ControlFlow &flow() { return _controlFlow.back(); } - - /// Pops the topmost control flow instance off of the stack. The - /// iteration value is deleted, if it has been defined. - void popFlow(); - - /// Sets the currently executed statement. - void setCurrent(Statement const *statement); - - private: - /// Type of the execution context. - Type _type; - - /// The process that owns this context. - Process *_owner; - - /// Control flow stack. - typedef std::vector FlowStack; - FlowStack _controlFlow; - - /// Expression evaluator. - Evaluator _evaluator; - - /// Determines whether the namespace is owned by the context. - bool _ownsNamespace; - - /// The local namespace of this context. - Record *_names; - - Variable _throwaway; + Statement const *_current; }; -} + +private: + /// Returns the topmost control flow information. + ControlFlow &flow() { return _controlFlow.back(); } + + /// Pops the topmost control flow instance off of the stack. The + /// iteration value is deleted, if it has been defined. + void popFlow(); + + /// Sets the currently executed statement. + void setCurrent(Statement const *statement); + +private: + /// Type of the execution context. + Type _type; + + /// The process that owns this context. + Process *_owner; + + /// Control flow stack. + typedef std::vector FlowStack; + FlowStack _controlFlow; + + /// Expression evaluator. + Evaluator _evaluator; + + /// Determines whether the namespace is owned by the context. + bool _ownsNamespace; + + /// The local namespace of this context. + Record *_names; + + Variable _throwaway; +}; + +} // namespace de #endif /* LIBDENG2_CONTEXT_H */ diff --git a/doomsday/libdeng2/include/de/scriptsys/deletestatement.h b/doomsday/libdeng2/include/de/scriptsys/deletestatement.h index 9202318d60..5a242d9ed5 100644 --- a/doomsday/libdeng2/include/de/scriptsys/deletestatement.h +++ b/doomsday/libdeng2/include/de/scriptsys/deletestatement.h @@ -26,41 +26,42 @@ #include #include -namespace de +namespace de { + +/** + * Deletes variables. + * + * @ingroup script + */ +class DeleteStatement : public Statement { +public: + /// Trying to delete something other than a reference (RefValue). @ingroup errors + DENG2_ERROR(LeftValueError); + +public: + DeleteStatement(); + /** - * Deletes variables. + * Constructor. * - * @ingroup script + * @param targets Expression that resolves to a reference (array of RefValues). + * Statement gets ownership. */ - class DeleteStatement : public Statement - { - public: - /// Trying to delete something other than a reference (RefValue). @ingroup errors - DENG2_ERROR(LeftValueError); - - public: - DeleteStatement(); - - /** - * Constructor. - * - * @param targets Expression that resolves to a reference (array of RefValues). - * Statement gets ownership. - */ - DeleteStatement(ArrayExpression *targets); - - ~DeleteStatement(); - - void execute(Context &context) const; - - // Implements ISerializable. - void operator >> (Writer &to) const; - void operator << (Reader &from); - - private: - ArrayExpression *_targets; - }; -} + DeleteStatement(ArrayExpression *targets); + + ~DeleteStatement(); + + void execute(Context &context) const; + + // Implements ISerializable. + void operator >> (Writer &to) const; + void operator << (Reader &from); + +private: + ArrayExpression *_targets; +}; + +} // namespace de #endif /* LIBDENG2_DELETESTATEMENT_H */ diff --git a/doomsday/libdeng2/include/de/scriptsys/dictionaryexpression.h b/doomsday/libdeng2/include/de/scriptsys/dictionaryexpression.h index 4ca21aa1da..a1bd25e284 100644 --- a/doomsday/libdeng2/include/de/scriptsys/dictionaryexpression.h +++ b/doomsday/libdeng2/include/de/scriptsys/dictionaryexpression.h @@ -24,51 +24,52 @@ #include -namespace de +namespace de { + +/** + * Evaluates arguments and forms a dictionary out of the results. + * + * @ingroup script + */ +class DictionaryExpression : public Expression { +public: + DictionaryExpression(); + ~DictionaryExpression(); + + void clear(); + /** - * Evaluates arguments and forms a dictionary out of the results. + * Adds an key/value pair to the array expression. Ownership of + * the expressions is transferred to the expression. * - * @ingroup script + * @param key Evaluates the key. + * @param value Evaluates the value. */ - class DictionaryExpression : public Expression - { - public: - DictionaryExpression(); - ~DictionaryExpression(); - - void clear(); + void add(Expression *key, Expression *value); - /** - * Adds an key/value pair to the array expression. Ownership of - * the expressions is transferred to the expression. - * - * @param key Evaluates the key. - * @param value Evaluates the value. - */ - void add(Expression *key, Expression *value); + void push(Evaluator &evaluator, Record *names = 0) const; - void push(Evaluator &evaluator, Record *names = 0) const; + /** + * Collects the result keys and values of the arguments and puts them + * into a dictionary. + * + * @param evaluator Evaluator. + * + * @return DictionaryValue with the results of the argument evaluations. + */ + Value *evaluate(Evaluator &evaluator) const; - /** - * Collects the result keys and values of the arguments and puts them - * into a dictionary. - * - * @param evaluator Evaluator. - * - * @return DictionaryValue with the results of the argument evaluations. - */ - Value *evaluate(Evaluator &evaluator) const; + // Implements ISerializable. + void operator >> (Writer &to) const; + void operator << (Reader &from); - // Implements ISerializable. - void operator >> (Writer &to) const; - void operator << (Reader &from); +private: + typedef std::pair ExpressionPair; + typedef std::vector Arguments; + Arguments _arguments; +}; - private: - typedef std::pair ExpressionPair; - typedef std::vector Arguments; - Arguments _arguments; - }; -} +} // namespace de #endif /* LIBDENG2_DICTIONARYEXPRESSION_H */ diff --git a/doomsday/libdeng2/include/de/scriptsys/evaluator.h b/doomsday/libdeng2/include/de/scriptsys/evaluator.h index 026dee7f33..5b2fe86be3 100644 --- a/doomsday/libdeng2/include/de/scriptsys/evaluator.h +++ b/doomsday/libdeng2/include/de/scriptsys/evaluator.h @@ -26,160 +26,161 @@ #include #include -namespace de +namespace de { + +class Context; +class Process; +class Expression; +class Value; +class Record; + +/** + * Stack for evaluating expressions. + * + * @ingroup script + */ +class DENG2_PUBLIC Evaluator { - class Context; - class Process; - class Expression; - class Value; - class Record; - +public: + /// Result is of wrong type. @ingroup errors + DENG2_ERROR(ResultTypeError); + + typedef std::list Namespaces; + +public: + Evaluator(Context &owner); + ~Evaluator(); + + Context &context() { return _context; } + + /** + * Returns the process that owns this evaluator. + */ + Process &process(); + + /** + * Resets the evaluator so it's ready for another expression. + * Called when the statement changes in the context. + */ + void reset(); + /** - * Stack for evaluating expressions. + * Fully evaluate the given expression. The result value will remain + * in the results stack. * - * @ingroup script + * @return Result of the evaluation. */ - class DENG2_PUBLIC Evaluator - { - public: - /// Result is of wrong type. @ingroup errors - DENG2_ERROR(ResultTypeError); - - typedef std::list Namespaces; - - public: - Evaluator(Context &owner); - ~Evaluator(); - - Context &context() { return _context; } - - /** - * Returns the process that owns this evaluator. - */ - Process &process(); - - /** - * Resets the evaluator so it's ready for another expression. - * Called when the statement changes in the context. - */ - void reset(); - - /** - * Fully evaluate the given expression. The result value will remain - * in the results stack. - * - * @return Result of the evaluation. - */ - Value &evaluate(Expression const *expression); - - template - Type &evaluateTo(Expression const *expr) { - Type *r = dynamic_cast(&evaluate(expr)); - if(!r) { - throw ResultTypeError("Evaluator::result", "Unexpected result type"); - } - return *r; + Value &evaluate(Expression const *expression); + + template + Type &evaluateTo(Expression const *expr) { + Type *r = dynamic_cast(&evaluate(expr)); + if(!r) { + throw ResultTypeError("Evaluator::result", "Unexpected result type"); } + return *r; + } + + /** + * Determines the namespace for the currently evaluated expression. + * Those expressions whose operation depends on the current + * namespace scope, should use this to look identifiers from. + * This changes as expressions are popped off the stack. + * + * @return Namespace scope of the current evaluation. If @c NULL, + * expressions should assume that all namespaces are available. + */ + Record *names() const; + + /** + * Collect the namespaces currently visible. + * + * @param spaces List of namespaces. The order is important: the earlier + * namespaces shadow the subsequent ones. + */ + void namespaces(Namespaces &spaces); + + /** + * Insert the given expression to the top of the expression stack. + * + * @param expression Expression to push on the stack. + * @param names Namespace scope for this expression only. + */ + void push(Expression const *expression, Record *names = 0); - /** - * Determines the namespace for the currently evaluated expression. - * Those expressions whose operation depends on the current - * namespace scope, should use this to look identifiers from. - * This changes as expressions are popped off the stack. - * - * @return Namespace scope of the current evaluation. If @c NULL, - * expressions should assume that all namespaces are available. - */ - Record *names() const; - - /** - * Collect the namespaces currently visible. - * - * @param spaces List of namespaces. The order is important: the earlier - * namespaces shadow the subsequent ones. - */ - void namespaces(Namespaces &spaces); - - /** - * Insert the given expression to the top of the expression stack. - * - * @param expression Expression to push on the stack. - * @param names Namespace scope for this expression only. - */ - void push(Expression const *expression, Record *names = 0); - - /** - * Push a value onto the result stack. - * - * @param value Value to push on the result stack. The evaluator - * gets ownership of the value. - */ - void pushResult(Value *value); - - /** - * Pop a value off of the result stack. - * - * @return Value resulting from expression evaluation. Caller - * gets ownership of the returned object. - */ - Value *popResult(); - - /** - * Pop a value off of the result stack, making sure it has a specific type. - * - * @return Value resulting from expression evaluation. Caller - * gets ownership of the returned object. - */ - template - Type *popResultAs() { - if(!dynamic_cast(&result())) { - throw ResultTypeError("Evaluator::result", - "Result type is not compatible with Type"); - } - return dynamic_cast(popResult()); + /** + * Push a value onto the result stack. + * + * @param value Value to push on the result stack. The evaluator + * gets ownership of the value. + */ + void pushResult(Value *value); + + /** + * Pop a value off of the result stack. + * + * @return Value resulting from expression evaluation. Caller + * gets ownership of the returned object. + */ + Value *popResult(); + + /** + * Pop a value off of the result stack, making sure it has a specific type. + * + * @return Value resulting from expression evaluation. Caller + * gets ownership of the returned object. + */ + template + Type *popResultAs() { + if(!dynamic_cast(&result())) { + throw ResultTypeError("Evaluator::result", + "Result type is not compatible with Type"); } - - /** - * Determines whether a final result has been evaluated. - */ - bool hasResult() const; - - /** - * Determines the result of the evaluation without relinquishing - * ownership of the value instances. - * - * @return The final result of the evaluation. - */ - Value &result(); - - private: - void clearNames(); - void clearResults(); - void clearStack(); - - /// The context that owns this evaluator. - Context &_context; - - struct ScopedExpression { - Expression const *expression; - Record *names; - ScopedExpression(Expression const *e = 0, Record *n = 0) : expression(e), names(n) {} - }; - typedef std::vector Expressions; - typedef std::vector Results; - - /// The expression that is currently being evaluated. - Expression const *_current; - - /// Namespace for the current expression. - Record *_names; - - Expressions _stack; - Results _results; - - /// Returned when there is no result to give. - NoneValue _noResult; + return dynamic_cast(popResult()); + } + + /** + * Determines whether a final result has been evaluated. + */ + bool hasResult() const; + + /** + * Determines the result of the evaluation without relinquishing + * ownership of the value instances. + * + * @return The final result of the evaluation. + */ + Value &result(); + +private: + void clearNames(); + void clearResults(); + void clearStack(); + + /// The context that owns this evaluator. + Context &_context; + + struct ScopedExpression { + Expression const *expression; + Record *names; + ScopedExpression(Expression const *e = 0, Record *n = 0) : expression(e), names(n) {} }; -} + typedef std::vector Expressions; + typedef std::vector Results; + + /// The expression that is currently being evaluated. + Expression const *_current; + + /// Namespace for the current expression. + Record *_names; + + Expressions _stack; + Results _results; + + /// Returned when there is no result to give. + NoneValue _noResult; +}; + +} // namespace de #endif /* LIBDENG2_EVALUATOR_H */ diff --git a/doomsday/libdeng2/include/de/scriptsys/expression.h b/doomsday/libdeng2/include/de/scriptsys/expression.h index c91443de39..553c815859 100644 --- a/doomsday/libdeng2/include/de/scriptsys/expression.h +++ b/doomsday/libdeng2/include/de/scriptsys/expression.h @@ -24,121 +24,122 @@ #include -namespace de +namespace de { + +class Evaluator; +class Value; +class Record; + +/** + * Base class for expressions. + * + * @note All expression classes must call the serialization methods of this class + * so that the expression flags are properly serialized. + * + * @ingroup script + */ +class Expression : public ISerializable { - class Evaluator; - class Value; - class Record; +public: + /// Deserialization of an expression failed. @ingroup errors + DENG2_ERROR(DeserializationError); + + // Flags for evaluating expressions. + // Note: these are serialized as is, so don't change the existing values. + enum Flag + { + /// Evaluates to a value. In conjunction with IMPORT, causes the imported + /// record to be copied to the local namespace. + ByValue = 0x1, + + /// Evaluates to a reference. + ByReference = 0x2, + + /// If missing, create a new variable. + NewVariable = 0x4, + + /// If missing, create a new subrecord (i.e., Variable that owns a Record). + NewSubrecord = 0x8, + + /// Identifier must exist and will be deleted. + //Delete = 0x10, + + /// Imports an external namespace into the local namespace (as a reference). + Import = 0x20, + + /// Look for object in local namespace only. + LocalOnly = 0x40, + + /// If the identifier is in scope, returns a reference to the process's + /// throwaway variable. + ThrowawayIfInScope = 0x80, + + /// Identifier must not already exist in scope. + NotInScope = 0x100, + + /// Variable will be set to read-only mode. + ReadOnly = 0x200, + + /// Variable will be raised into a higher namespace. + Export = 0x400 + }; + Q_DECLARE_FLAGS(Flags, Flag) + +public: + virtual ~Expression(); + + virtual void push(Evaluator &evaluator, Record *names = 0) const; + + virtual Value *evaluate(Evaluator &evaluator) const = 0; + + /** + * Returns the flags of the expression. + */ + Flags const &flags () const; + + /** + * Sets the flags of the expression. + */ + void setFlags(Flags f); /** - * Base class for expressions. + * Subclasses must call this in their serialization method. + */ + void operator >> (Writer &to) const; + + /** + * Subclasses must call this in their deserialization method. + */ + void operator << (Reader &from); + +public: + /** + * Constructs an expression by deserializing one from a reader. * - * @note All expression classes must call the serialization methods of this class - * so that the expression flags are properly serialized. + * @param reader Reader. * - * @ingroup script + * @return The deserialized expression. Caller gets ownership. */ - class Expression : public ISerializable - { - public: - /// Deserialization of an expression failed. @ingroup errors - DENG2_ERROR(DeserializationError); - - // Flags for evaluating expressions. - // Note: these are serialized as is, so don't change the existing values. - enum Flag - { - /// Evaluates to a value. In conjunction with IMPORT, causes the imported - /// record to be copied to the local namespace. - ByValue = 0x1, - - /// Evaluates to a reference. - ByReference = 0x2, - - /// If missing, create a new variable. - NewVariable = 0x4, - - /// If missing, create a new subrecord (i.e., Variable that owns a Record). - NewSubrecord = 0x8, - - /// Identifier must exist and will be deleted. - //Delete = 0x10, - - /// Imports an external namespace into the local namespace (as a reference). - Import = 0x20, - - /// Look for object in local namespace only. - LocalOnly = 0x40, - - /// If the identifier is in scope, returns a reference to the process's - /// throwaway variable. - ThrowawayIfInScope = 0x80, - - /// Identifier must not already exist in scope. - NotInScope = 0x100, - - /// Variable will be set to read-only mode. - ReadOnly = 0x200, - - /// Variable will be raised into a higher namespace. - Export = 0x400 - }; - Q_DECLARE_FLAGS(Flags, Flag) - - public: - virtual ~Expression(); - - virtual void push(Evaluator &evaluator, Record *names = 0) const; - - virtual Value *evaluate(Evaluator &evaluator) const = 0; - - /** - * Returns the flags of the expression. - */ - Flags const &flags () const; - - /** - * Sets the flags of the expression. - */ - void setFlags(Flags f); - - /** - * Subclasses must call this in their serialization method. - */ - void operator >> (Writer &to) const; - - /** - * Subclasses must call this in their deserialization method. - */ - void operator << (Reader &from); - - public: - /** - * Constructs an expression by deserializing one from a reader. - * - * @param reader Reader. - * - * @return The deserialized expression. Caller gets ownership. - */ - static Expression *constructFrom(Reader &reader); - - protected: - typedef dbyte SerialId; - - enum SerialIds { - ARRAY, - BUILT_IN, - CONSTANT, - DICTIONARY, - NAME, - OPERATOR - }; - - private: - Flags _flags; + static Expression *constructFrom(Reader &reader); + +protected: + typedef dbyte SerialId; + + enum SerialIds { + ARRAY, + BUILT_IN, + CONSTANT, + DICTIONARY, + NAME, + OPERATOR }; - Q_DECLARE_OPERATORS_FOR_FLAGS(Expression::Flags) -} +private: + Flags _flags; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(Expression::Flags) + +} // namespace de #endif /* LIBDENG2_EXPRESSION_H */ diff --git a/doomsday/libdeng2/include/de/scriptsys/expressionstatement.h b/doomsday/libdeng2/include/de/scriptsys/expressionstatement.h index d7215605cc..7daaad8834 100644 --- a/doomsday/libdeng2/include/de/scriptsys/expressionstatement.h +++ b/doomsday/libdeng2/include/de/scriptsys/expressionstatement.h @@ -22,37 +22,38 @@ #include "../Statement" -namespace de +namespace de { + +class Expression; + +/** + * Evaluates an expression but does not store the result anywhere. An example of + * this would be a statement that just does a single method call. + * + * @ingroup script + */ +class ExpressionStatement : public Statement { - class Expression; - +public: /** - * Evaluates an expression but does not store the result anywhere. An example of - * this would be a statement that just does a single method call. + * Constructs a new expression statement. * - * @ingroup script + * @param expression Statement gets ownership. */ - class ExpressionStatement : public Statement - { - public: - /** - * Constructs a new expression statement. - * - * @param expression Statement gets ownership. - */ - ExpressionStatement(Expression *expression = 0) : _expression(expression) {} - - ~ExpressionStatement(); - - void execute(Context &context) const; - - // Implements ISerializable. - void operator >> (Writer &to) const; - void operator << (Reader &from); - - private: - Expression *_expression; - }; -} + ExpressionStatement(Expression *expression = 0) : _expression(expression) {} + + ~ExpressionStatement(); + + void execute(Context &context) const; + + // Implements ISerializable. + void operator >> (Writer &to) const; + void operator << (Reader &from); + +private: + Expression *_expression; +}; + +} // namespace de #endif /* LIBDENG2_EXPRESSIONSTATEMENT_H */ diff --git a/doomsday/libdeng2/include/de/scriptsys/flowstatement.h b/doomsday/libdeng2/include/de/scriptsys/flowstatement.h index c5b4a3b95b..45570bf3e2 100644 --- a/doomsday/libdeng2/include/de/scriptsys/flowstatement.h +++ b/doomsday/libdeng2/include/de/scriptsys/flowstatement.h @@ -22,44 +22,45 @@ #include "../Statement" -namespace de +namespace de { + +class Expression; + +/** + * Controls the script's flow of execution. + * + * @ingroup script + */ +class FlowStatement : public Statement { - class Expression; - - /** - * Controls the script's flow of execution. - * - * @ingroup script - */ - class FlowStatement : public Statement - { - public: - /// Type of control flow operation. - enum Type { - PASS, - CONTINUE, - BREAK, - RETURN, - THROW - }; - - public: - FlowStatement(); - - FlowStatement(Type type, Expression *countArgument = 0); - - ~FlowStatement(); - - void execute(Context &context) const; - - // Implements ISerializable. - void operator >> (Writer &to) const; - void operator << (Reader &from); - - private: - Type _type; - Expression *_arg; +public: + /// Type of control flow operation. + enum Type { + PASS, + CONTINUE, + BREAK, + RETURN, + THROW }; -} + +public: + FlowStatement(); + + FlowStatement(Type type, Expression *countArgument = 0); + + ~FlowStatement(); + + void execute(Context &context) const; + + // Implements ISerializable. + void operator >> (Writer &to) const; + void operator << (Reader &from); + +private: + Type _type; + Expression *_arg; +}; + +} // namespace de #endif /* LIBDENG2_FLOWSTATEMENT_H */ diff --git a/doomsday/libdeng2/include/de/scriptsys/forstatement.h b/doomsday/libdeng2/include/de/scriptsys/forstatement.h index d74508a408..448d263f6e 100644 --- a/doomsday/libdeng2/include/de/scriptsys/forstatement.h +++ b/doomsday/libdeng2/include/de/scriptsys/forstatement.h @@ -26,41 +26,42 @@ #include -namespace de +namespace de { + +class Expression; + +/** + * Keeps looping until the iterable value runs out of elements. + * + * @ingroup script + */ +class ForStatement : public Statement { - class Expression; - - /** - * Keeps looping until the iterable value runs out of elements. - * - * @ingroup script - */ - class ForStatement : public Statement - { - public: - ForStatement(); - - ForStatement(Expression *iter, Expression *iteration) - : _iterator(iter), _iteration(iteration) {} - - ~ForStatement(); - - /// Returns the compound of the statement. - Compound &compound() { - return _compound; - } - - void execute(Context &context) const; +public: + ForStatement(); + + ForStatement(Expression *iter, Expression *iteration) + : _iterator(iter), _iteration(iteration) {} + + ~ForStatement(); + + /// Returns the compound of the statement. + Compound &compound() { + return _compound; + } + + void execute(Context &context) const; + + // Implements ISerializable. + void operator >> (Writer &to) const; + void operator << (Reader &from); - // Implements ISerializable. - void operator >> (Writer &to) const; - void operator << (Reader &from); +private: + Expression *_iterator; + Expression *_iteration; + Compound _compound; +}; - private: - Expression *_iterator; - Expression *_iteration; - Compound _compound; - }; -} +} // namespace de #endif /* LIBDENG2_FORSTATEMENT_H */ diff --git a/doomsday/libdeng2/include/de/scriptsys/function.h b/doomsday/libdeng2/include/de/scriptsys/function.h index f2ca6bb8ba..e003b153c3 100644 --- a/doomsday/libdeng2/include/de/scriptsys/function.h +++ b/doomsday/libdeng2/include/de/scriptsys/function.h @@ -29,194 +29,195 @@ #include #include -namespace de +namespace de { + +class Statement; +class Context; +class Expression; +class Value; +class ArrayValue; + +/** + * Callable set of statements ready for execution, or a wrapper for a native + * function. + * + * A function can either consist of a compound of statements or it can use + * a native entry point that will perform processing using native code. Both + * are defined in scripts using the @c def keyword, which allows the script + * engine to set up all the arguments in the way that the function expects. + * + * Functions are reference-counted so that they exist as long as other + * objects need them (FunctionStatement, FunctionValue).The argument list + * defines what kind of arguments can be passed to the function and what + * are the default values for the arguments. + * + * @ingroup script + */ +class DENG2_PUBLIC Function : public Counted, public ISerializable, DENG2_OBSERVES(Record, Deletion) { - class Statement; - class Context; - class Expression; - class Value; - class ArrayValue; +public: + /// An incorrect number of arguments is given in a function call. @ingroup errors + DENG2_ERROR(WrongArgumentsError); + + /// An unknown native entry point was specified. @ingroup errors + DENG2_ERROR(UnknownEntryPointError); + + typedef QList Arguments; + typedef QMap Defaults; + typedef QList ArgumentValues; + +public: + Function(); + + /** + * Constructor. + * + * @param args Names of the function arguments. + * @param defaults Default values for some or all of the arguments. + */ + Function(Arguments const &args, Defaults const &defaults); + + /** + * Construct a function that uses a native entry point. + * + * @param nativeName Name of the entry point. + * @param args Names of the function arguments. + * @param defaults Default values for some or all of the arguments. + * + * @see nativeEntryPoint() + */ + Function(String const &nativeName, + Arguments const &args = Arguments(), + Defaults const &defaults = Defaults()); + + /// Returns a human-readable representation of the function. + String asText() const; + + Compound &compound(); + + Compound const &compound() const; + + Arguments &arguments(); + + Arguments const &arguments() const; + + Defaults &defaults(); + + Defaults const &defaults() const; + + /** + * Maps a set of named and unnamed argument values to the list of values that + * will be passed to the function. Default values will be used for any arguments + * that have been given no value. No copies of any values are made. + * + * @param args The array's first element must be a DictionaryValue containing + * values for the named arguments of the call. The rest of the array + * are the unnamed arguments. + * @param values The resulting list of values to the passed to the function. + * The values are in the order the arguments have been declared in + * the function statement. + */ + void mapArgumentValues(ArrayValue const &args, ArgumentValues &values) const; + + /** + * Sets the global namespace of the function. This is the namespace + * where the function was initially created. + */ + void setGlobals(Record *globals); /** - * Callable set of statements ready for execution, or a wrapper for a native - * function. + * Returns the global namespace of the function. + * Return @c NULL when the originating namespace has been deleted. + */ + Record *globals() const; + + /** + * Determines if this is a native function. callNative() is called to + * execute native functions instead of pushing a new context on the + * process's stack. + * + * @return @c true, iff this is a native function. + */ + bool isNative() const; + + /** + * Name of the native entry point. + * + * @return Entry point name (if native). + */ + String nativeName() const; + + /** + * Perform a native call of the function. + * + * @param context Execution context. Any results generated by a + * native function are placed here. + * @param args Arguments to the function. The array's first element + * is always a dictionary that contains the labeled values. + * + * @return Return value from the native function. Always a valid Value. + * + * @return @c false, if the context should proceed with the non-native + * function call by creating a new execution context and running + * the statements of the function there. @c true, if the + * native call handles everything, including placing the + * return value into the evaluator. + */ + virtual Value *callNative(Context &context, ArgumentValues const &args) const; + + // Implements ISerializable. + void operator >> (Writer &to) const; + void operator << (Reader &from); + + // Observes Record deletion. + void recordBeingDeleted(Record &record); + +public: + /** + * Signature for native entry points. If the native function does not + * produce a return value (returns @c NULL), a NoneValue is + * automatically created. + */ + typedef Value *(*NativeEntryPoint)(Context &, ArgumentValues const &); + + /** + * Registers a native entry point. + * + * @param name Name of the entry point. Will be included in + * serialized data. + * @param entryPoint Pointer to the entry point. (Not serialized.) + */ + static void registerNativeEntryPoint(String const &name, NativeEntryPoint entryPoint); + + /** + * Unregisters a native entry point. This is required for instance when + * the entry point is located in a plugin and it is being unloaded. + * Whoever registered the entry point is responsible for making sure + * the supplied function pointer remains valid. * - * A function can either consist of a compound of statements or it can use - * a native entry point that will perform processing using native code. Both - * are defined in scripts using the @c def keyword, which allows the script - * engine to set up all the arguments in the way that the function expects. + * @param name Name of a previously registered native entry point. + */ + static void unregisterNativeEntryPoint(String const &name); + + /** + * Finds a native entry point. The entry point needs to be either one + * of the built-in entry points or previously registered with + * registerNativeEntryPoint(). * - * Functions are reference-counted so that they exist as long as other - * objects need them (FunctionStatement, FunctionValue).The argument list - * defines what kind of arguments can be passed to the function and what - * are the default values for the arguments. + * @param name Name of the entry point. * - * @ingroup script + * @return Native entry point. */ - class DENG2_PUBLIC Function : public Counted, public ISerializable, DENG2_OBSERVES(Record, Deletion) - { - public: - /// An incorrect number of arguments is given in a function call. @ingroup errors - DENG2_ERROR(WrongArgumentsError); - - /// An unknown native entry point was specified. @ingroup errors - DENG2_ERROR(UnknownEntryPointError); - - typedef QList Arguments; - typedef QMap Defaults; - typedef QList ArgumentValues; - - public: - Function(); - - /** - * Constructor. - * - * @param args Names of the function arguments. - * @param defaults Default values for some or all of the arguments. - */ - Function(Arguments const &args, Defaults const &defaults); - - /** - * Construct a function that uses a native entry point. - * - * @param nativeName Name of the entry point. - * @param args Names of the function arguments. - * @param defaults Default values for some or all of the arguments. - * - * @see nativeEntryPoint() - */ - Function(String const &nativeName, - Arguments const &args = Arguments(), - Defaults const &defaults = Defaults()); - - /// Returns a human-readable representation of the function. - String asText() const; - - Compound &compound(); - - Compound const &compound() const; - - Arguments &arguments(); - - Arguments const &arguments() const; - - Defaults &defaults(); - - Defaults const &defaults() const; - - /** - * Maps a set of named and unnamed argument values to the list of values that - * will be passed to the function. Default values will be used for any arguments - * that have been given no value. No copies of any values are made. - * - * @param args The array's first element must be a DictionaryValue containing - * values for the named arguments of the call. The rest of the array - * are the unnamed arguments. - * @param values The resulting list of values to the passed to the function. - * The values are in the order the arguments have been declared in - * the function statement. - */ - void mapArgumentValues(ArrayValue const &args, ArgumentValues &values) const; - - /** - * Sets the global namespace of the function. This is the namespace - * where the function was initially created. - */ - void setGlobals(Record *globals); - - /** - * Returns the global namespace of the function. - * Return @c NULL when the originating namespace has been deleted. - */ - Record *globals() const; - - /** - * Determines if this is a native function. callNative() is called to - * execute native functions instead of pushing a new context on the - * process's stack. - * - * @return @c true, iff this is a native function. - */ - bool isNative() const; - - /** - * Name of the native entry point. - * - * @return Entry point name (if native). - */ - String nativeName() const; - - /** - * Perform a native call of the function. - * - * @param context Execution context. Any results generated by a - * native function are placed here. - * @param args Arguments to the function. The array's first element - * is always a dictionary that contains the labeled values. - * - * @return Return value from the native function. Always a valid Value. - * - * @return @c false, if the context should proceed with the non-native - * function call by creating a new execution context and running - * the statements of the function there. @c true, if the - * native call handles everything, including placing the - * return value into the evaluator. - */ - virtual Value *callNative(Context &context, ArgumentValues const &args) const; - - // Implements ISerializable. - void operator >> (Writer &to) const; - void operator << (Reader &from); - - // Observes Record deletion. - void recordBeingDeleted(Record &record); - - public: - /** - * Signature for native entry points. If the native function does not - * produce a return value (returns @c NULL), a NoneValue is - * automatically created. - */ - typedef Value *(*NativeEntryPoint)(Context &, ArgumentValues const &); - - /** - * Registers a native entry point. - * - * @param name Name of the entry point. Will be included in - * serialized data. - * @param entryPoint Pointer to the entry point. (Not serialized.) - */ - static void registerNativeEntryPoint(String const &name, NativeEntryPoint entryPoint); - - /** - * Unregisters a native entry point. This is required for instance when - * the entry point is located in a plugin and it is being unloaded. - * Whoever registered the entry point is responsible for making sure - * the supplied function pointer remains valid. - * - * @param name Name of a previously registered native entry point. - */ - static void unregisterNativeEntryPoint(String const &name); - - /** - * Finds a native entry point. The entry point needs to be either one - * of the built-in entry points or previously registered with - * registerNativeEntryPoint(). - * - * @param name Name of the entry point. - * - * @return Native entry point. - */ - static NativeEntryPoint nativeEntryPoint(String const &name); - - protected: - ~Function(); // Counted - - private: - struct Instance; - Instance *d; - }; -} + static NativeEntryPoint nativeEntryPoint(String const &name); + +protected: + ~Function(); // Counted + +private: + struct Instance; + Instance *d; +}; + +} // namespace de #endif /* LIBDENG2_FUNCTION_H */ diff --git a/doomsday/libdeng2/include/de/scriptsys/functionstatement.h b/doomsday/libdeng2/include/de/scriptsys/functionstatement.h index c76d8d82e4..1d9b777bb9 100644 --- a/doomsday/libdeng2/include/de/scriptsys/functionstatement.h +++ b/doomsday/libdeng2/include/de/scriptsys/functionstatement.h @@ -28,42 +28,43 @@ #include -namespace de +namespace de { + +class Expression; + +/** + * Creates a new function. + * + * @ingroup script + */ +class FunctionStatement : public Statement { - class Expression; - - /** - * Creates a new function. - * - * @ingroup script - */ - class FunctionStatement : public Statement - { - public: - FunctionStatement(Expression *identifier = 0); - - ~FunctionStatement(); - - void addArgument(String const &argName, Expression *defaultValue = 0); - - /// Returns the statement compound of the function. - Compound &compound(); - - void execute(Context &context) const; - - // Implements ISerializable. - void operator >> (Writer &to) const; - void operator << (Reader &from); - - private: - Expression *_identifier; - - // The statement holds one reference to the function. - Function *_function; - - /// Expression that evaluates into the default values of the method. - DictionaryExpression _defaults; - }; -} +public: + FunctionStatement(Expression *identifier = 0); + + ~FunctionStatement(); + + void addArgument(String const &argName, Expression *defaultValue = 0); + + /// Returns the statement compound of the function. + Compound &compound(); + + void execute(Context &context) const; + + // Implements ISerializable. + void operator >> (Writer &to) const; + void operator << (Reader &from); + +private: + Expression *_identifier; + + // The statement holds one reference to the function. + Function *_function; + + /// Expression that evaluates into the default values of the method. + DictionaryExpression _defaults; +}; + +} // namespace de #endif /* LIBDENG2_FUNCTIONSTATEMENT_H */ diff --git a/doomsday/libdeng2/include/de/scriptsys/functionvalue.h b/doomsday/libdeng2/include/de/scriptsys/functionvalue.h index e0c6bcffb5..3c43c3a89c 100644 --- a/doomsday/libdeng2/include/de/scriptsys/functionvalue.h +++ b/doomsday/libdeng2/include/de/scriptsys/functionvalue.h @@ -23,37 +23,38 @@ #include "../Value" #include "../Function" -namespace de +namespace de { + +/** + * Holds a reference to a function and provides a way to call the function. + * + * @ingroup script + */ +class FunctionValue : public Value { - /** - * Holds a reference to a function and provides a way to call the function. - * - * @ingroup script - */ - class FunctionValue : public Value - { - public: - FunctionValue(); - FunctionValue(Function *func); - ~FunctionValue(); - - /// Returns the function. - Function const &function() const { return *_func; } - - Value *duplicate() const; - Text asText() const; - bool isTrue() const; - bool isFalse() const; - dint compare(Value const &value) const; - void call(Process &process, Value const &arguments) const; - - // Implements ISerializable. - void operator >> (Writer &to) const; - void operator << (Reader &from); - - private: - Function *_func; - }; -} +public: + FunctionValue(); + FunctionValue(Function *func); + ~FunctionValue(); + + /// Returns the function. + Function const &function() const { return *_func; } + + Value *duplicate() const; + Text asText() const; + bool isTrue() const; + bool isFalse() const; + dint compare(Value const &value) const; + void call(Process &process, Value const &arguments) const; + + // Implements ISerializable. + void operator >> (Writer &to) const; + void operator << (Reader &from); + +private: + Function *_func; +}; + +} // namespace de #endif /* LIBDENG2_FUNCTIONVALUE_H */ diff --git a/doomsday/libdeng2/include/de/scriptsys/ifstatement.h b/doomsday/libdeng2/include/de/scriptsys/ifstatement.h index 5769055faf..9df2cb1d0c 100644 --- a/doomsday/libdeng2/include/de/scriptsys/ifstatement.h +++ b/doomsday/libdeng2/include/de/scriptsys/ifstatement.h @@ -25,61 +25,62 @@ #include -namespace de +namespace de { + +class Expression; + +/** + * Branching statement for conditionally executing one or more compounds. + * + * @ingroup script + */ +class IfStatement : public Statement { - class Expression; - +public: + ~IfStatement(); + + void clear(); + + /** + * Add a new branch to the statement. + */ + void newBranch(); + + /** + * Sets the condition expression of the latest branch. + */ + void setBranchCondition(Expression *expression); + + /** + * Returns the compound of the latest branch. + */ + Compound &branchCompound(); + /** - * Branching statement for conditionally executing one or more compounds. - * - * @ingroup script + * Returns the else-compound of the statement. */ - class IfStatement : public Statement - { - public: - ~IfStatement(); - - void clear(); - - /** - * Add a new branch to the statement. - */ - void newBranch(); - - /** - * Sets the condition expression of the latest branch. - */ - void setBranchCondition(Expression *expression); - - /** - * Returns the compound of the latest branch. - */ - Compound &branchCompound(); - - /** - * Returns the else-compound of the statement. - */ - Compound &elseCompound() { - return _elseCompound; - } - - void execute(Context &context) const; - - // Implements ISerializable. - void operator >> (Writer &to) const; - void operator << (Reader &from); - - private: - struct Branch { - Expression *condition; - Compound *compound; - Branch(Compound *c = 0) : condition(0), compound(c) {} - }; - typedef std::list Branches; - - Branches _branches; - Compound _elseCompound; + Compound &elseCompound() { + return _elseCompound; + } + + void execute(Context &context) const; + + // Implements ISerializable. + void operator >> (Writer &to) const; + void operator << (Reader &from); + +private: + struct Branch { + Expression *condition; + Compound *compound; + Branch(Compound *c = 0) : condition(0), compound(c) {} }; -} + typedef std::list Branches; + + Branches _branches; + Compound _elseCompound; +}; + +} // namespace de #endif /* LIBDENG2_IFSTATEMENT_H */ diff --git a/doomsday/libdeng2/include/de/scriptsys/iparser.h b/doomsday/libdeng2/include/de/scriptsys/iparser.h index f9c1df0500..8c9b08d27e 100644 --- a/doomsday/libdeng2/include/de/scriptsys/iparser.h +++ b/doomsday/libdeng2/include/de/scriptsys/iparser.h @@ -22,35 +22,36 @@ #include "../String" -namespace de +namespace de { + +class Script; + +/** + * Interface for objects responsible for reading a script in text form and + * producing an executable Script object, with Statements and related + * atoms. + * + * This is an interface for parsers. A concrete Parser implementation + * uses a specific syntax for the input text. + * + * @ingroup script + */ +class IParser { - class Script; - +public: + virtual ~IParser() {} + /** - * Interface for objects responsible for reading a script in text form and - * producing an executable Script object, with Statements and related - * atoms. + * Reads an input script in text format, and according to the + * syntax specified by the parser, creates a set of statements + * and related atoms in the output Script object. * - * This is an interface for parsers. A concrete Parser implementation - * uses a specific syntax for the input text. - * - * @ingroup script + * @param input Input script in text format. + * @param output Output Script object. */ - class IParser - { - public: - virtual ~IParser() {} - - /** - * Reads an input script in text format, and according to the - * syntax specified by the parser, creates a set of statements - * and related atoms in the output Script object. - * - * @param input Input script in text format. - * @param output Output Script object. - */ - virtual void parse(String const &input, Script &output) = 0; - }; -} + virtual void parse(String const &input, Script &output) = 0; +}; + +} // namespace de #endif /* LIBDENG2_IPARSER_H */ diff --git a/doomsday/libdeng2/include/de/scriptsys/lex.h b/doomsday/libdeng2/include/de/scriptsys/lex.h index 137104ec24..8571f23221 100644 --- a/doomsday/libdeng2/include/de/scriptsys/lex.h +++ b/doomsday/libdeng2/include/de/scriptsys/lex.h @@ -25,141 +25,142 @@ #include -namespace de +namespace de { + +/** + * Base class for lexical analyzers. It provides the basic service of reading + * characters one by one from an input text. It also classifies characters. + * + * @ingroup script + */ +class Lex { +public: + /// Attempt to read characters when there are non left. @ingroup errors + DENG2_ERROR(OutOfInputError); + + enum ModeFlag + { + SkipComments = 0x1 + }; + Q_DECLARE_FLAGS(ModeFlags, ModeFlag) + /** - * Base class for lexical analyzers. It provides the basic service of reading - * characters one by one from an input text. It also classifies characters. - * - * @ingroup script + * Utility for setting flags in a Lex instance. The flags specified + * in the mode span are in effect during the lifetime of the ModeSpan instance. + * When the ModeSpan goes out of scope, the original flags are restored + * (the ones that were in use when the ModeSpan was constructed). */ - class Lex + class ModeSpan { public: - /// Attempt to read characters when there are non left. @ingroup errors - DENG2_ERROR(OutOfInputError); - - enum ModeFlag - { - SkipComments = 0x1 - }; - Q_DECLARE_FLAGS(ModeFlags, ModeFlag) - - /** - * Utility for setting flags in a Lex instance. The flags specified - * in the mode span are in effect during the lifetime of the ModeSpan instance. - * When the ModeSpan goes out of scope, the original flags are restored - * (the ones that were in use when the ModeSpan was constructed). - */ - class ModeSpan - { - public: - ModeSpan(Lex &lex, ModeFlags const &m) : _lex(lex), _originalMode(lex._mode) { - lex._mode = m; - } - - ~ModeSpan() { - _lex._mode = _originalMode; - } - - private: - Lex &_lex; - ModeFlags _originalMode; - }; - - // Constants. - static String const T_PARENTHESIS_OPEN; - static String const T_PARENTHESIS_CLOSE; - static String const T_BRACKET_OPEN; - static String const T_BRACKET_CLOSE; - static String const T_CURLY_OPEN; - static String const T_CURLY_CLOSE; + ModeSpan(Lex &lex, ModeFlags const &m) : _lex(lex), _originalMode(lex._mode) { + lex._mode = m; + } - public: - Lex(String const &input = ""); - - /// Returns the input string in its entirety. - String const &input() const; - - /// Returns the current position of the analyzer. - duint pos() const; - - /// Returns the next character, according to the position. - /// Characters past the end of the input string are returned - /// as zero. - QChar peek() const; - - /// Returns the next character and increments the position. - /// Returns zero if the end of the input is reached. - QChar get(); - - /// Skips until a non-whitespace character is found. - void skipWhite(); - - /// Skips until a non-whitespace character, or newline, is found. - void skipWhiteExceptNewline(); - - /// Skips until a new line begins. - void skipToNextLine(); - - /// Returns the current line of the reading position. The character - /// returned from get() will be on this line. - duint lineNumber() const { - return _state.lineNumber; + ~ModeSpan() { + _lex._mode = _originalMode; } - /// Determines whether there is only whitespace (or nothing) - /// remaining on the current line. - bool onlyWhiteOnLine(); - - /// Counts the number of whitespace characters in the beginning of - /// the current line. - duint countLineStartSpace() const; + private: + Lex &_lex; + ModeFlags _originalMode; + }; - public: - /// Determines whether a character is whitespace. - /// @param c Character to check. - static bool isWhite(QChar c); - - /// Determine whether a character is alphabetic. - /// @param c Character to check. - static bool isAlpha(QChar c); - - /// Determine whether a character is numeric. - /// @param c Character to check. - static bool isNumeric(QChar c); - - /// Determine whether a character is hexadecimal numeric. - /// @param c Character to check. - static bool isHexNumeric(QChar c); - - /// Determine whether a character is alphanumeric. - /// @param c Character to check. - static bool isAlphaNumeric(QChar c); + // Constants. + static String const T_PARENTHESIS_OPEN; + static String const T_PARENTHESIS_CLOSE; + static String const T_BRACKET_OPEN; + static String const T_BRACKET_CLOSE; + static String const T_CURLY_OPEN; + static String const T_CURLY_CLOSE; - private: - /// Input text being analyzed. - String const *_input; - - mutable duint _nextPos; - - struct State { - duint pos; ///< Current reading position. - duint lineNumber; ///< Keeps track of the line number on which the current position is. - duint lineStartPos; ///< Position which begins the current line. - - State() : pos(0), lineNumber(1), lineStartPos(0) {} - }; - - State _state; - - /// Character that begins a line comment. - duchar _lineCommentChar; - - ModeFlags _mode; +public: + Lex(String const &input = ""); + + /// Returns the input string in its entirety. + String const &input() const; + + /// Returns the current position of the analyzer. + duint pos() const; + + /// Returns the next character, according to the position. + /// Characters past the end of the input string are returned + /// as zero. + QChar peek() const; + + /// Returns the next character and increments the position. + /// Returns zero if the end of the input is reached. + QChar get(); + + /// Skips until a non-whitespace character is found. + void skipWhite(); + + /// Skips until a non-whitespace character, or newline, is found. + void skipWhiteExceptNewline(); + + /// Skips until a new line begins. + void skipToNextLine(); + + /// Returns the current line of the reading position. The character + /// returned from get() will be on this line. + duint lineNumber() const { + return _state.lineNumber; + } + + /// Determines whether there is only whitespace (or nothing) + /// remaining on the current line. + bool onlyWhiteOnLine(); + + /// Counts the number of whitespace characters in the beginning of + /// the current line. + duint countLineStartSpace() const; + +public: + /// Determines whether a character is whitespace. + /// @param c Character to check. + static bool isWhite(QChar c); + + /// Determine whether a character is alphabetic. + /// @param c Character to check. + static bool isAlpha(QChar c); + + /// Determine whether a character is numeric. + /// @param c Character to check. + static bool isNumeric(QChar c); + + /// Determine whether a character is hexadecimal numeric. + /// @param c Character to check. + static bool isHexNumeric(QChar c); + + /// Determine whether a character is alphanumeric. + /// @param c Character to check. + static bool isAlphaNumeric(QChar c); + +private: + /// Input text being analyzed. + String const *_input; + + mutable duint _nextPos; + + struct State { + duint pos; ///< Current reading position. + duint lineNumber; ///< Keeps track of the line number on which the current position is. + duint lineStartPos; ///< Position which begins the current line. + + State() : pos(0), lineNumber(1), lineStartPos(0) {} }; - Q_DECLARE_OPERATORS_FOR_FLAGS(Lex::ModeFlags) -} + State _state; + + /// Character that begins a line comment. + duchar _lineCommentChar; + + ModeFlags _mode; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(Lex::ModeFlags) + +} // namespace de #endif /* LIBDENG2_LEX_H */ diff --git a/doomsday/libdeng2/include/de/scriptsys/module.h b/doomsday/libdeng2/include/de/scriptsys/module.h index 9dda7ea2ed..621b6d8e4f 100644 --- a/doomsday/libdeng2/include/de/scriptsys/module.h +++ b/doomsday/libdeng2/include/de/scriptsys/module.h @@ -22,63 +22,64 @@ #include "../String" -namespace de +namespace de { + +class File; +class Process; +class Record; +class Script; + +/** + * Modules are scripts that are loaded from the file system and then stay + * in memory for other scripts to use. For instance, a module could contain + * functions that are useful for many other scripts. Scripts can use the + * import statement to gain access to a module's namespace. The module's + * source script is executed only the first time it gets imported -- + * subsequent calls simply provide a reference to the existing module's namespace. + * + * @ingroup script + */ +class Module { - class File; - class Process; - class Record; - class Script; - +public: + /** + * Constructs a new module. The source script is loaded from a + * file and executed. + * + * @param sourcePath Path of the source file. + */ + Module(String const &sourcePath); + /** - * Modules are scripts that are loaded from the file system and then stay - * in memory for other scripts to use. For instance, a module could contain - * functions that are useful for many other scripts. Scripts can use the - * import statement to gain access to a module's namespace. The module's - * source script is executed only the first time it gets imported -- - * subsequent calls simply provide a reference to the existing module's namespace. + * Constructs a new module. The source script is loaded from a + * file and executed. * - * @ingroup script + * @param sourceFile Script source file. */ - class Module - { - public: - /** - * Constructs a new module. The source script is loaded from a - * file and executed. - * - * @param sourcePath Path of the source file. - */ - Module(String const &sourcePath); - - /** - * Constructs a new module. The source script is loaded from a - * file and executed. - * - * @param sourceFile Script source file. - */ - Module(File const &sourceFile); - - virtual ~Module(); - - /// Returns the module's source script's absolute path. - String const &sourcePath() const { return _sourcePath; } - - /// Returns the namespace of the module. The import statement gives access - /// to this. - Record &names(); + Module(File const &sourceFile); + + virtual ~Module(); + + /// Returns the module's source script's absolute path. + String const &sourcePath() const { return _sourcePath; } + + /// Returns the namespace of the module. The import statement gives access + /// to this. + Record &names(); + +protected: + void initialize(Script const &script); + +private: + /// Path of the script source file. Used to identify whether a script has + /// already been loaded or not. Imported scripts are run only once. + String _sourcePath; + + /// Process where the source script of the module was executed. Owns + /// the namespace of the module. + Process *_process; +}; - protected: - void initialize(Script const &script); - - private: - /// Path of the script source file. Used to identify whether a script has - /// already been loaded or not. Imported scripts are run only once. - String _sourcePath; - - /// Process where the source script of the module was executed. Owns - /// the namespace of the module. - Process *_process; - }; -} +} // namespace de #endif /* LIBDENG2_MODULE_H */ diff --git a/doomsday/libdeng2/include/de/scriptsys/nameexpression.h b/doomsday/libdeng2/include/de/scriptsys/nameexpression.h index 7396acb45f..86d9545d05 100644 --- a/doomsday/libdeng2/include/de/scriptsys/nameexpression.h +++ b/doomsday/libdeng2/include/de/scriptsys/nameexpression.h @@ -25,43 +25,44 @@ #include -namespace de +namespace de { + +/** + * Responsible for referencing, creating, and deleting variables and record + * references based an textual identifier. + * + * @ingroup script + */ +class NameExpression : public Expression { - /** - * Responsible for referencing, creating, and deleting variables and record - * references based an textual identifier. - * - * @ingroup script - */ - class NameExpression : public Expression - { - public: - /// Identifier is not text. @ingroup errors - DENG2_ERROR(IdentifierError); +public: + /// Identifier is not text. @ingroup errors + DENG2_ERROR(IdentifierError); + + /// Variable already exists when it was required not to. @ingroup errors + DENG2_ERROR(AlreadyExistsError); + + /// The identifier does not specify an existing variable. @ingroup errors + DENG2_ERROR(NotFoundError); - /// Variable already exists when it was required not to. @ingroup errors - DENG2_ERROR(AlreadyExistsError); +public: + NameExpression(); + NameExpression(String const &identifier, Flags const &flags = ByValue); + ~NameExpression(); - /// The identifier does not specify an existing variable. @ingroup errors - DENG2_ERROR(NotFoundError); + /// Returns the identifier in the name expression. + String const &identifier() const { return _identifier; } - public: - NameExpression(); - NameExpression(String const &identifier, Flags const &flags = ByValue); - ~NameExpression(); + Value *evaluate(Evaluator &evaluator) const; - /// Returns the identifier in the name expression. - String const &identifier() const { return _identifier; } + // Implements ISerializable. + void operator >> (Writer &to) const; + void operator << (Reader &from); - Value *evaluate(Evaluator &evaluator) const; +private: + String _identifier; +}; - // Implements ISerializable. - void operator >> (Writer &to) const; - void operator << (Reader &from); - - private: - String _identifier; - }; -} +} // namespace de #endif /* LIBDENG2_NAMEEXPRESSION_H */ diff --git a/doomsday/libdeng2/include/de/scriptsys/operator.h b/doomsday/libdeng2/include/de/scriptsys/operator.h index 03b66c9e4c..520235ab61 100644 --- a/doomsday/libdeng2/include/de/scriptsys/operator.h +++ b/doomsday/libdeng2/include/de/scriptsys/operator.h @@ -20,52 +20,53 @@ #ifndef LIBDENG2_OPERATOR_H #define LIBDENG2_OPERATOR_H -namespace de -{ - class String; - - /** - * Operators. - * - * @note These are serialized as is, so don't change the existing values. - * - * @ingroup script - */ - enum Operator { - NONE = 0, - NOT, - IN, - EQUAL, - NOT_EQUAL, - LESS, - GREATER, - LEQUAL, - GEQUAL, - PLUS, - MINUS, - MULTIPLY, - DIVIDE, - MODULO, - PLUS_ASSIGN, - MINUS_ASSIGN, - MULTIPLY_ASSIGN, - DIVIDE_ASSIGN, - MODULO_ASSIGN, - DOT, - MEMBER, - CALL, - ARRAY, - DICTIONARY, - INDEX, - SLICE, - PARENTHESIS, - AND, - OR - }; - - String operatorToText(Operator op); - - bool leftOperandByReference(Operator op); -} +namespace de { + +class String; + +/** + * Operators. + * + * @note These are serialized as is, so don't change the existing values. + * + * @ingroup script + */ +enum Operator { + NONE = 0, + NOT, + IN, + EQUAL, + NOT_EQUAL, + LESS, + GREATER, + LEQUAL, + GEQUAL, + PLUS, + MINUS, + MULTIPLY, + DIVIDE, + MODULO, + PLUS_ASSIGN, + MINUS_ASSIGN, + MULTIPLY_ASSIGN, + DIVIDE_ASSIGN, + MODULO_ASSIGN, + DOT, + MEMBER, + CALL, + ARRAY, + DICTIONARY, + INDEX, + SLICE, + PARENTHESIS, + AND, + OR +}; + +String operatorToText(Operator op); + +bool leftOperandByReference(Operator op); + +} // namespace de #endif /* LIBDENG2_OPERATOR_H */ diff --git a/doomsday/libdeng2/include/de/scriptsys/operatorexpression.h b/doomsday/libdeng2/include/de/scriptsys/operatorexpression.h index 920976f719..17aba7aeb8 100644 --- a/doomsday/libdeng2/include/de/scriptsys/operatorexpression.h +++ b/doomsday/libdeng2/include/de/scriptsys/operatorexpression.h @@ -24,86 +24,87 @@ #include "../Operator" #include "../Expression" -namespace de +namespace de { + +class Evaluator; +class Value; + +/** + * Evaluates the results of unary and binary operators. + * This includes, for example, arithmetic operators, text concatenation, + * and logical expressions. + * + * @ingroup script + */ +class OperatorExpression : public Expression { - class Evaluator; - class Value; +public: + /// A unary operation is attempted even though the selected operation cannot + /// be unary. @ingroup errors + DENG2_ERROR(NonUnaryError); + + /// A binary operation is attempted even though the selected operation cannot be binary. + /// @ingroup errors + DENG2_ERROR(NonBinaryError); + + /// Attempt to assign to a value that cannot be assigned to. @ingroup errors + DENG2_ERROR(NotAssignableError); + + /// The MEMBER operator receives a non-Record scope on the left side. @ingroup errors + DENG2_ERROR(ScopeError); + + /// The SLICE operator has invalid arguments. @ingroup errors + DENG2_ERROR(SliceError); + +public: + OperatorExpression(); + + /** + * Constructor for unary operations (+, -). + * @param op Operation to perform. + * @param operand Expression that provides the right-hand operand. + */ + OperatorExpression(Operator op, Expression *operand); /** - * Evaluates the results of unary and binary operators. - * This includes, for example, arithmetic operators, text concatenation, - * and logical expressions. + * Constructor for binary operations. + * @param op Operation to perform. + * @param leftOperand Expression that provides the left-hand operand. + * @param rightOperand Expression that provides the right-hand operand. + */ + OperatorExpression(Operator op, Expression *leftOperand, Expression *rightOperand); + + ~OperatorExpression(); + + void push(Evaluator &evaluator, Record *names = 0) const; + + Value *evaluate(Evaluator &evaluator) const; + + /** + * Verifies that @a value can be used as the l-value of an operator that + * does assignment. * - * @ingroup script - */ - class OperatorExpression : public Expression - { - public: - /// A unary operation is attempted even though the selected operation cannot - /// be unary. @ingroup errors - DENG2_ERROR(NonUnaryError); - - /// A binary operation is attempted even though the selected operation cannot be binary. - /// @ingroup errors - DENG2_ERROR(NonBinaryError); - - /// Attempt to assign to a value that cannot be assigned to. @ingroup errors - DENG2_ERROR(NotAssignableError); - - /// The MEMBER operator receives a non-Record scope on the left side. @ingroup errors - DENG2_ERROR(ScopeError); - - /// The SLICE operator has invalid arguments. @ingroup errors - DENG2_ERROR(SliceError); - - public: - OperatorExpression(); - - /** - * Constructor for unary operations (+, -). - * @param op Operation to perform. - * @param operand Expression that provides the right-hand operand. - */ - OperatorExpression(Operator op, Expression *operand); - - /** - * Constructor for binary operations. - * @param op Operation to perform. - * @param leftOperand Expression that provides the left-hand operand. - * @param rightOperand Expression that provides the right-hand operand. - */ - OperatorExpression(Operator op, Expression *leftOperand, Expression *rightOperand); - - ~OperatorExpression(); - - void push(Evaluator &evaluator, Record *names = 0) const; - - Value *evaluate(Evaluator &evaluator) const; - - /** - * Verifies that @a value can be used as the l-value of an operator that - * does assignment. - * - * @param value Value to check. - */ - static void verifyAssignable(Value *value); - - // Implements ISerializable. - void operator >> (Writer &to) const; - void operator << (Reader &from); - - private: - /// Performs the slice operation (Python semantics). - Value *performSlice(Value *leftValue, Value *rightValue) const; - - /// Used to create return values of boolean operations. - static Value *newBooleanValue(bool isTrue); - - private: - Operator _op; - Expression *_leftOperand; - Expression *_rightOperand; - }; -} + * @param value Value to check. + */ + static void verifyAssignable(Value *value); + + // Implements ISerializable. + void operator >> (Writer &to) const; + void operator << (Reader &from); + +private: + /// Performs the slice operation (Python semantics). + Value *performSlice(Value *leftValue, Value *rightValue) const; + + /// Used to create return values of boolean operations. + static Value *newBooleanValue(bool isTrue); + +private: + Operator _op; + Expression *_leftOperand; + Expression *_rightOperand; +}; + +} // namespace de #endif /* LIBDENG2_OPERATOREXPRESSION_H */ diff --git a/doomsday/libdeng2/include/de/scriptsys/parser.h b/doomsday/libdeng2/include/de/scriptsys/parser.h index 9c37ab4f01..1b99bfbbe2 100644 --- a/doomsday/libdeng2/include/de/scriptsys/parser.h +++ b/doomsday/libdeng2/include/de/scriptsys/parser.h @@ -30,134 +30,135 @@ #include -namespace de +namespace de { + +class Compound; +class ExpressionStatement; +class PrintStatement; +class IfStatement; +class WhileStatement; +class ForStatement; +class AssignStatement; +class DeleteStatement; +class FunctionStatement; +class ArrayExpression; +class DictionaryExpression; +class OperatorExpression; +class NameExpression; + +/** + * Reads Doomsday script source in text format and outputs the statements + * of the script into a Script object. + * + * @ingroup script + */ +class Parser : public IParser { - class Compound; - class ExpressionStatement; - class PrintStatement; - class IfStatement; - class WhileStatement; - class ForStatement; - class AssignStatement; - class DeleteStatement; - class FunctionStatement; - class ArrayExpression; - class DictionaryExpression; - class OperatorExpression; - class NameExpression; - - /** - * Reads Doomsday script source in text format and outputs the statements - * of the script into a Script object. - * - * @ingroup script - */ - class Parser : public IParser +public: + /// A syntax error is detected during the parsing. Note that the Lex classes + /// also define syntax errors. @ingroup errors + DENG2_ERROR(SyntaxError); + + /// A token is encountered where we don't know what to do with it. @ingroup errors + DENG2_SUB_ERROR(SyntaxError, UnexpectedTokenError); + + /// A token is expected, but nothing was found. @ingroup errors + DENG2_SUB_ERROR(SyntaxError, MissingTokenError); + + /// A colon is expected but not found. @ingroup errors + DENG2_SUB_ERROR(SyntaxError, MissingColonError); + + // Flags for parsing conditional compounds. + enum CompoundFlag { - public: - /// A syntax error is detected during the parsing. Note that the Lex classes - /// also define syntax errors. @ingroup errors - DENG2_ERROR(SyntaxError); - - /// A token is encountered where we don't know what to do with it. @ingroup errors - DENG2_SUB_ERROR(SyntaxError, UnexpectedTokenError); - - /// A token is expected, but nothing was found. @ingroup errors - DENG2_SUB_ERROR(SyntaxError, MissingTokenError); - - /// A colon is expected but not found. @ingroup errors - DENG2_SUB_ERROR(SyntaxError, MissingColonError); - - // Flags for parsing conditional compounds. - enum CompoundFlag - { - HasCondition = 0x1, - StayAtClosingStatement = 0x2, - IgnoreExtraBeforeColon = 0x4 - }; - Q_DECLARE_FLAGS(CompoundFlags, CompoundFlag) - - public: - Parser(); - ~Parser(); - - // Implements IParser. - void parse(String const &input, Script &output); - - void parseCompound(Compound &compound); - - void parseStatement(Compound &compound); - - Expression *parseConditionalCompound(Compound &compound, CompoundFlags const &flags = 0); - - IfStatement *parseIfStatement(); - - WhileStatement *parseWhileStatement(); - - ForStatement *parseForStatement(); - - ExpressionStatement *parseImportStatement(); - - ExpressionStatement *parseExportStatement(); - - ExpressionStatement *parseDeclarationStatement(); - - DeleteStatement *parseDeleteStatement(); - - FunctionStatement *parseFunctionStatement(); - - void parseTryCatchSequence(Compound &compound); - - PrintStatement *parsePrintStatement(); - - AssignStatement *parseAssignStatement(); - - ExpressionStatement *parseExpressionStatement(); - - /// Parse a range of tokens as a comma-separated argument list: - ArrayExpression *parseList(TokenRange const &range, - QChar const *separator = Token::COMMA, - Expression::Flags const &flags = Expression::ByValue); - - /// Parse a range of tokens as an operator-based expression. - Expression *parseExpression(TokenRange const &range, - Expression::Flags const &flags = Expression::ByValue); - - ArrayExpression *parseArrayExpression(TokenRange const &range); - - DictionaryExpression *parseDictionaryExpression(TokenRange const &range); - - Expression *parseCallExpression(TokenRange const &nameRange, - TokenRange const &argumentRange); - - OperatorExpression *parseOperatorExpression(Operator op, - TokenRange const &leftSide, TokenRange const &rightSide, - Expression::Flags const &rightFlags = Expression::ByValue); - - Expression *parseTokenExpression(TokenRange const &range, - Expression::Flags const &flags = Expression::ByValue); - - Operator findLowestOperator(TokenRange const &range, - TokenRange &leftSide, TokenRange &rightSide); - - protected: - /// Gets the set of tokens for the next statement. - /// @return Number of tokens found. - duint nextStatement(); - - private: - ScriptLex _analyzer; - - TokenBuffer _tokens; - - // Range of the current statement. Can be a subrange of the full - // set of tokens. - TokenRange _statementRange; - - duint _currentIndent; - }; - - Q_DECLARE_OPERATORS_FOR_FLAGS(de::Parser::CompoundFlags) -} + HasCondition = 0x1, + StayAtClosingStatement = 0x2, + IgnoreExtraBeforeColon = 0x4 + }; + Q_DECLARE_FLAGS(CompoundFlags, CompoundFlag) + +public: + Parser(); + ~Parser(); + + // Implements IParser. + void parse(String const &input, Script &output); + + void parseCompound(Compound &compound); + + void parseStatement(Compound &compound); + + Expression *parseConditionalCompound(Compound &compound, CompoundFlags const &flags = 0); + + IfStatement *parseIfStatement(); + + WhileStatement *parseWhileStatement(); + + ForStatement *parseForStatement(); + + ExpressionStatement *parseImportStatement(); + + ExpressionStatement *parseExportStatement(); + + ExpressionStatement *parseDeclarationStatement(); + + DeleteStatement *parseDeleteStatement(); + + FunctionStatement *parseFunctionStatement(); + + void parseTryCatchSequence(Compound &compound); + + PrintStatement *parsePrintStatement(); + + AssignStatement *parseAssignStatement(); + + ExpressionStatement *parseExpressionStatement(); + + /// Parse a range of tokens as a comma-separated argument list: + ArrayExpression *parseList(TokenRange const &range, + QChar const *separator = Token::COMMA, + Expression::Flags const &flags = Expression::ByValue); + + /// Parse a range of tokens as an operator-based expression. + Expression *parseExpression(TokenRange const &range, + Expression::Flags const &flags = Expression::ByValue); + + ArrayExpression *parseArrayExpression(TokenRange const &range); + + DictionaryExpression *parseDictionaryExpression(TokenRange const &range); + + Expression *parseCallExpression(TokenRange const &nameRange, + TokenRange const &argumentRange); + + OperatorExpression *parseOperatorExpression(Operator op, + TokenRange const &leftSide, TokenRange const &rightSide, + Expression::Flags const &rightFlags = Expression::ByValue); + + Expression *parseTokenExpression(TokenRange const &range, + Expression::Flags const &flags = Expression::ByValue); + + Operator findLowestOperator(TokenRange const &range, + TokenRange &leftSide, TokenRange &rightSide); + +protected: + /// Gets the set of tokens for the next statement. + /// @return Number of tokens found. + duint nextStatement(); + +private: + ScriptLex _analyzer; + + TokenBuffer _tokens; + + // Range of the current statement. Can be a subrange of the full + // set of tokens. + TokenRange _statementRange; + + duint _currentIndent; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(de::Parser::CompoundFlags) + +} // namespace de #endif /* LIBDENG2_PARSER_H */ diff --git a/doomsday/libdeng2/include/de/scriptsys/printstatement.h b/doomsday/libdeng2/include/de/scriptsys/printstatement.h index 23c85f19be..4ea3cbcf32 100644 --- a/doomsday/libdeng2/include/de/scriptsys/printstatement.h +++ b/doomsday/libdeng2/include/de/scriptsys/printstatement.h @@ -22,37 +22,38 @@ #include "../Statement" -namespace de -{ - class ArrayExpression; +namespace de { + +class ArrayExpression; +/** + * Prints arguments to standard output. + * + * @ingroup script + */ +class PrintStatement : public Statement +{ +public: /** - * Prints arguments to standard output. + * Constructor. * - * @ingroup script + * @param arguments Array expression that contains all the arguments + * of the print statement. Ownership transferred to the statement. */ - class PrintStatement : public Statement - { - public: - /** - * Constructor. - * - * @param arguments Array expression that contains all the arguments - * of the print statement. Ownership transferred to the statement. - */ - PrintStatement(ArrayExpression *arguments = 0); - - ~PrintStatement(); - - void execute(Context &context) const; - - // Implements ISerializable. - void operator >> (Writer &to) const; - void operator << (Reader &from); - - private: - ArrayExpression *_arg; - }; -} + PrintStatement(ArrayExpression *arguments = 0); + + ~PrintStatement(); + + void execute(Context &context) const; + + // Implements ISerializable. + void operator >> (Writer &to) const; + void operator << (Reader &from); + +private: + ArrayExpression *_arg; +}; + +} // namespace de #endif /* LIBDENG2_PRINTSTATEMENT_H */ diff --git a/doomsday/libdeng2/include/de/scriptsys/process.h b/doomsday/libdeng2/include/de/scriptsys/process.h index 15d225d6cb..5a0d5e1045 100644 --- a/doomsday/libdeng2/include/de/scriptsys/process.h +++ b/doomsday/libdeng2/include/de/scriptsys/process.h @@ -29,187 +29,188 @@ #include -namespace de +namespace de { + +class ArrayValue; + +/** + * Executes a script. The process maintains the execution environment, including things + * like local variables and keeping track of which statement is being executed. + * + * @ingroup script + */ +class DENG2_PUBLIC Process { - class ArrayValue; - +public: + /// The process is running while an operation is attempted that requires the + /// process to be stopped. @ingroup errors + DENG2_ERROR(NotStoppedError); + + /// Suspending or resuming fails. @ingroup errors + DENG2_ERROR(SuspendError); + + /// Execution is taking too long to complete. @ingroup errors + DENG2_ERROR(HangError); + + /// A process is always in one of these states. + enum State { + RUNNING, /**< The process is running normally. */ + SUSPENDED, /**< The process has been suspended and will + * not continue running until restored. A + * process cannot restore itself from a + * suspended state. */ + STOPPED /**< The process has reached the end of the + * script or has been terminated. */ + }; + + typedef std::list Namespaces; + +public: /** - * Executes a script. The process maintains the execution environment, including things - * like local variables and keeping track of which statement is being executed. - * - * @ingroup script + * Constructs a new process. The process is initialized to STOPPED state. + * + * @param externalGlobalNamespace Namespace to use as the global namespace + * of the process. If not specified, a private + * global namespace is created for the process. + * The process does not get ownership of the + * external global namespace. */ - class DENG2_PUBLIC Process - { - public: - /// The process is running while an operation is attempted that requires the - /// process to be stopped. @ingroup errors - DENG2_ERROR(NotStoppedError); - - /// Suspending or resuming fails. @ingroup errors - DENG2_ERROR(SuspendError); - - /// Execution is taking too long to complete. @ingroup errors - DENG2_ERROR(HangError); - - /// A process is always in one of these states. - enum State { - RUNNING, /**< The process is running normally. */ - SUSPENDED, /**< The process has been suspended and will - * not continue running until restored. A - * process cannot restore itself from a - * suspended state. */ - STOPPED /**< The process has reached the end of the - * script or has been terminated. */ - }; - - typedef std::list Namespaces; - - public: - /** - * Constructs a new process. The process is initialized to STOPPED state. - * - * @param externalGlobalNamespace Namespace to use as the global namespace - * of the process. If not specified, a private - * global namespace is created for the process. - * The process does not get ownership of the - * external global namespace. - */ - Process(Record *externalGlobalNamespace = 0); - - /** - * Constructs a new process. The process is initialized to RUNNING state. - * - * @param script Script to run. No reference to the script is retained - * apart from pointing to its statements. The script instance - * must remain in existence while the process is running, - * as it is the owner of the statements. - */ - Process(Script const &script); - - virtual ~Process(); - - State state() const { return _state; } - - /// Determines the current depth of the call stack. - duint depth() const; - - /** - * Starts running the given script. Note that the process must be - * in the FINISHED state for this to be a valid operation. - * - * @param script Script to run. No reference to the script is retained - * apart from pointing to its statements. The script instance - * must remain in existence while the process is running, - * as it is the owner of the statements. - */ - void run(Script const &script); - - /** - * Suspends or resumes execution of the script. - */ - void suspend(bool suspended = true); - - /** - * Stops the execution of the script. The process is set to the - * FINISHED state, which means it must be rerun with a new script. - */ - void stop(); - - /** - * Execute the next command(s) in the script. Execution continues until - * the script leaves RUNNING state. - */ - void execute(); - - /** - * Finish the execution of the topmost context. Execution will - * continue from the second topmost context. - * - * @param returnValue Value to use as the return value from the - * context. Takes ownership of the value. - */ - void finish(Value *returnValue = 0); - - /** - * Changes the working path of the process. File system access within the - * process is relative to the working path. - * - * @param newWorkingPath New working path for the process. - */ - void setWorkingPath(String const &newWorkingPath); - - /** - * Returns the current working path. - */ - String const &workingPath() const; - - /** - * Return an execution context. By default returns the topmost context. - * - * @param downDepth How many levels to go down. There are depth() levels - * in the context stack. - * - * @return Context at @a downDepth. - */ - Context &context(duint downDepth = 0); - - /** - * Performs a function call. A new context is created on the context - * stack and the function's statements are executed on the new stack. - * After the call is finished, the result value is pushed to the - * calling context's evaluator. - * - * @param function Function to call. - * @param arguments Arguments for the function. The array's first element - * must be a DictionaryValue containing values for the - * named arguments of the call. The rest of the array - * are the unnamed arguments. - */ - void call(Function const &function, ArrayValue const &arguments); - - /** - * Collects the namespaces currently visible. This includes the process's - * own stack and the global namespaces. - * - * @param spaces The namespaces are collected here. The order is important: - * earlier namespaces shadow the subsequent ones. - */ - void namespaces(Namespaces &spaces); - - /** - * Returns the global namespace of the process. This is always the - * bottommost context in the stack. - */ - Record &globals(); - - protected: - /// Pops contexts off the stack until depth @a downToLevel is reached. - void clearStack(duint downToLevel = 0); - - /// Pops the topmost context off the stack and returns it. Ownership given - /// to caller. - Context *popContext(); - - /// Fast forward to a suitable catch statement for @a err. - /// @return @c true, if suitable catch statement found. - bool jumpIntoCatch(Error const &err); - - private: - State _state; - - // The execution environment. - typedef std::vector ContextStack; - ContextStack _stack; - - /// This is the current working folder of the process. Relative paths - /// given to workingFile() are located in relation to this - /// folder. Initial value is the root folder. - String _workingPath; - - /// Time when execution was started at depth 1. - Time _startedAt; - }; -} + Process(Record *externalGlobalNamespace = 0); + + /** + * Constructs a new process. The process is initialized to RUNNING state. + * + * @param script Script to run. No reference to the script is retained + * apart from pointing to its statements. The script instance + * must remain in existence while the process is running, + * as it is the owner of the statements. + */ + Process(Script const &script); + + virtual ~Process(); + + State state() const { return _state; } + + /// Determines the current depth of the call stack. + duint depth() const; + + /** + * Starts running the given script. Note that the process must be + * in the FINISHED state for this to be a valid operation. + * + * @param script Script to run. No reference to the script is retained + * apart from pointing to its statements. The script instance + * must remain in existence while the process is running, + * as it is the owner of the statements. + */ + void run(Script const &script); + + /** + * Suspends or resumes execution of the script. + */ + void suspend(bool suspended = true); + + /** + * Stops the execution of the script. The process is set to the + * FINISHED state, which means it must be rerun with a new script. + */ + void stop(); + + /** + * Execute the next command(s) in the script. Execution continues until + * the script leaves RUNNING state. + */ + void execute(); + + /** + * Finish the execution of the topmost context. Execution will + * continue from the second topmost context. + * + * @param returnValue Value to use as the return value from the + * context. Takes ownership of the value. + */ + void finish(Value *returnValue = 0); + + /** + * Changes the working path of the process. File system access within the + * process is relative to the working path. + * + * @param newWorkingPath New working path for the process. + */ + void setWorkingPath(String const &newWorkingPath); + + /** + * Returns the current working path. + */ + String const &workingPath() const; + + /** + * Return an execution context. By default returns the topmost context. + * + * @param downDepth How many levels to go down. There are depth() levels + * in the context stack. + * + * @return Context at @a downDepth. + */ + Context &context(duint downDepth = 0); + + /** + * Performs a function call. A new context is created on the context + * stack and the function's statements are executed on the new stack. + * After the call is finished, the result value is pushed to the + * calling context's evaluator. + * + * @param function Function to call. + * @param arguments Arguments for the function. The array's first element + * must be a DictionaryValue containing values for the + * named arguments of the call. The rest of the array + * are the unnamed arguments. + */ + void call(Function const &function, ArrayValue const &arguments); + + /** + * Collects the namespaces currently visible. This includes the process's + * own stack and the global namespaces. + * + * @param spaces The namespaces are collected here. The order is important: + * earlier namespaces shadow the subsequent ones. + */ + void namespaces(Namespaces &spaces); + + /** + * Returns the global namespace of the process. This is always the + * bottommost context in the stack. + */ + Record &globals(); + +protected: + /// Pops contexts off the stack until depth @a downToLevel is reached. + void clearStack(duint downToLevel = 0); + + /// Pops the topmost context off the stack and returns it. Ownership given + /// to caller. + Context *popContext(); + + /// Fast forward to a suitable catch statement for @a err. + /// @return @c true, if suitable catch statement found. + bool jumpIntoCatch(Error const &err); + +private: + State _state; + + // The execution environment. + typedef std::vector ContextStack; + ContextStack _stack; + + /// This is the current working folder of the process. Relative paths + /// given to workingFile() are located in relation to this + /// folder. Initial value is the root folder. + String _workingPath; + + /// Time when execution was started at depth 1. + Time _startedAt; +}; + +} // namespace de #endif /* LIBDENG2_PROCESS_H */ diff --git a/doomsday/libdeng2/include/de/scriptsys/script.h b/doomsday/libdeng2/include/de/scriptsys/script.h index 670dc465c5..f3686c9db9 100644 --- a/doomsday/libdeng2/include/de/scriptsys/script.h +++ b/doomsday/libdeng2/include/de/scriptsys/script.h @@ -31,61 +31,62 @@ #include -namespace de +namespace de { + +class File; + +/** + * Contains statements and expressions which are ready to be executed. + * A Script instance is built from source code text, which is parsed and + * converted to statements and expressions. + * + * @see Process (used to execute scripts) + * + * @ingroup script + */ +class DENG2_PUBLIC Script { - class File; - +public: + /// Constructs an empty script with no statements. + Script(); + /** - * Contains statements and expressions which are ready to be executed. - * A Script instance is built from source code text, which is parsed and - * converted to statements and expressions. + * Parses the source into statements. * - * @see Process (used to execute scripts) + * @param source Script source. + */ + Script(String const &source); + + /** + * Parses the source file info statements. The path of the source file + * is saved and used when importing modules. * - * @ingroup script + * @param file Source file. */ - class DENG2_PUBLIC Script - { - public: - /// Constructs an empty script with no statements. - Script(); - - /** - * Parses the source into statements. - * - * @param source Script source. - */ - Script(String const &source); - - /** - * Parses the source file info statements. The path of the source file - * is saved and used when importing modules. - * - * @param file Source file. - */ - Script(File const &file); - - virtual ~Script(); - - String const &path() const { return _path; } - - /// Returns the statement that begins the script. This is where - /// a process begins the execution of a script. - Statement const *firstStatement() const; - - /// Returns a modifiable reference to the main statement compound - /// of the script. - Compound &compound() { - return _compound; - } - - private: - Compound _compound; - - /// File path where the script was loaded. Will be visible in the namespace - /// of the process executing the script. - String _path; - }; -} + Script(File const &file); + + virtual ~Script(); + + String const &path() const { return _path; } + + /// Returns the statement that begins the script. This is where + /// a process begins the execution of a script. + Statement const *firstStatement() const; + + /// Returns a modifiable reference to the main statement compound + /// of the script. + Compound &compound() { + return _compound; + } + +private: + Compound _compound; + + /// File path where the script was loaded. Will be visible in the namespace + /// of the process executing the script. + String _path; +}; + +} // namespace de #endif diff --git a/doomsday/libdeng2/include/de/scriptsys/scriptlex.h b/doomsday/libdeng2/include/de/scriptsys/scriptlex.h index f615f0c5e2..d8a80facc9 100644 --- a/doomsday/libdeng2/include/de/scriptsys/scriptlex.h +++ b/doomsday/libdeng2/include/de/scriptsys/scriptlex.h @@ -23,107 +23,108 @@ #include "../Lex" #include "../TokenBuffer" -namespace de -{ +namespace de { + +/** + * Lexical analyzer specific to Doomsday scripts. + * + * @ingroup script + */ +class ScriptLex : public Lex +{ +public: + /// Base error for syntax errors at the level of lexical analysis (e.g., + /// a non-terminated string constant). @ingroup errors + DENG2_ERROR(SyntaxError); + + /// A unexpected character is encountered. @ingroup errors + DENG2_SUB_ERROR(SyntaxError, UnexpectedCharacterError); + + /// An unterminated string token is encountered. @ingroup errors + DENG2_SUB_ERROR(SyntaxError, UnterminatedStringError); + + /// The bracket level goes below zero, i.e., when more brackets are closed + /// than opened, or when the input ends before all brackets are closed. @ingroup errors + DENG2_SUB_ERROR(SyntaxError, MismatchedBracketError); + + // Keywords. + static String const AND; + static String const OR; + static String const NOT; + static String const ELSIF; + static String const ELSE; + static String const THROW; + static String const CATCH; + static String const IN; + static String const END; + static String const IF; + static String const WHILE; + static String const FOR; + static String const DEF; + static String const TRY; + static String const IMPORT; + static String const EXPORT; + static String const RECORD; + static String const DEL; + static String const PASS; + static String const CONTINUE; + static String const BREAK; + static String const RETURN; + static String const PRINT; + static String const CONST; + static String const T_TRUE; + static String const T_FALSE; + static String const NONE; + static String const PI; + + // Operators. + static String const ASSIGN; + static String const SCOPE_ASSIGN; + static String const WEAK_ASSIGN; + +public: + ScriptLex(String const &input = ""); + + /** + * Analyze one complete statement from the input. + * + * @param output Buffer for output tokens. + * + * @return The number of tokens added to the output token buffer. + */ + duint getStatement(TokenBuffer &output); + /** - * Lexical analyzer specific to Doomsday scripts. + * Parse a string. + * + * @param startChar Character that begun the string. This is already + * in the token. + * @param startIndentation Indentation level for the line that starts the token. + * @param output Output token buffer. * - * @ingroup script + * @return Type of the parsed string. */ - class ScriptLex : public Lex - { - public: - /// Base error for syntax errors at the level of lexical analysis (e.g., - /// a non-terminated string constant). @ingroup errors - DENG2_ERROR(SyntaxError); - - /// A unexpected character is encountered. @ingroup errors - DENG2_SUB_ERROR(SyntaxError, UnexpectedCharacterError); - - /// An unterminated string token is encountered. @ingroup errors - DENG2_SUB_ERROR(SyntaxError, UnterminatedStringError); - - /// The bracket level goes below zero, i.e., when more brackets are closed - /// than opened, or when the input ends before all brackets are closed. @ingroup errors - DENG2_SUB_ERROR(SyntaxError, MismatchedBracketError); - - // Keywords. - static String const AND; - static String const OR; - static String const NOT; - static String const ELSIF; - static String const ELSE; - static String const THROW; - static String const CATCH; - static String const IN; - static String const END; - static String const IF; - static String const WHILE; - static String const FOR; - static String const DEF; - static String const TRY; - static String const IMPORT; - static String const EXPORT; - static String const RECORD; - static String const DEL; - static String const PASS; - static String const CONTINUE; - static String const BREAK; - static String const RETURN; - static String const PRINT; - static String const CONST; - static String const T_TRUE; - static String const T_FALSE; - static String const NONE; - static String const PI; - - // Operators. - static String const ASSIGN; - static String const SCOPE_ASSIGN; - static String const WEAK_ASSIGN; - - public: - ScriptLex(String const &input = ""); - - /** - * Analyze one complete statement from the input. - * - * @param output Buffer for output tokens. - * - * @return The number of tokens added to the output token buffer. - */ - duint getStatement(TokenBuffer &output); - - /** - * Parse a string. - * - * @param startChar Character that begun the string. This is already - * in the token. - * @param startIndentation Indentation level for the line that starts the token. - * @param output Output token buffer. - * - * @return Type of the parsed string. - */ - Token::Type parseString(QChar startChar, duint startIndentation, - TokenBuffer &output); - - public: - /// Determines whether a character is an operator character. - static bool isOperator(QChar c); - - /// Determines whether a token is a Haw script keyword. - static bool isKeyword(Token const &token); - - /// Determines whether one character should join another to - /// form a longer token. - static bool combinesWith(QChar a, QChar b); - - /// Unescapes a string token into a std::string. - static String unescapeStringToken(Token const &token); - - /// Converts a token to a number. - static ddouble tokenToNumber(Token const &token); - }; -} + Token::Type parseString(QChar startChar, duint startIndentation, + TokenBuffer &output); + +public: + /// Determines whether a character is an operator character. + static bool isOperator(QChar c); + + /// Determines whether a token is a Haw script keyword. + static bool isKeyword(Token const &token); + + /// Determines whether one character should join another to + /// form a longer token. + static bool combinesWith(QChar a, QChar b); + + /// Unescapes a string token into a std::string. + static String unescapeStringToken(Token const &token); + + /// Converts a token to a number. + static ddouble tokenToNumber(Token const &token); +}; + +} // namespace de #endif /* LIBDENG2_SCRIPTLEX_H */ diff --git a/doomsday/libdeng2/include/de/scriptsys/statement.h b/doomsday/libdeng2/include/de/scriptsys/statement.h index 381b916693..cf8395d77a 100644 --- a/doomsday/libdeng2/include/de/scriptsys/statement.h +++ b/doomsday/libdeng2/include/de/scriptsys/statement.h @@ -22,64 +22,65 @@ #include "../ISerializable" -namespace de +namespace de { + +class Context; + +/** + * The abstract base class for all statements. + * + * @ingroup script + */ +class Statement : public ISerializable { - class Context; - +public: + /// Deserialization of a statement failed. @ingroup errors + DENG2_ERROR(DeserializationError); + +public: + Statement() : _next(0) {} + + virtual ~Statement() {} + + virtual void execute(Context &context) const = 0; + + Statement *next() const { return _next; } + + void setNext(Statement *statement) { _next = statement; } + +public: /** - * The abstract base class for all statements. + * Constructs a statement by deserializing one from a reader. * - * @ingroup script + * @param from Reader. + * + * @return The deserialized statement. Caller gets ownership. */ - class Statement : public ISerializable - { - public: - /// Deserialization of a statement failed. @ingroup errors - DENG2_ERROR(DeserializationError); - - public: - Statement() : _next(0) {} - - virtual ~Statement() {} - - virtual void execute(Context &context) const = 0; - - Statement *next() const { return _next; } - - void setNext(Statement *statement) { _next = statement; } - - public: - /** - * Constructs a statement by deserializing one from a reader. - * - * @param from Reader. - * - * @return The deserialized statement. Caller gets ownership. - */ - static Statement *constructFrom(Reader &from); - - protected: - typedef dbyte SerialId; - - enum SerialIds { - ASSIGN, - CATCH, - EXPRESSION, - FLOW, - FOR, - FUNCTION, - IF, - PRINT, - TRY, - WHILE, - DELETE - }; - - private: - /// Pointer to the statement that follows this one, or NULL if - /// this is the final statement. - Statement *_next; + static Statement *constructFrom(Reader &from); + +protected: + typedef dbyte SerialId; + + enum SerialIds { + ASSIGN, + CATCH, + EXPRESSION, + FLOW, + FOR, + FUNCTION, + IF, + PRINT, + TRY, + WHILE, + DELETE }; -} + +private: + /// Pointer to the statement that follows this one, or NULL if + /// this is the final statement. + Statement *_next; +}; + +} // namespace de #endif /* LIBDENG2_STATEMENT_H */ diff --git a/doomsday/libdeng2/include/de/scriptsys/tokenbuffer.h b/doomsday/libdeng2/include/de/scriptsys/tokenbuffer.h index 7ed8a7dca6..6d066d00d4 100755 --- a/doomsday/libdeng2/include/de/scriptsys/tokenbuffer.h +++ b/doomsday/libdeng2/include/de/scriptsys/tokenbuffer.h @@ -24,207 +24,208 @@ #include -namespace de +namespace de { + +class String; + +/** + * Character sequence allocated out of the token buffer. + */ +class Token { - class String; - - /** - * Character sequence allocated out of the token buffer. - */ - class Token - { - public: - /// Types for tokens. This much can be analyzed without knowing - /// anything about the context. - enum Type { - UNKNOWN, - KEYWORD, - OPERATOR, - LITERAL_STRING_APOSTROPHE, - LITERAL_STRING_QUOTED, - LITERAL_STRING_LONG, - LITERAL_NUMBER, - IDENTIFIER - }; - - // Token constants. - static String const PARENTHESIS_OPEN; - static String const PARENTHESIS_CLOSE; - static String const BRACKET_OPEN; - static String const BRACKET_CLOSE; - static String const CURLY_OPEN; - static String const CURLY_CLOSE; - static String const COLON; - static String const COMMA; - static String const SEMICOLON; - - public: - Token(QChar *begin = 0, QChar *end = 0, duint line = 0) - : _type(UNKNOWN), _begin(begin), _end(end), _line(line) {} - - void setType(Type type) { _type = type; } - - Type type() const { return _type; } - - /// Returns the address of the beginning of the token. - /// @return Pointer to the first character of the token. - QChar const *begin() const { return _begin; } - - /// Returns the address of the end of the token. - /// @return Pointer to the character just after the last - /// character of the token. - QChar const *end() const { return _end; } - - /// Returns the address of the beginning of the token. - /// @return Pointer to the first character of the token. - QChar *begin() { return _begin; } - - /// Returns the address of the end of the token. - /// @return Pointer to the character just after the last - /// character of the token. This is where a new character is - /// appended when the token is being compiled. - QChar *end() { return _end; } - - /// Determines the length of the token. - /// @return Length of the token as number of characters. - int size() const { - if(!_begin || !_end) return 0; - return _end - _begin; - } +public: + /// Types for tokens. This much can be analyzed without knowing + /// anything about the context. + enum Type { + UNKNOWN, + KEYWORD, + OPERATOR, + LITERAL_STRING_APOSTROPHE, + LITERAL_STRING_QUOTED, + LITERAL_STRING_LONG, + LITERAL_NUMBER, + IDENTIFIER + }; - bool isEmpty() const { - return !size(); + // Token constants. + static String const PARENTHESIS_OPEN; + static String const PARENTHESIS_CLOSE; + static String const BRACKET_OPEN; + static String const BRACKET_CLOSE; + static String const CURLY_OPEN; + static String const CURLY_CLOSE; + static String const COLON; + static String const COMMA; + static String const SEMICOLON; + +public: + Token(QChar *begin = 0, QChar *end = 0, duint line = 0) + : _type(UNKNOWN), _begin(begin), _end(end), _line(line) {} + + void setType(Type type) { _type = type; } + + Type type() const { return _type; } + + /// Returns the address of the beginning of the token. + /// @return Pointer to the first character of the token. + QChar const *begin() const { return _begin; } + + /// Returns the address of the end of the token. + /// @return Pointer to the character just after the last + /// character of the token. + QChar const *end() const { return _end; } + + /// Returns the address of the beginning of the token. + /// @return Pointer to the first character of the token. + QChar *begin() { return _begin; } + + /// Returns the address of the end of the token. + /// @return Pointer to the character just after the last + /// character of the token. This is where a new character is + /// appended when the token is being compiled. + QChar *end() { return _end; } + + /// Determines the length of the token. + /// @return Length of the token as number of characters. + int size() const { + if(!_begin || !_end) return 0; + return _end - _begin; + } + + bool isEmpty() const { + return !size(); + } + + void appendChar(QChar c) { + *_end++ = c; + } + + /// Determines whether the token equals @c str. Case sensitive. + /// @return @c true if an exact match, otherwise @c false. + bool equals(QChar const *str) const; + + /// Determines whether the token begins with @c str. Case + /// sensitive. @return @c true if an exact match, otherwise @c false. + bool beginsWith(QChar const *str) const; + + /// Determines the line on which the token begins in the source. + duint line() const { return _line; } + + /// Converts the token into a String. This is human-readably output, + /// with the line number included. + String asText() const; + + /// Converts a substring of the token into a String. + /// This includes nothing extra but the text of the token. + String str() const; + + static char const *typeToText(Type type) { + switch(type) + { + case UNKNOWN: + return "UNKNOWN"; + case KEYWORD: + return "KEYWORD"; + case OPERATOR: + return "OPERATOR"; + case LITERAL_STRING_APOSTROPHE: + return "LITERAL_STRING_APOSTROPHE"; + case LITERAL_STRING_QUOTED: + return "LITERAL_STRING_QUOTED"; + case LITERAL_STRING_LONG: + return "LITERAL_STRING_LONG"; + case LITERAL_NUMBER: + return "LITERAL_NUMBER"; + case IDENTIFIER: + return "IDENTIFIER"; } + return ""; + } + +private: + Type _type; ///< Type of the token. + QChar *_begin; ///< Points to the first character. + QChar *_end; ///< Points to the last character + 1. + duint _line; ///< On which line the token begins. +}; + +/** + * Buffer of tokens, used as an efficient way to compile and store tokens. + * Does its own memory management: tokens are allocated out of large blocks + * of memory. + * + * @ingroup script + */ +class TokenBuffer +{ +public: + /// Attempt to append characters while no token is being formed. @ingroup errors + DENG2_ERROR(TokenNotStartedError); - void appendChar(QChar c) { - *_end++ = c; - } + /// Parameter was out of range. @ingroup errors + DENG2_ERROR(OutOfRangeError); - /// Determines whether the token equals @c str. Case sensitive. - /// @return @c true if an exact match, otherwise @c false. - bool equals(QChar const *str) const; - - /// Determines whether the token begins with @c str. Case - /// sensitive. @return @c true if an exact match, otherwise @c false. - bool beginsWith(QChar const *str) const; - - /// Determines the line on which the token begins in the source. - duint line() const { return _line; } - - /// Converts the token into a String. This is human-readably output, - /// with the line number included. - String asText() const; - - /// Converts a substring of the token into a String. - /// This includes nothing extra but the text of the token. - String str() const; - - static char const *typeToText(Type type) { - switch(type) - { - case UNKNOWN: - return "UNKNOWN"; - case KEYWORD: - return "KEYWORD"; - case OPERATOR: - return "OPERATOR"; - case LITERAL_STRING_APOSTROPHE: - return "LITERAL_STRING_APOSTROPHE"; - case LITERAL_STRING_QUOTED: - return "LITERAL_STRING_QUOTED"; - case LITERAL_STRING_LONG: - return "LITERAL_STRING_LONG"; - case LITERAL_NUMBER: - return "LITERAL_NUMBER"; - case IDENTIFIER: - return "IDENTIFIER"; - } - return ""; - } +public: + TokenBuffer(); + virtual ~TokenBuffer(); - private: - Type _type; ///< Type of the token. - QChar *_begin; ///< Points to the first character. - QChar *_end; ///< Points to the last character + 1. - duint _line; ///< On which line the token begins. - }; + /// Deletes all Tokens, but does not free the token pools. + void clear(); + + /// Begins forming a new Token. + /// @param line Input source line number for the token. + void newToken(duint line); + + /// Appends a character to the Token being formed. + /// @param c Character to append. + void appendChar(QChar c); - /** - * Buffer of tokens, used as an efficient way to compile and store tokens. - * Does its own memory management: tokens are allocated out of large blocks - * of memory. - * - * @ingroup script + /// Sets the type of the token being formed. + void setType(Token::Type type); + + /// Finishes the current Token. + void endToken(); + + /// Returns the number of tokens in the buffer. + duint size() const; + + bool empty() const { return !size(); } + + /// Returns a specific token in the buffer. + Token const &at(duint i) const; + + Token const &latest() const; + +private: + /** + * Tokens are allocated out of Pools. If a pool runs out of + * space, a new one is created with more space. Existing pools + * are not resized, because existing Tokens will point to their + * memory. */ - class TokenBuffer - { - public: - /// Attempt to append characters while no token is being formed. @ingroup errors - DENG2_ERROR(TokenNotStartedError); - - /// Parameter was out of range. @ingroup errors - DENG2_ERROR(OutOfRangeError); - - public: - TokenBuffer(); - virtual ~TokenBuffer(); - - /// Deletes all Tokens, but does not free the token pools. - void clear(); - - /// Begins forming a new Token. - /// @param line Input source line number for the token. - void newToken(duint line); - - /// Appends a character to the Token being formed. - /// @param c Character to append. - void appendChar(QChar c); - - /// Sets the type of the token being formed. - void setType(Token::Type type); - - /// Finishes the current Token. - void endToken(); - - /// Returns the number of tokens in the buffer. - duint size() const; - - bool empty() const { return !size(); } - - /// Returns a specific token in the buffer. - Token const &at(duint i) const; - - Token const &latest() const; - - private: - /** - * Tokens are allocated out of Pools. If a pool runs out of - * space, a new one is created with more space. Existing pools - * are not resized, because existing Tokens will point to their - * memory. - */ - struct Pool { - QString chars; - duint size; - duint rover; - - Pool() : size(0), rover(0) {} - }; - - QChar *advanceToPoolWithSpace(duint minimum); - - typedef std::vector Pools; - Pools _pools; - - typedef std::vector Tokens; - Tokens _tokens; - - /// Token being currently formed. - Token *_forming; - - /// Index of pool used for token forming. - duint _formPool; + struct Pool { + QString chars; + duint size; + duint rover; + + Pool() : size(0), rover(0) {} }; -} + + QChar *advanceToPoolWithSpace(duint minimum); + + typedef std::vector Pools; + Pools _pools; + + typedef std::vector Tokens; + Tokens _tokens; + + /// Token being currently formed. + Token *_forming; + + /// Index of pool used for token forming. + duint _formPool; +}; + +} // namespace de #endif /* LIBDENG2_TOKENBUFFER_H */ diff --git a/doomsday/libdeng2/include/de/scriptsys/tokenrange.h b/doomsday/libdeng2/include/de/scriptsys/tokenrange.h index 8b57f376d4..4eb55a7644 100644 --- a/doomsday/libdeng2/include/de/scriptsys/tokenrange.h +++ b/doomsday/libdeng2/include/de/scriptsys/tokenrange.h @@ -23,200 +23,201 @@ #include "../String" #include "../TokenBuffer" -namespace de +namespace de { + +/** + * Utility class for handling a range of tokens inside a token buffer. + * Parsers use this for keeping track of which section of the tokens is + * being analyzed. + * + * "Indices" refer to indices in the token buffer. "Positions" refer to + * locations relative to the beginning of the range, starting from zero. + * + * @ingroup script + */ +class TokenRange { +public: + /// The token range is unexpectedly empty. @ingroup errors + DENG2_ERROR(EmptyRangeError); + + /// A position outside the range is accessed. @ingroup errors + DENG2_ERROR(OutOfBoundsError); + + /// A matching bracket cannot be located within the range. @ingroup errors + DENG2_ERROR(MismatchedBracketError); + +public: + TokenRange(); + + /// Constructor that uses the entire range of tokens. + TokenRange(TokenBuffer const &tokens); + + /// Constructor that uses a specific set of tokens. + TokenRange(TokenBuffer const &tokens, duint startIndex, duint endIndex); + + TokenBuffer const &buffer() const { + return *_tokens; + } + + /// Determines the length of the range. + /// @return Number of tokens in the range. + duint size() const { + return _end - _start; + } + + bool empty() const { return !size(); } + + TokenRange undefinedRange() const; + + bool undefined() const; + + /// Converts a position within the range to an index in the buffer. + duint tokenIndex(duint pos) const; + + duint tokenPos(duint index) const; + + /// Returns a specific token from the token buffer. + /// @param pos Position of the token within the range. + Token const &token(duint pos) const; + + Token const &firstToken() const; + + Token const &lastToken() const; + + /// Determines whether the range begins with a specific token. + bool beginsWith(QChar const *token) const; + + /** + * Composes a subrange that starts from a specific position. + * + * @param pos Start position of subrange. + * + * @return Subrange that starts from position @a pos and continues until + * the end of the range. + */ + TokenRange startingFrom(duint pos) const; + + /** + * Composes a subrange that ends at a specific position. + * + * @param pos End position of subrange. + * + * @return Subrange that starts from the beginning of this range + * and ends to @a pos. + */ + TokenRange endingTo(duint pos) const; + + TokenRange between(duint startPos, duint endPos) const; + + TokenRange shrink(duint count) const { + return between(count, size() - count); + } + /** - * Utility class for handling a range of tokens inside a token buffer. - * Parsers use this for keeping track of which section of the tokens is - * being analyzed. + * Determines if the range contains a specific token. * - * "Indices" refer to indices in the token buffer. "Positions" refer to - * locations relative to the beginning of the range, starting from zero. + * @param token Token to look for. * - * @ingroup script + * @return @c true, if token was found, otherwise @c false. */ - class TokenRange - { - public: - /// The token range is unexpectedly empty. @ingroup errors - DENG2_ERROR(EmptyRangeError); - - /// A position outside the range is accessed. @ingroup errors - DENG2_ERROR(OutOfBoundsError); - - /// A matching bracket cannot be located within the range. @ingroup errors - DENG2_ERROR(MismatchedBracketError); - - public: - TokenRange(); - - /// Constructor that uses the entire range of tokens. - TokenRange(TokenBuffer const &tokens); - - /// Constructor that uses a specific set of tokens. - TokenRange(TokenBuffer const &tokens, duint startIndex, duint endIndex); - - TokenBuffer const &buffer() const { - return *_tokens; - } - - /// Determines the length of the range. - /// @return Number of tokens in the range. - duint size() const { - return _end - _start; - } - - bool empty() const { return !size(); } - - TokenRange undefinedRange() const; - - bool undefined() const; - - /// Converts a position within the range to an index in the buffer. - duint tokenIndex(duint pos) const; - - duint tokenPos(duint index) const; - - /// Returns a specific token from the token buffer. - /// @param pos Position of the token within the range. - Token const &token(duint pos) const; - - Token const &firstToken() const; - - Token const &lastToken() const; - - /// Determines whether the range begins with a specific token. - bool beginsWith(QChar const *token) const; - - /** - * Composes a subrange that starts from a specific position. - * - * @param pos Start position of subrange. - * - * @return Subrange that starts from position @a pos and continues until - * the end of the range. - */ - TokenRange startingFrom(duint pos) const; - - /** - * Composes a subrange that ends at a specific position. - * - * @param pos End position of subrange. - * - * @return Subrange that starts from the beginning of this range - * and ends to @a pos. - */ - TokenRange endingTo(duint pos) const; - - TokenRange between(duint startPos, duint endPos) const; - - TokenRange shrink(duint count) const { - return between(count, size() - count); - } - - /** - * Determines if the range contains a specific token. - * - * @param token Token to look for. - * - * @return @c true, if token was found, otherwise @c false. - */ - bool has(QChar const *token) const { - return find(token) >= 0; - } - - /** - * Determines if the range contains a specific token, but only if - * it is outside any brackets. - * - * @param token Token to look for. - * - * @return @c true, if token was found, otherwise @c false. - */ - bool hasBracketless(QChar const *token) const { - return findIndexSkippingBrackets(token, _start) >= 0; - } - - /** - * Finds the position of a specific token within the range. - * - * @param token Token to find. - * @param startPos Position where to start looking. - * - * @return Position of the token, or -1 if not found. - */ - dint find(QChar const *token, dint startPos = 0) const; - - dint findBracketless(QChar const *token, dint startPos = 0) const; - - /** - * Finds the index of a specific token within the range. When - * an opening bracket is encountered, its contents are skipped. - * - * @param token Token to find. - * @param startIndex Index where to start looking. - * - * @return Index of the token, or -1 if not found. - */ - dint findIndexSkippingBrackets(QChar const *token, dint startIndex) const; - - /** - * Finds the next token subrange which is delimited with @c - * delimiter. @c subrange is adjusted so that if @c true is - * returned, it will contain the correct subrange. When calling - * this the first time, set the subrange to undefinedRange(). - * - * @param delimiter Delimiting token. - * @param subrange Token range that receives the delimiting subrange. - * - * @return @c true, if the next delimited subrange found successfully. - * Otherwise @c false. - */ - bool getNextDelimited(QChar const *delimiter, TokenRange &subrange) const; - - /** - * Locates the matching closing bracket. If the matching bracket - * is not found, an exception is thrown. - * - * @param openBracketPos Position of the opening bracket. - * - * @return Position of the closing bracket. - */ - duint closingBracket(duint openBracketPos) const; - - /** - * Locates the matching opening bracket. If the matching bracket - * is not found, an exception is thrown. - * - * @param closeBracketPos Position of the closing bracket. - * - * @return Position of the opening bracket. - */ - duint openingBracket(duint closeBracketPos) const; - - /** - * Composes a string representation of the token range. Intended - * for error reporting. - * - * @return String containing the text of the tokens. - */ - String asText() const; - - public: - static void bracketTokens(Token const &openingToken, - QChar const * &opening, QChar const * &closing); - - private: - TokenBuffer const *_tokens; - - /// Index of the start of the range. This is the first token in - /// the range. - duint _start; - - /// Index of the end of the range, plus one. This is the token - /// just after the last token of the range. - duint _end; - }; -} + bool has(QChar const *token) const { + return find(token) >= 0; + } + + /** + * Determines if the range contains a specific token, but only if + * it is outside any brackets. + * + * @param token Token to look for. + * + * @return @c true, if token was found, otherwise @c false. + */ + bool hasBracketless(QChar const *token) const { + return findIndexSkippingBrackets(token, _start) >= 0; + } + + /** + * Finds the position of a specific token within the range. + * + * @param token Token to find. + * @param startPos Position where to start looking. + * + * @return Position of the token, or -1 if not found. + */ + dint find(QChar const *token, dint startPos = 0) const; + + dint findBracketless(QChar const *token, dint startPos = 0) const; + + /** + * Finds the index of a specific token within the range. When + * an opening bracket is encountered, its contents are skipped. + * + * @param token Token to find. + * @param startIndex Index where to start looking. + * + * @return Index of the token, or -1 if not found. + */ + dint findIndexSkippingBrackets(QChar const *token, dint startIndex) const; + + /** + * Finds the next token subrange which is delimited with @c + * delimiter. @c subrange is adjusted so that if @c true is + * returned, it will contain the correct subrange. When calling + * this the first time, set the subrange to undefinedRange(). + * + * @param delimiter Delimiting token. + * @param subrange Token range that receives the delimiting subrange. + * + * @return @c true, if the next delimited subrange found successfully. + * Otherwise @c false. + */ + bool getNextDelimited(QChar const *delimiter, TokenRange &subrange) const; + + /** + * Locates the matching closing bracket. If the matching bracket + * is not found, an exception is thrown. + * + * @param openBracketPos Position of the opening bracket. + * + * @return Position of the closing bracket. + */ + duint closingBracket(duint openBracketPos) const; + + /** + * Locates the matching opening bracket. If the matching bracket + * is not found, an exception is thrown. + * + * @param closeBracketPos Position of the closing bracket. + * + * @return Position of the opening bracket. + */ + duint openingBracket(duint closeBracketPos) const; + + /** + * Composes a string representation of the token range. Intended + * for error reporting. + * + * @return String containing the text of the tokens. + */ + String asText() const; + +public: + static void bracketTokens(Token const &openingToken, + QChar const * &opening, QChar const * &closing); + +private: + TokenBuffer const *_tokens; + + /// Index of the start of the range. This is the first token in + /// the range. + duint _start; + + /// Index of the end of the range, plus one. This is the token + /// just after the last token of the range. + duint _end; +}; + +} // namespace de #endif /* LIBDENG2_TOKENRANGE_H */ diff --git a/doomsday/libdeng2/include/de/scriptsys/trystatement.h b/doomsday/libdeng2/include/de/scriptsys/trystatement.h index 348d05ca6e..b152c1c0ae 100644 --- a/doomsday/libdeng2/include/de/scriptsys/trystatement.h +++ b/doomsday/libdeng2/include/de/scriptsys/trystatement.h @@ -23,25 +23,26 @@ #include "../Statement" #include "../Compound" -namespace de +namespace de { + +/** + * Begins a try/catch compound. Always followed by one or more catch statements. + */ +class TryStatement : public Statement { - /** - * Begins a try/catch compound. Always followed by one or more catch statements. - */ - class TryStatement : public Statement - { - public: - void execute(Context &context) const; - - Compound &compound() { return _compound; } - - // Implements ISerializable. - void operator >> (Writer &to) const; - void operator << (Reader &from); - - private: - Compound _compound; - }; -} +public: + void execute(Context &context) const; + + Compound &compound() { return _compound; } + + // Implements ISerializable. + void operator >> (Writer &to) const; + void operator << (Reader &from); + +private: + Compound _compound; +}; + +} // namespace de #endif /* LIBDENG2_TRYSTATEMENT_H */ diff --git a/doomsday/libdeng2/include/de/scriptsys/whilestatement.h b/doomsday/libdeng2/include/de/scriptsys/whilestatement.h index 7e3d6ae159..e4562f13fb 100644 --- a/doomsday/libdeng2/include/de/scriptsys/whilestatement.h +++ b/doomsday/libdeng2/include/de/scriptsys/whilestatement.h @@ -23,39 +23,40 @@ #include "../Statement" #include "../Compound" -namespace de +namespace de { + +class Expression; + +/** + * Keeps looping as long as the loop condition evaluates to True. + * + * @ingroup script + */ +class WhileStatement : public Statement { - class Expression; - - /** - * Keeps looping as long as the loop condition evaluates to True. - * - * @ingroup script - */ - class WhileStatement : public Statement - { - public: - WhileStatement() : _loopCondition(0) {} - ~WhileStatement(); - - void setCondition(Expression *condition) { - _loopCondition = condition; - } - - Compound &compound() { - return _compound; - } - - void execute(Context &context) const; - - // Implements ISerializable. - void operator >> (Writer &to) const; - void operator << (Reader &from); - - private: - Expression *_loopCondition; - Compound _compound; - }; -} +public: + WhileStatement() : _loopCondition(0) {} + ~WhileStatement(); + + void setCondition(Expression *condition) { + _loopCondition = condition; + } + + Compound &compound() { + return _compound; + } + + void execute(Context &context) const; + + // Implements ISerializable. + void operator >> (Writer &to) const; + void operator << (Reader &from); + +private: + Expression *_loopCondition; + Compound _compound; +}; + +} // namespace de #endif /* LIBDENG2_WHILESTATEMENT_H */