Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
fglock committed Oct 21, 2024
1 parent 0384791 commit 1152ad6
Show file tree
Hide file tree
Showing 8 changed files with 283 additions and 278 deletions.
95 changes: 67 additions & 28 deletions src/main/java/org/perlonjava/parser/ListParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public class ListParser {
// Comma is allowed after the argument: rand, rand 10,
//
static ListNode parseZeroOrOneList(Parser parser, int minItems) {
if (parser.looksLikeEmptyList()) {
if (looksLikeEmptyList(parser)) {
// return an empty list
if (minItems > 0) {
throw new PerlCompilerException(parser.tokenIndex, "Syntax error", parser.ctx.errorUtil);
Expand All @@ -25,11 +25,11 @@ static ListNode parseZeroOrOneList(Parser parser, int minItems) {
}

ListNode expr;
LexerToken token = parser.peek();
LexerToken token = TokenUtils.peek(parser);
if (token.text.equals("(")) {
// argument in parentheses, can be 0 or 1 argument: rand(), rand(10)
// Commas are allowed after the single argument: rand(10,)
parser.consume();
TokenUtils.consume(parser);
expr = new ListNode(parseList(parser, ")", 0), parser.tokenIndex);
if (expr.elements.size() > 1) {
throw new PerlCompilerException(parser.tokenIndex, "Syntax error", parser.ctx.errorUtil);
Expand Down Expand Up @@ -71,20 +71,20 @@ static ListNode parseZeroOrMoreList(Parser parser, int minItems, boolean wantBlo

if (wantRegex) {
boolean matched = false;
if (parser.peek().text.equals("(")) {
parser.consume();
if (TokenUtils.peek(parser).text.equals("(")) {
TokenUtils.consume(parser);
hasParen = true;
}
if (parser.peek().text.equals("/") || parser.peek().text.equals("//")) {
parser.consume();
if (TokenUtils.peek(parser).text.equals("/") || TokenUtils.peek(parser).text.equals("//")) {
TokenUtils.consume(parser);
Node regex = StringParser.parseRawString(parser, "/");
if (regex != null) {
matched = true;
expr.elements.add(regex);
token = parser.peek();
token = TokenUtils.peek(parser);
if (token.type != LexerTokenType.EOF && !Parser.LIST_TERMINATORS.contains(token.text)) {
// consume comma
parser.consume(LexerTokenType.OPERATOR, ",");
TokenUtils.consume(parser, LexerTokenType.OPERATOR, ",");
}
}
}
Expand All @@ -96,8 +96,8 @@ static ListNode parseZeroOrMoreList(Parser parser, int minItems, boolean wantBlo
}

if (wantFileHandle) {
if (parser.peek().text.equals("(")) {
parser.consume();
if (TokenUtils.peek(parser).text.equals("(")) {
TokenUtils.consume(parser);
hasParen = true;
}
expr.handle = parser.parseFileHandle();
Expand All @@ -109,37 +109,37 @@ static ListNode parseZeroOrMoreList(Parser parser, int minItems, boolean wantBlo
}

if (wantBlockNode) {
if (parser.peek().text.equals("(")) {
parser.consume();
if (TokenUtils.peek(parser).text.equals("(")) {
TokenUtils.consume(parser);
hasParen = true;
}
if (parser.peek().text.equals("{")) {
parser.consume();
if (TokenUtils.peek(parser).text.equals("{")) {
TokenUtils.consume(parser);
expr.handle = parser.parseBlock();
parser.consume(LexerTokenType.OPERATOR, "}");
TokenUtils.consume(parser, LexerTokenType.OPERATOR, "}");
}
if (!parser.isSpaceAfterPrintBlock() || parser.looksLikeEmptyList()) {
if (!parser.isSpaceAfterPrintBlock() || looksLikeEmptyList(parser)) {
throw new PerlCompilerException(parser.tokenIndex, "Syntax error", parser.ctx.errorUtil);
}
}

if (!parser.looksLikeEmptyList()) {
if (!looksLikeEmptyList(parser)) {
// it doesn't look like an empty list
token = parser.peek();
token = TokenUtils.peek(parser);
if (obeyParentheses && token.text.equals("(")) {
// arguments in parentheses, can be 0 or more arguments: print(), print(10)
// Commas are allowed after the arguments: print(10,)
parser.consume();
TokenUtils.consume(parser);
expr.elements.addAll(parseList(parser, ")", 0));
} else {
while (token.type != LexerTokenType.EOF && !Parser.LIST_TERMINATORS.contains(token.text)) {
// Argument without parentheses
expr.elements.add(parser.parseExpression(parser.getPrecedence(",")));
token = parser.peek();
token = TokenUtils.peek(parser);
if (token.text.equals(",") || token.text.equals("=>")) {
while (token.text.equals(",") || token.text.equals("=>")) {
parser.consume();
token = parser.peek();
TokenUtils.consume(parser);
token = TokenUtils.peek(parser);
}
} else {
break;
Expand All @@ -149,7 +149,7 @@ static ListNode parseZeroOrMoreList(Parser parser, int minItems, boolean wantBlo
}

if (hasParen) {
parser.consume(LexerTokenType.OPERATOR, ")");
TokenUtils.consume(parser, LexerTokenType.OPERATOR, ")");
}
parser.ctx.logDebug("parseZeroOrMoreList end: " + expr);

Expand All @@ -174,16 +174,16 @@ static List<Node> parseList(Parser parser, String close, int minItems) {
parser.ctx.logDebug("parseList start");
ListNode expr;

LexerToken token = parser.peek();
LexerToken token = TokenUtils.peek(parser);
parser.ctx.logDebug("parseList start at " + token);
if (token.text.equals(close)) {
// empty list
parser.consume();
TokenUtils.consume(parser);
expr = new ListNode(parser.tokenIndex);
} else {
expr = ListNode.makeList(parser.parseExpression(0));
parser.ctx.logDebug("parseList end at " + parser.peek());
parser.consume(LexerTokenType.OPERATOR, close);
parser.ctx.logDebug("parseList end at " + TokenUtils.peek(parser));
TokenUtils.consume(parser, LexerTokenType.OPERATOR, close);
}

if (expr.elements.size() < minItems) {
Expand All @@ -193,4 +193,43 @@ static List<Node> parseList(Parser parser, String close, int minItems) {

return expr.elements;
}

public static boolean looksLikeEmptyList(Parser parser) {
boolean isEmptyList = false;
int previousIndex = parser.tokenIndex;
LexerToken token = TokenUtils.consume(parser);
LexerToken token1 = parser.tokens.get(parser.tokenIndex); // next token including spaces
LexerToken nextToken = TokenUtils.peek(parser); // after spaces

if (token.type == LexerTokenType.EOF || Parser.LIST_TERMINATORS.contains(token.text)) {
isEmptyList = true;
} else if (token.text.equals("-")
&& token1.type == LexerTokenType.IDENTIFIER
&& token1.text.length() == 1) {
// -d, -e, -f, -l, -p, -x
isEmptyList = false;
} else if (Parser.INFIX_OP.contains(token.text) || token.text.equals(",")) {
// tokenIndex++;
parser.ctx.logDebug("parseZeroOrMoreList infix `" + token.text + "` followed by `" + nextToken.text + "`");
if (token.text.equals("&")) {
// looks like a subroutine call, not an infix `&`
parser.ctx.logDebug("parseZeroOrMoreList looks like subroutine call");
} else if (token.text.equals("%") && (nextToken.text.equals("$") || nextToken.type == LexerTokenType.IDENTIFIER)) {
// looks like a hash deref, not an infix `%`
parser.ctx.logDebug("parseZeroOrMoreList looks like Hash");
} else if (token.text.equals(".") && token1.type == LexerTokenType.NUMBER) {
// looks like a fractional number, not an infix `.`
parser.ctx.logDebug("parseZeroOrMoreList looks like Number");
} else {
// subroutine call with zero arguments, followed by infix operator: `pos = 3`
parser.ctx.logDebug("parseZeroOrMoreList return zero at `" + parser.tokens.get(parser.tokenIndex) + "`");
// if (LVALUE_INFIX_OP.contains(token.text)) {
// throw new PerlCompilerException(tokenIndex, "Can't modify non-lvalue subroutine call", ctx.errorUtil);
// }
isEmptyList = true;
}
}
parser.tokenIndex = previousIndex;
return isEmptyList;
}
}
16 changes: 8 additions & 8 deletions src/main/java/org/perlonjava/parser/NumberParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ public static NumberNode parseNumber(Parser parser, LexerToken token) {
char secondChar = letter.charAt(0);
if (secondChar == 'b' || secondChar == 'B') {
// Binary number: 0b...
parser.consume();
TokenUtils.consume(parser);
int num = Integer.parseInt(letter.substring(1), 2);
return new NumberNode(Integer.toString(num), parser.tokenIndex);
} else if (secondChar == 'x' || secondChar == 'X') {
// Hexadecimal number: 0x...
parser.consume();
TokenUtils.consume(parser);
int num = Integer.parseInt(letter.substring(1), 16);
return new NumberNode(Integer.toString(num), parser.tokenIndex);
}
Expand All @@ -48,9 +48,9 @@ public static NumberNode parseNumber(Parser parser, LexerToken token) {

// Check for fractional part
if (parser.tokens.get(parser.tokenIndex).text.equals(".")) {
number.append(parser.consume().text); // consume '.'
number.append(TokenUtils.consume(parser).text); // consume '.'
if (parser.tokens.get(parser.tokenIndex).type == LexerTokenType.NUMBER) {
number.append(parser.consume().text); // consume digits after '.'
number.append(TokenUtils.consume(parser).text); // consume digits after '.'
}
}
// Check for exponent part
Expand Down Expand Up @@ -89,9 +89,9 @@ public static Node parseFractionalNumber(Parser parser) {
*/
public static void checkNumberExponent(Parser parser, StringBuilder number) {
// Check for exponent part
String exponentPart = parser.peek().text;
String exponentPart = TokenUtils.peek(parser).text;
if (exponentPart.startsWith("e") || exponentPart.startsWith("E")) {
parser.consume(); // consume 'e' or 'E' and possibly more 'E10'
TokenUtils.consume(parser); // consume 'e' or 'E' and possibly more 'E10'

// Check if the rest of the token contains digits (e.g., "E10")
int index = 1;
Expand All @@ -106,11 +106,11 @@ public static void checkNumberExponent(Parser parser, StringBuilder number) {
if (index == 1) {
// Check for optional sign
if (parser.tokens.get(parser.tokenIndex).text.equals("-") || parser.tokens.get(parser.tokenIndex).text.equals("+")) {
number.append(parser.consume().text); // consume '-' or '+'
number.append(TokenUtils.consume(parser).text); // consume '-' or '+'
}

// Consume exponent digits
number.append(parser.consume(LexerTokenType.NUMBER).text);
number.append(TokenUtils.consume(parser, LexerTokenType.NUMBER).text);
}
}
}
Expand Down
18 changes: 9 additions & 9 deletions src/main/java/org/perlonjava/parser/OperatorParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ static BinaryOperatorNode parseMapGrepSort(Parser parser, LexerToken token) {
static Node parseRequire(Parser parser) {
LexerToken token;
// Handle 'require' keyword which can be followed by a version, bareword or filename
token = parser.peek();
token = TokenUtils.peek(parser);
Node operand;
if (token.type == LexerTokenType.IDENTIFIER) {
// TODO `require` version
Expand Down Expand Up @@ -78,11 +78,11 @@ static Node parseDoOperator(Parser parser) {
LexerToken token;
Node block;
// Handle 'do' keyword which can be followed by a block or filename
token = parser.peek();
token = TokenUtils.peek(parser);
if (token.type == LexerTokenType.OPERATOR && token.text.equals("{")) {
parser.consume(LexerTokenType.OPERATOR, "{");
TokenUtils.consume(parser, LexerTokenType.OPERATOR, "{");
block = parser.parseBlock();
parser.consume(LexerTokenType.OPERATOR, "}");
TokenUtils.consume(parser, LexerTokenType.OPERATOR, "}");
return block;
}
// `do` file
Expand All @@ -101,12 +101,12 @@ static AbstractNode parseEval(Parser parser) {
Node operand;
LexerToken token;
// Handle 'eval' keyword which can be followed by a block or an expression
token = parser.peek();
token = TokenUtils.peek(parser);
if (token.type == LexerTokenType.OPERATOR && token.text.equals("{")) {
// If the next token is '{', parse a block
parser.consume(LexerTokenType.OPERATOR, "{");
TokenUtils.consume(parser, LexerTokenType.OPERATOR, "{");
block = parser.parseBlock();
parser.consume(LexerTokenType.OPERATOR, "}");
TokenUtils.consume(parser, LexerTokenType.OPERATOR, "}");
// transform: eval { 123 }
// into: sub { 123 }->() with useTryCatch flag
return new BinaryOperatorNode("->",
Expand Down Expand Up @@ -146,7 +146,7 @@ static Node parseDiamondOperator(Parser parser, LexerToken token) {

// Check if the next token is a closing angle bracket
if (parser.tokens.get(parser.tokenIndex).text.equals(">")) {
parser.consume(); // Consume the '>' token
TokenUtils.consume(parser); // Consume the '>' token
// Return a BinaryOperatorNode representing a readline operation
return new BinaryOperatorNode("readline",
var,
Expand All @@ -165,7 +165,7 @@ static Node parseDiamondOperator(Parser parser, LexerToken token) {

// Check if the next token is a closing angle bracket
if (parser.tokens.get(parser.tokenIndex).text.equals(">")) {
parser.consume(); // Consume the '>' token
TokenUtils.consume(parser); // Consume the '>' token
// Return a BinaryOperatorNode representing a readline operation
return new BinaryOperatorNode("readline",
new IdentifierNode("main::" + tokenText, currentTokenIndex),
Expand Down
Loading

0 comments on commit 1152ad6

Please sign in to comment.