hawk/lib/Hawk.hpp

2092 lines
57 KiB
C++
Raw Normal View History

2019-12-13 04:29:58 +00:00
/*
* $Id$
*
Copyright (c) 2006-2020 Chung, Hyung-Hwan. All rights reserved.
2019-12-13 04:29:58 +00:00
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _HAWK_HAWK_HPP_
#define _HAWK_HAWK_HPP_
#include <hawk.h>
#define HAWK_USE_HTB_FOR_FUNCTION_MAP 1
//#define HAWK_VALUE_USE_IN_CLASS_PLACEMENT_NEW 1
//#define HAWK_NO_LOCATION_IN_EXCEPTION 1
2019-12-13 04:29:58 +00:00
// TOOD: redefine these NAMESPACE stuffs or move them somewhere else
#define HAWK_BEGIN_NAMESPACE(x) namespace x {
#define HAWK_END_NAMESPACE(x) }
#if defined(HAWK_USE_HTB_FOR_FUNCTION_MAP)
2019-12-13 04:29:58 +00:00
# include <hawk-htb.h>
#else
// this part not supported for now
2019-12-13 04:29:58 +00:00
# include <hawk/HashTable.hpp>
# include <hawk/Cstr.hpp>
#endif
/// \file
/// Hawk Interpreter
2019-12-13 04:29:58 +00:00
/////////////////////////////////
2019-12-16 15:09:58 +00:00
HAWK_BEGIN_NAMESPACE(HAWK)
2019-12-13 04:29:58 +00:00
/////////////////////////////////
#if (__cplusplus >= 201103L) || (defined(_MSC_VER) && _MSC_VER >= 1900) // C++11 or later
#define HAWK_LANG_CXX11 1
#define HAWK_CXX_NOEXCEPT noexcept(true)
/// The HAWK_CXX_ENABLE_CXX11_MOVE macro enables C++11 move semantics in various classes.
#define HAWK_CXX_ENABLE_CXX11_MOVE 1
// The HAWK_CXX_CALL_DESTRUCTOR() macro calls a destructor explicitly.
#define HAWK_CXX_CALL_DESTRUCTOR(ptr, class_name) ((ptr)->~class_name())
// The HAWK_CXX_CALL_PLACEMENT_DELETE1() macro calls the global operator delete
// with 1 extra argument given.
#define HAWK_CXX_CALL_PLACEMENT_DELETE1(ptr, arg1) (::operator delete((ptr), (arg1)))
#elif (__cplusplus >= 199711L) // C++98
#undef HAWK_LANG_CXX11
#define HAWK_CXX_NOEXCEPT throw()
#define HAWK_CXX_CALL_DESTRUCTOR(ptr, class_name) ((ptr)->~class_name())
#define HAWK_CXX_CALL_PLACEMENT_DELETE1(ptr, arg1) (::operator delete((ptr), (arg1)))
#else
#undef HAWK_LANG_CXX11
#define HAWK_CXX_NOEXCEPT
#if defined(__BORLANDC__)
// Explicit destructor call requires a class name depending on the
// C++ standard/compiler.
//
// Node* x;
// x->~Node ();
//
// While x->~Node() is ok with modern compilers, some old compilers
// like BCC55 required the class name in the call as shown below.
//
// x->Node::~Node ();
#define HAWK_CXX_CALL_DESTRUCTOR(ptr, class_name) ((ptr)->class_name::~class_name())
#define HAWK_CXX_CALL_PLACEMENT_DELETE1(ptr, arg1) (::operator delete((ptr), (arg1)))
#elif defined(__WATCOMC__)
// WATCOM has a problem with this syntax.
// Node* x; x->Node::~Node().
// But it doesn't support operator delete overloading.
#define HAWK_CXX_CALL_DESTRUCTOR(ptr, class_name) ((ptr)->~class_name())
#define HAWK_CXX_CALL_PLACEMENT_DELETE1(ptr, arg1) (::hawk_operator_delete((ptr), (arg1)))
// When the name of a member template specialization appears after . or
// -> in a postfix-expression, or after :: in a qualified-id that explic-
// itly depends on a template-argument (_temp.dep_), the member template
// name must be prefixed by the keyword template. Otherwise the name is
// assumed to name a non-template. [Example:
// class X {
// public:
// template<size_t> X* alloc();
// };
// void f(X* p)
// {
// X* p1 = p->alloc<200>();
// // ill-formed: < means less than
// X* p2 = p->template alloc<200>();
// // fine: < starts explicit qualification
// }
// --end example]
//
// WATCOM doesn't support this qualifier.
#define HAWK_CXX_NO_OPERATOR_DELETE_OVERLOADING 1
#else
#define HAWK_CXX_CALL_DESTRUCTOR(ptr, class_name) ((ptr)->~class_name())
#define HAWK_CXX_CALL_PLACEMENT_DELETE1(ptr, arg1) (::operator delete((ptr), (arg1)))
#endif
#endif
#if defined(HAWK_CXX_ENABLE_CXX11_MOVE)
template<typename T> struct HAWK_CXX_RMREF { typedef T Type; };
template<typename T> struct HAWK_CXX_RMREF<T&> { typedef T Type; };
template<typename T> struct HAWK_CXX_RMREF<T&&> { typedef T Type; };
template<typename T> inline
typename HAWK_CXX_RMREF<T>::Type&& HAWK_CXX_RVREF(T&& v)
{
return (typename HAWK_CXX_RMREF<T>::Type&&)v;
}
#else
/*
template<typename T> inline
T& HAWK_CXX_RVREF(T& v) { return (T&)v; }
template<typename T> inline
const T& HAWK_CXX_RVREF(const T& v) { return (const T&)v; }
*/
#define HAWK_CXX_RVREF(x) x
#endif
/// The Exception class implements the exception object.
class HAWK_EXPORT Exception
{
public:
Exception (
const hawk_ooch_t* name, const hawk_ooch_t* msg,
const hawk_ooch_t* file, hawk_oow_t line) HAWK_CXX_NOEXCEPT:
name(name), msg(msg)
#if !defined(HAWK_NO_LOCATION_IN_EXCEPTION)
, file(file), line(line)
#endif
{
}
const hawk_ooch_t* name;
const hawk_ooch_t* msg;
#if !defined(HAWK_NO_LOCATION_IN_EXCEPTION)
const hawk_ooch_t* file;
hawk_oow_t line;
#endif
};
#define HAWK_THROW(ex_name) \
throw ex_name(HAWK_Q(ex_name),HAWK_Q(ex_name), HAWK_T(__FILE__), (hawk_oow_t)__LINE__)
#define HAWK_THROW_WITH_MSG(ex_name,msg) \
throw ex_name(HAWK_Q(ex_name),msg, HAWK_T(__FILE__), (hawk_oow_t)__LINE__)
#define HAWK_EXCEPTION(ex_name) \
class ex_name: public HAWK::Exception \
{ \
public: \
ex_name (const hawk_ooch_t* name, const hawk_ooch_t* msg, \
const hawk_ooch_t* file, hawk_oow_t line) HAWK_CXX_NOEXCEPT: \
HAWK::Exception (name, msg, file, line) {} \
}
#define HAWK_EXCEPTION_NAME(exception_object) ((exception_object).name)
#define HAWK_EXCEPTION_MSG(exception_object) ((exception_object).msg)
#if !defined(HAWK_NO_LOCATION_IN_EXCEPTION)
# define HAWK_EXCEPTION_FILE(exception_object) ((exception_object).file)
# define HAWK_EXCEPTION_LINE(exception_object) ((exception_object).line)
#else
# define HAWK_EXCEPTION_FILE(exception_object) (HAWK_T(""))
# define HAWK_EXCEPTION_LINE(exception_object) (0)
#endif
class HAWK_EXPORT Uncopyable
{
public:
Uncopyable () HAWK_CXX_NOEXCEPT {}
//virtual ~Uncopyable () {}
private:
Uncopyable (const Uncopyable&);
const Uncopyable& operator= (const Uncopyable&);
};
///
/// The Mmgr class defines a memory manager interface that can be inherited
/// by a class in need of a memory manager as defined in the primitive
/// #hawk_mmgr_t type. Using the class over the primitive type enables you to
/// write code in more object-oriented fashion. An inheriting class should
/// implement three pure virtual functions.
///
/// You are free to call allocMem(), reallocMem(), and freeMem() in C++ context
/// where no exception raising is desired. If you want an exception to be
/// raised upon memory allocation errors, you can call allocate(), reallocate(),
/// dispose() instead.
///
///
class HAWK_EXPORT Mmgr: public hawk_mmgr_t
{
public:
/// defines an alias type to #hawk_mmgr_t
typedef hawk_mmgr_t mmgr_t;
HAWK_EXCEPTION (MemoryError);
public:
///
/// The Mmgr() function builds a memory manager composed of bridge
/// functions connecting itself with it.
///
Mmgr () HAWK_CXX_NOEXCEPT
{
// NOTE:
// the #hawk_mmgr_t interface is not affected by raise_exception
// because direct calls to the virtual functions that don't raise
// exceptions are made via bridge functions below.
this->alloc = alloc_mem;
this->realloc = realloc_mem;
this->free = free_mem;
this->ctx = this;
}
///
/// The ~Mmgr() function finalizes a memory manager.
///
virtual ~Mmgr () HAWK_CXX_NOEXCEPT {}
///
/// The allocate() function calls allocMem() for memory
/// allocation. if it fails, it raise an exception if it's
/// configured to do so.
///
void* allocate (hawk_oow_t n, bool raise_exception = true)
{
void* xptr = this->allocMem (n);
if (!xptr && raise_exception) HAWK_THROW (MemoryError);
return xptr;
}
///
/// The callocate() function allocates memory like allocate() and
/// clears the memory before returning.
///
void* callocate (hawk_oow_t n, bool raise_exception = true);
///
/// The reallocate() function calls reallocMem() for memory
/// reallocation. if it fails, it raise an exception if it's
/// configured to do so.
///
void* reallocate (void* ptr, hawk_oow_t n, bool raise_exception = true)
{
void* xptr = this->reallocMem (ptr, n);
if (!xptr && raise_exception) HAWK_THROW (MemoryError);
return xptr;
}
///
/// The dispose() function calls freeMem() for memory disposal.
///
void dispose (void* ptr) HAWK_CXX_NOEXCEPT
{
this->freeMem (ptr);
}
//protected:
///
/// The allocMem() function allocates a chunk of memory of the
/// size \a n and return the pointer to the beginning of the chunk.
/// If it fails to allocate memory, it should return #HAWK_NULL.
///
virtual void* allocMem (
hawk_oow_t n ///< size of memory chunk to allocate in bytes
) HAWK_CXX_NOEXCEPT = 0;
///
/// The reallocMem() function resizes a chunk of memory previously
/// allocated with the allocMem() function. When resized, the contents
/// of the surviving part of a memory chunk is preserved. If it fails to
/// resize memory, it should return HAWK_NULL.
///
virtual void* reallocMem (
void* ptr, ///< pointer to memory chunk to resize
hawk_oow_t n ///< new size in bytes
) HAWK_CXX_NOEXCEPT = 0;
///
/// The freeMem() function frees a chunk of memory allocated with
/// the allocMem() function or resized with the reallocMem() function.
///
virtual void freeMem (
void* ptr ///< pointer to memory chunk to free
) HAWK_CXX_NOEXCEPT = 0;
protected:
///
/// bridge function from the #hawk_mmgr_t type the allocMem() function.
///
static void* alloc_mem (mmgr_t* mmgr, hawk_oow_t n) HAWK_CXX_NOEXCEPT;
///
/// bridge function from the #hawk_mmgr_t type the reallocMem() function.
///
static void* realloc_mem (mmgr_t* mmgr, void* ptr, hawk_oow_t n) HAWK_CXX_NOEXCEPT;
///
/// bridge function from the #hawk_mmgr_t type the freeMem() function.
///
static void free_mem (mmgr_t* mmgr, void* ptr) HAWK_CXX_NOEXCEPT;
public:
static Mmgr* getDFL () HAWK_CXX_NOEXCEPT;
static void setDFL (Mmgr* mmgr) HAWK_CXX_NOEXCEPT;
protected:
static Mmgr* dfl_mmgr;
};
class HAWK_EXPORT Mmged
{
public:
Mmged (Mmgr* mmgr = HAWK_NULL);
///
/// The getMmgr() function returns the memory manager associated.
///
Mmgr* getMmgr () const { return this->_mmgr; }
protected:
///
/// The setMmgr() function changes the memory manager.
/// Changing memory manager requires extra care to be taken
/// especially when you have some data allocated with the previous
/// manager. for this reason, i put this as a protected function.
///
void setMmgr(Mmgr* mmgr);
private:
Mmgr* _mmgr;
};
2019-12-13 04:29:58 +00:00
///
/// The Hawk class implements an AWK interpreter by wrapping around
2020-01-05 15:12:24 +00:00
/// #hhawk_t and #hawk_rtx_t.
2019-12-13 04:29:58 +00:00
///
class HAWK_EXPORT Hawk: public Uncopyable, public Mmged
2019-12-13 04:29:58 +00:00
{
public:
enum depth_t
{
2020-04-15 08:38:41 +00:00
DEPTH_INCLUDE = HAWK_OPT_DEPTH_INCLUDE,
DEPTH_BLOCK_PARSE = HAWK_OPT_DEPTH_BLOCK_PARSE,
DEPTH_BLOCK_RUN = HAWK_OPT_DEPTH_BLOCK_RUN,
DEPTH_EXPR_PARSE = HAWK_OPT_DEPTH_EXPR_PARSE,
DEPTH_EXPR_RUN = HAWK_OPT_DEPTH_EXPR_RUN,
DEPTH_REX_BUILD = HAWK_OPT_DEPTH_REX_BUILD,
DEPTH_REX_MATCH = HAWK_OPT_DEPTH_REX_MATCH
2019-12-13 04:29:58 +00:00
};
class Run;
friend class Run;
protected:
///
/// \name Error Handling
///
/// \{
///
/// The getErrorString() function returns a formatting string
/// for an error code \a num. You can override this function
/// to customize an error message. You must include the same numbers
/// of ${X}'s as the orginal formatting string. Their order may be
/// different. The example below changes the formatting string for
/// #HAWK_ENOENT.
2019-12-13 04:29:58 +00:00
/// \code
/// const hawk_ooch_t* MyHawk::getErrorString (hawk_errnum_t num) const
2019-12-13 04:29:58 +00:00
/// {
/// if (num == HAWK_ENOENT) return HAWK_T("cannot find '${0}'");
2022-06-04 15:00:13 +00:00
/// return Hawk::getErrorString(num);
2019-12-13 04:29:58 +00:00
/// }
/// \endcode
///
virtual const hawk_ooch_t* getErrorString (
2020-01-05 15:12:24 +00:00
hawk_errnum_t num
2019-12-13 04:29:58 +00:00
) const;
public:
///
/// The getErrorNumber() function returns the number of the last
/// error occurred.
///
2020-01-05 15:12:24 +00:00
hawk_errnum_t getErrorNumber () const;
2019-12-13 04:29:58 +00:00
///
/// The getErrorLocation() function returns the location of the
/// last error occurred.
///
2020-01-05 15:12:24 +00:00
hawk_loc_t getErrorLocation () const;
const hawk_ooch_t* getErrorLocationFile () const;
const hawk_uch_t* getErrorLocationFileU () const;
const hawk_bch_t* getErrorLocationFileB () const;
2019-12-13 04:29:58 +00:00
///
/// The Hawk::getErrorMessage() function returns a message describing
/// the last error occurred.
///
const hawk_ooch_t* getErrorMessage () const;
const hawk_uch_t* getErrorMessageU () const;
const hawk_bch_t* getErrorMessageB () const;
2019-12-13 04:29:58 +00:00
void setError (
2020-01-05 15:12:24 +00:00
hawk_errnum_t code, ///< error code
const hawk_loc_t* loc = HAWK_NULL ///< error location
2019-12-13 04:29:58 +00:00
);
2020-01-05 15:12:24 +00:00
void formatError (
hawk_errnum_t code,
const hawk_loc_t* loc,
const hawk_bch_t* fmt,
...
);
void formatError (
hawk_errnum_t code,
const hawk_loc_t* loc,
const hawk_uch_t* fmt,
...
2019-12-13 04:29:58 +00:00
);
///
/// The clearError() function clears error information
///
void clearError ();
//protected: can't make it protected for borland
void retrieveError ();
void retrieveError (Run* run);
/// \}
protected:
class NoSource;
public:
///
/// The Source class is an abstract class to encapsulate
/// source script I/O. The Hawk::parse function requires a concrete
/// object instantiated from its child class.
///
class HAWK_EXPORT Source
{
public:
///
/// The Mode type defines opening mode.
///
enum Mode
{
2019-12-13 04:29:58 +00:00
READ, ///< open for read
WRITE ///< open for write
};
///
/// The Data class encapsulates information passed in and out
/// for source script I/O.
///
class HAWK_EXPORT Data
{
public:
friend class Hawk;
protected:
2020-01-09 09:28:32 +00:00
Data (Hawk* hawk, Mode mode, hawk_sio_arg_t* arg):
hawk(hawk), mode(mode), arg(arg)
2019-12-13 04:29:58 +00:00
{
}
public:
Mode getMode() const
{
return this->mode;
}
bool isMaster() const
{
return this->arg->prev == HAWK_NULL;
}
const hawk_ooch_t* getName() const
2019-12-13 04:29:58 +00:00
{
return this->arg->name;
}
// since it doesn't copy the contents,
// it should point to something that outlives this object.
void setName (const hawk_ooch_t* name)
2019-12-13 04:29:58 +00:00
{
this->arg->name = name;
}
const hawk_ooch_t* getPath() const
{
return this->arg->path;
}
void setPath (const hawk_ooch_t* path)
{
this->arg->path = (hawk_ooch_t*)path;
}
const hawk_ooch_t* getPrevName() const
2019-12-13 04:29:58 +00:00
{
return this->arg->prev->name;
}
const void* getPrevHandle() const
{
return this->arg->prev->handle;
}
void* getHandle () const
{
return this->arg->handle;
}
void setHandle (void* handle)
{
this->arg->handle = handle;
}
operator Hawk* () const
{
2020-01-09 09:28:32 +00:00
return this->hawk;
2019-12-13 04:29:58 +00:00
}
2020-01-05 15:12:24 +00:00
operator hawk_t* () const
2019-12-13 04:29:58 +00:00
{
2020-01-09 09:28:32 +00:00
return this->hawk->getHandle();
2019-12-13 04:29:58 +00:00
}
protected:
2020-01-09 09:28:32 +00:00
Hawk* hawk;
2019-12-13 04:29:58 +00:00
Mode mode;
hawk_sio_arg_t* arg;
2019-12-13 04:29:58 +00:00
};
Source () {}
virtual ~Source () {}
virtual int open (Data& io) = 0;
virtual int close (Data& io) = 0;
virtual hawk_ooi_t read (Data& io, hawk_ooch_t* buf, hawk_oow_t len) = 0;
virtual hawk_ooi_t write (Data& io, const hawk_ooch_t* buf, hawk_oow_t len) = 0;
2019-12-13 04:29:58 +00:00
///
/// The NONE object indicates no source.
///
static NoSource NONE;
private:
Source (const Source&);
Source& operator= (const Source&);
};
protected:
class HAWK_EXPORT NoSource: public Source
{
public:
int open (Data& io) { return -1; }
int close (Data& io) { return 0; }
hawk_ooi_t read (Data& io, hawk_ooch_t* buf, hawk_oow_t len) { return 0; }
hawk_ooi_t write (Data& io, const hawk_ooch_t* buf, hawk_oow_t len) { return 0; }
2019-12-13 04:29:58 +00:00
};
public:
///
/// The RIOBase class is a base class to represent runtime I/O
/// operations. The Console, File, Pipe classes implement more specific
/// I/O operations by inheriting this class.
///
class HAWK_EXPORT RIOBase
{
protected:
2020-01-07 16:34:26 +00:00
RIOBase (Run* run, hawk_rio_arg_t* riod): run(run), riod(riod) {}
2019-12-13 04:29:58 +00:00
public:
2020-01-07 16:34:26 +00:00
const hawk_ooch_t* getName() const { return this->riod->name; }
2019-12-13 04:29:58 +00:00
2020-01-07 16:34:26 +00:00
const void* getHandle () const { return this->riod->handle; }
void setHandle (void* handle) { this->riod->handle = handle; }
2019-12-13 04:29:58 +00:00
2020-01-07 16:34:26 +00:00
int getUflags () const { return this->riod->uflags; }
void setUflags (int uflags) { this->riod->uflags = uflags; }
2019-12-13 04:29:58 +00:00
2020-01-09 09:28:32 +00:00
operator Hawk* () const { return this->run->hawk; }
2020-01-06 16:18:33 +00:00
operator hawk_t* () const
{
2020-03-05 15:22:55 +00:00
HAWK_ASSERT (hawk_rtx_gethawk(this->run->rtx) == this->run->hawk->getHandle());
2020-01-09 09:28:32 +00:00
return this->run->hawk->getHandle();
2020-01-06 16:18:33 +00:00
}
operator hawk_rio_arg_t* () const { return this->riod; }
operator Run* () const { return this->run; }
operator hawk_rtx_t* () const { return this->run->rtx; }
operator hawk_gem_t* () const { return hawk_rtx_getgem(this->run->rtx); }
2019-12-13 04:29:58 +00:00
protected:
Run* run;
2020-01-05 15:12:24 +00:00
hawk_rio_arg_t* riod;
2019-12-13 04:29:58 +00:00
private:
RIOBase (const RIOBase&);
RIOBase& operator= (const RIOBase&);
};
///
/// The Pipe class encapsulates the pipe operations indicated by
/// the | and || operators.
///
class HAWK_EXPORT Pipe: public RIOBase
{
public:
friend class Hawk;
/// The Mode type defines the opening mode.
enum Mode
{
/// open for read-only access
READ = HAWK_RIO_PIPE_READ,
2019-12-13 04:29:58 +00:00
/// open for write-only access
WRITE = HAWK_RIO_PIPE_WRITE,
2019-12-13 04:29:58 +00:00
/// open for read and write
RW = HAWK_RIO_PIPE_RW
2019-12-13 04:29:58 +00:00
};
/// The CloseMode type defines the closing mode for a pipe
/// opened in the #RW mode.
enum CloseMode
{
/// close both read and write ends
CLOSE_FULL = HAWK_RIO_CMD_CLOSE_FULL,
2019-12-13 04:29:58 +00:00
/// close the read end only
CLOSE_READ = HAWK_RIO_CMD_CLOSE_READ,
2019-12-13 04:29:58 +00:00
/// close the write end only
CLOSE_WRITE = HAWK_RIO_CMD_CLOSE_WRITE
2019-12-13 04:29:58 +00:00
};
class HAWK_EXPORT Handler
{
public:
virtual ~Handler () {}
virtual int open (Pipe& io) = 0;
virtual int close (Pipe& io) = 0;
virtual hawk_ooi_t read (Pipe& io, hawk_ooch_t* buf, hawk_oow_t len) = 0;
virtual hawk_ooi_t readBytes (Pipe& io, hawk_bch_t* buf, hawk_oow_t len) = 0;
virtual hawk_ooi_t write (Pipe& io, const hawk_ooch_t* buf, hawk_oow_t len) = 0;
virtual hawk_ooi_t writeBytes (Pipe& io, const hawk_bch_t* buf, hawk_oow_t len) = 0;
virtual int flush (Pipe& io) = 0;
2019-12-13 04:29:58 +00:00
};
protected:
2020-01-05 15:12:24 +00:00
Pipe (Run* run, hawk_rio_arg_t* riod);
2019-12-13 04:29:58 +00:00
public:
/// The getMode() function returns the opening mode requested.
/// You can inspect the opening mode, typically in the
/// openPipe() function, to create a pipe with proper
/// access mode. It is harmless to call this function from
/// other pipe handling functions.
Mode getMode () const;
/// The getCloseMode() function returns the closing mode
/// requested. The returned value is valid if getMode()
/// returns #RW.
CloseMode getCloseMode () const;
};
///
/// The File class encapsulates file operations by inheriting RIOBase.
///
class HAWK_EXPORT File: public RIOBase
{
public:
friend class Hawk;
enum Mode
{
READ = HAWK_RIO_FILE_READ,
WRITE = HAWK_RIO_FILE_WRITE,
APPEND = HAWK_RIO_FILE_APPEND
2019-12-13 04:29:58 +00:00
};
class HAWK_EXPORT Handler
{
public:
virtual ~Handler () {}
virtual int open (File& io) = 0;
virtual int close (File& io) = 0;
virtual hawk_ooi_t read (File& io, hawk_ooch_t* buf, hawk_oow_t len) = 0;
virtual hawk_ooi_t readBytes (File& io, hawk_bch_t* buf, hawk_oow_t len) = 0;
virtual hawk_ooi_t write (File& io, const hawk_ooch_t* buf, hawk_oow_t len) = 0;
virtual hawk_ooi_t writeBytes (File& io, const hawk_bch_t* buf, hawk_oow_t len) = 0;
virtual int flush (File& io) = 0;
2019-12-13 04:29:58 +00:00
};
protected:
2020-01-05 15:12:24 +00:00
File (Run* run, hawk_rio_arg_t* riod);
2019-12-13 04:29:58 +00:00
public:
Mode getMode () const;
};
///
/// The Console class encapsulates the console operations by
/// inheriting RIOBase.
///
class HAWK_EXPORT Console: public RIOBase
{
public:
friend class Hawk;
/// Console mode enumerators
enum Mode
{
READ = HAWK_RIO_CONSOLE_READ, ///< open for input
WRITE = HAWK_RIO_CONSOLE_WRITE ///< open for output
2019-12-13 04:29:58 +00:00
};
///
/// The Handler class is an abstract class that can be
/// implemented for customized I/O handling.
class HAWK_EXPORT Handler
{
public:
virtual ~Handler () {}
/// The open() function is called before the initial
/// access to the console for input and output.
/// It must return 0 for success and -1 for failure.
/// Upon successful opening, it can store information
/// required using setHandle() and setUflags().
/// The information set here is available in subsequent
/// calls to other methods and are accessible with
/// getHandle() and getUflags().
virtual int open (Console& io) = 0;
/// The close() function is called when the console
/// is not needed any more. It must return 0 for success
/// and -1 for failure.
virtual int close (Console& io) = 0;
/// The read() function is called when the console
/// is read for input. It must fill the buffer \a buf with
/// data not more than \a len characters and return the
/// number of characters filled into the buufer. It can
/// return 0 to indicate EOF and -1 for failure.
virtual hawk_ooi_t read (Console& io, hawk_ooch_t* buf, hawk_oow_t len) = 0;
virtual hawk_ooi_t readBytes (Console& io, hawk_bch_t* buf, hawk_oow_t len) = 0;
2019-12-13 04:29:58 +00:00
/// The write() function is called when the console
/// is written for output. It can write upto \a len characters
/// available in the buffer \a buf and return the number of
/// characters written. It can return 0 to indicate EOF and -1
/// for failure.
virtual hawk_ooi_t write (Console& io, const hawk_ooch_t* buf, hawk_oow_t len) = 0;
2019-12-13 04:29:58 +00:00
virtual hawk_ooi_t writeBytes (Console& io, const hawk_bch_t* buf, hawk_oow_t len) = 0;
2019-12-13 04:29:58 +00:00
/// You may choose to buffer the data passed to the write()
/// function and perform actual writing when flush() is called.
/// It must return 0 for success and -1 for failure.
virtual int flush (Console& io) = 0;
/// The next() function is called when \b nextfile or
/// \b nextofile is executed. It must return 0 for success
/// and -1 for failure.
virtual int next (Console& io) = 0;
};
protected:
2020-01-05 15:12:24 +00:00
Console (Run* run, hawk_rio_arg_t* riod);
2019-12-13 04:29:58 +00:00
~Console ();
public:
/// The getMode() function returns if the console is
/// opened for reading or writing.
Mode getMode () const;
int setFileName (const hawk_ooch_t* name);
int setFNR (hawk_int_t fnr);
2019-12-13 04:29:58 +00:00
protected:
hawk_ooch_t* filename;
2019-12-13 04:29:58 +00:00
};
///
/// The Value class wraps around #hawk_val_t to provide a more
/// comprehensive interface.
///
class HAWK_EXPORT Value
{
public:
friend class Hawk;
#if defined(HAWK_VALUE_USE_IN_CLASS_PLACEMENT_NEW)
2019-12-13 04:29:58 +00:00
// initialization
void* operator new (hawk_oow_t n, Run* run) throw ();
void* operator new[] (hawk_oow_t n, Run* run) throw ();
2019-12-13 04:29:58 +00:00
#if !defined(__BORLANDC__) && !defined(__WATCOMC__)
// deletion when initialization fails
void operator delete (void* p, Run* run);
void operator delete[] (void* p, Run* run);
#endif
// normal deletion
void operator delete (void* p);
void operator delete[] (void* p);
#endif
///
/// The Index class encapsulates an index of an arrayed value.
///
class HAWK_EXPORT Index: protected hawk_oocs_t
{
public:
friend class Value;
/// The Index() function creates an empty array index.
Index ()
{
this->ptr = (hawk_ooch_t*)Value::getEmptyStr();
2019-12-13 04:29:58 +00:00
this->len = 0;
}
/// The Index() function creates a string array index.
Index (const hawk_ooch_t* ptr, hawk_oow_t len)
2019-12-13 04:29:58 +00:00
{
this->ptr = (hawk_ooch_t*)ptr;
2019-12-13 04:29:58 +00:00
this->len = len;
}
void set (const hawk_oocs_t* x)
{
this->ptr = x->ptr;
this->len = x->len;
}
Index& operator= (const hawk_oocs_t* x)
{
this->set (x);
return *this;
}
const hawk_ooch_t* pointer () const
2019-12-13 04:29:58 +00:00
{
return this->ptr;
}
hawk_oow_t length () const
2019-12-13 04:29:58 +00:00
{
return this->len;
}
};
///
/// Represents a numeric index of an arrayed value
///
class HAWK_EXPORT IntIndex: public Index
{
public:
IntIndex (hawk_int_t num);
2019-12-13 04:29:58 +00:00
protected:
// 2^32: 4294967296
// 2^64: 18446744073709551616
// 2^128: 340282366920938463463374607431768211456
// -(2^32/2): -2147483648
// -(2^64/2): -9223372036854775808
// -(2^128/2): -170141183460469231731687303715884105728
#if HAWK_SIZEOF_LONG_T > 16
# error SIZEOF(hawk_int_t) TOO LARGE.
2019-12-13 04:29:58 +00:00
# error INCREASE THE BUFFER SIZE TO SUPPORT IT.
#elif HAWK_SIZEOF_LONG_T == 16
hawk_ooch_t buf[41];
2019-12-13 04:29:58 +00:00
#elif HAWK_SIZEOF_LONG_T == 8
hawk_ooch_t buf[21];
2019-12-13 04:29:58 +00:00
#else
hawk_ooch_t buf[12];
2019-12-13 04:29:58 +00:00
#endif
};
///
/// The IndexIterator class is a helper class to make simple
/// iteration over array elements.
///
class HAWK_EXPORT IndexIterator: public hawk_val_map_itr_t
{
public:
friend class Value;
///
/// The END variable is a special variable to
/// represent the end of iteration.
///
static IndexIterator END;
///
/// The IndexIterator() function creates an iterator
/// for an arrayed value.
///
IndexIterator ()
{
hawk_init_map_itr (this, 0);
2019-12-13 04:29:58 +00:00
}
bool operator== (const IndexIterator& ii) const
2019-12-13 04:29:58 +00:00
{
// the most common use of this operator is to test it against END
#if defined(HAWK_MAP_IS_HTB)
2019-12-13 04:29:58 +00:00
return this->pair == ii.pair && this->buckno == ii.buckno;
#else
return this->pair == ii.pair && this->_prev == ii._prev;
#endif
2019-12-13 04:29:58 +00:00
}
bool operator!= (const IndexIterator& ii) const
2019-12-13 04:29:58 +00:00
{
return !this->operator==(ii);
2019-12-13 04:29:58 +00:00
}
};
///
/// The Value() function creates an empty value associated
/// with no runtime context. To set an actual inner value,
/// you must specify a context when calling setXXX() functions.
/// i.e., use setInt(run,10) instead of setInt(10).
///
Value ();
///
/// The Value() function creates an empty value associated
/// with a runtime context.
///
Value (Run& run);
///
/// The Value() function creates an empty value associated
/// with a runtime context.
///
Value (Run* run);
Value (const Value& v);
~Value ();
Value& operator= (const Value& v);
void clear ();
2020-01-14 09:10:47 +00:00
operator hawk_val_t* () const { return this->val; }
operator hawk_int_t () const;
operator hawk_flt_t () const;
operator const hawk_ooch_t* () const;
2019-12-13 04:29:58 +00:00
#if defined(HAWK_OOCH_IS_UCH)
operator const hawk_bch_t* () const;
#endif
2020-01-05 15:12:24 +00:00
hawk_val_t* toVal () const
2019-12-13 04:29:58 +00:00
{
2020-01-14 09:10:47 +00:00
return this->operator hawk_val_t* ();
2019-12-13 04:29:58 +00:00
}
hawk_int_t toInt () const
2019-12-13 04:29:58 +00:00
{
2020-01-14 09:10:47 +00:00
return this->operator hawk_int_t ();
2019-12-13 04:29:58 +00:00
}
hawk_flt_t toFlt () const
2019-12-13 04:29:58 +00:00
{
2020-01-14 09:10:47 +00:00
return this->operator hawk_flt_t ();
2019-12-13 04:29:58 +00:00
}
const hawk_ooch_t* toStr (hawk_oow_t* len) const
2019-12-13 04:29:58 +00:00
{
const hawk_ooch_t* p;
hawk_oow_t l;
2019-12-13 04:29:58 +00:00
if (this->getStr(&p, &l) <= -1)
{
p = this->getEmptyStr();
l = 0;
}
if (len) *len = l;
return p;
}
const hawk_bch_t* toMbs (hawk_oow_t* len) const
2019-12-13 04:29:58 +00:00
{
const hawk_bch_t* p;
hawk_oow_t l;
2019-12-13 04:29:58 +00:00
if (this->getMbs(&p, &l) <= -1)
{
p = this->getEmptyMbs();
l = 0;
}
if (len) *len = l;
return p;
}
2021-08-18 05:11:04 +00:00
int getType () const { return hawk_get_val_type(this->val); }
const hawk_ooch_t* getTypeName () const { return hawk_get_val_type_name(this->val); }
2021-08-18 05:11:04 +00:00
int getInt (hawk_int_t* v) const;
int getFlt (hawk_flt_t* v) const;
int getNum (hawk_int_t* lv, hawk_flt_t* fv) const;
int getStr (const hawk_ooch_t** str, hawk_oow_t* len) const;
int getMbs (const hawk_bch_t** str, hawk_oow_t* len) const;
2019-12-13 04:29:58 +00:00
2020-01-05 15:12:24 +00:00
int setVal (hawk_val_t* v);
int setVal (Run* r, hawk_val_t* v);
2019-12-13 04:29:58 +00:00
int setInt (hawk_int_t v);
int setInt (Run* r, hawk_int_t v);
int setFlt (hawk_flt_t v);
int setFlt (Run* r, hawk_flt_t v);
2019-12-13 04:29:58 +00:00
int setStr (const hawk_uch_t* str, hawk_oow_t len, bool numeric = false);
int setStr (Run* r, const hawk_uch_t* str, hawk_oow_t len, bool numeric = false);
int setStr (const hawk_uch_t* str, bool numeric = false);
int setStr (Run* r, const hawk_uch_t* str, bool numeric = false);
int setStr (const hawk_bch_t* str, hawk_oow_t len, bool numeric = false);
int setStr (Run* r, const hawk_bch_t* str, hawk_oow_t len, bool numeric = false);
int setStr (const hawk_bch_t* str, bool numeric = false);
int setStr (Run* r, const hawk_bch_t* str, bool numeric = false);
2019-12-13 04:29:58 +00:00
int setMbs (const hawk_bch_t* str, hawk_oow_t len);
int setMbs (Run* r, const hawk_bch_t* str, hawk_oow_t len);
2019-12-13 04:29:58 +00:00
int setMbs (const hawk_bch_t* str);
int setMbs (Run* r, const hawk_bch_t* str);
2020-01-05 15:12:24 +00:00
int setIndexedVal (const Index& idx, hawk_val_t* v);
int setIndexedVal (Run* r, const Index& idx, hawk_val_t* v);
int setIndexedInt (const Index& idx, hawk_int_t v);
int setIndexedInt (Run* r, const Index& idx, hawk_int_t v);
int setIndexedFlt (const Index& idx, hawk_flt_t v);
int setIndexedFlt (Run* r, const Index& idx, hawk_flt_t v);
2019-12-13 04:29:58 +00:00
int setIndexedStr (const Index& idx, const hawk_uch_t* str, hawk_oow_t len, bool numeric = false);
int setIndexedStr (Run* r, const Index& idx, const hawk_uch_t* str, hawk_oow_t len, bool numeric = false);
int setIndexedStr (const Index& idx, const hawk_uch_t* str, bool numeric = false);
int setIndexedStr (Run* r, const Index& idx, const hawk_uch_t* str, bool numeric = false);
int setIndexedStr (const Index& idx, const hawk_bch_t* str, hawk_oow_t len, bool numeric = false);
int setIndexedStr (Run* r, const Index& idx, const hawk_bch_t* str, hawk_oow_t len, bool numeric = false);
int setIndexedStr (const Index& idx, const hawk_bch_t* str, bool numeric = false);
int setIndexedStr (Run* r, const Index& idx, const hawk_bch_t* str, bool numeric = false);
2019-12-13 04:29:58 +00:00
int setIndexedMbs (const Index& idx, const hawk_bch_t* str, hawk_oow_t len);
int setIndexedMbs (Run* r, const Index& idx, const hawk_bch_t* str, hawk_oow_t len);
2019-12-13 04:29:58 +00:00
int setIndexedMbs (const Index& idx, const hawk_bch_t* str);
int setIndexedMbs (Run* r, const Index& idx, const hawk_bch_t* str);
///
/// The isIndexed() function determines if a value is arrayed.
/// \return true if indexed, false if not.
///
bool isIndexed () const;
///
/// The getIndexed() function gets a value at the given
/// index \a idx and sets it to \a val.
/// \return 0 on success, -1 on failure
///
int getIndexed (
const Index& idx, ///< array index
Value* val ///< value holder
) const;
///
/// The getFirstIndex() function stores the first index of
/// an arrayed value into \a idx.
/// \return IndexIterator::END if the arrayed value is empty,
/// iterator that can be passed to getNextIndex() if not
///
IndexIterator getFirstIndex (
Index* idx ///< index holder
) const;
///
/// The getNextIndex() function stores into \a idx the next
/// index of an array value from the position indicated by
/// \a iter.
/// \return IndexIterator::END if the arrayed value is empty,
/// iterator that can be passed to getNextIndex() if not
///
IndexIterator getNextIndex (
Index* idx, ///< index holder
const IndexIterator& curitr ///< current position
) const;
protected:
Run* run;
2020-01-05 15:12:24 +00:00
hawk_val_t* val;
2019-12-13 04:29:58 +00:00
mutable struct
{
hawk_oocs_t str;
hawk_bcs_t mbs;
} cached;
public:
static const hawk_ooch_t* getEmptyStr();
2019-12-13 04:29:58 +00:00
static const hawk_bch_t* getEmptyMbs();
};
public:
///
/// The Run class wraps around #hawk_rtx_t to represent the
/// runtime context.
///
class HAWK_EXPORT Run
{
protected:
friend class Hawk;
friend class Value;
friend class RIOBase;
friend class Console;
Run (Hawk* hawk);
Run (Hawk* hawk, hawk_rtx_t* run);
2019-12-13 04:29:58 +00:00
~Run ();
public:
2020-01-05 15:12:24 +00:00
operator Hawk* () const
{
2020-01-09 09:28:32 +00:00
return this->hawk;
2020-01-05 15:12:24 +00:00
}
operator hawk_rtx_t* () const
{
return this->rtx;
}
operator hawk_gem_t* () const
{
return this->rtx? hawk_rtx_getgem(this->rtx): HAWK_NULL;
}
2019-12-13 04:29:58 +00:00
void halt () const;
bool isHalt () const;
2020-01-05 15:12:24 +00:00
hawk_errnum_t getErrorNumber () const;
hawk_loc_t getErrorLocation () const;
const hawk_ooch_t* getErrorMessage () const;
const hawk_uch_t* getErrorMessageU () const;
const hawk_bch_t* getErrorMessageB () const;
2019-12-13 04:29:58 +00:00
2020-01-05 15:12:24 +00:00
///
/// The setError() function sets error information.
///
2019-12-13 04:29:58 +00:00
void setError (
2020-01-05 15:12:24 +00:00
hawk_errnum_t code, ///< error code
const hawk_loc_t* loc = HAWK_NULL ///< error location
2019-12-13 04:29:58 +00:00
);
2020-01-05 15:12:24 +00:00
void formatError (
hawk_errnum_t code,
const hawk_loc_t* loc,
const hawk_bch_t* fmt,
...
);
void formatError (
hawk_errnum_t code,
const hawk_loc_t* loc,
const hawk_uch_t* fmt,
...
2019-12-13 04:29:58 +00:00
);
///
/// The setGlobal() function sets the value of a global
/// variable identified by \a id
/// to \a v.
/// \return 0 on success, -1 on failure
///
int setGlobal (int id, hawk_int_t v);
2019-12-13 04:29:58 +00:00
///
/// The setGlobal() function sets the value of a global
/// variable identified by \a id
/// to \a v.
/// \return 0 on success, -1 on failure
///
int setGlobal (int id, hawk_flt_t v);
2019-12-13 04:29:58 +00:00
///
/// The setGlobal() function sets the value of a global
/// variable identified by \a id
/// to a string as long as \a len characters pointed to by
/// \a ptr.
/// \return 0 on success, -1 on failure
///
2020-03-03 12:00:13 +00:00
int setGlobal (int id, const hawk_uch_t* ptr, hawk_oow_t len, bool mbs = false);
int setGlobal (int id, const hawk_bch_t* ptr, hawk_oow_t len, bool mbs = false);
int setGlobal (int id, const hawk_uch_t* ptr, bool mbs = false);
int setGlobal (int id, const hawk_bch_t* ptr, bool mbs = false);
2019-12-13 04:29:58 +00:00
///
/// The setGlobal() function sets a global variable
/// identified by \a id to a value \a v.
/// \return 0 on success, -1 on failure
///
int setGlobal (int id, const Value& v);
///
/// The getGlobal() function gets the value of a global
/// variable identified by \a id and stores it in \a v.
/// \return 0 on success, -1 on failure
///
2019-12-13 04:29:58 +00:00
int getGlobal (int id, Value& v) const;
protected:
2020-01-09 09:28:32 +00:00
Hawk* hawk;
2020-01-05 15:12:24 +00:00
hawk_rtx_t* rtx;
2019-12-13 04:29:58 +00:00
};
///
/// Returns the primitive handle
///
2020-01-05 15:12:24 +00:00
operator hawk_t* () const
{
return this->hawk;
2020-01-05 15:12:24 +00:00
}
operator hawk_gem_t* () const
{
return this->hawk? hawk_getgem(this->hawk): HAWK_NULL;
2020-01-05 15:12:24 +00:00
}
2019-12-13 04:29:58 +00:00
///
/// \name Basic Functions
/// \{
///
/// The Hawk() function creates an interpreter without fully
/// initializing it. You must call open() for full initialization
/// before calling other functions.
Hawk (Mmgr* mmgr = HAWK_NULL);
/// The ~Hawk() function destroys an interpreter. Make sure to have
/// called close() for finalization before the destructor is executed.
virtual ~Hawk () {}
hawk_cmgr_t* getCmgr () const;
2020-01-15 05:25:43 +00:00
void setCmgr (hawk_cmgr_t* cmgr);
2019-12-13 04:29:58 +00:00
///
/// The open() function initializes an interpreter.
/// You must call this function before doing anything meaningful.
/// \return 0 on success, -1 on failure
///
int open ();
///
/// The close() function closes the interpreter.
///
void close ();
///
/// The uponClosing() function is called back after Hawk::close()
/// has cleared most of the internal data but before destroying
/// the underlying hawk object. This maps to the close callback
2019-12-13 04:29:58 +00:00
/// of #hawk_ecb_t.
///
virtual void uponClosing ();
///
/// The uponClearing() function is called back when Hawk::close()
/// begins clearing internal data. This maps to the clear callback
/// of #hawk_ecb_t.
///
virtual void uponClearing ();
///
/// The parse() function parses the source code read from the input
/// stream \a in and writes the parse tree to the output stream \a out.
/// To disable deparsing, you may set \a out to Hawk::Source::NONE.
/// However, it is not allowed to specify Hawk::Source::NONE for \a in.
///
/// \return Run object on success, #HAWK_NULL on failure
///
Hawk::Run* parse (
Source& in, ///< script to parse
Source& out ///< deparsing target
);
///
/// The getRunContext() funciton returns the execution context
/// returned by the parse() function. The returned context
/// is valid if parse() has been called. You may call this
/// function to get the context if you forgot to store it
/// in a call to parse().
///
const Hawk::Run* getRunContext () const
{
2020-04-17 17:19:34 +00:00
return &this->runctx;
2019-12-13 04:29:58 +00:00
}
///
/// The getRunContext() funciton returns the execution context
/// returned by the parse() function. The returned context
/// is valid if parse() has been called. You may call this
/// function to get the context if you forgot to store it
/// in a call to parse().
///
Hawk::Run* getRunContext ()
{
2020-04-17 17:19:34 +00:00
return &this->runctx;
2019-12-13 04:29:58 +00:00
}
///
/// The resetRunContext() function closes an existing
/// execution context and creates a new execution context.
/// You may want to call this function if you want to
/// reset it without calling the parse() function again
/// after the first call to it.
Hawk::Run* resetRunContext ();
///
/// The loop() function executes the BEGIN block, pattern-action blocks,
/// and the END block. The return value is stored into \a ret.
/// \return 0 on succes, -1 on failure
///
int loop (
Value* ret ///< return value holder
);
///
/// The call() function invokes a function named \a name.
///
int call (
const hawk_bch_t* name, ///< function name
2019-12-13 04:29:58 +00:00
Value* ret, ///< return value holder
const Value* args, ///< argument array
hawk_oow_t nargs ///< number of arguments
2019-12-13 04:29:58 +00:00
);
///
/// The call() function invokes a function named \a name.
///
int call (
const hawk_uch_t* name, ///< function name
2019-12-13 04:29:58 +00:00
Value* ret, ///< return value holder
const Value* args, ///< argument array
hawk_oow_t nargs ///< number of arguments
2019-12-13 04:29:58 +00:00
);
2020-01-14 09:10:47 +00:00
///
/// The exec() function is the same as loop() if no @pragma startup
/// is specified. It is the same as call() if it is specifed
///
int exec (
Value* ret, ///< return value holder
const Value* args, ///< argument array
hawk_oow_t nargs ///< number of arguments
);
2019-12-13 04:29:58 +00:00
///
/// The halt() function makes request to abort execution
///
void halt ();
/// \}
///
/// \name Configuration
/// \{
///
///
/// The getTrait() function gets the current options.
/// \return current traits
///
int getTrait () const;
///
/// The setTrait() function changes the current traits.
///
void setTrait (
int trait
);
///
/// The setMaxDepth() function sets the maximum processing depth
/// for operations identified by \a ids.
///
void setMaxDepth (
depth_t id, ///< depth identifier
hawk_oow_t depth ///< new depth
2019-12-13 04:29:58 +00:00
);
///
/// The getMaxDepth() function gets the maximum depth for an operation
/// type identified by \a id.
///
hawk_oow_t getMaxDepth (
2019-12-13 04:29:58 +00:00
depth_t id ///< depth identifier
) const;
int setIncludeDirs (const hawk_uch_t* dirs);
int setIncludeDirs (const hawk_bch_t* dirs);
2019-12-13 04:29:58 +00:00
///
/// The addArgument() function adds an ARGV string as long as \a len
/// characters pointed to
/// by \a arg. loop() and call() make a string added available
/// to a script through ARGV.
/// \return 0 on success, -1 on failure
///
int addArgument (
const hawk_uch_t* arg, ///< string pointer
hawk_oow_t len ///< string length
);
int addArgument (
const hawk_bch_t* arg, ///< string pointer
hawk_oow_t len ///< string length
2019-12-13 04:29:58 +00:00
);
///
/// The addArgument() function adds a null-terminated string \a arg.
/// loop() and call() make a string added available to a script
/// through ARGV.
/// \return 0 on success, -1 on failure
///
int addArgument (
const hawk_uch_t* arg ///< string pointer
);
int addArgument (
const hawk_bch_t* arg ///< string pointer
2019-12-13 04:29:58 +00:00
);
///
/// The clearArguments() function deletes all ARGV strings.
///
void clearArguments ();
2020-01-14 09:10:47 +00:00
hawk_oow_t getArgumentCount () const
{
return this->runarg.len;
}
const hawk_ooch_t* getArgument (hawk_oow_t index, hawk_oow_t* len = HAWK_NULL) const
{
if (len) *len = this->runarg.ptr[index].len;
return this->runarg.ptr[index].ptr;
}
2019-12-13 04:29:58 +00:00
///
/// The addGlobal() function registers an intrinsic global variable.
/// \return integer >= 0 on success, -1 on failure.
///
int addGlobal (
const hawk_bch_t* name ///< variable name
);
int addGlobal (
const hawk_uch_t* name ///< variable name
);
///
/// The deleteGlobal() function unregisters an intrinsic global
/// variable by name.
/// \return 0 on success, -1 on failure.
///
int deleteGlobal (
const hawk_bch_t* name ///< variable name
);
int deleteGlobal (
const hawk_uch_t* name ///< variable name
);
///
/// The findGlobal() function returns the numeric ID of an intrinsic
// global variable.
/// \return integer >= 0 on success, -1 on failure.
///
int findGlobal (
const hawk_bch_t* name, ///> variable name
bool inc_builtins = false
2019-12-13 04:29:58 +00:00
);
int findGlobal (
const hawk_uch_t* name, ///> variable name
bool inc_builtins = false
2019-12-13 04:29:58 +00:00
);
///
/// The setGlobal() function sets the value of a global variable
/// identified by \a id. The \a id is either a value returned by
/// addGlobal() or one of the #hawk_gbl_id_t enumerators. It is not allowed
2019-12-13 04:29:58 +00:00
/// to call this function prior to parse().
/// \return 0 on success, -1 on failure
///
int setGlobal (
int id, ///< numeric identifier
const Value& v ///< value
);
///
/// The getGlobal() function gets the value of a global variable
/// identified by \a id. The \a id is either a value returned by
/// addGlobal() or one of the #hawk_gbl_id_t enumerators. It is not allowed
2019-12-13 04:29:58 +00:00
/// to call this function before parse().
/// \return 0 on success, -1 on failure
///
int getGlobal (
int id, ///< numeric identifier
Value& v ///< value store
);
///
/// The FunctionHandler type defines a intrinsic function handler.
///
typedef int (Hawk::*FunctionHandler) (
Run& run,
Value& ret,
Value* args,
2020-01-05 15:12:24 +00:00
hawk_oow_t nargs,
const hawk_fnc_info_t* fi
2019-12-13 04:29:58 +00:00
);
///
/// The addFunction() function adds a new user-defined intrinsic
/// function.
///
int addFunction (
const hawk_bch_t* name, ///< function name
hawk_oow_t minArgs, ///< minimum numbers of arguments
hawk_oow_t maxArgs, ///< maximum numbers of arguments
2019-12-13 04:29:58 +00:00
const hawk_bch_t* argSpec, ///< argument specification
FunctionHandler handler, ///< function handler
int validOpts = 0 ///< valid if these options are set
);
int addFunction (
const hawk_uch_t* name, ///< function name
hawk_oow_t minArgs, ///< minimum numbers of arguments
hawk_oow_t maxArgs, ///< maximum numbers of arguments
2019-12-13 04:29:58 +00:00
const hawk_uch_t* argSpec, ///< argument specification
FunctionHandler handler, ///< function handler
int validOpts = 0 ///< valid if these options are set
);
///
/// The deleteFunction() function deletes a user-defined intrinsic
/// function by name.
///
int deleteFunction (
const hawk_ooch_t* name ///< function name
2019-12-13 04:29:58 +00:00
);
/// \}
Pipe::Handler* getPipeHandler ()
{
return this->pipe_handler;
}
const Pipe::Handler* getPipeHandler () const
{
return this->pipe_handler;
}
///
/// The setPipeHandler() function registers an external pipe
/// handler object. An external pipe handler can be implemented
/// outside this class without overriding various pipe functions.
/// Note that an external pipe handler must outlive an outer
/// hawk object.
2019-12-13 04:29:58 +00:00
///
void setPipeHandler (Pipe::Handler* handler)
{
this->pipe_handler = handler;
}
File::Handler* getFileHandler ()
{
return this->file_handler;
}
const File::Handler* getFileHandler () const
{
return this->file_handler;
}
///
/// The setFileHandler() function registers an external file
/// handler object. An external file handler can be implemented
/// outside this class without overriding various file functions.
/// Note that an external file handler must outlive an outer
/// hawk object.
2019-12-13 04:29:58 +00:00
///
void setFileHandler (File::Handler* handler)
{
this->file_handler = handler;
}
Console::Handler* getConsoleHandler ()
{
return this->console_handler;
}
const Console::Handler* getConsoleHandler () const
{
return this->console_handler;
}
///
/// The setConsoleHandler() function registers an external console
/// handler object. An external file handler can be implemented
/// outside this class without overriding various console functions.
/// Note that an external console handler must outlive an outer
/// hawk object.
2019-12-13 04:29:58 +00:00
///
void setConsoleHandler (Console::Handler* handler)
{
this->console_handler = handler;
}
protected:
///
/// \name Pipe I/O handlers
/// Pipe operations are achieved through the following functions
/// if no external pipe handler is set with setPipeHandler().
/// \{
/// The openPipe() function is a pure virtual function that must be
/// overridden by a child class to open a pipe. It must return 1
/// on success, 0 on end of a pipe, and -1 on failure.
virtual int openPipe (Pipe& io);
/// The closePipe() function is a pure virtual function that must be
/// overridden by a child class to close a pipe. It must return 0
/// on success and -1 on failure.
virtual int closePipe (Pipe& io);
virtual hawk_ooi_t readPipe (Pipe& io, hawk_ooch_t* buf, hawk_oow_t len);
virtual hawk_ooi_t readPipeBytes (Pipe& io, hawk_bch_t* buf, hawk_oow_t len);
virtual hawk_ooi_t writePipe (Pipe& io, const hawk_ooch_t* buf, hawk_oow_t len);
virtual hawk_ooi_t writePipeBytes (Pipe& io, const hawk_bch_t* buf, hawk_oow_t len);
virtual int flushPipe (Pipe& io);
2019-12-13 04:29:58 +00:00
/// \}
///
/// \name File I/O handlers
/// File operations are achieved through the following functions
/// if no external file handler is set with setFileHandler().
/// \{
///
virtual int openFile (File& io);
virtual int closeFile (File& io);
virtual hawk_ooi_t readFile (File& io, hawk_ooch_t* buf, hawk_oow_t len);
virtual hawk_ooi_t readFileBytes (File& io, hawk_bch_t* buf, hawk_oow_t len);
virtual hawk_ooi_t writeFile (File& io, const hawk_ooch_t* buf, hawk_oow_t len);
virtual hawk_ooi_t writeFileBytes (File& io, const hawk_bch_t* buf, hawk_oow_t len);
virtual int flushFile (File& io);
2019-12-13 04:29:58 +00:00
/// \}
///
/// \name Console I/O handlers
/// Console operations are achieved through the following functions.
/// if no external console handler is set with setConsoleHandler().
/// \{
///
virtual int openConsole (Console& io);
virtual int closeConsole (Console& io);
virtual hawk_ooi_t readConsole (Console& io, hawk_ooch_t* buf, hawk_oow_t len);
virtual hawk_ooi_t readConsoleBytes (Console& io, hawk_bch_t* buf, hawk_oow_t len);
virtual hawk_ooi_t writeConsole (Console& io, const hawk_ooch_t* buf, hawk_oow_t len);
virtual hawk_ooi_t writeConsoleBytes (Console& io, const hawk_bch_t* buf, hawk_oow_t len);
virtual int flushConsole (Console& io);
virtual int nextConsole (Console& io);
2019-12-13 04:29:58 +00:00
/// \}
// primitive handlers
virtual hawk_flt_t pow (hawk_flt_t x, hawk_flt_t y) = 0;
virtual hawk_flt_t mod (hawk_flt_t x, hawk_flt_t y) = 0;
2019-12-13 04:29:58 +00:00
virtual void* modopen (const hawk_mod_spec_t* spec) = 0;
2019-12-13 04:29:58 +00:00
virtual void modclose (void* handle) = 0;
virtual void* modgetsym (void* handle, const hawk_ooch_t* name) = 0;
2019-12-13 04:29:58 +00:00
// static glue members for various handlers
static hawk_ooi_t readSource (
hawk_t* hawk, hawk_sio_cmd_t cmd, hawk_sio_arg_t* arg,
hawk_ooch_t* data, hawk_oow_t count);
static hawk_ooi_t writeSource (
hawk_t* hawk, hawk_sio_cmd_t cmd, hawk_sio_arg_t* arg,
hawk_ooch_t* data, hawk_oow_t count);
2019-12-13 04:29:58 +00:00
static hawk_ooi_t pipeHandler (
hawk_rtx_t* rtx, hawk_rio_cmd_t cmd, hawk_rio_arg_t* riod,
void* data, hawk_oow_t count);
static hawk_ooi_t fileHandler (
hawk_rtx_t* rtx, hawk_rio_cmd_t cmd, hawk_rio_arg_t* riod,
void* data, hawk_oow_t count);
static hawk_ooi_t consoleHandler (
hawk_rtx_t* rtx, hawk_rio_cmd_t cmd, hawk_rio_arg_t* riod,
void* data, hawk_oow_t count);
2019-12-13 04:29:58 +00:00
static int functionHandler (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi);
2019-12-13 04:29:58 +00:00
static hawk_flt_t pow (hawk_t* hawk, hawk_flt_t x, hawk_flt_t y);
static hawk_flt_t mod (hawk_t* hawk, hawk_flt_t x, hawk_flt_t y);
2019-12-13 04:29:58 +00:00
static void* modopen (hawk_t* hawk, const hawk_mod_spec_t* spec);
static void modclose (hawk_t* hawk, void* handle);
static void* modgetsym (hawk_t* hawk, void* handle, const hawk_ooch_t* name);
2019-12-13 04:29:58 +00:00
public:
// use these with care
hawk_t* getHandle() const { return this->hawk; }
2019-12-13 04:29:58 +00:00
protected:
hawk_t* hawk;
2019-12-13 04:29:58 +00:00
hawk_errstr_t dflerrstr;
hawk_errinf_t errinf;
#if defined(HAWK_OOCH_IS_BCH)
mutable hawk_uch_t xerrmsg[HAWK_ERRMSG_CAPA];
mutable hawk_uch_t xerrlocfile[128];
#else
mutable hawk_bch_t xerrmsg[HAWK_ERRMSG_CAPA * 2];
mutable hawk_bch_t xerrlocfile[256];
#endif
2019-12-13 04:29:58 +00:00
#if defined(HAWK_USE_HTB_FOR_FUNCTION_MAP)
2019-12-13 04:29:58 +00:00
hawk_htb_t* functionMap;
#else
2019-12-13 04:29:58 +00:00
class FunctionMap: public HashTable<Cstr,FunctionHandler>
{
public:
FunctionMap (Hawk* hawk): hawk(hawk) {}
2019-12-13 04:29:58 +00:00
protected:
Hawk* hawk;
2019-12-13 04:29:58 +00:00
};
FunctionMap functionMap;
#endif
Source* source_reader;
Source* source_writer;
Pipe::Handler* pipe_handler;
File::Handler* file_handler;
Console::Handler* console_handler;
struct xstrs_t
{
xstrs_t (): ptr (HAWK_NULL), len (0), capa (0) {}
int add (hawk_t* hawk, const hawk_uch_t* arg, hawk_oow_t len);
int add (hawk_t* hawk, const hawk_bch_t* arg, hawk_oow_t len);
void clear (hawk_t* hawk);
2019-12-13 04:29:58 +00:00
hawk_oocs_t* ptr;
2020-01-05 15:12:24 +00:00
hawk_oow_t len;
hawk_oow_t capa;
2019-12-13 04:29:58 +00:00
};
xstrs_t runarg;
private:
hawk_cmgr_t* _cmgr;
2019-12-13 04:29:58 +00:00
Run runctx;
int init_runctx ();
void fini_runctx ();
int dispatch_function (Run* run, const hawk_fnc_info_t* fi);
2019-12-13 04:29:58 +00:00
2020-01-05 15:12:24 +00:00
static const hawk_ooch_t* xerrstr (hawk_t* a, hawk_errnum_t num);
2019-12-13 04:29:58 +00:00
};
2022-06-04 15:00:13 +00:00
// ----------------------------------------------------------------------------------------
class HAWK_EXPORT MmgrStd: public Mmgr
{
public:
MmgrStd () HAWK_CXX_NOEXCEPT: Mmgr () {}
void* allocMem (hawk_oow_t n) HAWK_CXX_NOEXCEPT;
void* reallocMem (void* ptr, hawk_oow_t n) HAWK_CXX_NOEXCEPT;
void freeMem (void* ptr) HAWK_CXX_NOEXCEPT;
#if 0
/// The getInstance() function returns the stock instance of the MmgrStd class.
static MmgrStd* getInstance () HAWK_CXX_NOEXCEPT;
#endif
};
// ----------------------------------------------------------------------------------------
///
/// The HawkStd class provides an easier-to-use interface by overriding
/// primitive methods, and implementing the file handler, the pipe handler,
/// and common intrinsic functions.
///
class HAWK_EXPORT HawkStd: public Hawk
{
public:
///
/// The SourceFile class implements script I/O from and to a file.
///
class HAWK_EXPORT SourceFile: public Source
{
public:
SourceFile (const hawk_uch_t* name, hawk_cmgr_t* cmgr = HAWK_NULL): _type(NAME_UCH), _name(name), cmgr(cmgr)
{
dir.ptr = HAWK_NULL; dir.len = 0;
}
SourceFile (const hawk_bch_t* name, hawk_cmgr_t* cmgr = HAWK_NULL): _type(NAME_BCH), _name(name), cmgr(cmgr)
{
dir.ptr = HAWK_NULL; dir.len = 0;
}
~SourceFile () {};
int open (Data& io);
int close (Data& io);
hawk_ooi_t read (Data& io, hawk_ooch_t* buf, hawk_oow_t len);
hawk_ooi_t write (Data& io, const hawk_ooch_t* buf, hawk_oow_t len);
protected:
enum
{
NAME_UCH,
NAME_BCH
} _type;
const void* _name;
hawk_oocs_t dir;
hawk_cmgr_t* cmgr;
};
///
/// The SourceString class implements script input from a string.
/// Deparsing is not supported.
///
class HAWK_EXPORT SourceString: public Source
{
public:
SourceString (const hawk_uch_t* str, hawk_cmgr_t* cmgr = HAWK_NULL): _type(STR_UCH), _str(str), _hawk(HAWK_NULL), str(HAWK_NULL), ptr(HAWK_NULL), cmgr(cmgr) {}
SourceString (const hawk_bch_t* str, hawk_cmgr_t* cmgr = HAWK_NULL): _type(STR_BCH), _str(str), _hawk(HAWK_NULL), str(HAWK_NULL), ptr(HAWK_NULL), cmgr(cmgr) {}
~SourceString ();
int open (Data& io);
int close (Data& io);
hawk_ooi_t read (Data& io, hawk_ooch_t* buf, hawk_oow_t len);
hawk_ooi_t write (Data& io, const hawk_ooch_t* buf, hawk_oow_t len);
protected:
enum
{
STR_UCH,
STR_BCH
} _type;
const void* _str;
hawk_t* _hawk;
hawk_ooch_t* str;
const hawk_ooch_t* ptr;
hawk_cmgr_t* cmgr; // for reading included files
};
HawkStd (Mmgr* mmgr = HAWK_NULL): Hawk(mmgr), cmgrtab_inited(false), stdmod_up(false), console_cmgr(HAWK_NULL)
{
}
int open ();
void close ();
void uponClosing ();
Run* parse (Source& in, Source& out);
/// The setConsoleCmgr() function sets the encoding type of
/// the console streams. They include both the input and the output
/// streams. It provides no way to specify a different encoding
/// type for the input and the output stream.
void setConsoleCmgr (const hawk_cmgr_t* cmgr);
/// The getConsoleCmgr() function returns the current encoding
/// type set for the console streams.
const hawk_cmgr_t* getConsoleCmgr () const;
/// The addConsoleOutput() function adds a file to form an
/// output console stream.
int addConsoleOutput (const hawk_uch_t* arg, hawk_oow_t len);
int addConsoleOutput (const hawk_uch_t* arg);
int addConsoleOutput (const hawk_bch_t* arg, hawk_oow_t len);
int addConsoleOutput (const hawk_bch_t* arg);
void clearConsoleOutputs ();
protected:
#define HAWK_STD_ENV_CHAR_IS_BCH
typedef hawk_bch_t env_char_t;
int make_additional_globals (Run* run);
int build_argcv (Run* run);
int build_environ (Run* run, env_char_t* envarr[]);
// intrinsic functions
hawk_cmgr_t* getiocmgr (const hawk_ooch_t* ioname);
int setioattr (Run& run, Value& ret, Value* args, hawk_oow_t nargs, const hawk_ooch_t* name, hawk_oow_t len);
int getioattr (Run& run, Value& ret, Value* args, hawk_oow_t nargs, const hawk_ooch_t* name, hawk_oow_t len);
// pipe io handlers
int openPipe (Pipe& io);
int closePipe (Pipe& io);
hawk_ooi_t readPipe (Pipe& io, hawk_ooch_t* buf, hawk_oow_t len);
hawk_ooi_t readPipeBytes (Pipe& io, hawk_bch_t* buf, hawk_oow_t len);
hawk_ooi_t writePipe (Pipe& io, const hawk_ooch_t* buf, hawk_oow_t len);
hawk_ooi_t writePipeBytes (Pipe& io, const hawk_bch_t* buf, hawk_oow_t len);
int flushPipe (Pipe& io);
// file io handlers
int openFile (File& io);
int closeFile (File& io);
hawk_ooi_t readFile (File& io, hawk_ooch_t* buf, hawk_oow_t len);
hawk_ooi_t readFileBytes (File& io, hawk_bch_t* buf, hawk_oow_t len);
hawk_ooi_t writeFile (File& io, const hawk_ooch_t* buf, hawk_oow_t len);
hawk_ooi_t writeFileBytes (File& io, const hawk_bch_t* buf, hawk_oow_t len);
int flushFile (File& io);
// console io handlers
int openConsole (Console& io);
int closeConsole (Console& io);
hawk_ooi_t readConsole (Console& io, hawk_ooch_t* buf, hawk_oow_t len);
hawk_ooi_t readConsoleBytes (Console& io, hawk_bch_t* buf, hawk_oow_t len);
hawk_ooi_t writeConsole (Console& io, const hawk_ooch_t* buf, hawk_oow_t len);
hawk_ooi_t writeConsoleBytes (Console& io, const hawk_bch_t* buf, hawk_oow_t len);
int flushConsole (Console& io);
int nextConsole (Console& io);
// primitive handlers
void* allocMem (hawk_oow_t n);
void* reallocMem (void* ptr, hawk_oow_t n);
void freeMem (void* ptr);
hawk_flt_t pow (hawk_flt_t x, hawk_flt_t y);
hawk_flt_t mod (hawk_flt_t x, hawk_flt_t y);
void* modopen (const hawk_mod_spec_t* spec);
void modclose (void* handle);
void* modgetsym (void* handle, const hawk_ooch_t* name);
protected:
hawk_htb_t cmgrtab;
bool cmgrtab_inited;
bool stdmod_up;
hawk_cmgr_t* console_cmgr;
// global variables
int gbl_argc;
int gbl_argv;
int gbl_environ;
// standard input console - reuse runarg
hawk_oow_t runarg_index;
hawk_oow_t runarg_count;
// standard output console
xstrs_t ofile;
hawk_oow_t ofile_index;
hawk_oow_t ofile_count;
public:
struct ioattr_t
{
hawk_cmgr_t* cmgr;
hawk_ooch_t cmgr_name[64]; // i assume that the cmgr name never exceeds this length.
hawk_ntime_t tmout[4];
ioattr_t (): cmgr (HAWK_NULL)
{
this->cmgr_name[0] = HAWK_T('\0');
for (hawk_oow_t i = 0; i < HAWK_COUNTOF(this->tmout); i++)
{
this->tmout[i].sec = -999;
this->tmout[i].nsec = 0;
}
}
};
static ioattr_t default_ioattr;
protected:
ioattr_t* get_ioattr (const hawk_ooch_t* ptr, hawk_oow_t len);
ioattr_t* find_or_make_ioattr (const hawk_ooch_t* ptr, hawk_oow_t len);
private:
int open_console_in (Console& io);
int open_console_out (Console& io);
int open_pio (Pipe& io);
int open_nwio (Pipe& io, int flags, void* nwad);
};
2019-12-13 04:29:58 +00:00
/////////////////////////////////
2019-12-16 15:09:58 +00:00
HAWK_END_NAMESPACE(HAWK)
2019-12-13 04:29:58 +00:00
/////////////////////////////////
HAWK_EXPORT void* operator new (hawk_oow_t size, HAWK::Mmgr* mmgr);
#if defined(HAWK_CXX_NO_OPERATOR_DELETE_OVERLOADING)
HAWK_EXPORT void hawk_operator_delete (void* ptr, HAWK::Mmgr* mmgr);
#else
HAWK_EXPORT void operator delete (void* ptr, HAWK::Mmgr* mmgr);
#endif
HAWK_EXPORT void* operator new (hawk_oow_t size, HAWK::Mmgr* mmgr, void* existing_ptr);
#if 0
// i found no way to delete an array allocated with
// the placement new operator. if the array element is an instance
// of a class, the pointer returned by the new operator call
// may not be the actual pointer allocated. some compilers
// seem to put some information about the array at the
// beginning of the allocated memory and return the pointer
// off a few bytes from the beginning.
void* operator new[] (hawk_oow_t size, HAWK::Mmgr* mmgr);
void operator delete[] (void* ptr, HAWK::Mmgr* mmgr);
#endif
#define HAWK_CXX_DELETE_WITH_MMGR(ptr, class_name, mmgr) \
do { \
HAWK_CXX_CALL_DESTRUCTOR (ptr, class_name); \
HAWK_CXX_CALL_PLACEMENT_DELETE1(ptr, mmgr); \
} while(0);
2019-12-13 04:29:58 +00:00
#endif