+}
+
+
+static script& regex_script()
+{
+ static script script;
+ static bool init = true;
+ if (init)
+ {
+ script.import_string_library();
+ script.globals().push_field("string").push_field("match");
+ script.globals().set_field("match");
+ script.top().push_field("gmatch");
+ script.globals().set_field("gmatch");
+ script.top().push_field("gsub");
+ script.globals().set_field("gsub");
+ script.push_nil();
+ script.globals().set_field("string");
+ script.pop();
+ init = false;
+ }
+ return script;
+}
+
+
+regex::regex(const string& pattern)
+{
+ regex::pattern(pattern);
+}
+
+regex::regex(const string& pattern, const string& source)
+{
+ regex::pattern(pattern);
+ match(source);
+}
+
+regex::~regex()
+{
+ script& script = regex_script();
+
+ script.push_pointer(this);
+ script.push_nil();
+ script.globals().set_field();
+ script.push_pointer(this);
+ script.push_nil();
+ script.registry().set_field();
+}
+
+
+string regex::pattern() const
+{
+ script& script = regex_script();
+ script.push_pointer(this);
+ script::slot saved = script.registry().push_field();
+
+ string pattern;
+ saved.get(pattern);
+
+ saved.pop();
+ return pattern;
+}
+
+void regex::pattern(const string& pattern)
+{
+ script& script = regex_script();
+ script.push_pointer(this);
+ script.push(pattern);
+ script.registry().set_field();
+}
+
+
+void regex::match(const string& source)
+{
+ script& script = regex_script();
+ script.push_pointer(this);
+
+ script.globals().push_field("gmatch");
+ script.push(source);
+ script.push_pointer(this);
+ script.registry().push_field();
+ script.call(2, 1);
+
+ script.globals().set_field();
+}
+
+bool regex::get(string& match)
+{
+ script& script = regex_script();
+ script.push_pointer(this);
+ script::slot value = script.globals().push_field();
+ if (!value.is_function())
+ {
+ script.clear_stack();
+ return false;
+ }
+
+ script.call(0, 1);
+ bool result = value.get(match);
+ script.pop();
+ return result;
+}
+
+bool regex::get(std::vector<string>& captures)
+{
+ script& script = regex_script();
+ script.push_pointer(this);
+ script::slot value = script.globals().push_field();
+ if (!value.is_function())
+ {
+ script.clear_stack();
+ return false;
+ }
+
+ script.call();
+ captures.clear();
+
+ while (value.is_string())
+ {
+ captures.resize(captures.size() + 1);
+ value.get(captures.back());
+ ++value.index;
+ }
+
+ script.clear_stack();
+ return 0 < captures.size();
+}
+
+
+bool regex::match(string& match,
+ const string& pattern,
+ const string& source,
+ int position)
+{
+ script& script = regex_script();
+
+ script::slot value = script.globals().push_field("match");
+ script.push(source);
+ script.push(pattern);
+ ++position; // Lua indices count from one.
+ script.push(position);
+ script.call(3, 1);
+
+ bool result = value.get(match);
+ script.clear_stack();
+ return result;
+}
+
+bool regex::match(std::vector<string>& captures,
+ const string& pattern,
+ const string& source,
+ int position)
+{
+ script& script = regex_script();
+
+ script::slot value = script.globals().push_field("match");
+ script.push(source);
+ script.push(pattern);
+ ++position; // Lua indices count from one.
+ script.push(position);
+ script.call(3);
+
+ captures.clear();
+
+ while (value.is_string())
+ {
+ captures.resize(captures.size() + 1);
+ value.get(captures.back());
+ ++value.index;
+ }
+
+ script.clear_stack();
+ return 0 < captures.size();
+}
+
+
+int regex::sub(string& substitution,
+ const string& pattern,
+ const string& source,
+ const string& replacement)
+{
+ script& script = regex_script();
+
+ script::slot value = script.globals().push_field("gsub");
+ script.push(source);
+ script.push(pattern);
+ script.push(replacement);
+ script.call(3, 2);
+
+ value.get(substitution);
+
+ ++value.index;
+ int count = 0;
+ value.get(count);
+
+ script.clear_stack();
+ return count;