diff --git a/jsconfig.json b/jsconfig.json
index 5ebfc59..f6bcfc4 100644
--- a/jsconfig.json
+++ b/jsconfig.json
@@ -1,6 +1,7 @@
 {
   "compilerOptions": {
     "checkJs": true,
-    "strict": true
+    "strict": true,
+    "lib": ["ES6", "DOM"]
   }
 }
diff --git a/notcl.js b/notcl.js
index c1f2308..fc43a8f 100644
--- a/notcl.js
+++ b/notcl.js
@@ -57,6 +57,8 @@ var Notcl = (() => {
     ([commands, _eof]) => commands
   );
 
+  const ERROR_CONTEXT = /(?<=([^\n]{0,50}))([^\n]{0,50})/y;
+
   return {
     /**
      * Parse out a Notcl script into an easier-to-interpret representation.
@@ -73,7 +75,21 @@ var Notcl = (() => {
       /* Parse */
       const commands = Script(code, 0);
 
-      return commands?.[0] ?? [];
+      if (commands[0]) {
+        return [true, commands[1]];
+      } else {
+        const errorPos = commands[1];
+        ERROR_CONTEXT.lastIndex = errorPos;
+        const [, before, after] = /** @type {RegExpExecArray} */ (
+          ERROR_CONTEXT.exec(code)
+        );
+        return [
+          false,
+          `Error at position ${commands[1]}
+${before}${after}
+${"-".repeat(before.length)}^`,
+        ];
+      }
     },
   };
 })();
diff --git a/peg.js b/peg.js
index 38a206c..e5677c0 100644
--- a/peg.js
+++ b/peg.js
@@ -7,7 +7,7 @@
  * @callback Peg.PatternCall
  * @param {string} source - the string being parsed
  * @param {number} index - the index in the string to begin matching from
- * @returns {[T, number] | null} - if successful, the captured value & the index to start parsing following symbols from. Else, null.
+ * @returns {[true, T, number] | [false, number]} - if successful, true, the captured value, and the index to start parsing following symbols from. Else, false, and the furthest index that could be understood.
  */
 /**
  * @template T
@@ -24,14 +24,14 @@ var Peg = window.Peg ?? {};
  * Makes a pattern from a function, adding helper methods.
  *
  * @template T
- * @param {(source: string, index: number) => ([T, number] | null)} pattern
+ * @param {(source: string, index: number) => ([true, T, number] | [false, number])} pattern
  * @returns {Peg.Pattern<T>}
  */
 Peg.WrapPattern = function (pattern) {
   /** @type {Peg.Pattern<T>} */ (pattern).map = function (map) {
     return Peg.WrapPattern(function (source, index) {
       const match = pattern(source, index);
-      return match ? [map(match[0]), match[1]] : null;
+      return match[0] ? [true, map(match[1]), match[2]] : [false, match[1]];
     });
   };
 
@@ -62,7 +62,7 @@ Peg.Regex = function (regex) {
   return Peg.WrapPattern(function (source, index) {
     regex.lastIndex = index;
     const matches = regex.exec(source);
-    return matches ? [matches, regex.lastIndex] : null;
+    return matches ? [true, matches, regex.lastIndex] : [false, index];
   });
 };
 
@@ -74,13 +74,16 @@ Peg.Regex = function (regex) {
  */
 Peg.Choose = function (...patterns) {
   return Peg.WrapPattern(function (source, index) {
+    let furthest = index;
     for (const pattern of patterns) {
       const match = pattern(source, index);
-      if (match) {
+      if (match[0]) {
         return match;
+      } else if (match[1] > furthest) {
+        furthest = match[1];
       }
     }
-    return null;
+    return [false, furthest];
   });
 };
 
@@ -98,13 +101,13 @@ Peg.Sequence = function (...patterns) {
     const values = /** @type {T} */ (/** @type {unknown} */ ([]));
     for (const pattern of patterns) {
       const match = pattern(source, index);
-      if (match == null) {
-        return null;
+      if (match[0] == false) {
+        return match;
       }
-      values.push(match[0]);
-      index = match[1];
+      values.push(match[1]);
+      index = match[2];
     }
-    return [values, index];
+    return [true, values, index];
   });
 };
 
@@ -124,17 +127,24 @@ Peg.Sequence = function (...patterns) {
 Peg.AtLeast = function (min, pattern) {
   return Peg.WrapPattern(function (source, index) {
     const values = /** @type {T[]} */ ([]);
+    let furthest = index;
     do {
       const match = pattern(source, index);
-      if (match == null) break;
-      values.push(match[0]);
-      if (index == match[1]) break;
-      index = match[1];
+      if (match[0] == false) {
+        furthest = match[1];
+        break;
+      }
+      values.push(match[1]);
+      if (index == match[2]) {
+        furthest = match[2];
+        break;
+      }
+      index = match[2];
     } while (true);
     if (values.length >= min) {
-      return [values, index];
+      return [true, values, index];
     } else {
-      return null;
+      return [false, furthest];
     }
   });
 };
@@ -145,8 +155,8 @@ Peg.AtLeast = function (min, pattern) {
  */
 Peg.End = Peg.WrapPattern(function End(source, index) {
   if (source.length == index) {
-    return [true, index];
+    return [true, true, index];
   } else {
-    return null;
+    return [false, index];
   }
 });