diff --git a/crystal/reader.cr b/crystal/reader.cr index 5eca482f08..dd7d62f56e 100644 --- a/crystal/reader.cr +++ b/crystal/reader.cr @@ -81,11 +81,11 @@ class Reader when token == "true" then true when token == "false" then false when token == "nil" then nil - when token[0] == '"' - parse_error "expected '\"', got EOF" if token[-1] != '"' + when token =~ /^"(?:\\.|[^\\"])*"$/ token[1..-2].gsub(/\\(.)/, {"\\\"" => "\"", "\\n" => "\n", "\\\\" => "\\"}) + when token[0] == '"' then parse_error "expected '\"', got EOF" when token[0] == ':' then "\u029e#{token[1..-1]}" else Mal::Symbol.new token end diff --git a/cs/reader.cs b/cs/reader.cs index 3136b904c6..7e0d6b5c35 100644 --- a/cs/reader.cs +++ b/cs/reader.cs @@ -53,7 +53,7 @@ public static List tokenize(string str) { public static MalVal read_atom(Reader rdr) { string token = rdr.next(); - string pattern = @"(^-?[0-9]+$)|(^-?[0-9][0-9.]*$)|(^nil$)|(^true$)|(^false$)|^("".*)|:(.*)|(^[^""]*$)"; + string pattern = @"(^-?[0-9]+$)|(^-?[0-9][0-9.]*$)|(^nil$)|(^true$)|(^false$)|(^""(?:[\\].|[^\\""])*""$)|(^"".*$)|:(.*)|(^[^""]*$)"; Regex regex = new Regex(pattern); Match match = regex.Match(token); //Console.WriteLine("token: ^" + token + "$"); @@ -70,9 +70,6 @@ public static MalVal read_atom(Reader rdr) { return Mal.types.False; } else if (match.Groups[6].Value != String.Empty) { string str = match.Groups[6].Value; - if (str[str.Length-1] != '"') { - throw new ParseError("expected '\"', got EOF"); - } str = str.Substring(1, str.Length-2) .Replace("\\\\", "\u029e") .Replace("\\\"", "\"") @@ -80,9 +77,11 @@ public static MalVal read_atom(Reader rdr) { .Replace("\u029e", "\\"); return new Mal.types.MalString(str); } else if (match.Groups[7].Value != String.Empty) { - return new Mal.types.MalString("\u029e" + match.Groups[7].Value); + throw new ParseError("expected '\"', got EOF"); } else if (match.Groups[8].Value != String.Empty) { - return new Mal.types.MalSymbol(match.Groups[8].Value); + return new Mal.types.MalString("\u029e" + match.Groups[8].Value); + } else if (match.Groups[9].Value != String.Empty) { + return new Mal.types.MalSymbol(match.Groups[9].Value); } else { throw new ParseError("unrecognized '" + match.Groups[0] + "'"); } diff --git a/es6/reader.mjs b/es6/reader.mjs index 597e739494..996a08be69 100644 --- a/es6/reader.mjs +++ b/es6/reader.mjs @@ -29,12 +29,11 @@ function read_atom (reader) { return parseInt(token,10) // integer } else if (token.match(/^-?[0-9][0-9.]*$/)) { return parseFloat(token,10) // float - } else if (token[0] === "\"") { - if (token.slice(-1) !== "\"") { - throw new Error("expected '\"', got EOF"); - } + } else if (token.match(/^"(?:\\.|[^\\"])*"$/)) { return token.slice(1,token.length-1) .replace(/\\(.)/g, (_, c) => c === "n" ? "\n" : c) + } else if (token[0] === "\"") { + throw new Error("expected '\"', got EOF"); } else if (token[0] === ":") { return _keyword(token.slice(1)) } else if (token === "nil") {