| // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| part of scanner; |
| |
| /** |
| * A keyword in the Dart programming language. |
| */ |
| class Keyword { |
| static const List<Keyword> values = const <Keyword> [ |
| const Keyword("assert"), |
| const Keyword("break"), |
| const Keyword("case"), |
| const Keyword("catch"), |
| const Keyword("class"), |
| const Keyword("const"), |
| const Keyword("continue"), |
| const Keyword("default"), |
| const Keyword("do"), |
| const Keyword("else"), |
| const Keyword("extends"), |
| const Keyword("false"), |
| const Keyword("final"), |
| const Keyword("finally"), |
| const Keyword("for"), |
| const Keyword("if"), |
| const Keyword("in"), |
| const Keyword("new"), |
| const Keyword("null"), |
| const Keyword("rethrow"), |
| const Keyword("return"), |
| const Keyword("super"), |
| const Keyword("switch"), |
| const Keyword("this"), |
| const Keyword("throw"), |
| const Keyword("true"), |
| const Keyword("try"), |
| const Keyword("var"), |
| const Keyword("void"), |
| const Keyword("while"), |
| const Keyword("with"), |
| |
| // TODO(ahe): Don't think this is a reserved word. |
| // See: http://dartbug.com/5579 |
| const Keyword("is", info: IS_INFO), |
| |
| const Keyword("abstract", isBuiltIn: true), |
| const Keyword("as", info: AS_INFO, isBuiltIn: true), |
| const Keyword("dynamic", isBuiltIn: true), |
| const Keyword("export", isBuiltIn: true), |
| const Keyword("external", isBuiltIn: true), |
| const Keyword("factory", isBuiltIn: true), |
| const Keyword("get", isBuiltIn: true), |
| const Keyword("implements", isBuiltIn: true), |
| const Keyword("import", isBuiltIn: true), |
| const Keyword("library", isBuiltIn: true), |
| const Keyword("operator", isBuiltIn: true), |
| const Keyword("part", isBuiltIn: true), |
| const Keyword("set", isBuiltIn: true), |
| const Keyword("static", isBuiltIn: true), |
| const Keyword("typedef", isBuiltIn: true), |
| |
| const Keyword("hide", isPseudo: true), |
| const Keyword("native", isPseudo: true), |
| const Keyword("of", isPseudo: true), |
| const Keyword("on", isPseudo: true), |
| const Keyword("show", isPseudo: true), |
| const Keyword("source", isPseudo: true), |
| const Keyword("deferred", isPseudo: true)]; |
| |
| final String syntax; |
| final bool isPseudo; |
| final bool isBuiltIn; |
| final PrecedenceInfo info; |
| |
| static Map<String, Keyword> _keywords; |
| static Map<String, Keyword> get keywords { |
| if (_keywords == null) { |
| _keywords = computeKeywordMap(); |
| } |
| return _keywords; |
| } |
| |
| const Keyword(this.syntax, |
| {this.isPseudo: false, |
| this.isBuiltIn: false, |
| this.info: KEYWORD_INFO}); |
| |
| static Map<String, Keyword> computeKeywordMap() { |
| Map<String, Keyword> result = new Map<String, Keyword>(); |
| for (Keyword keyword in values) { |
| result[keyword.syntax] = keyword; |
| } |
| return result; |
| } |
| |
| String toString() => syntax; |
| } |
| |
| /** |
| * Abstract state in a state machine for scanning keywords. |
| */ |
| abstract class KeywordState { |
| KeywordState(this.keyword); |
| |
| KeywordState next(int c); |
| final Keyword keyword; |
| |
| static KeywordState _KEYWORD_STATE; |
| static KeywordState get KEYWORD_STATE { |
| if (_KEYWORD_STATE == null) { |
| List<String> strings = |
| new List<String>(Keyword.values.length); |
| for (int i = 0; i < Keyword.values.length; i++) { |
| strings[i] = Keyword.values[i].syntax; |
| } |
| strings.sort((a,b) => a.compareTo(b)); |
| _KEYWORD_STATE = computeKeywordStateTable(0, strings, 0, strings.length); |
| } |
| return _KEYWORD_STATE; |
| } |
| |
| static KeywordState computeKeywordStateTable(int start, List<String> strings, |
| int offset, int length) { |
| List<KeywordState> result = new List<KeywordState>(26); |
| assert(length != 0); |
| int chunk = 0; |
| int chunkStart = -1; |
| bool isLeaf = false; |
| for (int i = offset; i < offset + length; i++) { |
| if (strings[i].length == start) { |
| isLeaf = true; |
| } |
| if (strings[i].length > start) { |
| int c = strings[i].codeUnitAt(start); |
| if (chunk != c) { |
| if (chunkStart != -1) { |
| assert(result[chunk - $a] == null); |
| result[chunk - $a] = computeKeywordStateTable(start + 1, strings, |
| chunkStart, |
| i - chunkStart); |
| } |
| chunkStart = i; |
| chunk = c; |
| } |
| } |
| } |
| if (chunkStart != -1) { |
| assert(result[chunk - $a] == null); |
| result[chunk - $a] = |
| computeKeywordStateTable(start + 1, strings, chunkStart, |
| offset + length - chunkStart); |
| } else { |
| assert(length == 1); |
| return new LeafKeywordState(strings[offset]); |
| } |
| if (isLeaf) { |
| return new ArrayKeywordState(result, strings[offset]); |
| } else { |
| return new ArrayKeywordState(result, null); |
| } |
| } |
| } |
| |
| /** |
| * A state with multiple outgoing transitions. |
| */ |
| class ArrayKeywordState extends KeywordState { |
| final List<KeywordState> table; |
| |
| ArrayKeywordState(List<KeywordState> this.table, String syntax) |
| : super((syntax == null) ? null : Keyword.keywords[syntax]); |
| |
| KeywordState next(int c) => table[c - $a]; |
| |
| String toString() { |
| StringBuffer sb = new StringBuffer(); |
| sb.write("["); |
| if (keyword != null) { |
| sb.write("*"); |
| sb.write(keyword); |
| sb.write(" "); |
| } |
| List<KeywordState> foo = table; |
| for (int i = 0; i < foo.length; i++) { |
| if (foo[i] != null) { |
| sb.write("${new String.fromCharCodes([i + $a])}: ${foo[i]}; "); |
| } |
| } |
| sb.write("]"); |
| return sb.toString(); |
| } |
| } |
| |
| /** |
| * A state that has no outgoing transitions. |
| */ |
| class LeafKeywordState extends KeywordState { |
| LeafKeywordState(String syntax) : super(Keyword.keywords[syntax]); |
| |
| KeywordState next(int c) => null; |
| |
| String toString() => keyword.syntax; |
| } |