implements PR-11.5
This commit is contained in:
parent
eb5cecc573
commit
852ff351ed
@ -4,16 +4,11 @@ import p.studio.compiler.pbs.ast.PbsAst;
|
|||||||
import p.studio.compiler.pbs.lexer.PbsToken;
|
import p.studio.compiler.pbs.lexer.PbsToken;
|
||||||
import p.studio.compiler.pbs.lexer.PbsTokenKind;
|
import p.studio.compiler.pbs.lexer.PbsTokenKind;
|
||||||
import p.studio.compiler.source.Span;
|
import p.studio.compiler.source.Span;
|
||||||
import p.studio.utilities.structures.ReadOnlyList;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dedicated expression parser for PBS.
|
* Dedicated expression parser for PBS precedence and orchestration.
|
||||||
*/
|
*/
|
||||||
final class PbsExprParser {
|
final class PbsExprParser {
|
||||||
private static final int MAX_TUPLE_LITERAL_ARITY = 6;
|
|
||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
interface BlockParserDelegate {
|
interface BlockParserDelegate {
|
||||||
PbsAst.Block parse(String message);
|
PbsAst.Block parse(String message);
|
||||||
@ -33,9 +28,6 @@ final class PbsExprParser {
|
|||||||
this.primaryParser = new PbsExprPrimaryParser(context, this::parseExpression, controlFlowParser::parseErrorPath);
|
this.primaryParser = new PbsExprPrimaryParser(context, this::parseExpression, controlFlowParser::parseErrorPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Entry point for expression parsing.
|
|
||||||
*/
|
|
||||||
PbsAst.Expression parseExpression() {
|
PbsAst.Expression parseExpression() {
|
||||||
return controlFlowParser.parseHandle();
|
return controlFlowParser.parseHandle();
|
||||||
}
|
}
|
||||||
@ -44,32 +36,6 @@ final class PbsExprParser {
|
|||||||
return parseApply();
|
return parseApply();
|
||||||
}
|
}
|
||||||
|
|
||||||
private PbsAst.Expression parseHandle() {
|
|
||||||
return controlFlowParser.parseHandle();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses right-associative else extraction: {@code a else (b else c)}.
|
|
||||||
*/
|
|
||||||
private PbsAst.Expression parseElse() {
|
|
||||||
return controlFlowParser.parseElse();
|
|
||||||
}
|
|
||||||
|
|
||||||
private PbsAst.Expression parseIfExpression() {
|
|
||||||
return controlFlowParser.parseIfExpression();
|
|
||||||
}
|
|
||||||
|
|
||||||
private PbsAst.IfExpr parseIfExpressionFromToken(final PbsToken ifToken) {
|
|
||||||
return controlFlowParser.parseIfExpressionFromToken(ifToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
private PbsAst.Expression parseSwitchExpression() {
|
|
||||||
return controlFlowParser.parseSwitchExpression();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses right-associative apply expressions.
|
|
||||||
*/
|
|
||||||
private PbsAst.Expression parseApply() {
|
private PbsAst.Expression parseApply() {
|
||||||
final var left = parseOr();
|
final var left = parseOr();
|
||||||
if (!cursor.match(PbsTokenKind.APPLY)) {
|
if (!cursor.match(PbsTokenKind.APPLY)) {
|
||||||
@ -85,7 +51,10 @@ final class PbsExprParser {
|
|||||||
while (cursor.match(PbsTokenKind.OR_OR, PbsTokenKind.OR)) {
|
while (cursor.match(PbsTokenKind.OR_OR, PbsTokenKind.OR)) {
|
||||||
final var operator = cursor.previous();
|
final var operator = cursor.previous();
|
||||||
final var right = parseAnd();
|
final var right = parseAnd();
|
||||||
expression = new PbsAst.BinaryExpr(operator.lexeme(), expression, right,
|
expression = new PbsAst.BinaryExpr(
|
||||||
|
operator.lexeme(),
|
||||||
|
expression,
|
||||||
|
right,
|
||||||
span(expression.span().getStart(), right.span().getEnd()));
|
span(expression.span().getStart(), right.span().getEnd()));
|
||||||
}
|
}
|
||||||
return expression;
|
return expression;
|
||||||
@ -96,7 +65,10 @@ final class PbsExprParser {
|
|||||||
while (cursor.match(PbsTokenKind.AND_AND, PbsTokenKind.AND)) {
|
while (cursor.match(PbsTokenKind.AND_AND, PbsTokenKind.AND)) {
|
||||||
final var operator = cursor.previous();
|
final var operator = cursor.previous();
|
||||||
final var right = parseEquality();
|
final var right = parseEquality();
|
||||||
expression = new PbsAst.BinaryExpr(operator.lexeme(), expression, right,
|
expression = new PbsAst.BinaryExpr(
|
||||||
|
operator.lexeme(),
|
||||||
|
expression,
|
||||||
|
right,
|
||||||
span(expression.span().getStart(), right.span().getEnd()));
|
span(expression.span().getStart(), right.span().getEnd()));
|
||||||
}
|
}
|
||||||
return expression;
|
return expression;
|
||||||
@ -107,10 +79,13 @@ final class PbsExprParser {
|
|||||||
if (cursor.match(PbsTokenKind.EQUAL_EQUAL, PbsTokenKind.BANG_EQUAL)) {
|
if (cursor.match(PbsTokenKind.EQUAL_EQUAL, PbsTokenKind.BANG_EQUAL)) {
|
||||||
final var operator = cursor.previous();
|
final var operator = cursor.previous();
|
||||||
final var right = parseComparison();
|
final var right = parseComparison();
|
||||||
expression = new PbsAst.BinaryExpr(operator.lexeme(), expression, right,
|
expression = new PbsAst.BinaryExpr(
|
||||||
|
operator.lexeme(),
|
||||||
|
expression,
|
||||||
|
right,
|
||||||
span(expression.span().getStart(), right.span().getEnd()));
|
span(expression.span().getStart(), right.span().getEnd()));
|
||||||
if (cursor.check(PbsTokenKind.EQUAL_EQUAL) || cursor.check(PbsTokenKind.BANG_EQUAL)) {
|
if (cursor.check(PbsTokenKind.EQUAL_EQUAL) || cursor.check(PbsTokenKind.BANG_EQUAL)) {
|
||||||
report(cursor.peek(), ParseErrors.E_PARSE_NON_ASSOC, "Chained equality is not allowed");
|
context.report(cursor.peek(), ParseErrors.E_PARSE_NON_ASSOC, "Chained equality is not allowed");
|
||||||
while (cursor.match(PbsTokenKind.EQUAL_EQUAL, PbsTokenKind.BANG_EQUAL)) {
|
while (cursor.match(PbsTokenKind.EQUAL_EQUAL, PbsTokenKind.BANG_EQUAL)) {
|
||||||
parseComparison();
|
parseComparison();
|
||||||
}
|
}
|
||||||
@ -124,11 +99,16 @@ final class PbsExprParser {
|
|||||||
if (cursor.match(PbsTokenKind.LESS, PbsTokenKind.LESS_EQUAL, PbsTokenKind.GREATER, PbsTokenKind.GREATER_EQUAL)) {
|
if (cursor.match(PbsTokenKind.LESS, PbsTokenKind.LESS_EQUAL, PbsTokenKind.GREATER, PbsTokenKind.GREATER_EQUAL)) {
|
||||||
final var operator = cursor.previous();
|
final var operator = cursor.previous();
|
||||||
final var right = parseAs();
|
final var right = parseAs();
|
||||||
expression = new PbsAst.BinaryExpr(operator.lexeme(), expression, right,
|
expression = new PbsAst.BinaryExpr(
|
||||||
|
operator.lexeme(),
|
||||||
|
expression,
|
||||||
|
right,
|
||||||
span(expression.span().getStart(), right.span().getEnd()));
|
span(expression.span().getStart(), right.span().getEnd()));
|
||||||
if (cursor.check(PbsTokenKind.LESS) || cursor.check(PbsTokenKind.LESS_EQUAL)
|
if (cursor.check(PbsTokenKind.LESS)
|
||||||
|| cursor.check(PbsTokenKind.GREATER) || cursor.check(PbsTokenKind.GREATER_EQUAL)) {
|
|| cursor.check(PbsTokenKind.LESS_EQUAL)
|
||||||
report(cursor.peek(), ParseErrors.E_PARSE_NON_ASSOC, "Chained comparison is not allowed");
|
|| cursor.check(PbsTokenKind.GREATER)
|
||||||
|
|| cursor.check(PbsTokenKind.GREATER_EQUAL)) {
|
||||||
|
context.report(cursor.peek(), ParseErrors.E_PARSE_NON_ASSOC, "Chained comparison is not allowed");
|
||||||
while (cursor.match(PbsTokenKind.LESS, PbsTokenKind.LESS_EQUAL, PbsTokenKind.GREATER, PbsTokenKind.GREATER_EQUAL)) {
|
while (cursor.match(PbsTokenKind.LESS, PbsTokenKind.LESS_EQUAL, PbsTokenKind.GREATER, PbsTokenKind.GREATER_EQUAL)) {
|
||||||
parseAs();
|
parseAs();
|
||||||
}
|
}
|
||||||
@ -140,8 +120,11 @@ final class PbsExprParser {
|
|||||||
private PbsAst.Expression parseAs() {
|
private PbsAst.Expression parseAs() {
|
||||||
var expression = parseTerm();
|
var expression = parseTerm();
|
||||||
if (cursor.match(PbsTokenKind.AS)) {
|
if (cursor.match(PbsTokenKind.AS)) {
|
||||||
final var contract = consume(PbsTokenKind.IDENTIFIER, "Expected contract identifier after 'as'");
|
final var contract = context.consume(PbsTokenKind.IDENTIFIER, "Expected contract identifier after 'as'");
|
||||||
expression = new PbsAst.AsExpr(expression, contract.lexeme(), span(expression.span().getStart(), contract.end()));
|
expression = new PbsAst.AsExpr(
|
||||||
|
expression,
|
||||||
|
contract.lexeme(),
|
||||||
|
span(expression.span().getStart(), contract.end()));
|
||||||
}
|
}
|
||||||
return expression;
|
return expression;
|
||||||
}
|
}
|
||||||
@ -151,7 +134,10 @@ final class PbsExprParser {
|
|||||||
while (cursor.match(PbsTokenKind.PLUS, PbsTokenKind.MINUS)) {
|
while (cursor.match(PbsTokenKind.PLUS, PbsTokenKind.MINUS)) {
|
||||||
final var operator = cursor.previous();
|
final var operator = cursor.previous();
|
||||||
final var right = parseFactor();
|
final var right = parseFactor();
|
||||||
expression = new PbsAst.BinaryExpr(operator.lexeme(), expression, right,
|
expression = new PbsAst.BinaryExpr(
|
||||||
|
operator.lexeme(),
|
||||||
|
expression,
|
||||||
|
right,
|
||||||
span(expression.span().getStart(), right.span().getEnd()));
|
span(expression.span().getStart(), right.span().getEnd()));
|
||||||
}
|
}
|
||||||
return expression;
|
return expression;
|
||||||
@ -162,7 +148,10 @@ final class PbsExprParser {
|
|||||||
while (cursor.match(PbsTokenKind.STAR, PbsTokenKind.SLASH, PbsTokenKind.PERCENT)) {
|
while (cursor.match(PbsTokenKind.STAR, PbsTokenKind.SLASH, PbsTokenKind.PERCENT)) {
|
||||||
final var operator = cursor.previous();
|
final var operator = cursor.previous();
|
||||||
final var right = parseUnary();
|
final var right = parseUnary();
|
||||||
expression = new PbsAst.BinaryExpr(operator.lexeme(), expression, right,
|
expression = new PbsAst.BinaryExpr(
|
||||||
|
operator.lexeme(),
|
||||||
|
expression,
|
||||||
|
right,
|
||||||
span(expression.span().getStart(), right.span().getEnd()));
|
span(expression.span().getStart(), right.span().getEnd()));
|
||||||
}
|
}
|
||||||
return expression;
|
return expression;
|
||||||
@ -177,100 +166,7 @@ final class PbsExprParser {
|
|||||||
return primaryParser.parsePostfix();
|
return primaryParser.parsePostfix();
|
||||||
}
|
}
|
||||||
|
|
||||||
private PbsAst.Expression parsePostfix() {
|
|
||||||
return primaryParser.parsePostfix();
|
|
||||||
}
|
|
||||||
|
|
||||||
private PbsAst.Expression parsePrimary() {
|
|
||||||
return primaryParser.parsePrimary();
|
|
||||||
}
|
|
||||||
|
|
||||||
private PbsAst.Expression parseParenthesizedPrimary(final PbsToken open) {
|
|
||||||
return primaryParser.parseParenthesizedPrimary(open);
|
|
||||||
}
|
|
||||||
|
|
||||||
private PbsAst.SwitchPattern parseSwitchPattern() {
|
|
||||||
return controlFlowParser.parseSwitchPattern();
|
|
||||||
}
|
|
||||||
|
|
||||||
private PbsAst.Expression parseLiteralPatternExpression() {
|
|
||||||
return controlFlowParser.parseLiteralPatternExpression();
|
|
||||||
}
|
|
||||||
|
|
||||||
private PbsAst.HandlePattern parseHandlePattern() {
|
|
||||||
return controlFlowParser.parseHandlePattern();
|
|
||||||
}
|
|
||||||
|
|
||||||
private PbsAst.ErrorPath parseErrorPath() {
|
|
||||||
return controlFlowParser.parseErrorPath();
|
|
||||||
}
|
|
||||||
|
|
||||||
private PbsAst.Block parseSurfaceBlock(final String message) {
|
|
||||||
return context.parseSurfaceBlock(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
private PbsToken consume(final PbsTokenKind kind, final String message) {
|
|
||||||
return context.consume(kind, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
private PbsToken consumeMemberName(final String message) {
|
|
||||||
return context.consumeMemberName(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Span span(final long start, final long end) {
|
private Span span(final long start, final long end) {
|
||||||
return context.span(start, end);
|
return context.span(start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void report(final PbsToken token, final ParseErrors parseErrors, final String message) {
|
|
||||||
context.report(token, parseErrors, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
private long parseLongOrDefault(final String text) {
|
|
||||||
try {
|
|
||||||
return Long.parseLong(text);
|
|
||||||
} catch (NumberFormatException ignored) {
|
|
||||||
return 0L;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private int parseIntOrDefault(final String text) {
|
|
||||||
try {
|
|
||||||
return Integer.parseInt(text);
|
|
||||||
} catch (NumberFormatException ignored) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private double parseDoubleOrDefault(final String text) {
|
|
||||||
try {
|
|
||||||
return Double.parseDouble(text);
|
|
||||||
} catch (NumberFormatException ignored) {
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String unescapeString(final String lexeme) {
|
|
||||||
if (lexeme.length() < 2) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
final var raw = lexeme.substring(1, lexeme.length() - 1);
|
|
||||||
final var sb = new StringBuilder(raw.length());
|
|
||||||
for (int i = 0; i < raw.length(); i++) {
|
|
||||||
final char c = raw.charAt(i);
|
|
||||||
if (c != '\\' || i + 1 >= raw.length()) {
|
|
||||||
sb.append(c);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
final char next = raw.charAt(++i);
|
|
||||||
switch (next) {
|
|
||||||
case 'n' -> sb.append('\n');
|
|
||||||
case 'r' -> sb.append('\r');
|
|
||||||
case 't' -> sb.append('\t');
|
|
||||||
case '"' -> sb.append('"');
|
|
||||||
case '\\' -> sb.append('\\');
|
|
||||||
default -> sb.append('\\').append(next);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user