#define ASCRIPT_DLL_MODULE
//-----------------------------------------------------------------------------
// AScript re (regular expression) module
//-----------------------------------------------------------------------------
#include "AScript.h"
#include "oniguruma.h"

AScript_BeginModule(re)

AScript_DeclarePrivSymbol(re);
AScript_DeclarePrivSymbol(string);
AScript_DeclarePrivSymbol(multiline);

static regex_t *CreateRegEx(Signal sig, const TCHAR *pattern, const Context &context);
static Value DoMatch(Environment &env, Signal sig, regex_t *pRegEx, const TCHAR *str);
static Value DoMatches(Environment &env, Signal sig, regex_t *pRegEx, const TCHAR *str, int cnt);
static Value DoSplit(Environment &env, Signal sig, regex_t *pRegEx, const TCHAR *str, int cnt);
static Value DoSub(Environment &env, Signal sig, regex_t *pRegEx,
							const TCHAR *repl, const TCHAR *str, int cnt);
static Value DoSubWithFunc(Environment &env, Signal sig, regex_t *pRegEx,
							const Function *pFunc, const TCHAR *str, int cnt);
static void SetError_OnigurumaError(Signal sig, int rtn);
static void SetError_FailInOniguruma(Signal sig);

// Class_RegEx / Object_RegEx
AScript_DeclareClass(RegEx);

class Object_RegEx : public Object {
private:
	String _pattern;
	regex_t *_pRegEx;
public:
	inline static Object_RegEx *GetSelfObj(Context &context) {
		return dynamic_cast<Object_RegEx *>(context.GetSelfObj());
	}
public:
	inline Object_RegEx(Class *pClass) : Object(pClass), _pRegEx(NULL) {}
	inline Object_RegEx(const Object_RegEx &obj) : Object(obj) {
		::_ftprintf(stderr, "not supported function\n");
		::exit(1);
	}
	virtual ~Object_RegEx();
	virtual Object *Clone() const;
	virtual String ToString(Signal sig, bool exprFlag);
	inline bool SetPattern(Signal sig, const TCHAR *pattern, const Context &context) {
		_pattern = pattern;
		_pRegEx = CreateRegEx(sig, pattern, context);
		return _pRegEx != NULL;
	}
	inline regex_t *GetRegEx() { return _pRegEx; }
};

Object_RegEx::~Object_RegEx()
{
	if (_pRegEx != NULL) {
		::onig_free(_pRegEx);
	}
}

Object *Object_RegEx::Clone() const
{
	return new Object_RegEx(*this);
}

String Object_RegEx::ToString(Signal sig, bool exprFlag)
{
	String rtn;
	rtn += _T("<RegEx:'");
	rtn += _pattern;
	rtn += _T("'>");
	return rtn;
}

// m = re.match(pat:string, str:string):map:[icase]
AScript_DeclareFunction(match)
{
	SetMode(RSLTMODE_Normal, MAP_On);
	DeclareArg(env, _T("pattern"), VTYPE_String);
	DeclareArg(env, _T("str"), VTYPE_String);
	DeclareAttr(AScript_Symbol(icase));
	DeclareAttr(AScript_PrivSymbol(multiline));
}

AScript_ImplementFunction(match)
{
	regex_t *pRegEx = CreateRegEx(sig, context.GetString(0), context);
	if (pRegEx == NULL) return Value::Null;
	Value result = DoMatch(env, sig, pRegEx, context.GetString(1));
	::onig_free(pRegEx);
	return result;
}

// list = re.matches(pat:string, str:string, count?:number):map:[icase]
AScript_DeclareFunction(matches)
{
	SetMode(RSLTMODE_Normal, MAP_On);
	DeclareArg(env, _T("pattern"), VTYPE_String);
	DeclareArg(env, _T("str"), VTYPE_String);
	DeclareArg(env, _T("count"), VTYPE_Number, false, OCCUR_ZeroOrOnce);
	DeclareAttr(AScript_Symbol(icase));
	DeclareAttr(AScript_PrivSymbol(multiline));
}

AScript_ImplementFunction(matches)
{
	regex_t *pRegEx = CreateRegEx(sig, context.GetString(0), context);
	if (pRegEx == NULL) return Value::Null;
	int cnt = context.IsNumber(1)? static_cast<int>(context.GetNumber(1)) : -1;
	Value result = DoMatches(env, sig, pRegEx, context.GetString(1), cnt);
	::onig_free(pRegEx);
	return result;
}

// m = re.RegEx#match(str:string):map
AScript_DeclareMethod(RegEx, match)
{
	SetMode(RSLTMODE_Normal, MAP_On);
	DeclareArg(env, _T("str"), VTYPE_String);
}

AScript_ImplementMethod(RegEx, match)
{
	Object_RegEx *pObj = Object_RegEx::GetSelfObj(context);
	return DoMatch(env, sig, pObj->GetRegEx(), context.GetString(0));
}

// list = re.RegEx#matches(str:string, count?:number):map
AScript_DeclareMethod(RegEx, matches)
{
	SetMode(RSLTMODE_Normal, MAP_On);
	DeclareArg(env, _T("str"), VTYPE_String);
	DeclareArg(env, _T("count"), VTYPE_Number, false, OCCUR_ZeroOrOnce);
}

AScript_ImplementMethod(RegEx, matches)
{
	Object_RegEx *pObj = Object_RegEx::GetSelfObj(context);
	int cnt = context.IsNumber(1)? static_cast<int>(context.GetNumber(1)) : -1;
	return DoMatches(env, sig, pObj->GetRegEx(), context.GetString(0), cnt);
}

// str = re.sub(pat:string, repl:string, str:string, count?:number):map:[icase]
AScript_DeclareFunction(sub)
{
	SetMode(RSLTMODE_Normal, MAP_On);
	DeclareArg(env, _T("pattern"), VTYPE_String);
	DeclareArg(env, _T("repl"), VTYPE_AnyType);
	DeclareArg(env, _T("str"), VTYPE_String);
	DeclareArg(env, _T("count"), VTYPE_Number, false, OCCUR_ZeroOrOnce);
	DeclareAttr(AScript_Symbol(icase));
	DeclareAttr(AScript_PrivSymbol(multiline));
}

AScript_ImplementFunction(sub)
{
	regex_t *pRegEx = CreateRegEx(sig, context.GetString(0), context);
	if (pRegEx == NULL) return Value::Null;
	int cnt = context.IsNumber(3)? static_cast<int>(context.GetNumber(3)) : -1;
	Value result;
	if (context.IsString(1)) {
		result = DoSub(env, sig, pRegEx,
						context.GetString(1), context.GetString(2), cnt);
	} else if (context.IsFunction(1)) {
		result = DoSubWithFunc(env, sig, pRegEx,
						context.GetFunction(1), context.GetString(2), cnt);
	} else {
		SetError_ArgumentTypeByIndex(sig, 1, context.GetValue(1));
	}
	::onig_free(pRegEx);
	return result;
}

// str = re.RegEx#sub(repl:string, str:string, count?:number):map
AScript_DeclareMethod(RegEx, sub)
{
	SetMode(RSLTMODE_Normal, MAP_On);
	DeclareArg(env, _T("repl"), VTYPE_AnyType);
	DeclareArg(env, _T("str"), VTYPE_String);
	DeclareArg(env, _T("count"), VTYPE_Number, false, OCCUR_ZeroOrOnce);
}

AScript_ImplementMethod(RegEx, sub)
{
	Object_RegEx *pObj = Object_RegEx::GetSelfObj(context);
	int cnt = context.IsNumber(2)? static_cast<int>(context.GetNumber(2)) : -1;
	if (context.IsString(0)) {
		return DoSub(env, sig, pObj->GetRegEx(),
						context.GetString(0), context.GetString(1), cnt);
	} else if (context.IsFunction(0)) {
		return DoSubWithFunc(env, sig, pObj->GetRegEx(),
						context.GetFunction(0), context.GetString(1), cnt);
	}
	SetError_ArgumentTypeByIndex(sig, 0, context.GetValue(0));
	return Value::Null;
}

// list = re.split(pattern:string, str:string, count?:number):map:[icase]
AScript_DeclareFunction(split)
{
	SetMode(RSLTMODE_Normal, MAP_On);
	DeclareArg(env, _T("pattern"), VTYPE_String);
	DeclareArg(env, _T("str"), VTYPE_String);
	DeclareArg(env, _T("count"), VTYPE_Number, false, OCCUR_ZeroOrOnce);
	DeclareAttr(AScript_Symbol(icase));
	DeclareAttr(AScript_PrivSymbol(multiline));
}

AScript_ImplementFunction(split)
{
	regex_t *pRegEx = CreateRegEx(sig, context.GetString(0), context);
	if (pRegEx == NULL) return Value::Null;
	int cnt = context.IsNumber(2)? static_cast<int>(context.GetNumber(2)) : -1;
	Value result;
	result = DoSplit(env, sig, pRegEx, context.GetString(1), cnt);
	::onig_free(pRegEx);
	return result;
}

// list = re.RegEx#split(str:string, count?:number):map
AScript_DeclareMethod(RegEx, split)
{
	SetMode(RSLTMODE_Normal, MAP_On);
	DeclareArg(env, _T("str"), VTYPE_String);
	DeclareArg(env, _T("count"), VTYPE_Number, false, OCCUR_ZeroOrOnce);
}

AScript_ImplementMethod(RegEx, split)
{
	Object_RegEx *pObj = Object_RegEx::GetSelfObj(context);
	int cnt = context.IsNumber(1)? static_cast<int>(context.GetNumber(1)) : -1;
	return DoSplit(env, sig, pObj->GetRegEx(), context.GetString(0), cnt);
}

// implementation of class RegEx
AScript_ImplementClass(RegEx)
{
	AScript_AssignMethod(RegEx, match);
	AScript_AssignMethod(RegEx, matches);
	AScript_AssignMethod(RegEx, sub);
	AScript_AssignMethod(RegEx, split);
}

// Class_Match / Object_Match
AScript_DeclareClass(Match);

class Object_Match : public Object {
public:
	class Group {
	private:
		int _posBegin, _posEnd;
	public:
		inline Group(int posBegin, int posEnd) :
						_posBegin(posBegin), _posEnd(posEnd) {}
		inline Group(const Group &group) :
						_posBegin(group._posBegin), _posEnd(group._posEnd) {}
		inline void operator=(const Group &group) {
			_posBegin = group._posBegin, _posEnd = group._posEnd;
		}
		inline int GetPosBegin() const { return _posBegin; }
		inline int GetPosEnd() const { return _posEnd; }
		inline int GetLength() const { return _posEnd - _posBegin; }
	};
	typedef std::vector<Group> GroupList;
	typedef std::map<String, size_t> GroupNameDict;
public:
	inline static Object_Match *GetSelfObj(Context &context) {
		return dynamic_cast<Object_Match *>(context.GetSelfObj());
	}
private:
	String _str;
	GroupList _groupList;
	GroupNameDict _groupNameDict;
public:
	inline Object_Match(Class *pClass) : Object(pClass) {}
	inline Object_Match(const Object_Match &obj) : Object(obj),
							_str(obj._str), _groupList(obj._groupList) {}
	virtual ~Object_Match();
	virtual Object *Clone() const;
	virtual String ToString(Signal sig, bool exprFlag);
	bool SetMatchInfo(const TCHAR *str, regex_t *pRegEx, const OnigRegion *pRegion);
	String GetGroup(Signal sig, size_t index) const;
	String GetGroup(GroupList::const_iterator pGroup) const {
		return String(_str, pGroup->GetPosBegin(), pGroup->GetLength());
	}
	String GetGroupByName(Signal sig, const TCHAR *name) const;
	const GroupList &GetGroupList() const { return _groupList; }
private:
	int ForeachNameCallback(const String &name, int nGroups,
											int *idxGroupTbl, regex_t *pRegEx);
	static int ForeachNameCallbackStub(
				const UChar *nameRaw, const UChar *nameRawEnd,
				int nGroups, int *idxGroupTbl, regex_t *pRegEx, void *pArg);
};

Object_Match::~Object_Match()
{
}

Object *Object_Match::Clone() const
{
	return new Object_Match(*this);
}

String Object_Match::ToString(Signal sig, bool exprFlag)
{
	String rtn;
	rtn += _T("<match:");
	foreach_const (GroupList, pGroup, _groupList) {
		if (pGroup != _groupList.begin()) rtn += _T(",");
		TCHAR str[80];
		::_stprintf(str, _T("%d-%d"), pGroup->GetPosBegin(), pGroup->GetPosEnd());
		rtn += str;
	}
	rtn += _T(">");
	return rtn;
}

bool Object_Match::SetMatchInfo(const TCHAR *str,
								regex_t *pRegEx, const OnigRegion *pRegion)
{
	if (pRegion->num_regs == 0) return false;
	::onig_foreach_name(pRegEx, &ForeachNameCallbackStub, this);
	_str = str;
	AssignValue(AScript_Symbol(string), Value(*this, str), false);
	for (int iGroup = 0; iGroup < pRegion->num_regs; iGroup++) {
		int posBegin = pRegion->beg[iGroup];
		int posEnd = pRegion->end[iGroup];
		if (posBegin >= posEnd) return false;
		_groupList.push_back(Group(posBegin, posEnd));
	}
	return true;
}

String Object_Match::GetGroup(Signal sig, size_t index) const
{
	if (index >= _groupList.size()) {
		sig.SetError(ERR_IndexError, _T("index is out of range"));
		return _T("");
	}
	const Group &group = _groupList[index];
	return String(_str, group.GetPosBegin(), group.GetLength());
}

String Object_Match::GetGroupByName(Signal sig, const TCHAR *name) const
{
	GroupNameDict::const_iterator iter = _groupNameDict.find(name);
	if (iter == _groupNameDict.end()) {
		sig.SetError(ERR_IndexError,
			_T("regular expression doesn't have a group named '%s%"), name);
		return _T("");
	}
	return GetGroup(sig, iter->second);
}

int Object_Match::ForeachNameCallback(const String &name, int nGroups,
											int *idxGroupTbl, regex_t *pRegEx)
{
	if (nGroups > 0) _groupNameDict[name] = idxGroupTbl[0];
	return 0;
}

int Object_Match::ForeachNameCallbackStub(
			const UChar *nameRaw, const UChar *nameRawEnd,
			int nGroups, int *idxGroupTbl, regex_t *pRegEx, void *pArg)
{
	String name(reinterpret_cast<const TCHAR *>(nameRaw), nameRawEnd - nameRaw);
	return reinterpret_cast<Object_Match *>(pArg)->
					ForeachNameCallback(name, nGroups, idxGroupTbl, pRegEx);
}

// regex = re.compile(pat:string):map:[icase]
AScript_DeclareFunction(compile)
{
	SetMode(RSLTMODE_Normal, MAP_On);
	DeclareArg(env, _T("pattern"), VTYPE_String);
	DeclareAttr(AScript_Symbol(icase));
	DeclareAttr(AScript_PrivSymbol(multiline));
}

AScript_ImplementFunction(compile)
{
	OnigOptionType option = ONIG_OPTION_DEFAULT;
	Object_RegEx *pObj = new Object_RegEx(AScript_Class(RegEx, env));
	if (!pObj->SetPattern(sig, context.GetString(0), context)) {
		delete pObj;
		return Value::Null;
	}
	return Value(pObj, VTYPE_Object);
}

// str = re.Match#group(index):map
AScript_DeclareMethod(Match, group)
{
	SetMode(RSLTMODE_Normal, MAP_On);
	DeclareArg(env, _T("index"), VTYPE_AnyType);
}

AScript_ImplementMethod(Match, group)
{
	Object_Match *pObj = Object_Match::GetSelfObj(context);
	Value result;
	if (context.IsNumber(0)) {
		size_t index = static_cast<size_t>(context.GetNumber(0));
		String str = pObj->GetGroup(sig, index);
		if (sig.IsSignalled()) return Value::Null;
		result = Value(env, str.c_str());
	} else if (context.IsString(0)) {
		String str = pObj->GetGroupByName(sig, context.GetString(0));
		if (sig.IsSignalled()) return Value::Null;
		result = Value(env, str.c_str());
	} else {
		sig.SetError(ERR_TypeError, _T("invalid argument type"));
	}
	return result;
}

// list = re.Match#groups()
AScript_DeclareMethod(Match, groups)
{
	SetMode(RSLTMODE_Normal, MAP_Off);
}

AScript_ImplementMethod(Match, groups)
{
	Object_Match *pObj = Object_Match::GetSelfObj(context);
	Value result;
	ValueList &valList = result.InitAsList(env);
	const Object_Match::GroupList &groupList = pObj->GetGroupList();
	Object_Match::GroupList::const_iterator pGroup = groupList.begin();
	if (pGroup != groupList.end()) pGroup++;
	for ( ; pGroup != groupList.end(); pGroup++) {
		valList.push_back(Value(env, pObj->GetGroup(pGroup).c_str()));
	}
	return result;
}

// implementation of class Match
AScript_ImplementClass(Match)
{
	AScript_AssignMethod(Match, group);
	AScript_AssignMethod(Match, groups);
}

static regex_t *CreateRegEx(Signal sig, const TCHAR *pattern, const Context &context)
{
	// ::onig_end() call may be necessary when module is destroyed
	regex_t *pRegEx = NULL;
	OnigOptionType option = ONIG_OPTION_CAPTURE_GROUP; //ONIG_OPTION_NONE
	OnigEncoding enc = ONIG_ENCODING_SJIS;
	OnigErrorInfo errInfo;
	size_t len = ::_tcslen(pattern);
	if (context.IsSet(AScript_Symbol(icase))) {
		option |= ONIG_OPTION_IGNORECASE;
	}
	if (context.IsSet(AScript_PrivSymbol(multiline))) {
		option |= ONIG_OPTION_MULTILINE;
	}
	int rtn = ::onig_new(&pRegEx, pattern, pattern + len,
								option, enc, ONIG_SYNTAX_DEFAULT, &errInfo);
	if (rtn != ONIG_NORMAL) {
		SetError_OnigurumaError(sig, rtn);
		return NULL;
	}
	return pRegEx;
}

static Value DoMatch(Environment &env, Signal sig, regex_t *pRegEx, const TCHAR *str)
{
	Value result;
	size_t len = ::_tcslen(str);
	const TCHAR *start = str;
	OnigRegion *pRegion = ::onig_region_new();
	int rtn = ::onig_search(pRegEx, str, str + len, start, start + len,
											pRegion, ONIG_OPTION_NONE);
	if (rtn >= 0) {
		Object_Match *pObj = new Object_Match(AScript_Class(Match, env));
		if (pObj->SetMatchInfo(str, pRegEx, pRegion)) {
			result.InitAsObject(pObj, VTYPE_Object);
		} else {
			SetError_FailInOniguruma(sig);
			delete pObj;
		}
	} else if (rtn == ONIG_MISMATCH) {
		// nothing to do
	} else { // error
		SetError_OnigurumaError(sig, rtn);
	}
	::onig_region_free(pRegion, 1); // 1:free self, 0:free contents only
	return result;
}

static Value DoMatches(Environment &env, Signal sig, regex_t *pRegEx, const TCHAR *str, int cnt)
{
	Value result;
	size_t len = ::_tcslen(str);
	ValueList &valList = result.InitAsList(env);
	OnigRegion *pRegion = ::onig_region_new();
	int pos = 0;
	for ( ; cnt != 0; cnt--) {
		int rtn = ::onig_search(pRegEx, str, str + len,
							str + pos, str + len, pRegion, ONIG_OPTION_NONE);
		if (rtn >= 0) {
		Object_Match *pObj = new Object_Match(AScript_Class(Match, env));
			if (!pObj->SetMatchInfo(str, pRegEx, pRegion)) {
				SetError_FailInOniguruma(sig);
				delete pObj;
				goto error_done;
			}
			valList.push_back(Value(pObj, VTYPE_Object));
			pos = pRegion->end[0];
		} else if (rtn == ONIG_MISMATCH) {
			break;
		} else { // error
			SetError_OnigurumaError(sig, rtn);
			goto error_done;
		}
	}
	::onig_region_free(pRegion, 1); // 1:free self, 0:free contents only
	return result;
error_done:
	::onig_region_free(pRegion, 1); // 1:free self, 0:free contents only
	return Value::Null;
}

static Value DoSub(Environment &env, Signal sig, regex_t *pRegEx,
							const TCHAR *repl, const TCHAR *str, int cnt)
{
	enum Stat { STAT_Start, STAT_Escape };
	size_t len = ::_tcslen(str);
	String result;
	OnigRegion *pRegion = ::onig_region_new();
	int pos = 0;
	for ( ; cnt != 0; cnt--) {
		int rtn = ::onig_search(pRegEx, str, str + len,
							str + pos, str + len, pRegion, ONIG_OPTION_NONE);
		if (rtn >= 0) {
			if (rtn < pos || pRegion->num_regs == 0 || pRegion->end[0] <= pos) {
				SetError_FailInOniguruma(sig);
				goto error_done;
			}
			result += String(str + pos, rtn - pos);
			Stat stat = STAT_Start;
			for (const TCHAR *p = repl; *p != _T('\0'); p++) {
				TCHAR ch = *p;
				if (stat == STAT_Start) {
					if (ch == _T('\\')) {
						stat = STAT_Escape;
					} else {
						result.push_back(*p);
					}
				} else if (stat == STAT_Escape) {
					if (IsDigit(ch)) {
						int iGroup = ch - _T('0');
						if (iGroup < pRegion->num_regs) {
							int posBegin = pRegion->beg[iGroup];
							int posEnd = pRegion->end[iGroup];
							result += String(str + posBegin, posEnd - posBegin);
						}
						stat = STAT_Start;
					} else {
						result.push_back(GetEscaped(ch));
						stat = STAT_Start;
					}
				}
			}
			pos = pRegion->end[0];
		} else if (rtn == ONIG_MISMATCH) {
			break;
		} else { // error
			SetError_OnigurumaError(sig, rtn);
			goto error_done;
		}
	}
	::onig_region_free(pRegion, 1); // 1:free self, 0:free contents only
	result += String(str + pos);
	return Value(env, result.c_str());
error_done:
	::onig_region_free(pRegion, 1); // 1:free self, 0:free contents only
	return Value::Null;
}

static Value DoSubWithFunc(Environment &env, Signal sig, regex_t *pRegEx,
						const Function *pFunc, const TCHAR *str, int cnt)
{
	enum Stat { STAT_Start, STAT_Escape };
	size_t len = ::_tcslen(str);
	String result;
	OnigRegion *pRegion = ::onig_region_new();
	int pos = 0;
	for ( ; cnt != 0; cnt--) {
		int rtn = ::onig_search(pRegEx, str, str + len,
							str + pos, str + len, pRegion, ONIG_OPTION_NONE);
		if (rtn >= 0) {
			Object_Match *pObj = new Object_Match(AScript_Class(Match, env));
			if (!pObj->SetMatchInfo(str, pRegEx, pRegion)) {
				SetError_FailInOniguruma(sig);
				delete pObj;
				goto error_done;
			}
			Value value(pObj, VTYPE_Object);
			Value resultFunc = pFunc->Eval(env, sig, Context(ValueList(value)));
			if (sig.IsSignalled()) goto error_done;
			result += String(str + pos, rtn - pos);
			result += resultFunc.ToString(sig, false);
			if (sig.IsSignalled()) goto error_done;
			pos = pRegion->end[0];
		} else if (rtn == ONIG_MISMATCH) {
			break;
		} else { // error
			SetError_OnigurumaError(sig, rtn);
			goto error_done;
		}
	}
	::onig_region_free(pRegion, 1); // 1:free self, 0:free contents only
	result += String(str + pos);
	return Value(env, result.c_str());
error_done:
	::onig_region_free(pRegion, 1); // 1:free self, 0:free contents only
	return Value::Null;
}

static Value DoSplit(Environment &env, Signal sig, regex_t *pRegEx, const TCHAR *str, int cnt)
{
	Value result;
	size_t len = ::_tcslen(str);
	ValueList &valList = result.InitAsList(env);
	OnigRegion *pRegion = ::onig_region_new();
	int pos = 0;
	for ( ; cnt != 0; cnt--) {
		int rtn = ::onig_search(pRegEx, str, str + len,
							str + pos, str + len, pRegion, ONIG_OPTION_NONE);
		if (rtn >= 0) {
			if (rtn < pos || pRegion->num_regs == 0 || pRegion->end[0] <= pos) {
				SetError_FailInOniguruma(sig);
				goto error_done;
			}
			valList.push_back(Value(env, String(str + pos, rtn - pos).c_str()));
			pos = pRegion->end[0];
		} else if (rtn == ONIG_MISMATCH) {
			break;
		} else { // error
			SetError_OnigurumaError(sig, rtn);
			goto error_done;
		}
	}
	::onig_region_free(pRegion, 1); // 1:free self, 0:free contents only
	valList.push_back(Value(env, String(str + pos).c_str()));
	return result;
error_done:
	::onig_region_free(pRegion, 1); // 1:free self, 0:free contents only
	return Value::Null;
}

void SetError_OnigurumaError(Signal sig, int rtn)
{
	TCHAR errMsg[ONIG_MAX_ERROR_MESSAGE_LEN];
	::onig_error_code_to_str(errMsg, rtn);
	sig.SetError(ERR_ValueError, _T("oniguruma: %s"), errMsg);
}

void SetError_FailInOniguruma(Signal sig)
{
	sig.SetError(ERR_SystemError,
				_T("something's wrong in the process of Oniguruma library"));
}

// Module entry
AScript_ModuleEntry()
{
	AScript_RealizePrivSymbol(re);
	AScript_RealizePrivSymbol(string);
	AScript_RealizePrivSymbol(multiline);
	AScript_AssignFunction(compile);
	AScript_AssignFunction(match);
	AScript_AssignFunction(matches);
	AScript_AssignFunction(sub);
	AScript_AssignFunction(split);
}

AScript_EndModule(re)

AScript_DLLModuleEntry(re)
