io.doov.tsparser.JavaScriptBaseLexer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of doov-ts-parser Show documentation
Show all versions of doov-ts-parser Show documentation
dOOv, a fluent API for type-safe domain model validation
package io.doov.tsparser;
import java.util.Stack;
import org.antlr.v4.runtime.*;
/**
* All lexer methods that used in grammar (IsStrictMode)
* should start with Upper Case Char similar to Lexer rules.
*/
public abstract class JavaScriptBaseLexer extends Lexer
{
/**
* Stores values of nested modes. By default mode is strict or
* defined externally (useStrictDefault)
*/
private Stack scopeStrictModes = new Stack();
private Token lastToken = null;
/**
* Default value of strict mode
* Can be defined externally by setUseStrictDefault
*/
private boolean useStrictDefault = false;
/**
* Current value of strict mode
* Can be defined during parsing, see StringFunctions.js and StringGlobal.js samples
*/
private boolean useStrictCurrent = false;
public JavaScriptBaseLexer(CharStream input) {
super(input);
}
public boolean getStrictDefault() {
return useStrictDefault;
}
public void setUseStrictDefault(boolean value) {
useStrictDefault = value;
useStrictCurrent = value;
}
public boolean IsSrictMode() {
return useStrictCurrent;
}
/**
* Return the next token from the character stream and records this last
* token in case it resides on the default channel. This recorded token
* is used to determine when the lexer could possibly match a regex
* literal. Also changes scopeStrictModes stack if tokenize special
* string 'use strict';
*
* @return the next token from the character stream.
*/
@Override
public Token nextToken() {
Token next = super.nextToken();
if (next.getType() == JavaScriptLexer.OpenBrace)
{
useStrictCurrent = scopeStrictModes.size() > 0 && scopeStrictModes.peek() ? true : useStrictDefault;
scopeStrictModes.push(useStrictCurrent);
}
else if (next.getType() == JavaScriptLexer.CloseBrace)
{
useStrictCurrent = scopeStrictModes.size() > 0 ? scopeStrictModes.pop() : useStrictDefault;
}
else if (next.getType() == JavaScriptLexer.StringLiteral &&
(lastToken == null || lastToken.getType() == JavaScriptLexer.OpenBrace) &&
(next.getText().substring(1, next.getText().length() - 1)).equals("use strict"))
{
if (scopeStrictModes.size() > 0)
scopeStrictModes.pop();
useStrictCurrent = true;
scopeStrictModes.push(useStrictCurrent);
}
if (next.getChannel() == Token.DEFAULT_CHANNEL) {
// Keep track of the last token on the default channel.
this.lastToken = next;
}
return next;
}
/**
* Returns {@code true} if the lexer can match a regex literal.
*
* @return regexPossible
*/
protected boolean RegexPossible() {
if (this.lastToken == null) {
// No token has been produced yet: at the start of the input,
// no division is possible, so a regex literal _is_ possible.
return true;
}
switch (this.lastToken.getType()) {
case JavaScriptLexer.Identifier:
case JavaScriptLexer.NullLiteral:
case JavaScriptLexer.BooleanLiteral:
case JavaScriptLexer.This:
case JavaScriptLexer.CloseBracket:
case JavaScriptLexer.CloseParen:
case JavaScriptLexer.OctalIntegerLiteral:
case JavaScriptLexer.DecimalLiteral:
case JavaScriptLexer.HexIntegerLiteral:
case JavaScriptLexer.StringLiteral:
case JavaScriptLexer.PlusPlus:
case JavaScriptLexer.MinusMinus:
// After any of the tokens above, no regex literal can follow.
return false;
default:
// In all other cases, a regex literal _is_ possible.
return true;
}
}
}