Repository: source-academy/js-slang
Pull request #192 (2019-03-04 07:32:05)

Implement partial parsing of program to obtain first line
Rationale: Syntax error or broken rule occurring anywhere within the program previously meant the entire program could not be parsed. This would mean that we cannot check for the verbose toggle in the first line, so we cannot provide elaborated versions of the syntax error messages, even if the student requested it. This pull request makes it such that the first line of the program will always be parsed regardless of the rest of the program.

coveralls: ## Pull Request Test Coverage Report for [Build 811](https://coveralls.io/builds/21964107)

* **16** of **17**   **(94.12%)**  changed or added relevant lines in **2** files are covered.
* No unchanged relevant lines lost coverage.
* Overall coverage decreased (**-0.07%**) to **92.954%**

---

|  Changes Missing Coverage | Covered Lines | Changed/Added Lines | % |
| :-----|--------------|--------|---: |
| [src/parser.ts](https://coveralls.io/builds/21964107/source?filename=src%2Fparser.ts#L111) | 8 | 9 | 88.89%
<!-- | **Total:** | **16** | **17** | **94.12%** | -->


|  Totals | [![Coverage Status](https://coveralls.io/builds/21964107/badge)](https://coveralls.io/builds/21964107) |
| :-- | --: |
| Change from base [Build 806](https://coveralls.io/builds/21960599): |  -0.07% |
| Covered Lines: | 1573 |
| Relevant Lines: | 1677 |

---
##### 💛  - [Coveralls](https://coveralls.io)


Patch:
diff --git a/src/index.ts b/src/index.ts
index 85b3d38d..93e3aca0 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,4 +1,4 @@
-import { ExpressionStatement, Program } from 'estree'
+import { Literal } from 'estree'
 import { RawSourceMap, SourceMapConsumer } from 'source-map'
 import { JSSLANG_PROPERTIES, UNKNOWN_LOCATION } from './constants'
 import createContext from './createContext'
@@ -10,18 +10,10 @@ import {
   RuntimeSourceError,
   UndefinedVariable
 } from './interpreter-errors'
-import { parse } from './parser'
+import { parse, parseAt } from './parser'
 import { AsyncScheduler, PreemptiveScheduler } from './schedulers'
 import { transpile } from './transpiler'
-import {
-  Context,
-  Directive,
-  Error as ResultError,
-  Finished,
-  Result,
-  Scheduler,
-  SourceError
-} from './types'
+import { Context, Error as ResultError, Finished, Result, Scheduler, SourceError } from './types'
 import { locationDummyNode } from './utils/astCreator'
 import { sandboxedEval } from './utils/evalContainer'
 
@@ -115,22 +107,21 @@ export function runInContext(
   context: Context,
   options: Partial<IOptions> = {}
 ): Promise<Result> {
-  function getFirstLine(theProgram: Program) {
-    if (theProgram.body[0] && theProgram.body[0].type === 'ExpressionStatement') {
-      const firstLineOfProgram = theProgram.body[0] as ExpressionStatement
-      const theDirective = (firstLineOfProgram as Directive).directive
-      if (theDirective !== undefined) {
-        return theDirective
-      }
+  function getFirstLine(theCode: string) {
+    const theProgramFirstExpression = parseAt(theCode, 0)
+
+    if (theProgramFirstExpression && theProgramFirstExpression.type === 'Literal') {
+      return ((theProgramFirstExpression as unknown) as Literal).value
     }
 
     return undefined
   }
   const theOptions: IOptions = { ...DEFAULT_OPTIONS, ...options }
   context.errors = []
+
+  verboseErrors = getFirstLine(code) === 'enable verbose'
   const program = parse(code, context)
   if (program) {
-    verboseErrors = getFirstLine(program) === 'enable verbose'
     if (theOptions.isNativeRunnable) {
       if (previousCode === code) {
         JSSLANG_PROPERTIES.maxExecTime *= JSSLANG_PROPERTIES.factorToIncreaseBy
diff --git a/src/parser.ts b/src/parser.ts
index 7de216e9..7b8edc32 100644
--- a/src/parser.ts
+++ b/src/parser.ts
@@ -1,5 +1,10 @@
 /* tslint:disable:max-classes-per-file */
-import { Options as AcornOptions, parse as acornParse, Position } from 'acorn'
+import {
+  Options as AcornOptions,
+  parse as acornParse,
+  parseExpressionAt as acornParseAt,
+  Position
+} from 'acorn'
 import { ancestor, AncestorWalker } from 'acorn-walk/dist/walk'
 import { stripIndent } from 'common-tags'
 import * as es from 'estree'
@@ -26,7 +31,7 @@ export class DisallowedConstructError implements SourceError {
 
   public elaborate() {
     return stripIndent`
-      You are trying to use ${this.nodeType}, which is not yet allowed (yet).
+      You are trying to use ${this.nodeType}, which is not allowed (yet).
     `
   }
 
@@ -92,6 +97,16 @@ export class TrailingCommaError implements SourceError {
   }
 }
 
+export function parseAt(source: string, num: number) {
+  let theNode: acorn.Node | undefined
+  try {
+    theNode = acornParseAt(source, num)
+  } catch (error) {
+    return undefined
+  }
+  return theNode
+}
+
 export function parse(source: string, context: Context) {
   let program: es.Program | undefined
   try {


Test patch:
diff --git a/src/__tests__/__snapshots__/disallowed-syntax.ts.snap b/src/__tests__/__snapshots__/disallowed-syntax.ts.snap
index 6770847e..4cd0ac6a 100644
--- a/src/__tests__/__snapshots__/disallowed-syntax.ts.snap
+++ b/src/__tests__/__snapshots__/disallowed-syntax.ts.snap
@@ -94,7 +94,13 @@ Object {
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 2: Missing \\"else\\" in \\"if-else\\" statement.",
+  "parsedErrors": "Line 2, Column 1: Missing \\"else\\" in \\"if-else\\" statement.
+This \\"if\\" block requires corresponding \\"else\\" block which will be
+evaluated when true expression evaluates to false.
+
+Later in the course we will lift this restriction and allow \\"if\\" without
+else.
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -223,7 +229,9 @@ Object {
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 2: Missing semicolon at the end of statement",
+  "parsedErrors": "Line 2, Column 1: Missing semicolon at the end of statement
+Every statement must be terminated by a semicolon.
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -328,7 +336,9 @@ break;
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 2: Missing init, test, update expressions in for statement.",
+  "parsedErrors": "Line 2, Column 1: Missing init, test, update expressions in for statement.
+This for statement requires all three parts (initialiser, test, update) to be present.
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -607,7 +617,9 @@ break;
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 2: Missing init expression in for statement.",
+  "parsedErrors": "Line 2, Column 1: Missing init expression in for statement.
+This for statement requires all three parts (initialiser, test, update) to be present.
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -1029,7 +1041,9 @@ break;
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 2: Missing test expression in for statement.",
+  "parsedErrors": "Line 2, Column 1: Missing test expression in for statement.
+This for statement requires all three parts (initialiser, test, update) to be present.
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -1436,7 +1450,9 @@ Object {
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 2: Missing update expression in for statement.",
+  "parsedErrors": "Line 2, Column 3: Missing update expression in for statement.
+This for statement requires all three parts (initialiser, test, update) to be present.
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -1655,7 +1671,9 @@ Object {
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 2: SyntaxError: Unexpected token (2:7)",
+  "parsedErrors": "Line 2, Column 7: SyntaxError: Unexpected token (2:7)
+There is a syntax error in your program
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -1756,7 +1774,11 @@ x;",
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 3: Assignment inside an expression is not allowed. Only assignment in a statement is allowed.",
+  "parsedErrors": "Line 3, Column 8: Assignment inside an expression is not allowed. Only assignment in a statement is allowed.
+Try moving this to another line:
+
+	x = 5;
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -1827,7 +1849,11 @@ x;",
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 4: Assignment inside an expression is not allowed. Only assignment in a statement is allowed.",
+  "parsedErrors": "Line 4, Column 4: Assignment inside an expression is not allowed. Only assignment in a statement is allowed.
+Try moving this to another line:
+
+	y = 5;
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -1984,8 +2010,16 @@ Object {
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 5: Assignment inside an expression is not allowed. Only assignment in a statement is allowed.
-Line 5: Assignment inside an expression is not allowed. Only assignment in a statement is allowed.",
+  "parsedErrors": "Line 5, Column 9: Assignment inside an expression is not allowed. Only assignment in a statement is allowed.
+Try moving this to another line:
+
+	z = 6;
+
+Line 5, Column 5: Assignment inside an expression is not allowed. Only assignment in a statement is allowed.
+Try moving this to another line:
+
+	y = 6;
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -2056,7 +2090,11 @@ for (let x = y = 1; x < 1; x = x + 1) {
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 3: Assignment inside an expression is not allowed. Only assignment in a statement is allowed.",
+  "parsedErrors": "Line 3, Column 13: Assignment inside an expression is not allowed. Only assignment in a statement is allowed.
+Try moving this to another line:
+
+	y = 1;
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -2493,7 +2531,9 @@ a;",
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 3: Array patterns are not allowed",
+  "parsedErrors": "Line 3, Column 4: Array patterns are not allowed
+You are trying to use Array patterns, which is not allowed (yet).
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -2926,7 +2966,9 @@ Object {
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 2: Function expressions are not allowed",
+  "parsedErrors": "Line 2, Column 1: Function expressions are not allowed
+You are trying to use Function expressions, which is not allowed (yet).
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -3063,7 +3105,9 @@ Object {
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 2: Function expressions are not allowed",
+  "parsedErrors": "Line 2, Column 1: Function expressions are not allowed
+You are trying to use Function expressions, which is not allowed (yet).
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -3825,7 +3869,13 @@ x;",
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 2: Multiple declaration in a single statement.",
+  "parsedErrors": "Line 2, Column 0: Multiple declaration in a single statement.
+Split the variable declaration into multiple lines as follows
+
+	let x = 3;
+	let y = 5;
+
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -4143,7 +4193,9 @@ x;",
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 3: Update expressions are not allowed",
+  "parsedErrors": "Line 3, Column 0: Update expressions are not allowed
+You are trying to use Update expressions, which is not allowed (yet).
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -4267,7 +4319,10 @@ Object {
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 3: The assignment operator += is not allowed. Use = instead.",
+  "parsedErrors": "Line 3, Column 1: The assignment operator += is not allowed. Use = instead.
+
+	x = x + 5;
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -4337,7 +4392,9 @@ x;",
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 3: The assignment operator <<= is not allowed. Use = instead.",
+  "parsedErrors": "Line 3, Column 0: The assignment operator <<= is not allowed. Use = instead.
+
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -4511,7 +4568,9 @@ Object {
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 2: Array expressions are not allowed",
+  "parsedErrors": "Line 2, Column 0: Array expressions are not allowed
+You are trying to use Array expressions, which is not allowed (yet).
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -4581,7 +4640,9 @@ Object {
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 2: Empty statements are not allowed",
+  "parsedErrors": "Line 2, Column 2: Empty statements are not allowed
+You are trying to use Empty statements, which is not allowed (yet).
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -4669,7 +4730,9 @@ return rest;
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 2: Rest elements are not allowed",
+  "parsedErrors": "Line 2, Column 12: Rest elements are not allowed
+You are trying to use Rest elements, which is not allowed (yet).
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -4811,7 +4874,9 @@ return x + y;
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 5: Spread elements are not allowed",
+  "parsedErrors": "Line 5, Column 3: Spread elements are not allowed
+You are trying to use Spread elements, which is not allowed (yet).
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -5252,7 +5317,13 @@ i;",
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 2: Missing curly braces around \\"for\\" block.",
+  "parsedErrors": "Line 2, Column 1: Missing curly braces around \\"for\\" block.
+Remember to enclose your \\"for\\" block with braces:
+
+ 	for (let i = 0; i < 1; i = i + 1) {
+		//code goes here
+	}
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -5733,8 +5804,64 @@ false;",
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 2: Missing curly braces around \\"if\\" block.
-Line 2: Missing curly braces around \\"else\\" block.",
+  "parsedErrors": "Line 2, Column 1: Missing curly braces around \\"if\\" block.
+if block need to be enclosed with a pair of curly braces.
+
+if (true) {
+  true;
+}
+
+An exception is when you have an \\"if\\" followed by \\"else if\\", in this case
+\\"else if\\" block does not need to be surrounded by curly braces.
+
+if (someCondition) {
+  // ...
+} else /* notice missing { here */ if (someCondition) {
+  // ...
+} else {
+  // ...
+}
+
+Rationale: Readability in dense packed code.
+
+In the snippet below, for instance, with poor indentation it is easy to
+mistaken hello() and world() to belong to the same branch of logic.
+
+if (someCondition) {
+  2;
+} else
+  hello();
+world();
+
+Line 2, Column 1: Missing curly braces around \\"else\\" block.
+else block need to be enclosed with a pair of curly braces.
+
+else {
+  false;
+}
+
+An exception is when you have an \\"if\\" followed by \\"else if\\", in this case
+\\"else if\\" block does not need to be surrounded by curly braces.
+
+if (someCondition) {
+  // ...
+} else /* notice missing { here */ if (someCondition) {
+  // ...
+} else {
+  // ...
+}
+
+Rationale: Readability in dense packed code.
+
+In the snippet below, for instance, with poor indentation it is easy to
+mistaken hello() and world() to belong to the same branch of logic.
+
+if (someCondition) {
+  2;
+} else
+  hello();
+world();
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -5984,7 +6111,9 @@ Object {
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 2: SyntaxError: The keyword 'package' is reserved (2:3)",
+  "parsedErrors": "Line 2, Column 3: SyntaxError: The keyword 'package' is reserved (2:3)
+There is a syntax error in your program
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -6103,8 +6232,12 @@ class Box {
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 2: Class bodys are not allowed
-Line 2: Class declarations are not allowed",
+  "parsedErrors": "Line 2, Column 10: Class bodys are not allowed
+You are trying to use Class bodys, which is not allowed (yet).
+
+Line 2, Column 0: Class declarations are not allowed
+You are trying to use Class declarations, which is not allowed (yet).
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -6229,7 +6362,9 @@ Object {
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 2: Debugger statements are not allowed",
+  "parsedErrors": "Line 2, Column 3: Debugger statements are not allowed
+You are trying to use Debugger statements, which is not allowed (yet).
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -6298,7 +6433,14 @@ Object {
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 2: Missing value in variable declaration.",
+  "parsedErrors": "Line 2, Column 5: Missing value in variable declaration.
+A variable declaration assigns a value to a name.
+For instance, to assign 20 to x, you can write:
+
+  let x = 20;
+
+  x + x; // 40
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -6362,7 +6504,9 @@ let yield = 5;",
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 2: SyntaxError: The keyword 'yield' is reserved (2:4)",
+  "parsedErrors": "Line 2, Column 4: SyntaxError: The keyword 'yield' is reserved (2:4)
+There is a syntax error in your program
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -6494,7 +6638,9 @@ export const x = 1;",
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 2: Export named declarations are not allowed",
+  "parsedErrors": "Line 2, Column 0: Export named declarations are not allowed
+You are trying to use Export named declarations, which is not allowed (yet).
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -6648,7 +6794,9 @@ export default x;",
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 3: Export default declarations are not allowed",
+  "parsedErrors": "Line 3, Column 0: Export default declarations are not allowed
+You are trying to use Export default declarations, which is not allowed (yet).
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -6837,7 +6985,9 @@ return x;
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 2: Export named declarations are not allowed",
+  "parsedErrors": "Line 2, Column 1: Export named declarations are not allowed
+You are trying to use Export named declarations, which is not allowed (yet).
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -7217,8 +7367,17 @@ for (let i in { a: 1, b: 2 }) {
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 2: Missing value in variable declaration.
-Line 2: For in statements are not allowed",
+  "parsedErrors": "Line 2, Column 9: Missing value in variable declaration.
+A variable declaration assigns a value to a name.
+For instance, to assign 20 to i, you can write:
+
+  let i = 20;
+
+  i + i; // 40
+
+Line 2, Column 0: For in statements are not allowed
+You are trying to use For in statements, which is not allowed (yet).
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -7615,8 +7774,17 @@ Object {
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 2: Missing value in variable declaration.
-Line 2: For of statements are not allowed",
+  "parsedErrors": "Line 2, Column 12: Missing value in variable declaration.
+A variable declaration assigns a value to a name.
+For instance, to assign 20 to i, you can write:
+
+  let i = 20;
+
+  i + i; // 40
+
+Line 2, Column 3: For of statements are not allowed
+You are trying to use For of statements, which is not allowed (yet).
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -7826,7 +7994,9 @@ return 1;
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 3: Yield expressions are not allowed",
+  "parsedErrors": "Line 3, Column 0: Yield expressions are not allowed
+You are trying to use Yield expressions, which is not allowed (yet).
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -7918,7 +8088,12 @@ Object {
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 3: Missing value in return statement.",
+  "parsedErrors": "Line 3, Column 5: Missing value in return statement.
+This return statement is missing a value.
+For instance, to return the value 42, you can write
+
+  return 42;
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -8107,8 +8282,12 @@ import { stripIndent } from 'common-tags';",
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 2: Import specifiers are not allowed
-Line 2: Import declarations are not allowed",
+  "parsedErrors": "Line 2, Column 9: Import specifiers are not allowed
+You are trying to use Import specifiers, which is not allowed (yet).
+
+Line 2, Column 0: Import declarations are not allowed
+You are trying to use Import declarations, which is not allowed (yet).
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -8292,7 +8471,9 @@ interface Box {
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 2: SyntaxError: The keyword 'interface' is reserved (2:0)",
+  "parsedErrors": "Line 2, Column 0: SyntaxError: The keyword 'interface' is reserved (2:0)
+There is a syntax error in your program
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -8377,8 +8558,12 @@ Object {
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 3: Missing semicolon at the end of statement
-Line 3: 'RegExp' literals are not allowed.",
+  "parsedErrors": "Line 3, Column 10: Missing semicolon at the end of statement
+Every statement must be terminated by a semicolon.
+
+Line 3, Column 1: 'RegExp' literals are not allowed.
+
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -8464,7 +8649,9 @@ return x;
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 2: SyntaxError: Argument name clash (2:15)",
+  "parsedErrors": "Line 2, Column 15: SyntaxError: Argument name clash (2:15)
+There is a syntax error in your program
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -8566,7 +8753,9 @@ Object {
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 2: Sequence expressions are not allowed",
+  "parsedErrors": "Line 2, Column 1: Sequence expressions are not allowed
+You are trying to use Sequence expressions, which is not allowed (yet).
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -9278,11 +9467,21 @@ constructor() {
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 4: Supers are not allowed
-Line 3: Function expressions are not allowed
-Line 3: Method definitions are not allowed
-Line 2: Class bodys are not allowed
-Line 2: Class declarations are not allowed",
+  "parsedErrors": "Line 4, Column 2: Supers are not allowed
+You are trying to use Supers, which is not allowed (yet).
+
+Line 3, Column 11: Function expressions are not allowed
+You are trying to use Function expressions, which is not allowed (yet).
+
+Line 3, Column 0: Method definitions are not allowed
+You are trying to use Method definitions, which is not allowed (yet).
+
+Line 2, Column 30: Class bodys are not allowed
+You are trying to use Class bodys, which is not allowed (yet).
+
+Line 2, Column 1: Class declarations are not allowed
+You are trying to use Class declarations, which is not allowed (yet).
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -9957,7 +10156,9 @@ Object {
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 3: Missing semicolon at the end of statement",
+  "parsedErrors": "Line 3, Column 5: Missing semicolon at the end of statement
+Every statement must be terminated by a semicolon.
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -10093,7 +10294,9 @@ this[0] = 5;
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 3: 'this' expressions are not allowed",
+  "parsedErrors": "Line 3, Column 0: 'this' expressions are not allowed
+You are trying to use 'this' expressions, which is not allowed (yet).
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -10604,9 +10807,15 @@ display(e);
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 6: Spread elements are not allowed
-Line 7: Catch clauses are not allowed
-Line 5: Try statements are not allowed",
+  "parsedErrors": "Line 6, Column 2: Spread elements are not allowed
+You are trying to use Spread elements, which is not allowed (yet).
+
+Line 7, Column 3: Catch clauses are not allowed
+You are trying to use Catch clauses, which is not allowed (yet).
+
+Line 5, Column 1: Try statements are not allowed
+You are trying to use Try statements, which is not allowed (yet).
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -11151,7 +11360,9 @@ Object {
       "unspecifiedOperator": "<<",
     },
   ],
-  "parsedErrors": "Line 2: Operator '<<' is not allowed.",
+  "parsedErrors": "Line 2, Column 0: Operator '<<' is not allowed.
+
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -11274,7 +11485,9 @@ typeof x;",
       "unspecifiedOperator": "typeof",
     },
   ],
-  "parsedErrors": "Line 3: Operator 'typeof' is not allowed.",
+  "parsedErrors": "Line 3, Column 0: Operator 'typeof' is not allowed.
+
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
@@ -11508,7 +11721,13 @@ i = i + 1;",
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 3: Missing curly braces around \\"while\\" block.",
+  "parsedErrors": "Line 3, Column 1: Missing curly braces around \\"while\\" block.
+Remember to enclose your \\"while\\" block with braces:
+
+ 	while (i < 1) {
+		//code goes here
+	}
+",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
diff --git a/src/__tests__/__snapshots__/interpreter-errors.ts.snap b/src/__tests__/__snapshots__/interpreter-errors.ts.snap
index 7ad47861..496c1455 100644
--- a/src/__tests__/__snapshots__/interpreter-errors.ts.snap
+++ b/src/__tests__/__snapshots__/interpreter-errors.ts.snap
@@ -1284,9 +1284,7 @@ Object {
       "type": "Syntax",
     },
   ],
-  "parsedErrors": "Line 1, Column 0: null literals are not allowed.
-They're not part of the Source §1 specs.
-",
+  "parsedErrors": "Line 1: null literals are not allowed.",
   "result": undefined,
   "resultStatus": "error",
   "visualiseListResult": Array [],
diff --git a/src/__tests__/disallowed-syntax.ts b/src/__tests__/disallowed-syntax.ts
index 13fcd50e..26945dd0 100644
--- a/src/__tests__/disallowed-syntax.ts
+++ b/src/__tests__/disallowed-syntax.ts
@@ -20,7 +20,11 @@ test('Cannot leave blank init in for loop - verbose', () => {
 	  }
 	`,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 2: Missing init expression in for statement."`)
+  ).toMatchInlineSnapshot(`
+"Line 2, Column 1: Missing init expression in for statement.
+This for statement requires all three parts (initialiser, test, update) to be present.
+"
+`)
 })
 
 test('Cannot leave blank test in for loop', () => {
@@ -43,7 +47,11 @@ test('Cannot leave blank test in for loop - verbose', () => {
 	  }
 	`,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 2: Missing test expression in for statement."`)
+  ).toMatchInlineSnapshot(`
+"Line 2, Column 1: Missing test expression in for statement.
+This for statement requires all three parts (initialiser, test, update) to be present.
+"
+`)
 })
 
 test('Cannot leave blank update in for loop', () => {
@@ -66,7 +74,11 @@ test('Cannot leave blank update in for loop - verbose', () => {
     }
   `,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 2: Missing update expression in for statement."`)
+  ).toMatchInlineSnapshot(`
+"Line 2, Column 3: Missing update expression in for statement.
+This for statement requires all three parts (initialiser, test, update) to be present.
+"
+`)
 })
 
 test('Cannot leave blank expressions in for loop', () => {
@@ -89,7 +101,11 @@ test('Cannot leave blank expressions in for loop - verbose', () => {
 	  }
 	`,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 2: Missing init, test, update expressions in for statement."`)
+  ).toMatchInlineSnapshot(`
+"Line 2, Column 1: Missing init, test, update expressions in for statement.
+This for statement requires all three parts (initialiser, test, update) to be present.
+"
+`)
 })
 
 test('Cannot leave while loop predicate blank', () => {
@@ -112,7 +128,11 @@ test('Cannot leave while loop predicate blank - verbose', () => {
   }
   `,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 2: SyntaxError: Unexpected token (2:7)"`)
+  ).toMatchInlineSnapshot(`
+"Line 2, Column 7: SyntaxError: Unexpected token (2:7)
+There is a syntax error in your program
+"
+`)
 })
 
 test('Cannot use update expressions', () => {
@@ -135,7 +155,11 @@ test('Cannot use update expressions - verbose', () => {
 	x;
 	`,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 3: Update expressions are not allowed"`)
+  ).toMatchInlineSnapshot(`
+"Line 3, Column 0: Update expressions are not allowed
+You are trying to use Update expressions, which is not allowed (yet).
+"
+`)
 })
 
 test('Cannot have incomplete statements', () => {
@@ -154,7 +178,11 @@ test('Cannot have incomplete statements - verbose', () => {
 	5
 	`,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 2: Missing semicolon at the end of statement"`)
+  ).toMatchInlineSnapshot(`
+"Line 2, Column 1: Missing semicolon at the end of statement
+Every statement must be terminated by a semicolon.
+"
+`)
 })
 
 test('Cannot have if without else', () => {
@@ -173,7 +201,15 @@ test('Cannot have if without else - verbose', () => {
   if (true) { 5; }
   `,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 2: Missing \\"else\\" in \\"if-else\\" statement."`)
+  ).toMatchInlineSnapshot(`
+"Line 2, Column 1: Missing \\"else\\" in \\"if-else\\" statement.
+This \\"if\\" block requires corresponding \\"else\\" block which will be
+evaluated when true expression evaluates to false.
+
+Later in the course we will lift this restriction and allow \\"if\\" without
+else.
+"
+`)
 })
 
 test('Cannot use assignment expressions', () => {
@@ -198,9 +234,13 @@ test('Cannot use assignment expressions - verbose', () => {
 	x;
 	`,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(
-    `"Line 3: Assignment inside an expression is not allowed. Only assignment in a statement is allowed."`
-  )
+  ).toMatchInlineSnapshot(`
+"Line 3, Column 8: Assignment inside an expression is not allowed. Only assignment in a statement is allowed.
+Try moving this to another line:
+
+	x = 5;
+"
+`)
 })
 
 test('Cannot use assignment expressions', () => {
@@ -227,9 +267,13 @@ test('Cannot use assignment expressions - verbose', () => {
 	x;
 	`,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(
-    `"Line 4: Assignment inside an expression is not allowed. Only assignment in a statement is allowed."`
-  )
+  ).toMatchInlineSnapshot(`
+"Line 4, Column 4: Assignment inside an expression is not allowed. Only assignment in a statement is allowed.
+Try moving this to another line:
+
+	y = 5;
+"
+`)
 })
 
 test('Cannot use assignment expressions', () => {
@@ -260,8 +304,16 @@ test('Cannot use assignment expressions - verbose', () => {
 	  `,
     { chapter: 100 }
   ).toMatchInlineSnapshot(`
-"Line 5: Assignment inside an expression is not allowed. Only assignment in a statement is allowed.
-Line 5: Assignment inside an expression is not allowed. Only assignment in a statement is allowed."
+"Line 5, Column 9: Assignment inside an expression is not allowed. Only assignment in a statement is allowed.
+Try moving this to another line:
+
+	z = 6;
+
+Line 5, Column 5: Assignment inside an expression is not allowed. Only assignment in a statement is allowed.
+Try moving this to another line:
+
+	y = 6;
+"
 `)
 })
 
@@ -289,9 +341,13 @@ test('Cannot use assignment expressions - verbose', () => {
 	}
 	`,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(
-    `"Line 3: Assignment inside an expression is not allowed. Only assignment in a statement is allowed."`
-  )
+  ).toMatchInlineSnapshot(`
+"Line 3, Column 13: Assignment inside an expression is not allowed. Only assignment in a statement is allowed.
+Try moving this to another line:
+
+	y = 1;
+"
+`)
 })
 
 test('Cannot use multiple declarations', () => {
@@ -312,7 +368,15 @@ test('Cannot use multiple declarations - verbose', () => {
 	x;
 	`,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 2: Multiple declaration in a single statement."`)
+  ).toMatchInlineSnapshot(`
+"Line 2, Column 0: Multiple declaration in a single statement.
+Split the variable declaration into multiple lines as follows
+
+	let x = 3;
+	let y = 5;
+
+"
+`)
 })
 
 test('Cannot use destructuring declarations', () => {
@@ -335,7 +399,11 @@ test('Cannot use destructuring declarations - verbose', () => {
 	a;
 	`,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 3: Array patterns are not allowed"`)
+  ).toMatchInlineSnapshot(`
+"Line 3, Column 4: Array patterns are not allowed
+You are trying to use Array patterns, which is not allowed (yet).
+"
+`)
 })
 
 test('no declaration without assignment', () => {
@@ -354,7 +422,16 @@ test('no declaration without assignment - verbose', () => {
   let x;
   `,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 2: Missing value in variable declaration."`)
+  ).toMatchInlineSnapshot(`
+"Line 2, Column 5: Missing value in variable declaration.
+A variable declaration assigns a value to a name.
+For instance, to assign 20 to x, you can write:
+
+  let x = 20;
+
+  x + x; // 40
+"
+`)
 })
 
 test('Cannot use update statements', () => {
@@ -377,7 +454,12 @@ test('Cannot use update statements - verbose', () => {
   x;
   `,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 3: The assignment operator += is not allowed. Use = instead."`)
+  ).toMatchInlineSnapshot(`
+"Line 3, Column 1: The assignment operator += is not allowed. Use = instead.
+
+	x = x + 5;
+"
+`)
 })
 
 test('Cannot use update statements', () => {
@@ -400,7 +482,11 @@ test('Cannot use update statements - verbose', () => {
 	x;
 	`,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 3: The assignment operator <<= is not allowed. Use = instead."`)
+  ).toMatchInlineSnapshot(`
+"Line 3, Column 0: The assignment operator <<= is not allowed. Use = instead.
+
+"
+`)
 })
 
 test('Cannot use function expressions', () => {
@@ -419,7 +505,11 @@ test('Cannot use function expressions - verbose', () => {
 	(function fib(x) { return x <= 1 ? x : fib(x-1) + fib(x-2); })(4);
 	`,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 2: Function expressions are not allowed"`)
+  ).toMatchInlineSnapshot(`
+"Line 2, Column 1: Function expressions are not allowed
+You are trying to use Function expressions, which is not allowed (yet).
+"
+`)
 })
 
 test('Cannot use function expressions', () => {
@@ -438,7 +528,11 @@ test('Cannot use function expressions - verbose', () => {
 	(function(x) { return x + 1; })(4);
 	`,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 2: Function expressions are not allowed"`)
+  ).toMatchInlineSnapshot(`
+"Line 2, Column 1: Function expressions are not allowed
+You are trying to use Function expressions, which is not allowed (yet).
+"
+`)
 })
 
 test('if needs braces', () => {
@@ -467,8 +561,64 @@ test('if needs braces - verbose', () => {
 	`,
     { chapter: 100 }
   ).toMatchInlineSnapshot(`
-"Line 2: Missing curly braces around \\"if\\" block.
-Line 2: Missing curly braces around \\"else\\" block."
+"Line 2, Column 1: Missing curly braces around \\"if\\" block.
+if block need to be enclosed with a pair of curly braces.
+
+if (true) {
+  true;
+}
+
+An exception is when you have an \\"if\\" followed by \\"else if\\", in this case
+\\"else if\\" block does not need to be surrounded by curly braces.
+
+if (someCondition) {
+  // ...
+} else /* notice missing { here */ if (someCondition) {
+  // ...
+} else {
+  // ...
+}
+
+Rationale: Readability in dense packed code.
+
+In the snippet below, for instance, with poor indentation it is easy to
+mistaken hello() and world() to belong to the same branch of logic.
+
+if (someCondition) {
+  2;
+} else
+  hello();
+world();
+
+Line 2, Column 1: Missing curly braces around \\"else\\" block.
+else block need to be enclosed with a pair of curly braces.
+
+else {
+  false;
+}
+
+An exception is when you have an \\"if\\" followed by \\"else if\\", in this case
+\\"else if\\" block does not need to be surrounded by curly braces.
+
+if (someCondition) {
+  // ...
+} else /* notice missing { here */ if (someCondition) {
+  // ...
+} else {
+  // ...
+}
+
+Rationale: Readability in dense packed code.
+
+In the snippet below, for instance, with poor indentation it is easy to
+mistaken hello() and world() to belong to the same branch of logic.
+
+if (someCondition) {
+  2;
+} else
+  hello();
+world();
+"
 `)
 })
 
@@ -490,7 +640,15 @@ test('for needs braces - verbose', () => {
 		i;
 	`,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 2: Missing curly braces around \\"for\\" block."`)
+  ).toMatchInlineSnapshot(`
+"Line 2, Column 1: Missing curly braces around \\"for\\" block.
+Remember to enclose your \\"for\\" block with braces:
+
+ 	for (let i = 0; i < 1; i = i + 1) {
+		//code goes here
+	}
+"
+`)
 })
 
 test('while needs braces', () => {
@@ -513,7 +671,15 @@ test('while needs braces - verbose', () => {
 		i = i + 1;
 	`,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 3: Missing curly braces around \\"while\\" block."`)
+  ).toMatchInlineSnapshot(`
+"Line 3, Column 1: Missing curly braces around \\"while\\" block.
+Remember to enclose your \\"while\\" block with braces:
+
+ 	while (i < 1) {
+		//code goes here
+	}
+"
+`)
 })
 
 test('No empty statements', () => {
@@ -532,7 +698,11 @@ test('No empty statements - verbose', () => {
 	  ;
 	`,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 2: Empty statements are not allowed"`)
+  ).toMatchInlineSnapshot(`
+"Line 2, Column 2: Empty statements are not allowed
+You are trying to use Empty statements, which is not allowed (yet).
+"
+`)
 })
 
 test('No array expressions in chapter 2', () => {
@@ -551,7 +721,11 @@ test('No array expressions in chapter 2 - verbose', () => {
 	  [];
 	`,
     { chapter: 2 }
-  ).toMatchInlineSnapshot(`"Line 2: Array expressions are not allowed"`)
+  ).toMatchInlineSnapshot(`
+"Line 2, Column 0: Array expressions are not allowed
+You are trying to use Array expressions, which is not allowed (yet).
+"
+`)
 })
 
 test('No trailing commas in arrays', () => {
@@ -611,7 +785,11 @@ test('No rest pattern - verbose', () => {
 	  f(1, 2);
 	`,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 2: Rest elements are not allowed"`)
+  ).toMatchInlineSnapshot(`
+"Line 2, Column 12: Rest elements are not allowed
+You are trying to use Rest elements, which is not allowed (yet).
+"
+`)
 })
 
 test('No spread operator', () => {
@@ -636,7 +814,11 @@ test('No spread operator - verbose', () => {
 	  f(...[1, 2]);
 	`,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 5: Spread elements are not allowed"`)
+  ).toMatchInlineSnapshot(`
+"Line 5, Column 3: Spread elements are not allowed
+You are trying to use Spread elements, which is not allowed (yet).
+"
+`)
 })
 
 test('no try statements', () => {
@@ -674,9 +856,15 @@ test('no try statements - verbose', () => {
 	`,
     { chapter: 100 }
   ).toMatchInlineSnapshot(`
-"Line 6: Spread elements are not allowed
-Line 7: Catch clauses are not allowed
-Line 5: Try statements are not allowed"
+"Line 6, Column 2: Spread elements are not allowed
+You are trying to use Spread elements, which is not allowed (yet).
+
+Line 7, Column 3: Catch clauses are not allowed
+You are trying to use Catch clauses, which is not allowed (yet).
+
+Line 5, Column 1: Try statements are not allowed
+You are trying to use Try statements, which is not allowed (yet).
+"
 `)
 })
 
@@ -702,8 +890,17 @@ test('no for of loops - verbose', () => {
   `,
     { chapter: 100 }
   ).toMatchInlineSnapshot(`
-"Line 2: Missing value in variable declaration.
-Line 2: For of statements are not allowed"
+"Line 2, Column 12: Missing value in variable declaration.
+A variable declaration assigns a value to a name.
+For instance, to assign 20 to i, you can write:
+
+  let i = 20;
+
+  i + i; // 40
+
+Line 2, Column 3: For of statements are not allowed
+You are trying to use For of statements, which is not allowed (yet).
+"
 `)
 })
 
@@ -729,8 +926,17 @@ test('no for in loops - verbose', () => {
 	`,
     { chapter: 100 }
   ).toMatchInlineSnapshot(`
-"Line 2: Missing value in variable declaration.
-Line 2: For in statements are not allowed"
+"Line 2, Column 9: Missing value in variable declaration.
+A variable declaration assigns a value to a name.
+For instance, to assign 20 to i, you can write:
+
+  let i = 20;
+
+  i + i; // 40
+
+Line 2, Column 0: For in statements are not allowed
+You are trying to use For in statements, which is not allowed (yet).
+"
 `)
 })
 
@@ -750,7 +956,11 @@ test('no debugger statement - verbose', () => {
     debugger;
   `,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 2: Debugger statements are not allowed"`)
+  ).toMatchInlineSnapshot(`
+"Line 2, Column 3: Debugger statements are not allowed
+You are trying to use Debugger statements, which is not allowed (yet).
+"
+`)
 })
 
 test('no generator functions', () => {
@@ -775,7 +985,11 @@ test('no generator functions - verbose', () => {
 	  }
 	`,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 3: Yield expressions are not allowed"`)
+  ).toMatchInlineSnapshot(`
+"Line 3, Column 0: Yield expressions are not allowed
+You are trying to use Yield expressions, which is not allowed (yet).
+"
+`)
 })
 
 test('no classes', () => {
@@ -800,8 +1014,12 @@ test('no classes - verbose', () => {
 	`,
     { chapter: 100 }
   ).toMatchInlineSnapshot(`
-"Line 2: Class bodys are not allowed
-Line 2: Class declarations are not allowed"
+"Line 2, Column 10: Class bodys are not allowed
+You are trying to use Class bodys, which is not allowed (yet).
+
+Line 2, Column 0: Class declarations are not allowed
+You are trying to use Class declarations, which is not allowed (yet).
+"
 `)
 })
 
@@ -836,11 +1054,21 @@ test('no super - verbose', () => {
 	`,
     { chapter: 100 }
   ).toMatchInlineSnapshot(`
-"Line 4: Supers are not allowed
-Line 3: Function expressions are not allowed
-Line 3: Method definitions are not allowed
-Line 2: Class bodys are not allowed
-Line 2: Class declarations are not allowed"
+"Line 4, Column 2: Supers are not allowed
+You are trying to use Supers, which is not allowed (yet).
+
+Line 3, Column 11: Function expressions are not allowed
+You are trying to use Function expressions, which is not allowed (yet).
+
+Line 3, Column 0: Method definitions are not allowed
+You are trying to use Method definitions, which is not allowed (yet).
+
+Line 2, Column 30: Class bodys are not allowed
+You are trying to use Class bodys, which is not allowed (yet).
+
+Line 2, Column 1: Class declarations are not allowed
+You are trying to use Class declarations, which is not allowed (yet).
+"
 `)
 })
 
@@ -864,7 +1092,11 @@ test('no export function - verbose', () => {
 	  }
 	`,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 2: Export named declarations are not allowed"`)
+  ).toMatchInlineSnapshot(`
+"Line 2, Column 1: Export named declarations are not allowed
+You are trying to use Export named declarations, which is not allowed (yet).
+"
+`)
 })
 
 test('no export constant', () => {
@@ -883,7 +1115,11 @@ test('no export constant - verbose', () => {
 	  export const x = 1;
 	`,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 2: Export named declarations are not allowed"`)
+  ).toMatchInlineSnapshot(`
+"Line 2, Column 0: Export named declarations are not allowed
+You are trying to use Export named declarations, which is not allowed (yet).
+"
+`)
 })
 
 test('no export default', () => {
@@ -904,7 +1140,11 @@ test('no export default - verbose', () => {
 	  export default x;
 	`,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 3: Export default declarations are not allowed"`)
+  ).toMatchInlineSnapshot(`
+"Line 3, Column 0: Export default declarations are not allowed
+You are trying to use Export default declarations, which is not allowed (yet).
+"
+`)
 })
 
 test('no import', () => {
@@ -927,8 +1167,12 @@ test('no import - verbose', () => {
 	`,
     { chapter: 100 }
   ).toMatchInlineSnapshot(`
-"Line 2: Import specifiers are not allowed
-Line 2: Import declarations are not allowed"
+"Line 2, Column 9: Import specifiers are not allowed
+You are trying to use Import specifiers, which is not allowed (yet).
+
+Line 2, Column 0: Import declarations are not allowed
+You are trying to use Import declarations, which is not allowed (yet).
+"
 `)
 })
 
@@ -948,7 +1192,11 @@ test('no sequence expression - verbose', () => {
 	  (1, 2);
 	`,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 2: Sequence expressions are not allowed"`)
+  ).toMatchInlineSnapshot(`
+"Line 2, Column 1: Sequence expressions are not allowed
+You are trying to use Sequence expressions, which is not allowed (yet).
+"
+`)
 })
 
 test('no interface', () => {
@@ -969,7 +1217,11 @@ test('no interface - verbose', () => {
 	  }
 	`,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 2: SyntaxError: The keyword 'interface' is reserved (2:0)"`)
+  ).toMatchInlineSnapshot(`
+"Line 2, Column 0: SyntaxError: The keyword 'interface' is reserved (2:0)
+There is a syntax error in your program
+"
+`)
 })
 
 test('no template literals', () => {
@@ -986,7 +1238,11 @@ test('no template literals - verbose', () => {
 	"enable verbose";
 	'hi'`,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 3: Missing semicolon at the end of statement"`)
+  ).toMatchInlineSnapshot(`
+"Line 3, Column 5: Missing semicolon at the end of statement
+Every statement must be terminated by a semicolon.
+"
+`)
 })
 
 test('no regexp', () => {
@@ -1003,8 +1259,12 @@ test('no regexp - verbose', () => {
 	/pattern/`,
     { chapter: 100 }
   ).toMatchInlineSnapshot(`
-"Line 3: Missing semicolon at the end of statement
-Line 3: 'RegExp' literals are not allowed."
+"Line 3, Column 10: Missing semicolon at the end of statement
+Every statement must be terminated by a semicolon.
+
+Line 3, Column 1: 'RegExp' literals are not allowed.
+
+"
 `)
 })
 
@@ -1030,7 +1290,11 @@ test('no this, no new - verbose', () => {
 	  const box = new Box();
 	`,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 3: 'this' expressions are not allowed"`)
+  ).toMatchInlineSnapshot(`
+"Line 3, Column 0: 'this' expressions are not allowed
+You are trying to use 'this' expressions, which is not allowed (yet).
+"
+`)
 })
 
 test('no unspecified operators', () => {
@@ -1049,7 +1313,11 @@ test('no unspecified operators - verbose', () => {
 	  1 << 10;
 	`,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 2: Operator '<<' is not allowed."`)
+  ).toMatchInlineSnapshot(`
+"Line 2, Column 0: Operator '<<' is not allowed.
+
+"
+`)
 })
 
 test('no unspecified unary operators', () => {
@@ -1070,7 +1338,11 @@ test('no unspecified unary operators - verbose', () => {
 	  typeof x;
 	`,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 3: Operator 'typeof' is not allowed."`)
+  ).toMatchInlineSnapshot(`
+"Line 3, Column 0: Operator 'typeof' is not allowed.
+
+"
+`)
 })
 
 test('no implicit undefined return', () => {
@@ -1092,7 +1364,14 @@ test('no implicit undefined return - verbose', () => {
     }
   `,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 3: Missing value in return statement."`)
+  ).toMatchInlineSnapshot(`
+"Line 3, Column 5: Missing value in return statement.
+This return statement is missing a value.
+For instance, to return the value 42, you can write
+
+  return 42;
+"
+`)
 })
 
 test('no repeated params', () => {
@@ -1115,7 +1394,11 @@ test('no repeated params - verbose', () => {
 	  }
 	`,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 2: SyntaxError: Argument name clash (2:15)"`)
+  ).toMatchInlineSnapshot(`
+"Line 2, Column 15: SyntaxError: Argument name clash (2:15)
+There is a syntax error in your program
+"
+`)
 })
 
 test('no declaring reserved keywords', () => {
@@ -1134,7 +1417,11 @@ test('no declaring reserved keywords - verbose', () => {
 	  let yield = 5;
 	`,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 2: SyntaxError: The keyword 'yield' is reserved (2:4)"`)
+  ).toMatchInlineSnapshot(`
+"Line 2, Column 4: SyntaxError: The keyword 'yield' is reserved (2:4)
+There is a syntax error in your program
+"
+`)
 })
 
 test('no assigning to reserved keywords', () => {
@@ -1153,5 +1440,9 @@ test('no assigning to reserved keywords - verbose', () => {
     package = 5;
   `,
     { chapter: 100 }
-  ).toMatchInlineSnapshot(`"Line 2: SyntaxError: The keyword 'package' is reserved (2:3)"`)
+  ).toMatchInlineSnapshot(`
+"Line 2, Column 3: SyntaxError: The keyword 'package' is reserved (2:3)
+There is a syntax error in your program
+"
+`)
 })
diff --git a/src/__tests__/interpreter-errors.ts b/src/__tests__/interpreter-errors.ts
index 8f30b6c3..3b107c3d 100644
--- a/src/__tests__/interpreter-errors.ts
+++ b/src/__tests__/interpreter-errors.ts
@@ -292,11 +292,9 @@ const callingNonFunctionValueNullVerbose = stripIndent`
 `
 
 test('Error when calling non function value null', () => {
-  return expectParsedError(callingNonFunctionValueNull).toMatchInlineSnapshot(`
-"Line 1, Column 0: null literals are not allowed.
-They're not part of the Source §1 specs.
-"
-`)
+  return expectParsedError(callingNonFunctionValueNull).toMatchInlineSnapshot(
+    `"Line 1: null literals are not allowed."`
+  )
 })
 
 test('Error when calling non function value null - verbose', () => {