Chromium Code Reviews| Index: runtime/bin/vmservice/client/lib/src/service/object.dart |
| diff --git a/runtime/bin/vmservice/client/lib/src/service/object.dart b/runtime/bin/vmservice/client/lib/src/service/object.dart |
| index 09b0de853ab1bc0a891d5aa9d999b71d3a811573..5fe97e6bec5e4ae4ffe1f92348e401c653972e5e 100644 |
| --- a/runtime/bin/vmservice/client/lib/src/service/object.dart |
| +++ b/runtime/bin/vmservice/client/lib/src/service/object.dart |
| @@ -1103,6 +1103,146 @@ class Allocations { |
| bool get empty => accumulated.empty && current.empty; |
| } |
| +class ClassParser { |
|
hausner
2014/07/01 23:49:07
When we spoke offline I was under the impression t
|
| + List<ScriptLine> _source; |
| + int _offset; |
| + |
| + ClassParser(this._source) { |
| + assert(_source != null && _source.length > 0); |
| + _offset = this._source.first.line; |
| + } |
| + |
| + // Internal state for parsing the class. |
| + var _line; |
| + var _col; |
| + int _currentToken; |
| + |
| + int _char(String str) => str.codeUnitAt(0); |
| + |
| + void _initTokens() { |
| + _line = 0; |
| + _col = 0; |
| + _currentToken = _source[_line].text.codeUnitAt(_col); |
| + } |
| + |
| + int _advanceToken([int num, stripWhite=true]) { |
| + _col++; |
| + if (_col >= _source[_line].text.codeUnits.length) { |
| + var col = _col; |
| + _col = 0; |
| + _line++; |
| + if (_line == _source.length) { |
| + _line--; |
| + _col = col; |
| + _currentToken = 0; |
| + return 0; |
| + } |
| + } |
| + |
| + while (_source[_line].text.length == 0) { _line++; } |
| + _currentToken = _source[_line].text.codeUnitAt(_col); |
| + if (stripWhite && _currentToken == _char(' ')) { |
| + _advanceToken(); |
| + } |
| + if (num != null) { |
| + for (int i = 1; i < num; i++) { |
| + _advanceToken(); |
| + } |
| + } |
| + return _currentToken; |
| + } |
| + |
| + int _peek(int len, [stripWhite=true]) { |
| + int saved_line = _line; |
| + int saved_col = _col; |
| + int c = _advanceToken(len,stripWhite); |
| + _line = saved_line; |
| + _col = saved_col; |
| + return c; |
| + } |
| + |
| + void _consumeMultilineString(int quote) { |
| + _advanceToken(3); |
| + for (int c = _currentToken; c != 0; c = _advanceToken()) { |
| + if (c == quote && _peek(1) == quote && _peek(2) == quote) { |
| + _advanceToken(3); |
| + break; |
| + } |
| + } |
| + } |
| + |
| + void _consumeString(int quote) { |
| + _advanceToken(); |
| + for (int c = _currentToken; c != 0; c = _advanceToken()) { |
| + if (c == _char('\\')) { |
| + _advanceToken(); |
| + } |
| + if (c == quote) { |
| + _advanceToken(); |
| + break; |
| + } |
| + } |
| + } |
| + |
| + void _consumeComment() { |
| + _col = _source[_line].text.codeUnits.length; |
| + } |
| + |
| + void _consumeMultilineComment() { |
| + _advanceToken(2); |
| + int commentLevel = 1; |
| + for (int c = _currentToken; c != 0; c = _advanceToken()) { |
| + if (c == _char('/') && _peek(1, false) == _char('*')) { |
| + commentLevel++; |
| + _advanceToken(); |
| + } else if (c == _char('*') && _peek(1, false) == _char('/')) { |
| + commentLevel--; |
| + _advanceToken(); |
| + if (commentLevel == 0) { |
| + _advanceToken(); |
| + break; |
| + } |
| + } |
| + } |
| + } |
| + |
| + /// Finds the end position, i.e., the closing curly brackets of the given |
| + /// class. |
| + /// Returns a tuple [line, col]. |
| + List findEndPos() { |
| + int level = 0; |
| + _initTokens(); |
| + for (int c = _currentToken; c != 0; c=_currentToken) { |
| + if ((c == _char("'") && |
| + _peek(1) == _char("'") && |
| + _peek(2) == _char("'")) || |
| + (c == _char('"') && |
| + _peek(1) == _char('"') && |
| + _peek(2) == _char('"'))) { |
| + _consumeMultilineString(c); |
| + continue; |
| + } else if (c == _char("'") || c == _char('"')) { |
| + _consumeString(c); |
| + continue; |
| + } else if (c == _char('/') && _peek(1, false) == _char('/')) { |
| + _consumeComment(); |
| + continue; |
| + } else if (c == _char('/') && _peek(1, false) == _char('*')) { |
| + _consumeMultilineComment(); |
| + continue; |
| + } else if (c == _char('{')) { |
| + level++; |
| + } else if (c == _char('}')) { |
| + if (--level == 0) { |
| + break; |
| + } |
| + } |
| + c = _advanceToken(); |
| + } |
| + return [_line + _offset, _col + 1]; |
| + } |
| +} |
| + |
| class Class extends ServiceObject with Coverage { |
| @observable Library library; |
| @observable Script script; |
| @@ -1116,6 +1256,14 @@ class Class extends ServiceObject with Coverage { |
| @observable int tokenPos; |
| + int _endTokenPos = null; |
| + @observable int get endTokenPos { |
| + if (_endTokenPos == null) { |
| + _computeEndTokenPos(); |
| + } |
| + return _endTokenPos; |
| + } |
| + |
| @observable ServiceMap error; |
| final Allocations newSpace = new Allocations(); |
| @@ -1201,6 +1349,26 @@ class Class extends ServiceObject with Coverage { |
| Future<ServiceObject> get(String command) { |
| return isolate.get(id + "/$command"); |
| } |
| + |
| + void _computeEndTokenPos() { |
| + script.load().whenComplete(() { |
| + int line = script.tokenToLine(tokenPos); // Lines are 1-based. |
| + ClassParser clsp = new ClassParser(script.lines.sublist(line - 1)); |
| + List posTuple = clsp.findEndPos(); |
| + // Search for the token one this line and column. |
| + List tokenCandidates = []; |
| + script._tokenToLine.forEach((k,v) { |
| + if (script._tokenToLine[k] == posTuple[0]) { |
| + tokenCandidates.add(k); |
| + } |
| + }); |
| + Iterable tokenIndex = |
| + tokenCandidates.where((e) => script._tokenToCol[e] == posTuple[1]); |
| + assert(tokenIndex.length == 1); |
| + _endTokenPos = tokenIndex.first; |
| + notifyPropertyChange(#endTokenPos, null, _endTokenPos); |
| + }); |
| + } |
| } |
| class ScriptLine extends Observable { |