Skip to content

Commit

Permalink
local keyword wip
Browse files Browse the repository at this point in the history
  • Loading branch information
fglock committed Oct 22, 2024
1 parent b33de15 commit 3677eaf
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 32 deletions.
50 changes: 30 additions & 20 deletions src/main/java/org/perlonjava/parser/Parser.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

import java.util.*;

import static org.perlonjava.parser.TokenUtils.peek;

public class Parser {
public static final Set<String> TERMINATORS =
Set.of(":", ";", ")", "}", "]", "if", "unless", "while", "until", "for", "foreach", "when");
Expand Down Expand Up @@ -95,15 +97,15 @@ public BlockNode parseBlock() {
int currentIndex = tokenIndex;
ctx.symbolTable.enterScope();
List<Node> statements = new ArrayList<>();
LexerToken token = TokenUtils.peek(this);
LexerToken token = peek(this);
while (token.type != LexerTokenType.EOF
&& !(token.type == LexerTokenType.OPERATOR && token.text.equals("}"))) {
if (token.text.equals(";")) {
TokenUtils.consume(this);
} else {
statements.add(parseStatement());
}
token = TokenUtils.peek(this);
token = peek(this);
}
if (statements.isEmpty()) {
statements.add(new ListNode(tokenIndex));
Expand All @@ -114,17 +116,17 @@ public BlockNode parseBlock() {

public Node parseStatement() {
int currentIndex = tokenIndex;
LexerToken token = TokenUtils.peek(this);
LexerToken token = peek(this);
ctx.logDebug("parseStatement `" + token.text + "`");

// check for label:
String label = null;
if (token.type == LexerTokenType.IDENTIFIER) {
String id = TokenUtils.consume(this).text;
if (TokenUtils.peek(this).text.equals(":")) {
if (peek(this).text.equals(":")) {
label = id;
TokenUtils.consume(this);
token = TokenUtils.peek(this);
token = peek(this);
} else {
tokenIndex = currentIndex; // backtrack
}
Expand All @@ -149,7 +151,7 @@ public Node parseStatement() {
case "sub":
// Must be followed by an identifier
tokenIndex++;
if (TokenUtils.peek(this).type == LexerTokenType.IDENTIFIER) {
if (peek(this).type == LexerTokenType.IDENTIFIER) {
return SubroutineParser.parseSubroutineDefinition(this, true);
}
// otherwise backtrack
Expand All @@ -176,7 +178,7 @@ public Node parseStatement() {
}
}
Node expression = parseExpression(0);
token = TokenUtils.peek(this);
token = peek(this);
if (token.type == LexerTokenType.IDENTIFIER) {
// statement modifier: if, for ...
switch (token.text) {
Expand Down Expand Up @@ -232,7 +234,7 @@ public Node parseStatement() {
}

public void parseStatementTerminator() {
LexerToken token = TokenUtils.peek(this);
LexerToken token = peek(this);
if (token.type != LexerTokenType.EOF && !token.text.equals("}") && !token.text.equals(";")) {
throw new PerlCompilerException(tokenIndex, "Syntax error", ctx.errorUtil);
}
Expand Down Expand Up @@ -306,7 +308,7 @@ public Node parseExpression(int precedence) {
// Continuously process tokens until we reach the end of the expression.
while (true) {
// Peek at the next token to determine what to do next.
LexerToken token = TokenUtils.peek(this);
LexerToken token = peek(this);

// Check if we have reached the end of the input (EOF) or a terminator (like `;`).
if (token.type == LexerTokenType.EOF || TERMINATORS.contains(token.text)) {
Expand Down Expand Up @@ -539,6 +541,14 @@ public Node parseCoreOperator(LexerToken token) {
// Handle 'my' keyword as a unary operator with an operand
operand = parsePrimary();
return new OperatorNode(token.text, operand, currentIndex);
case "local":
// Handle 'local' keyword as a unary operator with an operand
if (peek(this).text.equals("(")) {
operand = parsePrimary();
} else {
operand = parseExpression(getPrecedence("++"));
}
return new OperatorNode(token.text, operand, currentIndex);
case "last":
case "next":
case "redo":
Expand Down Expand Up @@ -630,7 +640,7 @@ public Node parsePrimary() {

switch (token.type) {
case IDENTIFIER:
String nextTokenText = TokenUtils.peek(this).text;
String nextTokenText = peek(this).text;
if (nextTokenText.equals("=>")) {
// Autoquote
return new StringNode(token.text, tokenIndex);
Expand Down Expand Up @@ -708,7 +718,7 @@ public Node parsePrimary() {
// Handle `-d`
String operator = "-" + nextToken.text;
tokenIndex++;
nextToken = TokenUtils.peek(this);
nextToken = peek(this);
if (nextToken.text.equals("_")) {
// Handle `-f _`
TokenUtils.consume(this);
Expand Down Expand Up @@ -769,7 +779,7 @@ private Node parseCoderefVariable(LexerToken token) {

Node list;
// If the next token is not `(`, handle auto-call by transforming `&subr` to `&subr(@_)`
if (!TokenUtils.peek(this).text.equals("(")) {
if (!peek(this).text.equals("(")) {
list = new OperatorNode("@", new IdentifierNode("_", tokenIndex), tokenIndex);
} else {
// Otherwise, parse the list of arguments
Expand Down Expand Up @@ -810,7 +820,7 @@ public Node parseVariable(String sigil) {
if (varName != null) {
// Variable name is valid.
// Check for illegal characters after a variable
if (TokenUtils.peek(this).text.equals("(") && !sigil.equals("&") && !parsingForLoopVariable) {
if (peek(this).text.equals("(") && !sigil.equals("&") && !parsingForLoopVariable) {
// Parentheses are only allowed after a variable in specific cases:
// - `for my $v (...`
// - `&name(...`
Expand All @@ -820,7 +830,7 @@ public Node parseVariable(String sigil) {

// Create a Variable node
return new OperatorNode(sigil, new IdentifierNode(varName, tokenIndex), tokenIndex);
} else if (TokenUtils.peek(this).text.equals("{")) {
} else if (peek(this).text.equals("{")) {
// Handle curly brackets to parse a nested expression `${v}`
TokenUtils.consume(this); // Consume the '{'
Node block = parseBlock(); // Parse the block inside the curly brackets
Expand Down Expand Up @@ -860,7 +870,7 @@ public Node parseInfixOperation(Node left, int precedence) {
// Autoquote - Convert IdentifierNode to StringNode
left = new StringNode(((IdentifierNode) left).name, ((IdentifierNode) left).tokenIndex);
}
token = TokenUtils.peek(this);
token = peek(this);
if (token.type == LexerTokenType.EOF || LIST_TERMINATORS.contains(token.text) || token.text.equals(",") || token.text.equals("=>")) {
// "postfix" comma
return ListNode.makeList(left);
Expand All @@ -873,7 +883,7 @@ public Node parseInfixOperation(Node left, int precedence) {
right = parseExpression(precedence);
return new TernaryOperatorNode(token.text, left, middle, right, tokenIndex);
case "->":
String nextText = TokenUtils.peek(this).text;
String nextText = peek(this).text;
switch (nextText) {
case "(":
TokenUtils.consume(this);
Expand Down Expand Up @@ -918,11 +928,11 @@ public Node parseInfixOperation(Node left, int precedence) {

public Node parseFileHandle() {
boolean hasBracket = false;
if (TokenUtils.peek(this).text.equals("{")) {
if (peek(this).text.equals("{")) {
TokenUtils.consume(this);
hasBracket = true;
}
LexerToken token = TokenUtils.peek(this);
LexerToken token = peek(this);
Node fileHandle = null;
if (token.type == LexerTokenType.IDENTIFIER) {
// bareword
Expand All @@ -944,7 +954,7 @@ public Node parseFileHandle() {
fileHandle = parsePrimary();
if (!hasBracket) {
// assert that is not followed by infix
String nextText = TokenUtils.peek(this).text;
String nextText = peek(this).text;
if (INFIX_OP.contains(nextText) || "{[".contains(nextText) || "->".equals(nextText)) {
// print $fh + 2; # not a file handle
fileHandle = null;
Expand All @@ -964,7 +974,7 @@ public Node parseFileHandle() {

public boolean isSpaceAfterPrintBlock() {
int currentIndex = tokenIndex;
LexerToken token = TokenUtils.peek(this);
LexerToken token = peek(this);
boolean isSpace = false;
switch (token.type) {
case EOF:
Expand Down
19 changes: 7 additions & 12 deletions src/main/java/org/perlonjava/runtime/ScalarSpecialVariable.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,18 +67,13 @@ public RuntimeScalar addToScalar(RuntimeScalar var) {
public String getStringValue() {
try {
// Return the appropriate string based on the type of special variable.
switch (variableId) {
case CAPTURE:
return RuntimeRegex.captureString(position);
case MATCH:
return RuntimeRegex.matchString();
case PREMATCH:
return RuntimeRegex.preMatchString();
case POSTMATCH:
return RuntimeRegex.postMatchString();
default:
return null;
}
return switch (variableId) {
case CAPTURE -> RuntimeRegex.captureString(position);
case MATCH -> RuntimeRegex.matchString();
case PREMATCH -> RuntimeRegex.preMatchString();
case POSTMATCH -> RuntimeRegex.postMatchString();
default -> null;
};
} catch (IllegalStateException e) {
return null; // Return null if the matcher is in an invalid state.
}
Expand Down

0 comments on commit 3677eaf

Please sign in to comment.