perl, python, tcl: Correctly detect more unterminated strings.
authorBen Harris <bjh21@bjh21.me.uk>
Wed, 8 May 2019 21:00:55 +0000 (22:00 +0100)
committerBen Harris <bjh21@bjh21.me.uk>
Wed, 8 May 2019 21:47:34 +0000 (22:47 +0100)
In all cases, this is just by using the equivalent of the full
string-matching regexp from 'tokenize'.

While I'm in the area, also remove an unnecessary ".*" from the regexp
to match a leading quotation mark in Perl and Tcl.

perl/reader.pm
python/reader.py
tcl/reader.tcl

index 55616d6..e31ee54 100644 (file)
@@ -31,13 +31,13 @@ sub read_atom {
     my $token = $rdr->next();
     given ($token) {
         when(/^-?[0-9]+$/) { return Integer->new($token) }
-        when(/^".*"$/) {
+        when(/^"(?:\\.|[^\\"])*"$/) {
             my %escaped_chars = ( "\\\\" => "\\", "\\\"" => "\"", "\\n" => "\n" );
             my $str = substr $token, 1, -1;
             $str =~ s/\\./$escaped_chars{$&}/ge;
             return String->new($str)
         }
-        when(/^".*/) {
+        when(/^"/) {
             die "expected '\"', got EOF";
         }
         when(/^:/) { return _keyword(substr($token,1)) }
index 84c46c5..59d24cc 100644 (file)
@@ -28,12 +28,12 @@ def _unescape(s):
 def read_atom(reader):
     int_re = re.compile(r"-?[0-9]+$")
     float_re = re.compile(r"-?[0-9][0-9.]*$")
+    string_re = re.compile(r'"(?:[\\].|[^\\"])*"')
     token = reader.next()
     if re.match(int_re, token):     return int(token)
     elif re.match(float_re, token): return int(token)
-    elif token[0] == '"':
-        if token[-1] == '"':        return _s2u(_unescape(token[1:-1]))
-        else:                       raise Exception("expected '\"', got EOF")
+    elif re.match(string_re, token):return _s2u(_unescape(token[1:-1]))
+    elif token[0] == '"':           raise Exception("expected '\"', got EOF")
     elif token[0] == ':':           return _keyword(token[1:])
     elif token == "nil":            return None
     elif token == "true":           return True
index ee7a7ec..c1c7072 100644 (file)
@@ -83,8 +83,9 @@ proc read_atom {reader} {
         ^true$     { return $::mal_true }
         ^false$    { return $::mal_false }
         ^:         { return [keyword_new [parse_keyword $token]] }
-        ^\".*\"$   { return [string_new [parse_string $token]] }
-        ^\".*$     { error "expected '\"', got EOF" }
+        ^\"(\\\\.|[^\\\\\"])*\"$
+                  { return [string_new [parse_string $token]] }
+        ^\"        { error "expected '\"', got EOF" }
         default    { return [symbol_new $token] }
     }
 }