Small modifications for null-safety (#296)

These include nullability hints for the migration tool, local variables for
non-promotable fields, and local variables for regex matches.
diff --git a/lib/src/block_parser.dart b/lib/src/block_parser.dart
index ca6102f..311c2be 100644
--- a/lib/src/block_parser.dart
+++ b/lib/src/block_parser.dart
@@ -51,6 +51,10 @@
 /// A line of hyphens separated by at least one pipe.
 final _tablePattern = RegExp(r'^[ ]{0,3}\|?( *:?\-+:? *\|)+( *:?\-+:? *)?$');
 
+/// A pattern which should never be used. It just satisfies non-nullability of
+/// pattern fields.
+final _dummyPattern = RegExp('');
+
 /// Maintains the internal state needed to parse a series of lines into blocks
 /// of Markdown suitable for further inline parsing.
 class BlockParser {
@@ -162,7 +166,7 @@
   const BlockSyntax();
 
   /// Gets the regex used to identify the beginning of this block, if any.
-  RegExp get pattern => null;
+  RegExp get pattern;
 
   bool get canEndBlock => true;
 
@@ -219,6 +223,9 @@
 
 /// Parses setext-style headers.
 class SetextHeaderSyntax extends BlockSyntax {
+  @override
+  RegExp get pattern => _dummyPattern;
+
   const SetextHeaderSyntax();
 
   @override
@@ -263,7 +270,7 @@
 
     var contents = UnparsedContent(lines.join('\n'));
 
-    return Element(tag, [contents]);
+    return Element(tag /*!*/, [contents]);
   }
 
   bool _interperableAsParagraph(String line) =>
@@ -334,7 +341,7 @@
     while (!parser.isDone) {
       var match = pattern.firstMatch(parser.current);
       if (match != null) {
-        childLines.add(match[1]);
+        childLines.add(match[1] /*!*/);
         parser.advance();
         continue;
       }
@@ -657,7 +664,7 @@
       }
     }
 
-    Match match;
+    /*late*/ Match match;
     bool tryMatch(RegExp pattern) {
       match = pattern.firstMatch(parser.current);
       return match != null;
@@ -689,12 +696,12 @@
         // Horizontal rule takes precedence to a new list item.
         break;
       } else if (tryMatch(_ulPattern) || tryMatch(_olPattern)) {
-        var precedingWhitespace = match[1];
+        var precedingWhitespace = match[1] /*!*/;
         var digits = match[2] ?? '';
         if (startNumber == null && digits.isNotEmpty) {
           startNumber = int.parse(digits);
         }
-        var marker = match[3];
+        var marker = match[3] /*!*/;
         var firstWhitespace = match[5] ?? '';
         var restWhitespace = match[6] ?? '';
         var content = match[7] ?? '';
@@ -768,11 +775,14 @@
       // We must post-process the list items, converting any top-level paragraph
       // elements to just text elements.
       for (var item in itemNodes) {
-        for (var i = 0; i < item.children.length; i++) {
-          var child = item.children[i];
-          if (child is Element && child.tag == 'p') {
-            item.children.removeAt(i);
-            item.children.insertAll(i, child.children);
+        var children = item.children;
+        if (children != null) {
+          for (var i = 0; i < children.length; i++) {
+            var child = children[i];
+            if (child is Element && child.tag == 'p') {
+              children.removeAt(i);
+              children.insertAll(i, child.children);
+            }
           }
         }
       }
@@ -844,6 +854,9 @@
   @override
   bool get canEndBlock => false;
 
+  @override
+  RegExp get pattern => _dummyPattern;
+
   const TableSyntax();
 
   @override
@@ -874,9 +887,15 @@
     var rows = <Element>[];
     while (!parser.isDone && !BlockSyntax.isAtBlockEnd(parser)) {
       var row = parseRow(parser, alignments, 'td');
-      while (row.children.length < columnCount) {
-        // Insert synthetic empty cells.
-        row.children.add(Element.empty('td'));
+      var children = row.children;
+      if (children != null) {
+        while (children.length < columnCount) {
+          // Insert synthetic empty cells.
+          children.add(Element.empty('td'));
+        }
+        while (children.length > columnCount) {
+          children.removeLast();
+        }
       }
       while (row.children.length > columnCount) {
         row.children.removeLast();
@@ -1036,6 +1055,9 @@
   static final _whitespacePattern = RegExp(r'^\s*$');
 
   @override
+  RegExp get pattern => _dummyPattern;
+
+  @override
   bool get canEndBlock => false;
 
   const ParagraphSyntax();
@@ -1169,7 +1191,7 @@
     }
 
     var label = match[1];
-    var destination = match[2] ?? match[3];
+    var destination = (match[2] ?? match[3]) /*!*/;
     var title = match[4];
 
     // The label must contain at least one non-whitespace character.
diff --git a/lib/src/inline_parser.dart b/lib/src/inline_parser.dart
index 78d945d..d1d0eaa 100644
--- a/lib/src/inline_parser.dart
+++ b/lib/src/inline_parser.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:charcode/charcode.dart';
+import 'package:meta/meta.dart';
 
 import 'ast.dart';
 import 'document.dart';
@@ -113,7 +114,7 @@
     }
 
     // Unwind any unmatched tags and get the results.
-    return _stack[0].close(this, null);
+    return _stack[0].close(this, null) ?? [];
   }
 
   int charAt(int index) => source.codeUnitAt(index);
@@ -303,7 +304,7 @@
 
   @override
   bool onMatch(InlineParser parser, Match match) {
-    var url = match[1];
+    var url = match[1] /*!*/;
     var text = parser.document.encodeHtml ? escapeHtml(url) : url;
     var anchor = Element.text('a', text);
     anchor.attributes['href'] = Uri.encodeFull('mailto:$url');
@@ -407,9 +408,10 @@
     // https://github.github.com/gfm/#example-599
     final trailingPunc = regExpTrailingPunc.firstMatch(url);
     if (trailingPunc != null) {
-      url = url.substring(0, url.length - trailingPunc[0].length);
-      href = href.substring(0, href.length - trailingPunc[0].length);
-      matchLength -= trailingPunc[0].length;
+      var trailingLength = trailingPunc[0].length;
+      url = url.substring(0, url.length - trailingLength);
+      href = href.substring(0, href.length - trailingLength);
+      matchLength -= trailingLength;
     }
 
     // If an autolink ends in a semicolon (;), we check to see if it appears
@@ -422,9 +424,10 @@
       final entityRef = regExpEndsWithColon.firstMatch(url);
       if (entityRef != null) {
         // Strip out HTML entity reference
-        url = url.substring(0, url.length - entityRef[0].length);
-        href = href.substring(0, href.length - entityRef[0].length);
-        matchLength -= entityRef[0].length;
+        var entityRefLength = entityRef[0].length;
+        url = url.substring(0, url.length - entityRefLength);
+        href = href.substring(0, href.length - entityRefLength);
+        matchLength -= entityRefLength;
       }
     }
 
@@ -499,12 +502,12 @@
   final bool isFollowedByPunctuation;
 
   _DelimiterRun._({
-    this.char,
-    this.length,
-    this.isLeftFlanking,
-    this.isRightFlanking,
-    this.isPrecededByPunctuation,
-    this.isFollowedByPunctuation,
+    @required this.char,
+    @required this.length,
+    @required this.isLeftFlanking,
+    @required this.isRightFlanking,
+    @required this.isPrecededByPunctuation,
+    @required this.isFollowedByPunctuation,
   });
 
   static _DelimiterRun tryParse(InlineParser parser, int runStart, int runEnd) {
diff --git a/tool/stats.dart b/tool/stats.dart
index 39e4aac..0edabca 100644
--- a/tool/stats.dart
+++ b/tool/stats.dart
@@ -51,10 +51,10 @@
   }
 
   var specifiedSection = options['section'] as String;
-  var raw = options['raw'] as bool;
-  var verbose = options['verbose'] as bool;
-  var verboseLooseMatch = options['verbose-loose'] as bool;
-  var updateFiles = options['update-files'] as bool;
+  var raw = options['raw'] as bool /*!*/;
+  var verbose = options['verbose'] as bool /*!*/;
+  var verboseLooseMatch = options['verbose-loose'] as bool /*!*/;
+  var updateFiles = options['update-files'] as bool /*!*/;
 
   if (updateFiles && (raw || verbose || (specifiedSection != null))) {
     stderr.writeln('The `update-files` flag must be used by itself');
diff --git a/tool/stats_lib.dart b/tool/stats_lib.dart
index 53fb0b9..11549df 100644
--- a/tool/stats_lib.dart
+++ b/tool/stats_lib.dart
@@ -74,10 +74,10 @@
   factory CommonMarkTestCase.fromJson(Map<String, dynamic> json) {
     return CommonMarkTestCase(
         json['example'] as int,
-        json['section'] as String,
+        json['section'] as String /*!*/,
         json['start_line'] as int,
         json['end_line'] as int,
-        json['markdown'] as String,
+        json['markdown'] as String /*!*/,
         json['html'] as String);
   }