diff --git a/index.html b/index.html
index f9c3689..7a0e9e4 100644
--- a/index.html
+++ b/index.html
@@ -6,6 +6,7 @@
+
diff --git a/notcl.js b/notcl.js
index 6ae8e6e..180d15c 100644
--- a/notcl.js
+++ b/notcl.js
@@ -5,91 +5,18 @@
* @property {string} text
*/
-/**
- * A Pattern is a function that matches against a string starting at a given index.
- *
- * If it matches successfully, it returns some captured value, and the index following the match.
- *
- * @template T
- * @typedef {(source: string, index: number) => ([T, number] | null)} Pattern
- */
+const InterCommandWhitespace = Peg.Regex(/[^\S\n;]*/y);
-/**
- * Creates a pattern that wraps another pattern, transforming the returned value on a match
- * @template T, U
- * @param {Pattern} pattern
- * @param {(value: T)=> U} map
- * @return {Pattern}
- */
-function MapPattern(pattern, map) {
- return function (source, index) {
- const match = pattern(source, index);
- return match ? [map(match[0]), match[1]] : null;
- };
-}
+const CommentPattern = Peg.Regex(/#.*\n/y);
-/**
- * Creates a pattern matching a regex & returning any captures. The regex needs to be sticky (using the //y modifier)
- * @param {RegExp} regex
- * @return {Pattern}
- */
-function RegexPattern(regex) {
- return function (source, index) {
- regex.lastIndex = index;
- const matches = regex.exec(source);
- return matches ? [matches, regex.lastIndex] : null;
- };
-}
+const PreWordWhitespace = Peg.Regex(/[^\S\n;]*/y);
-/**
- * @template T
- * @param {...Pattern} patterns
- * @return {Pattern}
- */
-function Choose(...patterns) {
- return function (source, index) {
- for (const pattern of patterns) {
- const match = pattern(source, index);
- if (match) {
- return match;
- }
- }
- return null;
- };
-}
-
-/**
- * @template {unknown[]} T
- * @param {{[K in keyof T]: Pattern}} patterns
- * @return {Pattern}
- */
-function Sequence(...patterns) {
- return function (source, index) {
- const values = /** @type {T} */ (/** @type {unknown} */ ([]));
- for (const pattern of patterns) {
- const match = pattern(source, index);
- if (match == null) {
- return null;
- }
- values.push(match[0]);
- index = match[1];
- }
- return [values, index];
- };
-}
-
-const InterCommandWhitespace = RegexPattern(/[^\S\n;]*/y);
-
-const CommentPattern = RegexPattern(/#.*\n/y);
-
-const PreWordWhitespace = RegexPattern(/[^\S\n;]*/y);
-
-const BasicWord = MapPattern(RegexPattern(/[^\s;]+/y), ([word]) => ({
+const BasicWord = Peg.Map(Peg.Regex(/[^\s;]+/y), ([word]) => ({
text: word,
}));
-const WordPattern = MapPattern(
- Sequence(PreWordWhitespace, BasicWord),
+const WordPattern = Peg.Map(
+ Peg.Sequence(PreWordWhitespace, BasicWord),
([_, word]) => word
);
diff --git a/peg.js b/peg.js
new file mode 100644
index 0000000..0b82fe7
--- /dev/null
+++ b/peg.js
@@ -0,0 +1,73 @@
+/**
+ * A Pattern is a function that matches against a string starting at a given index.
+ *
+ * If it matches successfully, it returns some captured value, and the index following the match.
+ *
+ * @template T
+ * @typedef {(source: string, index: number) => ([T, number] | null)} Peg.Pattern
+ */
+var Peg = {
+ /**
+ * Creates a pattern that wraps another pattern, transforming the returned value on a match
+ * @template T, U
+ * @param {Peg.Pattern} pattern
+ * @param {(value: T)=> U} map
+ * @return {Peg.Pattern}
+ */
+ Map(pattern, map) {
+ return function (source, index) {
+ const match = pattern(source, index);
+ return match ? [map(match[0]), match[1]] : null;
+ };
+ },
+
+ /**
+ * Creates a pattern matching a regex & returning any captures. The regex needs to be sticky (using the //y modifier)
+ * @param {RegExp} regex
+ * @return {Peg.Pattern}
+ */
+ Regex(regex) {
+ return function (source, index) {
+ regex.lastIndex = index;
+ const matches = regex.exec(source);
+ return matches ? [matches, regex.lastIndex] : null;
+ };
+ },
+
+ /**
+ * @template T
+ * @param {...Peg.Pattern} patterns
+ * @return {Peg.Pattern}
+ */
+ Choose(...patterns) {
+ return function (source, index) {
+ for (const pattern of patterns) {
+ const match = pattern(source, index);
+ if (match) {
+ return match;
+ }
+ }
+ return null;
+ };
+ },
+
+ /**
+ * @template {unknown[]} T
+ * @param {{[K in keyof T]: Peg.Pattern}} patterns
+ * @return {Peg.Pattern}
+ */
+ Sequence(...patterns) {
+ return function (source, index) {
+ const values = /** @type {T} */ (/** @type {unknown} */ ([]));
+ for (const pattern of patterns) {
+ const match = pattern(source, index);
+ if (match == null) {
+ return null;
+ }
+ values.push(match[0]);
+ index = match[1];
+ }
+ return [values, index];
+ };
+ },
+};