From 3cd72f9f361b3b97dd7993b2f957744c90a591ce Mon Sep 17 00:00:00 2001 From: Rebecca Turner Date: Wed, 14 Mar 2012 18:52:47 -0400 Subject: [PATCH] Improve error messages for invalid delimiters (#82) --- Modyllic/Parser.php | 2 +- Modyllic/Tokenizer.php | 24 ++++++++++++++++++------ test/General_Functional.t | 14 ++++++++++++++ 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/Modyllic/Parser.php b/Modyllic/Parser.php index 6b53603..87e939e 100644 --- a/Modyllic/Parser.php +++ b/Modyllic/Parser.php @@ -86,7 +86,7 @@ function partial($schema, $sql, $filename="SQL", $delim=null) { function next($whitespace=false) { $next = $this->tok->next($whitespace); if ( $next instanceOf Modyllic_Token_Error ) { - throw $this->error( "Syntax error" ); + throw $this->error( $next->value() ); } return $next; } diff --git a/Modyllic/Tokenizer.php b/Modyllic/Tokenizer.php index 3363101..91a18ef 100644 --- a/Modyllic/Tokenizer.php +++ b/Modyllic/Tokenizer.php @@ -197,18 +197,23 @@ class Modyllic_Token_EOF extends Modyllic_Token_EOC {} * one it will always be returned by next(). */ class Modyllic_Token_Error extends Modyllic_Token_Except { - private $row; - private $col; + protected $row; + protected $col; function __construct($pos, $row,$col) { $this->pos = $pos; $this->row = $row; $this->col = $col; } function value() { - return "Syntax Error at ".$this->row.", ".$this->col; + return "Syntax error"; } } +class Modyllic_Token_Delimiter_Error extends Modyllic_Token_Error { + function value() { + return "Invalid delimiter declaration"; + } +} class Modyllic_Token_SOC extends Modyllic_Token_EOC {} @@ -374,7 +379,7 @@ function is_delimiter() { return isset($this->delimiter) and preg_match( "/\G\Q$this->delimiter\E/", $this->cmdstr, $matches, 0, $this->pos ); } function is_new_delimiter(&$matches) { - return $this->prev instanceOf Modyllic_Token_SOC and preg_match( "/\G(DELIMITER\s+(\S+)\s*(?:\n|\z))/i", $this->cmdstr, $matches, 0, $this->pos); + return $this->prev instanceOf Modyllic_Token_SOC and preg_match( "/\G(DELIMITER\s+(\S+)([^\n]*?)(?=\n|\z))/i", $this->cmdstr, $matches, 0, $this->pos); } function is_string() { return isset( $this->quote_chars[$this->cmdstr[$this->pos]] ); @@ -537,9 +542,16 @@ function next( $whitespace = FALSE, $peek = FALSE ) { $this->cur = new Modyllic_Token_Whitespace( $this->pos, $matches[1] ); } else if ( $this->is_new_delimiter($matches) ) { - $this->pos += strlen($matches[1]); $this->delimiter = $matches[2]; - $this->cur = new Modyllic_Token_NewDelim( $this->pos, $matches[1]); + $this->pos += strlen($matches[1]); + if ( preg_match("/\S/",$matches[3], $offset, PREG_OFFSET_CAPTURE) ) { + $this->pos -= strlen($matches[3]); + $this->pos += $offset[0][1]; + $this->cur = new Modyllic_Token_Delimiter_Error($this->pos, $this->line(), $this->col() ); + } + else { + $this->cur = new Modyllic_Token_NewDelim( $this->pos, $matches[1]); + } } else if ( $this->is_reserved($matches) ) { $this->pos += strlen($matches[1]); diff --git a/test/General_Functional.t b/test/General_Functional.t index 76f7a11..273331c 100644 --- a/test/General_Functional.t +++ b/test/General_Functional.t @@ -59,3 +59,17 @@ $table = $schema->tables['test']; $index = array_pop($table->indexes); is( $index->name, "id", "Generated index name is correct"); is( $index->dynamic_name, true, "Generated index name is flagged as dynamic"); + +$msg = "Trailing words on DELIMITERs produce reasonable error messages"; +try { + $sql = 'DELIMITER ; |'; + $schema = $parser->parse($sql); + fail($msg); +} +catch (Modyllic_Exception $e) { + if ( ! ok( ! preg_match("/Modyllic_Token/",$e->getMessage()), $msg ) ) { + foreach (explode("\n",$e->getMessage()) as $line) { + diag($line); + } + } +}