Merge pull request #37 from leonsenft/fix-string-lexing

Fixes parsing string with unicode-range sequences
diff --git a/lib/parser.dart b/lib/parser.dart
index 205011f..168c9da 100644
--- a/lib/parser.dart
+++ b/lib/parser.dart
@@ -2168,7 +2168,8 @@
           if (_peekKind(TokenKind.INTEGER)) {
             String hexText1 = _peekToken.text;
             _next();
-            if (_peekIdentifier()) {
+            // Append identifier only if there's no delimiting whitespace.
+            if (_peekIdentifier() && _previousToken.end == _peekToken.start) {
               hexText = '$hexText1${identifier().name}';
             } else {
               hexText = hexText1;
diff --git a/lib/src/tokenizer.dart b/lib/src/tokenizer.dart
index 2999ddb..d7677f9 100644
--- a/lib/src/tokenizer.dart
+++ b/lib/src/tokenizer.dart
@@ -97,7 +97,7 @@
       case TokenChar.HASH:
         return _finishToken(TokenKind.HASH);
       case TokenChar.PLUS:
-        if (maybeEatDigit()) return finishNumber();
+        if (_nextCharsAreNumber(ch)) return finishNumber();
         return _finishToken(TokenKind.PLUS);
       case TokenChar.MINUS:
         if (inSelectorExpression || unicodeRange) {
@@ -105,7 +105,7 @@
           // not part of identifier e.g., interval value range (e.g. U+400-4ff)
           // or minus operator in selector expression.
           return _finishToken(TokenKind.MINUS);
-        } else if (maybeEatDigit()) {
+        } else if (_nextCharsAreNumber(ch)) {
           return finishNumber();
         } else if (TokenizerHelpers.isIdentifierStart(ch)) {
           return finishIdentifier();
diff --git a/lib/src/tokenizer_base.dart b/lib/src/tokenizer_base.dart
index ccdd7be..c2a448f 100644
--- a/lib/src/tokenizer_base.dart
+++ b/lib/src/tokenizer_base.dart
@@ -79,9 +79,9 @@
     }
   }
 
-  int _peekChar() {
-    if (_index < _text.length) {
-      return _text.codeUnitAt(_index);
+  int _peekChar([int offset = 0]) {
+    if (_index + offset < _text.length) {
+      return _text.codeUnitAt(_index + offset);
     } else {
       return 0;
     }
@@ -100,6 +100,17 @@
     }
   }
 
+  bool _nextCharsAreNumber(int first) {
+    if (TokenizerHelpers.isDigit(first)) return true;
+    var second = _peekChar();
+    if (first == TokenChar.DOT) return TokenizerHelpers.isDigit(second);
+    if (first == TokenChar.PLUS || first == TokenChar.MINUS) {
+      return TokenizerHelpers.isDigit(second) ||
+          (second == TokenChar.DOT && TokenizerHelpers.isDigit(_peekChar(1)));
+    }
+    return false;
+  }
+
   Token _finishToken(int kind) {
     return new Token(kind, _file.span(_startIndex, _index));
   }
diff --git a/test/declaration_test.dart b/test/declaration_test.dart
index f82896c..96600d8 100644
--- a/test/declaration_test.dart
+++ b/test/declaration_test.dart
@@ -172,8 +172,8 @@
   right: 300px;
   bottom: 400cm;
   border-width: 2.5mm;
-  margin-top: .5in;
-  margin-left: 5pc;
+  margin-top: -.5in;
+  margin-left: +5pc;
   margin-right: 5ex;
   margin-bottom: 5ch;
   font-size: 10pt;
@@ -210,8 +210,8 @@
   right: 300px;
   bottom: 400cm;
   border-width: 2.5mm;
-  margin-top: .5in;
-  margin-left: 5pc;
+  margin-top: -.5in;
+  margin-left: +5pc;
   margin-right: 5ex;
   margin-bottom: 5ch;
   font-size: 10pt;
@@ -568,6 +568,10 @@
 .test-background {
   background:  url(http://www.foo.com/bar.png);
 }
+
+.test-background-with-multiple-properties {
+  background: #000 url(http://www.foo.com/bar.png);
+}
 ''';
 
   final String generated = '@import "simple.css"; '
@@ -593,6 +597,9 @@
       '}\n'
       '.test-background {\n'
       '  background: url("http://www.foo.com/bar.png");\n'
+      '}\n'
+      '.test-background-with-multiple-properties {\n'
+      '  background: #000 url("http://www.foo.com/bar.png");\n'
       '}';
   var stylesheet = parseCss(input, errors: errors);