From cd725638cd29b3e2ba9ef8f2d20de7f34ca6663d Mon Sep 17 00:00:00 2001 From: Dave Holoway Date: Wed, 10 Jun 2020 18:43:43 +0100 Subject: [PATCH] parse labels and break/continue targets --- langserver/java/TokenList.js | 18 +++++++++++++++ langserver/java/body-parser3.js | 39 ++++++++++++++++++++++++++++++--- 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/langserver/java/TokenList.js b/langserver/java/TokenList.js index 342a206..7389060 100644 --- a/langserver/java/TokenList.js +++ b/langserver/java/TokenList.js @@ -25,6 +25,24 @@ class TokenList { } } } + + /** + * Token lookahead. The current token is unaffected by this method. + * @param {number} n number of tokens to look ahead + */ + peek(n) { + let token, idx = this.idx; + while (--n >= 0) { + for (; ;) { + token = this.tokens[idx += 1]; + if (!token || token.kind !== 'wsc') { + break; + } + } + } + return token; + } + /** * Check if the current token matches the specified value and consumes it * @param {string} value diff --git a/langserver/java/body-parser3.js b/langserver/java/body-parser3.js index 7fd91c5..3153f35 100644 --- a/langserver/java/body-parser3.js +++ b/langserver/java/body-parser3.js @@ -99,8 +99,19 @@ function statement(tokens, locals, method, imports, typemap) { case 'statement-kw': s = statementKeyword(tokens, locals, method, imports, typemap); return s; - case 'modifier': case 'ident': + // checking every statement identifier for a possible label is really inefficient, but trying to + // merge this into expression_or_var_decl is worse for now + if (tokens.peek(1).value === ':') { + const label = new Label(tokens.current); + tokens.inc(), tokens.inc(); + // ignore and just return the next statement + // - we cannot return the label as a statement because for/if/while check the next statement type + // the labels should be collated and checked for duplicates, etc + return statement(tokens, locals, method, imports, typemap); + } + // fall-through to expression_or_var_decl + case 'modifier': case 'primitive-type': s = expression_or_var_decl(tokens, locals, method, imports, typemap); if (Array.isArray(s)) { @@ -158,8 +169,14 @@ class WhileStatement extends Statement { test = null; statement = null; } -class BreakStatement extends Statement {} -class ContinueStatement extends Statement {} +class BreakStatement extends Statement { + /** @type {Token} */ + target = null; +} +class ContinueStatement extends Statement { + /** @type {Token} */ + target = null; +} class DoStatement extends Statement { test = null; block = null; @@ -193,6 +210,14 @@ class AssertStatement extends Statement { expression = null; message = null; } +class Label { + /** + * @param {Token} token + */ + constructor(token) { + this.name_token = token; + } +} /** * @param {TokenList} tokens @@ -253,11 +278,19 @@ function statementKeyword(tokens, locals, method, imports, typemap) { case 'break': tokens.inc(); s = new BreakStatement(); + if (tokens.current.kind === 'ident') { + s.target = tokens.current; + tokens.inc(); + } semicolon(tokens); break; case 'continue': tokens.inc(); s = new ContinueStatement(); + if (tokens.current.kind === 'ident') { + s.target = tokens.current; + tokens.inc(); + } semicolon(tokens); break; case 'switch':