+}
+
+
+static script& pattern_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;
+}
+
+pattern::pattern(const std::string& pattern)
+{
+ pattern::string(pattern);
+}
+
+pattern::pattern(const std::string& pattern, const std::string& source)
+{
+ pattern::string(pattern);
+ match(source);
+}
+
+pattern::~pattern()
+{
+ script& script = pattern_script();
+ script.push_pointer(this);
+ script.push_nil();
+ script.globals().set_field();
+ script.push_pointer(this);
+ script.push_nil();
+ script.registry().set_field();
+}
+
+std::string pattern::string() const
+{
+ script& script = pattern_script();
+ script.push_pointer(this);
+ script::slot saved = script.registry().push_field();
+
+ std::string pattern;
+ saved.get(pattern);
+
+ saved.pop();
+ return pattern;
+}
+
+void pattern::string(const std::string& pattern)
+{
+ script& script = pattern_script();
+ script.push_pointer(this);
+ script.push(pattern);
+ script.registry().set_field();
+}
+
+void pattern::match(const std::string& source)
+{
+ script& script = pattern_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 pattern::get(std::string& match)
+{
+ script& script = pattern_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 pattern::get(std::vector<std::string>& captures)
+{
+ script& script = pattern_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 pattern::match(std::string& match,
+ const std::string& pattern, const std::string& source, int position)
+{
+ script& script = pattern_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 pattern::match(std::vector<std::string>& captures,
+ const std::string& pattern, const std::string& source, int position)
+{
+ script& script = pattern_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 pattern::sub(std::string& substitution,
+ const std::string& pattern,
+ const std::string& source, const std::string& replacement)
+{
+ script& script = pattern_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;