Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(56)

Side by Side Diff: frog/leg/ssa/nodes.dart

Issue 9190038: Handle escapes in string literals. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Removed validation from scanner Created 8 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « frog/leg/ssa/codegen.dart ('k') | frog/leg/ssa/ssa.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 interface HVisitor<R> { 5 interface HVisitor<R> {
6 R visitAdd(HAdd node); 6 R visitAdd(HAdd node);
7 R visitBailoutTarget(HBailoutTarget node); 7 R visitBailoutTarget(HBailoutTarget node);
8 R visitBitAnd(HBitAnd node); 8 R visitBitAnd(HBitAnd node);
9 R visitBitNot(HBitNot node); 9 R visitBitNot(HBitNot node);
10 R visitBitOr(HBitOr node); 10 R visitBitOr(HBitOr node);
(...skipping 1567 matching lines...) Expand 10 before | Expand all | Expand 10 after
1578 /** 1578 /**
1579 * Finds the quote type for a string given a part of it containing the 1579 * Finds the quote type for a string given a part of it containing the
1580 * starting quote. Returns flags, but doesn't include HAS_LEFT_QUOTE 1580 * starting quote. Returns flags, but doesn't include HAS_LEFT_QUOTE
1581 * or HAS_RIGHT_QUOTE. 1581 * or HAS_RIGHT_QUOTE.
1582 */ 1582 */
1583 static int flagsFromLeftQuote(SourceString sourceString) { 1583 static int flagsFromLeftQuote(SourceString sourceString) {
1584 Iterator<int> source = sourceString.iterator(); 1584 Iterator<int> source = sourceString.iterator();
1585 int flags = 0; 1585 int flags = 0;
1586 int start = 0; 1586 int start = 0;
1587 int quoteChar = source.next(); 1587 int quoteChar = source.next();
1588 if (quoteChar == '@'.charCodeAt(0)) { 1588 if (quoteChar == $AT) {
1589 flags |= RAW; 1589 flags |= RAW;
1590 start = 1; 1590 start = 1;
1591 quoteChar = source.next(); 1591 quoteChar = source.next();
1592 } 1592 }
1593 if (quoteChar == '\''.charCodeAt(0)) { 1593 if (quoteChar == $SQ) {
1594 flags |= SINGLE_QUOTED; 1594 flags |= SINGLE_QUOTED;
1595 } else { 1595 } else {
1596 assert(quoteChar == '"'.charCodeAt(0)); 1596 assert(quoteChar == $DQ);
1597 } 1597 }
1598 // String has one quote. Check it if has three. 1598 // String has one quote. Check it if has three.
1599 // If it only have two, the string must be an empty string literal, 1599 // If it only have two, the string must be an empty string literal,
1600 // and end after the second quote. 1600 // and end after the second quote.
1601 if (source.hasNext() && source.next() == quoteChar && source.hasNext()) { 1601 if (source.hasNext() && source.next() == quoteChar && source.hasNext()) {
1602 assert(source.next() == quoteChar); 1602 assert(source.next() == quoteChar);
1603 flags |= MULTI_LINE; 1603 flags |= MULTI_LINE;
1604 } 1604 }
1605 return flags; 1605 return flags;
1606 } 1606 }
(...skipping 20 matching lines...) Expand all
1627 if ((flags & HAS_BOTH_QUOTES) == 0) return wrappedString; 1627 if ((flags & HAS_BOTH_QUOTES) == 0) return wrappedString;
1628 return wrappedString.copyWithoutQuotes(leftQuoteLength, 1628 return wrappedString.copyWithoutQuotes(leftQuoteLength,
1629 rightQuoteLength); 1629 rightQuoteLength);
1630 } 1630 }
1631 1631
1632 bool get hasLeftQuote() => (flags & HAS_LEFT_QUOTE) != 0; 1632 bool get hasLeftQuote() => (flags & HAS_LEFT_QUOTE) != 0;
1633 bool get hasRightQuote() => (flags & HAS_RIGHT_QUOTE) != 0; 1633 bool get hasRightQuote() => (flags & HAS_RIGHT_QUOTE) != 0;
1634 bool get isMultiLine() => (flags & MULTI_LINE) != 0; 1634 bool get isMultiLine() => (flags & MULTI_LINE) != 0;
1635 bool get isRaw() => (flags & RAW) != 0; 1635 bool get isRaw() => (flags & RAW) != 0;
1636 String get quoteChar() => ((flags & SINGLE_QUOTED) != 0) ? "'" : '"'; 1636 String get quoteChar() => ((flags & SINGLE_QUOTED) != 0) ? "'" : '"';
1637 int get quoteCharCode() => ((flags & SINGLE_QUOTED) != 0) ? $SQ : $DQ;
1637 1638
1638 int get leftQuoteLength() => 1639 int get leftQuoteLength() =>
1639 hasLeftQuote ? (isRaw ? 1 : 0) + (isMultiLine ? 3 : 1) : 0; 1640 hasLeftQuote ? (isRaw ? 1 : 0) + (isMultiLine ? 3 : 1) : 0;
1640 int get rightQuoteLength() => 1641 int get rightQuoteLength() =>
1641 hasRightQuote ? (isMultiLine ? 3 : 1) : 0; 1642 hasRightQuote ? (isMultiLine ? 3 : 1) : 0;
1642 static int leftQuoteLengthFromFlags(int flags) { 1643 static int leftQuoteLengthFromFlags(int flags) {
1643 if ((flags & HAS_LEFT_QUOTE) == 0) return 0; 1644 if ((flags & HAS_LEFT_QUOTE) == 0) return 0;
1644 return (flags & (RAW | MULTI_LINE)) + 1; 1645 return (flags & (RAW | MULTI_LINE)) + 1;
1645 } 1646 }
1646 static int rightQuoteLengthFromFlags(int flags) { 1647 static int rightQuoteLengthFromFlags(int flags) {
1647 if ((flags & HAS_RIGHT_QUOTE) == 0) return 0; 1648 if ((flags & HAS_RIGHT_QUOTE) == 0) return 0;
1648 return (flags & MULTI_LINE) + 1; 1649 return (flags & MULTI_LINE) + 1;
1649 } 1650 }
1650 1651
1651 bool isEmpty() => unquotedSource().isEmpty(); 1652 bool isEmpty() => unquotedSource().isEmpty();
1652 1653
1654 static int hexValue(int hexDigit) {
1655 // hexDigit is one of '0'..'9', 'A'..'F' and 'a'..'f'.
1656 if (hexDigit <= $9) {
1657 return hexDigit - $0;
1658 }
1659 // Make letters lowercase.
1660 hexDigit |= $a ^ $A;
1661 hexDigit -= $a - 10;
1662 assert(10 <= hexDigit && hexDigit <= 15);
1663 return hexDigit;
1664 }
1665
1666 static bool isHexDigit(int characterCode) {
1667 if ($0 <= characterCode && characterCode <= $9) return true;
1668 characterCode |= $a ^ $A;
1669 return ($a <= characterCode && characterCode <= $f);
1670 }
1671
1672 static int readUnicodeEscape(Iterator<int> iter,
1673 void cancel(String s)) {
1674 if (!iter.hasNext()) cancel("Incomplete unicode escape.");
1675 int code = iter.next();
1676 if (code == $OPEN_CURLY_BRACKET) {
1677 // In Dart, '\u{'x{0..7}'}' is a valid escape, but not in
1678 // JS. Convert to a \uxxxx escape.
1679 int value = 0;
1680 int length = 0;
1681 if (!iter.hasNext()) cancel("Incomplete unicode escape.");
1682 int hexDigit = iter.next();
1683 do {
1684 if (!isHexDigit(hexDigit)) {
1685 cancel("Invalid character in unicode escape");
1686 }
1687 value = value * 16 + hexValue(hexDigit);
1688 length++;
1689 if (length > 7) {
1690 cancel("Invalid unicode escape length.");
1691 }
1692 if (!iter.hasNext()) cancel("Incomplete unicode escape.");
1693 hexDigit = iter.next();
1694 } while (hexDigit !== $CLOSE_CURLY_BRACKET); // until '}'.
1695 return value;
1696 }
1697 // Simple four-digit unicode escape.
1698 int value = 0;
1699 for (int i = 0; i < 4; i++) {
1700 if (i > 0) {
1701 if (!iter.hasNext()) cancel("Incomplete unicode escape.");
1702 code = iter.next();
1703 }
1704 if (!isHexDigit(code)) cancel("Invalid character in unicode escape");
1705 value = value * 16 + hexValue(code);
1706 }
1707 return value;
1708 }
1709
1710 /**
1711 * Write the contents of the quoted string to a [StringBuffer] in
1712 * a form that is valid as JavaScript string literal content.
1713 * The string is assumed quoted by [quote] characters.
1714 * This method doesn't try to make the shortest string, but rather
1715 * to be as close to the original string as possible.
1716 */
1717 void writeEscaped(StringBuffer buffer, int quote, void cancel(String s)) {
1718 bool raw = this.isRaw;
1719 Iterator<int> iter =
1720 wrappedString.copyWithoutQuotes(leftQuoteLength,
1721 rightQuoteLength).iterator();
1722 while (iter.hasNext()) {
1723 int code = iter.next();
1724 if (code == quote) {
1725 // We need to add a backslash before quotes, both in normal
1726 // and in raw strings.
1727 buffer.add(@'\');
1728 buffer.add(code == $SQ ? "'" : '"');
1729 } else if (code == $LF) {
1730 // Newlines in strings only occour in multiline strings.
1731 // They need to be written using escapes in JS..
1732 assert(isMultiLine);
1733 buffer.add(@'\n');
1734 } else if (code == $CR) {
1735 assert(isMultiLine);
1736 buffer.add(@'\r');
1737 } else if (code == $LS || code == $PS) {
1738 // These Unicode line terminators are invalid in JS strings.
1739 buffer.add(code == $LS ? @'\u2028' : @'\u2029');
1740 } else if (code != $BACKSLASH) {
1741 buffer.add(new String.fromCharCodes([code]));
1742 } else if (raw) {
1743 buffer.add(@'\\');
1744 } else {
1745 code = iter.next();
1746 // TODO(lrn): Reading \x and \u escapes also validates the
1747 // escape sequences. This should be done at an earlier step
1748 // to catch errors even in dead code.
1749 switch (code) {
1750 case $u:
1751 int value = readUnicodeEscape(iter, cancel);
1752 if (value >= 0xD800 && value <= 0xDFFF || value > 0x10ffff) {
1753 cancel('Invalid unicode scalar value.');
1754 }
1755 if (value > 0xffff) {
1756 cancel('Unhandled Unicode value: $value - outside the BMP.');
1757 }
1758 buffer.add(@'\u');
1759 for (int j = 12; j >= 0; j -= 4) {
1760 int digit = (value >> j) & 0xf;
1761 buffer.add("0123456789abcdef"[digit]);
1762 }
1763 break;
1764 case $x:
1765 buffer.add(@'\x');
1766 List<int> codes = <int>[];
1767 for (int i = 0; i < 2; i++) {
1768 if (!iter.hasNext()) cancel("Incomplete hex escape");
1769 code = iter.next();
1770 if (!isHexDigit(code)) {
1771 cancel("Invalid hex digit: " +
1772 "${new String.fromCharCodes([code])}");
1773 }
1774 codes.add(code);
1775 }
1776 buffer.add(new String.fromCharCodes(codes));
1777 break;
1778 // Character escapes that identical in meaning in JS.
1779 case $b: buffer.add(@'\b'); break;
1780 case $f: buffer.add(@'\f'); break;
1781 case $n: buffer.add(@'\n'); break;
1782 case $r: buffer.add(@'\r'); break;
1783 case $t: buffer.add(@'\t'); break;
1784 case $v: buffer.add(@'\v'); break;
1785 // Identity escapes that must be escaped in JS strings.
1786 case $BACKSLASH: buffer.add(@'\\'); break;
1787 case $LF: buffer.add(@'\n'); break;
1788 case $CR: buffer.add(@'\r'); break;
1789 case $LS: buffer.add(@'\u2028'); break;
1790 case $PS: buffer.add(@'\u2029'); break;
1791 // Quotes may or may not need the escape.
1792 case $SQ:
1793 case $DQ:
1794 // Only escape quotes if they match the generated string quotes.
1795 if (code == quote) buffer.add(@'\');
1796 buffer.add(code === $SQ ? "'" : '"');
1797 break;
1798 default:
1799 // All other escaped characters are identity escapes,
1800 // and don't need a backslash in JS.
1801 buffer.add(new String.fromCharCodes([code]));
1802 break;
1803 }
1804 }
1805 }
1806 }
1807
1653 /** 1808 /**
1654 * Does a conservative test for equality between two quoted strings. 1809 * Does a conservative test for equality between two quoted strings.
1655 * Returns true if the two definitly have the same string. 1810 * Returns true if the two definitly have the same string.
1656 * Returns false if the strings are different, or if it's not possible 1811 * Returns false if the strings are different, or if it's not possible
1657 * to (quickly) determine whether they are equal. 1812 * to (quickly) determine whether they are equal.
1658 */ 1813 */
1659 bool definitlyEquals(QuotedString other) { 1814 bool definitlyEquals(QuotedString other) {
1660 return flags == other.flags && wrappedString == other.wrappedString; 1815 return flags == other.flags && wrappedString == other.wrappedString;
1661 } 1816 }
1662 1817
(...skipping 444 matching lines...) Expand 10 before | Expand all | Expand 10 after
2107 2262
2108 HInstruction get expression() => inputs[0]; 2263 HInstruction get expression() => inputs[0];
2109 2264
2110 HType computeType() => HType.BOOLEAN; 2265 HType computeType() => HType.BOOLEAN;
2111 bool hasExpectedType() => true; 2266 bool hasExpectedType() => true;
2112 2267
2113 accept(HVisitor visitor) => visitor.visitIs(this); 2268 accept(HVisitor visitor) => visitor.visitIs(this);
2114 2269
2115 toString() => "$expression is $typeExpression"; 2270 toString() => "$expression is $typeExpression";
2116 } 2271 }
OLDNEW
« no previous file with comments | « frog/leg/ssa/codegen.dart ('k') | frog/leg/ssa/ssa.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698