move parser out of pkl-core (#1024)

This commit is contained in:
Islon Scherer
2025-03-18 20:23:53 +01:00
committed by GitHub
parent 1cd0549bd6
commit aad530b9a8
80 changed files with 904 additions and 737 deletions

View File

@@ -0,0 +1,482 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser;
import org.pkl.parser.syntax.Annotation;
import org.pkl.parser.syntax.ArgumentList;
import org.pkl.parser.syntax.Class;
import org.pkl.parser.syntax.ClassBody;
import org.pkl.parser.syntax.ClassMethod;
import org.pkl.parser.syntax.ClassProperty;
import org.pkl.parser.syntax.DocComment;
import org.pkl.parser.syntax.Expr.AmendsExpr;
import org.pkl.parser.syntax.Expr.BinaryOperatorExpr;
import org.pkl.parser.syntax.Expr.BoolLiteralExpr;
import org.pkl.parser.syntax.Expr.FloatLiteralExpr;
import org.pkl.parser.syntax.Expr.FunctionLiteralExpr;
import org.pkl.parser.syntax.Expr.IfExpr;
import org.pkl.parser.syntax.Expr.ImportExpr;
import org.pkl.parser.syntax.Expr.IntLiteralExpr;
import org.pkl.parser.syntax.Expr.LetExpr;
import org.pkl.parser.syntax.Expr.LogicalNotExpr;
import org.pkl.parser.syntax.Expr.ModuleExpr;
import org.pkl.parser.syntax.Expr.MultiLineStringLiteralExpr;
import org.pkl.parser.syntax.Expr.NewExpr;
import org.pkl.parser.syntax.Expr.NonNullExpr;
import org.pkl.parser.syntax.Expr.NullLiteralExpr;
import org.pkl.parser.syntax.Expr.OuterExpr;
import org.pkl.parser.syntax.Expr.ParenthesizedExpr;
import org.pkl.parser.syntax.Expr.QualifiedAccessExpr;
import org.pkl.parser.syntax.Expr.ReadExpr;
import org.pkl.parser.syntax.Expr.SingleLineStringLiteralExpr;
import org.pkl.parser.syntax.Expr.SubscriptExpr;
import org.pkl.parser.syntax.Expr.SuperAccessExpr;
import org.pkl.parser.syntax.Expr.SuperSubscriptExpr;
import org.pkl.parser.syntax.Expr.ThisExpr;
import org.pkl.parser.syntax.Expr.ThrowExpr;
import org.pkl.parser.syntax.Expr.TraceExpr;
import org.pkl.parser.syntax.Expr.TypeCastExpr;
import org.pkl.parser.syntax.Expr.TypeCheckExpr;
import org.pkl.parser.syntax.Expr.UnaryMinusExpr;
import org.pkl.parser.syntax.Expr.UnqualifiedAccessExpr;
import org.pkl.parser.syntax.ExtendsOrAmendsClause;
import org.pkl.parser.syntax.Identifier;
import org.pkl.parser.syntax.ImportClause;
import org.pkl.parser.syntax.Keyword;
import org.pkl.parser.syntax.Modifier;
import org.pkl.parser.syntax.ModuleDecl;
import org.pkl.parser.syntax.Node;
import org.pkl.parser.syntax.ObjectBody;
import org.pkl.parser.syntax.ObjectMember.ForGenerator;
import org.pkl.parser.syntax.ObjectMember.MemberPredicate;
import org.pkl.parser.syntax.ObjectMember.ObjectElement;
import org.pkl.parser.syntax.ObjectMember.ObjectEntry;
import org.pkl.parser.syntax.ObjectMember.ObjectMethod;
import org.pkl.parser.syntax.ObjectMember.ObjectProperty;
import org.pkl.parser.syntax.ObjectMember.ObjectSpread;
import org.pkl.parser.syntax.ObjectMember.WhenGenerator;
import org.pkl.parser.syntax.Parameter;
import org.pkl.parser.syntax.ParameterList;
import org.pkl.parser.syntax.QualifiedIdentifier;
import org.pkl.parser.syntax.ReplInput;
import org.pkl.parser.syntax.StringConstant;
import org.pkl.parser.syntax.StringPart;
import org.pkl.parser.syntax.Type.ConstrainedType;
import org.pkl.parser.syntax.Type.DeclaredType;
import org.pkl.parser.syntax.Type.FunctionType;
import org.pkl.parser.syntax.Type.ModuleType;
import org.pkl.parser.syntax.Type.NothingType;
import org.pkl.parser.syntax.Type.NullableType;
import org.pkl.parser.syntax.Type.ParenthesizedType;
import org.pkl.parser.syntax.Type.StringConstantType;
import org.pkl.parser.syntax.Type.UnionType;
import org.pkl.parser.syntax.Type.UnknownType;
import org.pkl.parser.syntax.TypeAlias;
import org.pkl.parser.syntax.TypeAnnotation;
import org.pkl.parser.syntax.TypeArgumentList;
import org.pkl.parser.syntax.TypeParameter;
import org.pkl.parser.syntax.TypeParameterList;
public abstract class BaseParserVisitor<T> implements ParserVisitor<T> {
@Override
public T visitUnknownType(UnknownType type) {
return defaultValue();
}
@Override
public T visitNothingType(NothingType type) {
return defaultValue();
}
@Override
public T visitModuleType(ModuleType type) {
return defaultValue();
}
@Override
public T visitStringConstantType(StringConstantType type) {
return visitChildren(type);
}
@Override
public T visitDeclaredType(DeclaredType type) {
return visitChildren(type);
}
@Override
public T visitParenthesizedType(ParenthesizedType type) {
return visitChildren(type);
}
@Override
public T visitNullableType(NullableType type) {
return visitChildren(type);
}
@Override
public T visitConstrainedType(ConstrainedType type) {
return visitChildren(type);
}
@Override
public T visitUnionType(UnionType type) {
return visitChildren(type);
}
@Override
public T visitFunctionType(FunctionType type) {
return visitChildren(type);
}
@Override
public T visitThisExpr(ThisExpr expr) {
return defaultValue();
}
@Override
public T visitOuterExpr(OuterExpr expr) {
return defaultValue();
}
@Override
public T visitModuleExpr(ModuleExpr expr) {
return defaultValue();
}
@Override
public T visitNullLiteralExpr(NullLiteralExpr expr) {
return defaultValue();
}
@Override
public T visitBoolLiteralExpr(BoolLiteralExpr expr) {
return defaultValue();
}
@Override
public T visitIntLiteralExpr(IntLiteralExpr expr) {
return defaultValue();
}
@Override
public T visitFloatLiteralExpr(FloatLiteralExpr expr) {
return defaultValue();
}
@Override
public T visitThrowExpr(ThrowExpr expr) {
return visitChildren(expr);
}
@Override
public T visitTraceExpr(TraceExpr expr) {
return visitChildren(expr);
}
@Override
public T visitImportExpr(ImportExpr expr) {
return visitChildren(expr);
}
@Override
public T visitReadExpr(ReadExpr expr) {
return visitChildren(expr);
}
@Override
public T visitUnqualifiedAccessExpr(UnqualifiedAccessExpr expr) {
return visitChildren(expr);
}
@Override
public T visitStringConstant(StringConstant expr) {
return visitChildren(expr);
}
@Override
public T visitSingleLineStringLiteralExpr(SingleLineStringLiteralExpr expr) {
return visitChildren(expr);
}
@Override
public T visitMultiLineStringLiteralExpr(MultiLineStringLiteralExpr expr) {
return visitChildren(expr);
}
@Override
public T visitNewExpr(NewExpr expr) {
return visitChildren(expr);
}
@Override
public T visitAmendsExpr(AmendsExpr expr) {
return visitChildren(expr);
}
@Override
public T visitSuperAccessExpr(SuperAccessExpr expr) {
return visitChildren(expr);
}
@Override
public T visitSuperSubscriptExpr(SuperSubscriptExpr expr) {
return visitChildren(expr);
}
@Override
public T visitQualifiedAccessExpr(QualifiedAccessExpr expr) {
return visitChildren(expr);
}
@Override
public T visitSubscriptExpr(SubscriptExpr expr) {
return visitChildren(expr);
}
@Override
public T visitNonNullExpr(NonNullExpr expr) {
return visitChildren(expr);
}
@Override
public T visitUnaryMinusExpr(UnaryMinusExpr expr) {
return visitChildren(expr);
}
@Override
public T visitLogicalNotExpr(LogicalNotExpr expr) {
return visitChildren(expr);
}
@Override
public T visitBinaryOperatorExpr(BinaryOperatorExpr expr) {
return visitChildren(expr);
}
@Override
public T visitTypeCheckExpr(TypeCheckExpr expr) {
return visitChildren(expr);
}
@Override
public T visitTypeCastExpr(TypeCastExpr expr) {
return visitChildren(expr);
}
@Override
public T visitIfExpr(IfExpr expr) {
return visitChildren(expr);
}
@Override
public T visitLetExpr(LetExpr expr) {
return visitChildren(expr);
}
@Override
public T visitFunctionLiteralExpr(FunctionLiteralExpr expr) {
return visitChildren(expr);
}
@Override
public T visitParenthesizedExpr(ParenthesizedExpr expr) {
return visitChildren(expr);
}
@Override
public T visitObjectProperty(ObjectProperty member) {
return visitChildren(member);
}
@Override
public T visitObjectMethod(ObjectMethod member) {
return visitChildren(member);
}
@Override
public T visitMemberPredicate(MemberPredicate member) {
return visitChildren(member);
}
@Override
public T visitObjectElement(ObjectElement member) {
return visitChildren(member);
}
@Override
public T visitObjectEntry(ObjectEntry member) {
return visitChildren(member);
}
@Override
public T visitObjectSpread(ObjectSpread member) {
return visitChildren(member);
}
@Override
public T visitWhenGenerator(WhenGenerator member) {
return visitChildren(member);
}
@Override
public T visitForGenerator(ForGenerator member) {
return visitChildren(member);
}
@Override
public T visitModule(org.pkl.parser.syntax.Module module) {
return visitChildren(module);
}
@Override
public T visitModuleDecl(ModuleDecl decl) {
return visitChildren(decl);
}
@Override
public T visitExtendsOrAmendsClause(ExtendsOrAmendsClause decl) {
return visitChildren(decl);
}
@Override
public T visitImportClause(ImportClause imp) {
return visitChildren(imp);
}
@Override
public T visitClass(Class clazz) {
return visitChildren(clazz);
}
@Override
public T visitModifier(Modifier modifier) {
return defaultValue();
}
@Override
public T visitClassProperty(ClassProperty prop) {
return visitChildren(prop);
}
@Override
public T visitClassMethod(ClassMethod method) {
return visitChildren(method);
}
@Override
public T visitTypeAlias(TypeAlias typeAlias) {
return visitChildren(typeAlias);
}
@Override
public T visitAnnotation(Annotation annotation) {
return visitChildren(annotation);
}
@Override
public T visitParameter(Parameter param) {
return visitChildren(param);
}
@Override
public T visitParameterList(ParameterList paramList) {
return visitChildren(paramList);
}
@Override
public T visitTypeParameterList(TypeParameterList typeParameterList) {
return visitChildren(typeParameterList);
}
@Override
public T visitTypeAnnotation(TypeAnnotation typeAnnotation) {
return visitChildren(typeAnnotation);
}
@Override
public T visitArgumentList(ArgumentList argumentList) {
return visitChildren(argumentList);
}
@Override
public T visitStringPart(StringPart part) {
return visitChildren(part);
}
@Override
public T visitClassBody(ClassBody classBody) {
return visitChildren(classBody);
}
@Override
public T visitDocComment(DocComment docComment) {
return defaultValue();
}
@Override
public T visitIdentifier(Identifier identifier) {
return defaultValue();
}
@Override
public T visitQualifiedIdentifier(QualifiedIdentifier qualifiedIdentifier) {
return visitChildren(qualifiedIdentifier);
}
@Override
public T visitObjectBody(ObjectBody objectBody) {
return visitChildren(objectBody);
}
@Override
public T visitTypeParameter(TypeParameter typeParameter) {
return visitChildren(typeParameter);
}
@Override
public T visitReplInput(ReplInput replInput) {
return visitChildren(replInput);
}
@Override
public T visitKeyword(Keyword keyword) {
return defaultValue();
}
@Override
public T visitTypeArgumentList(TypeArgumentList typeArgumentList) {
return visitChildren(typeArgumentList);
}
private T visitChildren(Node node) {
T result = defaultValue();
var children = node.children();
if (children == null) return result;
for (var child : children) {
if (child != null) {
result = aggregateResult(result, child.accept(this));
}
}
return result;
}
protected abstract T defaultValue();
protected T aggregateResult(T result, T nextResult) {
return nextResult;
}
}

View File

@@ -0,0 +1,818 @@
/*
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Deque;
import org.pkl.parser.util.ErrorMessages;
public class Lexer {
private final char[] source;
private final int size;
protected int cursor = 0;
protected int sCursor = 0;
private char lookahead;
private State state = State.DEFAULT;
private final Deque<InterpolationScope> interpolationStack = new ArrayDeque<>();
private boolean stringEnded = false;
private boolean isEscape = false;
// how many newlines exist between two subsequent tokens
protected int newLinesBetween = 0;
private static final char EOF = Short.MAX_VALUE;
public Lexer(String input) {
source = input.toCharArray();
size = source.length;
if (size > 0) {
lookahead = source[cursor];
} else {
lookahead = EOF;
}
}
// The span of the last lexed token
public Span span() {
return new Span(sCursor, cursor - sCursor);
}
// The text of the last lexed token
public String text() {
return new String(source, sCursor, cursor - sCursor);
}
public char[] getSource() {
return source;
}
public String textFor(int offset, int size) {
return new String(source, offset, size);
}
public Token next() {
sCursor = cursor;
newLinesBetween = 0;
return switch (state) {
case DEFAULT -> nextDefault();
case STRING -> nextString();
};
}
private Token nextDefault() {
var ch = nextChar();
// ignore spaces
while (ch == ' ' || ch == '\n' || ch == '\t' || ch == '\f' || ch == '\r') {
sCursor = cursor;
if (ch == '\n') {
newLinesBetween++;
}
ch = nextChar();
}
return switch (ch) {
case EOF -> {
// when EOF is reached we overshot the span
cursor--;
yield Token.EOF;
}
case ';' -> Token.SEMICOLON;
case '(' -> {
var scope = interpolationStack.peek();
if (scope != null) {
scope.parens++;
}
yield Token.LPAREN;
}
case ')' -> {
var scope = interpolationStack.peek();
if (scope != null) {
scope.parens--;
if (scope.parens <= 0) {
// interpolation is over. Back to string
state = State.STRING;
}
}
yield Token.RPAREN;
}
case '{' -> Token.LBRACE;
case '}' -> Token.RBRACE;
case ',' -> Token.COMMA;
case '@' -> Token.AT;
case ':' -> Token.COLON;
case '+' -> Token.PLUS;
case '%' -> Token.MOD;
case '[' -> {
if (lookahead == '[') {
nextChar();
yield Token.LPRED;
} else yield Token.LBRACK;
}
case ']' -> Token.RBRACK;
case '=' -> {
if (lookahead == '=') {
nextChar();
yield Token.EQUAL;
} else yield Token.ASSIGN;
}
case '>' -> {
if (lookahead == '=') {
nextChar();
yield Token.GTE;
} else yield Token.GT;
}
case '<' -> {
if (lookahead == '=') {
nextChar();
yield Token.LTE;
} else yield Token.LT;
}
case '-' -> {
if (lookahead == '>') {
nextChar();
yield Token.ARROW;
} else yield Token.MINUS;
}
case '!' -> {
if (lookahead == '!') {
nextChar();
yield Token.NON_NULL;
} else if (lookahead == '=') {
nextChar();
yield Token.NOT_EQUAL;
} else yield Token.NOT;
}
case '?' -> {
if (lookahead == '.') {
nextChar();
yield Token.QDOT;
} else if (lookahead == '?') {
nextChar();
yield Token.COALESCE;
} else yield Token.QUESTION;
}
case '&' -> {
if (lookahead == '&') {
nextChar();
yield Token.AND;
} else {
throw unexpectedChar(ch, "&&");
}
}
case '|' -> {
if (lookahead == '>') {
nextChar();
yield Token.PIPE;
} else if (lookahead == '|') {
nextChar();
yield Token.OR;
} else {
yield Token.UNION;
}
}
case '*' -> {
if (lookahead == '*') {
nextChar();
yield Token.POW;
} else yield Token.STAR;
}
case '~' -> {
if (lookahead == '/') {
nextChar();
yield Token.INT_DIV;
} else {
throw unexpectedChar(ch, "~/");
}
}
case '.' -> {
if (lookahead == '.') {
nextChar();
if (lookahead == '.') {
nextChar();
if (lookahead == '?') {
nextChar();
yield Token.QSPREAD;
} else {
yield Token.SPREAD;
}
} else {
throw unexpectedChar("..", ".", "...", "...?");
}
} else if (lookahead >= 48 && lookahead <= 57) {
yield lexNumber(ch);
} else {
yield Token.DOT;
}
}
case '`' -> {
lexQuotedIdentifier();
yield Token.IDENTIFIER;
}
case '/' -> lexSlash();
case '"' -> lexStringStart(0);
case '#' -> {
if (lookahead == '!') {
yield lexShebang();
} else {
yield lexStringStartPounds();
}
}
default -> {
if (Character.isDigit(ch)) {
yield lexNumber(ch);
} else if (isIdentifierStart(ch)) {
yield lexIdentifier();
} else throw lexError(ErrorMessages.create("invalidCharacter", ch), cursor - 1, 1);
}
};
}
private Token nextString() {
var scope = interpolationStack.getFirst();
if (stringEnded) {
lexStringEnd(scope);
stringEnded = false;
interpolationStack.pop();
state = State.DEFAULT;
return Token.STRING_END;
}
if (lookahead == EOF) return Token.EOF;
if (isEscape) {
isEscape = false;
// consume the `\#*`
for (var i = 0; i < scope.pounds + 1; i++) {
nextChar();
}
return lexEscape();
}
if (scope.quotes == 1) {
lexString(scope.pounds);
} else {
if (lookahead == '\r') {
nextChar();
if (lookahead == '\n') {
nextChar();
}
return Token.STRING_NEWLINE;
}
if (lookahead == '\n') {
nextChar();
return Token.STRING_NEWLINE;
}
lexMultiString(scope.pounds);
}
return Token.STRING_PART;
}
private Token lexStringStartPounds() {
int pounds = 1;
while (lookahead == '#') {
nextChar();
pounds++;
}
if (lookahead == EOF) {
throw lexError(ErrorMessages.create("unexpectedEndOfFile"), span());
}
if (lookahead != '"') {
throw unexpectedChar(lookahead, "\"");
}
nextChar();
return lexStringStart(pounds);
}
private Token lexStringStart(int pounds) {
var quotes = 1;
if (lookahead == '"') {
nextChar();
if (lookahead == '"') {
nextChar();
quotes = 3;
} else {
backup();
}
}
state = State.STRING;
interpolationStack.push(new InterpolationScope(quotes, pounds));
stringEnded = false;
if (quotes == 1) return Token.STRING_START;
return Token.STRING_MULTI_START;
}
private void lexStringEnd(InterpolationScope scope) {
// don't actually need to check it here
for (var i = 0; i < scope.quotes + scope.pounds; i++) {
nextChar();
}
}
private void lexString(int pounds) {
var poundsInARow = 0;
var foundQuote = false;
var foundBackslash = false;
while (lookahead != EOF) {
var ch = nextChar();
switch (ch) {
case '\n', '\r' ->
throw lexError(
ErrorMessages.create("missingDelimiter", "\"" + "#".repeat(pounds)), cursor - 1, 1);
case '"' -> {
if (pounds == 0) {
backup();
stringEnded = true;
return;
}
foundQuote = true;
foundBackslash = false;
poundsInARow = 0;
}
case '\\' -> {
foundQuote = false;
foundBackslash = true;
poundsInARow = 0;
if (pounds == poundsInARow) {
backup(pounds + 1);
isEscape = true;
return;
}
}
case '#' -> {
poundsInARow++;
if (foundQuote && (pounds == poundsInARow)) {
backup(pounds + 1);
stringEnded = true;
return;
}
if (foundBackslash && pounds == poundsInARow) {
backup(pounds + 1);
isEscape = true;
return;
}
}
default -> {
foundQuote = false;
foundBackslash = false;
poundsInARow = 0;
}
}
}
}
private void lexMultiString(int pounds) {
var poundsInARow = 0;
var quotesInARow = 0;
var foundBackslash = false;
while (lookahead != EOF && lookahead != '\n' && lookahead != '\r') {
var ch = nextChar();
switch (ch) {
case '"' -> {
quotesInARow++;
if (quotesInARow == 3 && pounds == 0) {
backup(3);
stringEnded = true;
return;
}
poundsInARow = 0;
foundBackslash = false;
}
case '\\' -> {
quotesInARow = 0;
poundsInARow = 0;
foundBackslash = true;
if (pounds == poundsInARow) {
backup(pounds + 1);
isEscape = true;
return;
}
}
case '#' -> {
poundsInARow++;
if (quotesInARow == 3 && pounds == poundsInARow) {
backup(pounds + 3);
stringEnded = true;
return;
}
if (foundBackslash && pounds == poundsInARow) {
backup(pounds + 1);
isEscape = true;
return;
}
}
default -> {
quotesInARow = 0;
poundsInARow = 0;
foundBackslash = false;
}
}
}
}
private Token lexEscape() {
if (lookahead == EOF) throw unexpectedEndOfFile();
var ch = nextChar();
return switch (ch) {
case 'n' -> Token.STRING_ESCAPE_NEWLINE;
case '"' -> Token.STRING_ESCAPE_QUOTE;
case '\\' -> Token.STRING_ESCAPE_BACKSLASH;
case 't' -> Token.STRING_ESCAPE_TAB;
case 'r' -> Token.STRING_ESCAPE_RETURN;
case '(' -> {
var scope = interpolationStack.getFirst();
scope.parens++;
state = State.DEFAULT;
yield Token.INTERPOLATION_START;
}
case 'u' -> lexUnicodeEscape();
default ->
throw lexError(
ErrorMessages.create("invalidCharacterEscapeSequence", "\\" + ch, "\\"),
cursor - 2,
2);
};
}
private Token lexUnicodeEscape() {
if (lookahead != '{') {
throw unexpectedChar(lookahead, "{");
}
do {
nextChar();
} while (lookahead != '}' && lookahead != EOF && Character.isLetterOrDigit(lookahead));
if (lookahead == '}') {
// consume the close bracket
nextChar();
} else {
throw lexError(ErrorMessages.create("unterminatedUnicodeEscapeSequence", text()), span());
}
return Token.STRING_ESCAPE_UNICODE;
}
private Token lexIdentifier() {
while (isIdentifierPart(lookahead)) {
nextChar();
}
var identifierStr = text();
var identifier = getKeywordOrIdentifier(identifierStr);
return switch (identifier) {
case IMPORT -> {
if (lookahead == '*') {
nextChar();
yield Token.IMPORT_STAR;
} else yield Token.IMPORT;
}
case READ ->
switch (lookahead) {
case '*' -> {
nextChar();
yield Token.READ_STAR;
}
case '?' -> {
nextChar();
yield Token.READ_QUESTION;
}
default -> Token.READ;
};
default -> identifier;
};
}
private void lexQuotedIdentifier() {
while (lookahead != '`' && lookahead != '\n' && lookahead != '\r') {
nextChar();
}
if (lookahead == '`') {
nextChar();
} else {
throw unexpectedChar(lookahead, "backquote");
}
}
private Token lexNumber(char start) {
if (start == '0') {
if (lookahead == 'x' || lookahead == 'X') {
nextChar();
lexHexNumber();
return Token.HEX;
}
if (lookahead == 'b' || lookahead == 'B') {
nextChar();
lexBinNumber();
return Token.BIN;
}
if (lookahead == 'o' || lookahead == 'O') {
nextChar();
lexOctNumber();
return Token.OCT;
}
if (lookahead == 'e' || lookahead == 'E') {
nextChar();
lexExponent();
return Token.FLOAT;
}
} else if (start == '.') {
lexDotNumber();
return Token.FLOAT;
}
while ((lookahead >= 48 && lookahead <= 57) || lookahead == '_') {
nextChar();
}
if (lookahead == 'e' || lookahead == 'E') {
nextChar();
lexExponent();
return Token.FLOAT;
} else if (lookahead == '.') {
nextChar();
if (lookahead == '_') {
throw lexError("invalidSeparatorPosition");
}
if (lookahead < 48 || lookahead > 57) {
backup();
return Token.INT;
}
lexDotNumber();
return Token.FLOAT;
}
return Token.INT;
}
private Token lexSlash() {
switch (lookahead) {
case '/':
{
nextChar();
var token = lookahead == '/' ? Token.DOC_COMMENT : Token.LINE_COMMENT;
while (lookahead != '\n' && lookahead != '\r' && lookahead != EOF) {
nextChar();
}
return token;
}
case '*':
{
nextChar();
lexBlockComment();
return Token.BLOCK_COMMENT;
}
default:
return Token.DIV;
}
}
private void lexBlockComment() {
if (lookahead == EOF) throw unexpectedEndOfFile();
var prev = nextChar();
while (lookahead != EOF) {
if (prev == '*' && lookahead == '/') {
nextChar();
break;
}
prev = nextChar();
}
if (lookahead == EOF) throw unexpectedEndOfFile();
}
private void lexHexNumber() {
if (lookahead == '_') {
throw lexError("invalidSeparatorPosition");
}
if (!isHex(lookahead)) {
throw unexpectedChar(lookahead, "hexadecimal number");
}
while (isHex(lookahead) || lookahead == '_') {
nextChar();
}
}
private void lexBinNumber() {
if (lookahead == '_') {
throw lexError("invalidSeparatorPosition");
}
if (!(lookahead == '0' || lookahead == '1')) {
throw unexpectedChar(lookahead, "binary number");
}
while (lookahead == '0' || lookahead == '1' || lookahead == '_') {
nextChar();
}
}
private void lexOctNumber() {
if (lookahead == '_') {
throw lexError("invalidSeparatorPosition");
}
var ch = (int) lookahead;
if (!(ch >= 48 && ch <= 55)) {
throw unexpectedChar((char) ch, "octal number");
}
while ((ch >= 48 && ch <= 55) || ch == '_') {
nextChar();
ch = lookahead;
}
}
private void lexExponent() {
if (lookahead == '+' || lookahead == '-') {
nextChar();
}
if (lookahead == '_') {
throw lexError("invalidSeparatorPosition");
}
if (lookahead < 48 || lookahead > 57) {
throw unexpectedChar(lookahead, "number");
}
while ((lookahead >= 48 && lookahead <= 57) || lookahead == '_') {
nextChar();
}
}
private void lexDotNumber() {
if (lookahead == '_') {
throw lexError("invalidSeparatorPosition");
}
while ((lookahead >= 48 && lookahead <= 57) || lookahead == '_') {
nextChar();
}
if (lookahead == 'e' || lookahead == 'E') {
nextChar();
lexExponent();
}
}
private Token lexShebang() {
do {
nextChar();
} while (lookahead != '\n' && lookahead != '\r' && lookahead != EOF);
return Token.SHEBANG;
}
private boolean isHex(char ch) {
var code = (int) ch;
return (code >= 48 && code <= 57) || (code >= 97 && code <= 102) || (code >= 65 && code <= 70);
}
private static boolean isIdentifierStart(char c) {
return c == '_' || c == '$' || Character.isUnicodeIdentifierStart(c);
}
private static boolean isIdentifierPart(char c) {
return c != EOF && (c == '$' || Character.isUnicodeIdentifierPart(c));
}
private char nextChar() {
var tmp = lookahead;
cursor++;
if (cursor >= size) {
lookahead = EOF;
} else {
lookahead = source[cursor];
}
return tmp;
}
private void backup() {
lookahead = source[--cursor];
}
private void backup(int amount) {
cursor -= amount;
lookahead = source[cursor];
}
private ParserError lexError(String msg, Object... args) {
var length = lookahead == EOF ? 0 : 1;
var index = lookahead == EOF ? cursor - 1 : cursor;
return new ParserError(ErrorMessages.create(msg, args), new Span(index, length));
}
private ParserError lexError(String msg, int charIndex, int length) {
return new ParserError(msg, new Span(charIndex, length));
}
private ParserError lexError(String msg, Span span) {
return new ParserError(msg, span);
}
private ParserError unexpectedChar(char got, String didYouMean) {
return lexError("unexpectedCharacter", got, didYouMean);
}
private ParserError unexpectedChar(String got, String option1, String option2, String option3) {
return lexError("unexpectedCharacter3", got, option1, option2, option3);
}
private ParserError unexpectedEndOfFile() {
return lexError(ErrorMessages.create("unexpectedEndOfFile"), cursor, 0);
}
public static boolean isRegularIdentifier(String identifier) {
if (identifier.isEmpty()) return false;
if (isKeyword(identifier)) return false;
var firstCp = identifier.codePointAt(0);
return (firstCp == '$' || firstCp == '_' || Character.isUnicodeIdentifierStart(firstCp))
&& identifier
.codePoints()
.skip(1)
.allMatch(cp -> cp == '$' || Character.isUnicodeIdentifierPart(cp));
}
public static String maybeQuoteIdentifier(String identifier) {
return isRegularIdentifier(identifier) ? identifier : "`" + identifier + "`";
}
@SuppressWarnings("SuspiciousArrayMethodCall")
private static boolean isKeyword(String text) {
var index = Arrays.binarySearch(KEYWORDS, text);
return index >= 0;
}
@SuppressWarnings("SuspiciousArrayMethodCall")
private static Token getKeywordOrIdentifier(String text) {
var index = Arrays.binarySearch(KEYWORDS, text);
if (index < 0) return Token.IDENTIFIER;
return KEYWORDS[index].token;
}
protected static final KeywordEntry[] KEYWORDS = {
new KeywordEntry("_", Token.UNDERSCORE),
new KeywordEntry("abstract", Token.ABSTRACT),
new KeywordEntry("amends", Token.AMENDS),
new KeywordEntry("as", Token.AS),
new KeywordEntry("case", Token.CASE),
new KeywordEntry("class", Token.CLASS),
new KeywordEntry("const", Token.CONST),
new KeywordEntry("delete", Token.DELETE),
new KeywordEntry("else", Token.ELSE),
new KeywordEntry("extends", Token.EXTENDS),
new KeywordEntry("external", Token.EXTERNAL),
new KeywordEntry("false", Token.FALSE),
new KeywordEntry("fixed", Token.FIXED),
new KeywordEntry("for", Token.FOR),
new KeywordEntry("function", Token.FUNCTION),
new KeywordEntry("hidden", Token.HIDDEN),
new KeywordEntry("if", Token.IF),
new KeywordEntry("import", Token.IMPORT),
new KeywordEntry("in", Token.IN),
new KeywordEntry("is", Token.IS),
new KeywordEntry("let", Token.LET),
new KeywordEntry("local", Token.LOCAL),
new KeywordEntry("module", Token.MODULE),
new KeywordEntry("new", Token.NEW),
new KeywordEntry("nothing", Token.NOTHING),
new KeywordEntry("null", Token.NULL),
new KeywordEntry("open", Token.OPEN),
new KeywordEntry("out", Token.OUT),
new KeywordEntry("outer", Token.OUTER),
new KeywordEntry("override", Token.OVERRIDE),
new KeywordEntry("protected", Token.PROTECTED),
new KeywordEntry("read", Token.READ),
new KeywordEntry("record", Token.RECORD),
new KeywordEntry("super", Token.SUPER),
new KeywordEntry("switch", Token.SWITCH),
new KeywordEntry("this", Token.THIS),
new KeywordEntry("throw", Token.THROW),
new KeywordEntry("trace", Token.TRACE),
new KeywordEntry("true", Token.TRUE),
new KeywordEntry("typealias", Token.TYPE_ALIAS),
new KeywordEntry("unknown", Token.UNKNOWN),
new KeywordEntry("vararg", Token.VARARG),
new KeywordEntry("when", Token.WHEN)
};
protected record KeywordEntry(String name, Token token) implements Comparable<String> {
@Override
public int compareTo(String o) {
return name.compareTo(o);
}
}
private static class InterpolationScope {
final int quotes;
final int pounds;
int parens = 0;
protected InterpolationScope(int quotes, int pounds) {
this.quotes = quotes;
this.pounds = pounds;
}
}
private enum State {
DEFAULT,
STRING
}
}

View File

@@ -0,0 +1,140 @@
/*
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser;
import java.util.ArrayList;
import java.util.List;
import org.pkl.parser.syntax.Expr;
import org.pkl.parser.syntax.Expr.BinaryOperatorExpr;
import org.pkl.parser.syntax.Expr.OperatorExpr;
import org.pkl.parser.syntax.Expr.TypeCastExpr;
import org.pkl.parser.syntax.Expr.TypeCheckExpr;
import org.pkl.parser.syntax.Expr.TypeExpr;
import org.pkl.parser.syntax.Operator;
import org.pkl.parser.util.Nullable;
class OperatorResolver {
private OperatorResolver() {}
private enum Associativity {
LEFT,
RIGHT
}
public static int getPrecedence(Operator op) {
return switch (op) {
case NULL_COALESCE -> 0;
case PIPE -> 1;
case OR -> 2;
case AND -> 3;
case EQ_EQ, NOT_EQ -> 4;
case IS, AS -> 5;
case LT, LTE, GT, GTE -> 6;
case PLUS, MINUS -> 7;
case MULT, DIV, INT_DIV, MOD -> 8;
case POW -> 9;
case DOT, QDOT -> 10;
};
}
private static Associativity getAssociativity(Operator op) {
return switch (op) {
case POW, NULL_COALESCE -> Associativity.RIGHT;
default -> Associativity.LEFT;
};
}
private static @Nullable Operator getHighestPrecedence(List<Expr> exprs, int min) {
var highest = -1;
Operator op = null;
for (var expr : exprs) {
if (expr instanceof OperatorExpr o) {
var precedence = getPrecedence(o.getOp());
if (precedence > highest && precedence >= min) {
highest = precedence;
op = o.getOp();
}
}
}
return op;
}
private static int index(List<Expr> exprs, Associativity associativity, Operator op) {
if (associativity == Associativity.LEFT) {
for (var i = 0; i < exprs.size(); i++) {
if (exprs.get(i) instanceof OperatorExpr operator && operator.getOp() == op) {
return i;
}
}
} else {
for (var i = exprs.size() - 1; i >= 0; i--) {
if (exprs.get(i) instanceof OperatorExpr operator && operator.getOp() == op) {
return i;
}
}
}
return -1;
}
private static List<Expr> resolveOperator(
List<Expr> exprs, Associativity associativity, Operator op) {
var res = new ArrayList<>(exprs);
var i = index(res, associativity, op);
var left = res.get(i - 1);
var right = res.get(i + 1);
var span = left.span().endWith(right.span());
var binOp =
switch (op) {
case IS -> new TypeCheckExpr(left, ((TypeExpr) right).getType(), span);
case AS -> new TypeCastExpr(left, ((TypeExpr) right).getType(), span);
default -> new BinaryOperatorExpr(left, right, op, span);
};
res.remove(i - 1);
res.remove(i - 1);
res.remove(i - 1);
res.add(i - 1, binOp);
return res;
}
/**
* Resolve all operators based on their precedence and associativity. This requires that the list
* has a valid form: `expr` `op` `expr` ...
*/
public static Expr resolveOperators(List<Expr> exprs) {
if (exprs.size() == 1) return exprs.get(0);
var res = resolveOperatorsHigherThan(exprs, 0);
if (res.size() > 1) {
throw new ParserError(
"Malformed expression", exprs.get(0).span().endWith(exprs.get(exprs.size() - 1).span()));
}
return res.get(0);
}
public static List<Expr> resolveOperatorsHigherThan(List<Expr> exprs, int minPrecedence) {
var res = exprs;
var highest = getHighestPrecedence(res, minPrecedence);
while (highest != null) {
var associativity = getAssociativity(highest);
res = resolveOperator(res, associativity, highest);
highest = getHighestPrecedence(res, minPrecedence);
}
return res;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,41 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser;
import org.pkl.parser.syntax.Module;
import org.pkl.parser.util.Nullable;
public class ParserError extends RuntimeException {
private final Span span;
private @Nullable Module partialParseResult;
public ParserError(String msg, Span span) {
super(msg);
this.span = span;
}
public Span span() {
return span;
}
public void setPartialParseResult(@Nullable Module partialParseResult) {
this.partialParseResult = partialParseResult;
}
public @Nullable Module getPartialParseResult() {
return partialParseResult;
}
}

View File

@@ -0,0 +1,226 @@
/*
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser;
import org.pkl.parser.syntax.Annotation;
import org.pkl.parser.syntax.ArgumentList;
import org.pkl.parser.syntax.Class;
import org.pkl.parser.syntax.ClassBody;
import org.pkl.parser.syntax.ClassMethod;
import org.pkl.parser.syntax.ClassProperty;
import org.pkl.parser.syntax.DocComment;
import org.pkl.parser.syntax.Expr;
import org.pkl.parser.syntax.Expr.AmendsExpr;
import org.pkl.parser.syntax.Expr.BinaryOperatorExpr;
import org.pkl.parser.syntax.Expr.BoolLiteralExpr;
import org.pkl.parser.syntax.Expr.FloatLiteralExpr;
import org.pkl.parser.syntax.Expr.FunctionLiteralExpr;
import org.pkl.parser.syntax.Expr.IfExpr;
import org.pkl.parser.syntax.Expr.IntLiteralExpr;
import org.pkl.parser.syntax.Expr.LetExpr;
import org.pkl.parser.syntax.Expr.LogicalNotExpr;
import org.pkl.parser.syntax.Expr.ModuleExpr;
import org.pkl.parser.syntax.Expr.MultiLineStringLiteralExpr;
import org.pkl.parser.syntax.Expr.NewExpr;
import org.pkl.parser.syntax.Expr.NonNullExpr;
import org.pkl.parser.syntax.Expr.NullLiteralExpr;
import org.pkl.parser.syntax.Expr.OuterExpr;
import org.pkl.parser.syntax.Expr.ParenthesizedExpr;
import org.pkl.parser.syntax.Expr.QualifiedAccessExpr;
import org.pkl.parser.syntax.Expr.ReadExpr;
import org.pkl.parser.syntax.Expr.SingleLineStringLiteralExpr;
import org.pkl.parser.syntax.Expr.SubscriptExpr;
import org.pkl.parser.syntax.Expr.SuperAccessExpr;
import org.pkl.parser.syntax.Expr.SuperSubscriptExpr;
import org.pkl.parser.syntax.Expr.ThisExpr;
import org.pkl.parser.syntax.Expr.ThrowExpr;
import org.pkl.parser.syntax.Expr.TraceExpr;
import org.pkl.parser.syntax.Expr.TypeCastExpr;
import org.pkl.parser.syntax.Expr.TypeCheckExpr;
import org.pkl.parser.syntax.Expr.UnaryMinusExpr;
import org.pkl.parser.syntax.Expr.UnqualifiedAccessExpr;
import org.pkl.parser.syntax.ExtendsOrAmendsClause;
import org.pkl.parser.syntax.Identifier;
import org.pkl.parser.syntax.ImportClause;
import org.pkl.parser.syntax.Keyword;
import org.pkl.parser.syntax.Modifier;
import org.pkl.parser.syntax.Module;
import org.pkl.parser.syntax.ModuleDecl;
import org.pkl.parser.syntax.ObjectBody;
import org.pkl.parser.syntax.ObjectMember;
import org.pkl.parser.syntax.Parameter;
import org.pkl.parser.syntax.ParameterList;
import org.pkl.parser.syntax.QualifiedIdentifier;
import org.pkl.parser.syntax.ReplInput;
import org.pkl.parser.syntax.StringConstant;
import org.pkl.parser.syntax.StringPart;
import org.pkl.parser.syntax.Type;
import org.pkl.parser.syntax.TypeAlias;
import org.pkl.parser.syntax.TypeAnnotation;
import org.pkl.parser.syntax.TypeArgumentList;
import org.pkl.parser.syntax.TypeParameter;
import org.pkl.parser.syntax.TypeParameterList;
public interface ParserVisitor<Result> {
Result visitUnknownType(Type.UnknownType type);
Result visitNothingType(Type.NothingType type);
Result visitModuleType(Type.ModuleType type);
Result visitStringConstantType(Type.StringConstantType type);
Result visitDeclaredType(Type.DeclaredType type);
Result visitParenthesizedType(Type.ParenthesizedType type);
Result visitNullableType(Type.NullableType type);
Result visitConstrainedType(Type.ConstrainedType type);
Result visitUnionType(Type.UnionType type);
Result visitFunctionType(Type.FunctionType type);
Result visitThisExpr(ThisExpr expr);
Result visitOuterExpr(OuterExpr expr);
Result visitModuleExpr(ModuleExpr expr);
Result visitNullLiteralExpr(NullLiteralExpr expr);
Result visitBoolLiteralExpr(BoolLiteralExpr expr);
Result visitIntLiteralExpr(IntLiteralExpr expr);
Result visitFloatLiteralExpr(FloatLiteralExpr expr);
Result visitThrowExpr(ThrowExpr expr);
Result visitTraceExpr(TraceExpr expr);
Result visitImportExpr(Expr.ImportExpr expr);
Result visitReadExpr(ReadExpr expr);
Result visitUnqualifiedAccessExpr(UnqualifiedAccessExpr expr);
Result visitStringConstant(StringConstant expr);
Result visitSingleLineStringLiteralExpr(SingleLineStringLiteralExpr expr);
Result visitMultiLineStringLiteralExpr(MultiLineStringLiteralExpr expr);
Result visitNewExpr(NewExpr expr);
Result visitAmendsExpr(AmendsExpr expr);
Result visitSuperAccessExpr(SuperAccessExpr expr);
Result visitSuperSubscriptExpr(SuperSubscriptExpr expr);
Result visitQualifiedAccessExpr(QualifiedAccessExpr expr);
Result visitSubscriptExpr(SubscriptExpr expr);
Result visitNonNullExpr(NonNullExpr expr);
Result visitUnaryMinusExpr(UnaryMinusExpr expr);
Result visitLogicalNotExpr(LogicalNotExpr expr);
Result visitBinaryOperatorExpr(BinaryOperatorExpr expr);
Result visitTypeCheckExpr(TypeCheckExpr expr);
Result visitTypeCastExpr(TypeCastExpr expr);
Result visitIfExpr(IfExpr expr);
Result visitLetExpr(LetExpr expr);
Result visitFunctionLiteralExpr(FunctionLiteralExpr expr);
Result visitParenthesizedExpr(ParenthesizedExpr expr);
Result visitObjectProperty(ObjectMember.ObjectProperty member);
Result visitObjectMethod(ObjectMember.ObjectMethod member);
Result visitMemberPredicate(ObjectMember.MemberPredicate member);
Result visitObjectElement(ObjectMember.ObjectElement member);
Result visitObjectEntry(ObjectMember.ObjectEntry member);
Result visitObjectSpread(ObjectMember.ObjectSpread member);
Result visitWhenGenerator(ObjectMember.WhenGenerator member);
Result visitForGenerator(ObjectMember.ForGenerator member);
Result visitModule(Module module);
Result visitModuleDecl(ModuleDecl decl);
Result visitExtendsOrAmendsClause(ExtendsOrAmendsClause decl);
Result visitImportClause(ImportClause imp);
Result visitClass(Class clazz);
Result visitModifier(Modifier modifier);
Result visitClassProperty(ClassProperty entry);
Result visitClassMethod(ClassMethod entry);
Result visitClassBody(ClassBody classBody);
Result visitTypeAlias(TypeAlias typeAlias);
Result visitAnnotation(Annotation annotation);
Result visitParameter(Parameter param);
Result visitParameterList(ParameterList paramList);
Result visitTypeParameter(TypeParameter typeParameter);
Result visitTypeParameterList(TypeParameterList typeParameterList);
Result visitTypeAnnotation(TypeAnnotation typeAnnotation);
Result visitArgumentList(ArgumentList argumentList);
Result visitStringPart(StringPart part);
Result visitDocComment(DocComment docComment);
Result visitIdentifier(Identifier identifier);
Result visitQualifiedIdentifier(QualifiedIdentifier qualifiedIdentifier);
Result visitObjectBody(ObjectBody objectBody);
Result visitReplInput(ReplInput replInput);
Result visitKeyword(Keyword keyword);
Result visitTypeArgumentList(TypeArgumentList typeArgumentList);
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser;
public record Span(int charIndex, int length) {
/** Returns a span that starts with this span and ends with {@code end}. */
public Span endWith(Span end) {
return new Span(charIndex, end.charIndex - charIndex + end.length);
}
/** Checks wheter {@code other} starts directly after this span ends */
public boolean adjacent(Span other) {
return charIndex + length == other.charIndex;
}
public int stopIndex() {
return charIndex + length - 1;
}
public Span stopSpan() {
return new Span(charIndex + length - 1, 1);
}
public Span move(int amount) {
return new Span(charIndex + amount, length);
}
public Span grow(int amount) {
return new Span(charIndex, length + amount);
}
}

View File

@@ -0,0 +1,200 @@
/*
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser;
public enum Token {
ABSTRACT,
AMENDS,
AS,
CLASS,
CONST,
ELSE,
EXTENDS,
EXTERNAL,
FALSE,
FIXED,
FOR,
FUNCTION,
HIDDEN,
IF,
IMPORT,
IMPORT_STAR,
IN,
IS,
LET,
LOCAL,
MODULE,
NEW,
NOTHING,
NULL,
OPEN,
OUT,
OUTER,
READ,
READ_STAR,
READ_QUESTION,
SUPER,
THIS,
THROW,
TRACE,
TRUE,
TYPE_ALIAS,
UNKNOWN,
WHEN,
// reserved for future use
PROTECTED,
OVERRIDE,
RECORD,
DELETE,
CASE,
SWITCH,
VARARG,
// punctuation
LPAREN,
RPAREN,
LBRACE,
RBRACE,
LBRACK,
RBRACK,
LPRED,
COMMA,
DOT,
QDOT,
COALESCE,
NON_NULL,
AT,
ASSIGN,
GT,
LT,
// rest
NOT,
QUESTION,
COLON,
ARROW,
EQUAL,
NOT_EQUAL,
LTE,
GTE,
AND,
OR,
PLUS,
MINUS,
POW,
STAR,
DIV,
INT_DIV,
MOD,
UNION,
PIPE,
SPREAD,
QSPREAD,
UNDERSCORE,
EOF,
SEMICOLON,
INT,
FLOAT,
BIN,
OCT,
HEX,
IDENTIFIER,
LINE_COMMENT,
BLOCK_COMMENT,
DOC_COMMENT,
SHEBANG,
INTERPOLATION_START,
STRING_START,
STRING_MULTI_START,
STRING_NEWLINE,
STRING_ESCAPE_NEWLINE,
STRING_ESCAPE_TAB,
STRING_ESCAPE_RETURN,
STRING_ESCAPE_QUOTE,
STRING_ESCAPE_BACKSLASH,
STRING_ESCAPE_UNICODE,
STRING_END,
STRING_PART;
public boolean isModifier() {
return switch (this) {
case EXTERNAL, ABSTRACT, OPEN, LOCAL, HIDDEN, FIXED, CONST -> true;
default -> false;
};
}
public boolean isKeyword() {
return switch (this) {
case ABSTRACT,
AMENDS,
AS,
CLASS,
CONST,
ELSE,
EXTENDS,
EXTERNAL,
FALSE,
FIXED,
FOR,
FUNCTION,
HIDDEN,
IF,
IMPORT,
IMPORT_STAR,
IN,
IS,
LET,
LOCAL,
MODULE,
NEW,
NOTHING,
NULL,
OPEN,
OUT,
OUTER,
READ,
READ_STAR,
READ_QUESTION,
SUPER,
THIS,
THROW,
TRACE,
TRUE,
TYPE_ALIAS,
UNKNOWN,
WHEN,
UNDERSCORE,
PROTECTED,
OVERRIDE,
RECORD,
DELETE,
CASE,
SWITCH,
VARARG ->
true;
default -> false;
};
}
public String text() {
if (this == UNDERSCORE) {
return "_";
}
return name().toLowerCase();
}
}

View File

@@ -0,0 +1,4 @@
@NonnullByDefault
package org.pkl.parser;
import org.pkl.parser.util.NonnullByDefault;

View File

@@ -0,0 +1,88 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.syntax;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import org.pkl.parser.Span;
import org.pkl.parser.util.Nullable;
public abstract class AbstractNode implements Node {
protected final Span span;
protected final @Nullable List<? extends @Nullable Node> children;
protected @Nullable Node parent;
public AbstractNode(Span span, @Nullable List<? extends @Nullable Node> children) {
this.span = span;
if (children != null) {
this.children = Collections.unmodifiableList(children);
} else {
this.children = null;
}
if (children != null) {
for (var node : children) {
if (node != null) {
node.setParent(this);
}
}
}
}
@Override
public Span span() {
return span;
}
@Override
public @Nullable Node parent() {
return parent;
}
@Override
public void setParent(Node parent) {
this.parent = parent;
}
@Override
public @Nullable List<? extends @Nullable Node> children() {
return children;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
AbstractNode that = (AbstractNode) o;
return Objects.equals(span, that.span) && Objects.deepEquals(children, that.children);
}
@Override
public int hashCode() {
return Objects.hash(span, children);
}
@Override
public String toString() {
var name = getClass().getSimpleName();
return name + "{span=" + span + ", children=" + children + '}';
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.syntax;
import java.util.List;
import org.pkl.parser.ParserVisitor;
import org.pkl.parser.Span;
import org.pkl.parser.util.Nullable;
public class Annotation extends AbstractNode {
public Annotation(List<Node> nodes, Span span) {
super(span, nodes);
}
@Override
public <T> @Nullable T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitAnnotation(this);
}
public Type getType() {
assert children != null;
return (Type) children.get(0);
}
public @Nullable ObjectBody getBody() {
assert children != null;
return (ObjectBody) children.get(1);
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.syntax;
import java.util.List;
import org.pkl.parser.ParserVisitor;
import org.pkl.parser.Span;
import org.pkl.parser.util.Nullable;
public class ArgumentList extends AbstractNode {
public ArgumentList(List<Expr> arguments, Span span) {
super(span, arguments);
}
@Override
public <T> @Nullable T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitArgumentList(this);
}
@SuppressWarnings("unchecked")
public List<Expr> getArguments() {
assert children != null;
return (List<Expr>) children;
}
}

View File

@@ -0,0 +1,102 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.syntax;
import java.util.List;
import org.pkl.parser.ParserVisitor;
import org.pkl.parser.Span;
import org.pkl.parser.util.Nullable;
public final class Class extends AbstractNode {
private final int modifiersOffset;
private final int keywordOffset;
public Class(List<Node> nodes, int modifiersOffset, int keywordOffset, Span span) {
super(span, nodes);
this.modifiersOffset = modifiersOffset;
this.keywordOffset = keywordOffset;
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitClass(this);
}
public @Nullable DocComment getDocComment() {
assert children != null;
return (DocComment) children.get(0);
}
@SuppressWarnings("unchecked")
public List<Annotation> getAnnotations() {
assert children != null;
return (List<Annotation>) children.subList(1, modifiersOffset);
}
@SuppressWarnings("unchecked")
public List<Modifier> getModifiers() {
assert children != null;
return (List<Modifier>) children.subList(modifiersOffset, keywordOffset);
}
public Keyword getClassKeyword() {
assert children != null;
return (Keyword) children.get(keywordOffset);
}
public Identifier getName() {
assert children != null;
return (Identifier) children.get(keywordOffset + 1);
}
public @Nullable TypeParameterList getTypeParameterList() {
assert children != null;
return (TypeParameterList) children.get(keywordOffset + 2);
}
public @Nullable Type getSuperClass() {
assert children != null;
return (Type) children.get(keywordOffset + 3);
}
public @Nullable ClassBody getBody() {
assert children != null;
return (ClassBody) children.get(keywordOffset + 4);
}
@SuppressWarnings("DuplicatedCode")
public Span getHeaderSpan() {
Span start = null;
assert children != null;
for (var i = modifiersOffset; i < children.size(); i++) {
var child = children.get(i);
if (child != null) {
start = child.span();
break;
}
}
Span end;
if (getSuperClass() != null) {
end = getSuperClass().span();
} else if (getTypeParameterList() != null) {
end = getTypeParameterList().span();
} else {
end = getName().span();
}
assert start != null;
return start.endWith(end);
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.syntax;
import java.util.ArrayList;
import java.util.List;
import org.pkl.parser.ParserVisitor;
import org.pkl.parser.Span;
import org.pkl.parser.util.Nullable;
public class ClassBody extends AbstractNode {
public ClassBody(List<Node> nodes, Span span) {
super(span, nodes);
}
@Override
public <T> @Nullable T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitClassBody(this);
}
public List<ClassProperty> getProperties() {
var props = new ArrayList<ClassProperty>();
assert children != null;
for (var child : children) {
if (child instanceof ClassProperty prop) {
props.add(prop);
}
}
return props;
}
public List<ClassMethod> getMethods() {
var methods = new ArrayList<ClassMethod>();
assert children != null;
for (var child : children) {
if (child instanceof ClassMethod method) {
methods.add(method);
}
}
return methods;
}
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.syntax;
import java.util.List;
import org.pkl.parser.ParserVisitor;
import org.pkl.parser.Span;
import org.pkl.parser.util.Nullable;
public class ClassMethod extends AbstractNode {
private final int modifiersOffset;
private final int nameOffset;
private final Span headerSpan;
public ClassMethod(
List<Node> nodes, int modifiersOffset, int nameOffset, Span headerSpan, Span span) {
super(span, nodes);
this.headerSpan = headerSpan;
this.modifiersOffset = modifiersOffset;
this.nameOffset = nameOffset;
}
@Override
public <T> @Nullable T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitClassMethod(this);
}
public @Nullable DocComment getDocComment() {
assert children != null;
return (DocComment) children.get(0);
}
@SuppressWarnings("unchecked")
public List<Annotation> getAnnotations() {
assert children != null;
return (List<Annotation>) children.subList(1, modifiersOffset);
}
@SuppressWarnings("unchecked")
public List<Modifier> getModifiers() {
assert children != null;
return (List<Modifier>) children.subList(modifiersOffset, nameOffset);
}
public Identifier getName() {
assert children != null;
return (Identifier) children.get(nameOffset);
}
public @Nullable TypeParameterList getTypeParameterList() {
assert children != null;
return (TypeParameterList) children.get(nameOffset + 1);
}
public ParameterList getParameterList() {
assert children != null;
return (ParameterList) children.get(nameOffset + 2);
}
public @Nullable TypeAnnotation getTypeAnnotation() {
assert children != null;
return (TypeAnnotation) children.get(nameOffset + 3);
}
public @Nullable Expr getExpr() {
assert children != null;
return (Expr) children.get(nameOffset + 4);
}
public Span getHeaderSpan() {
return headerSpan;
}
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.syntax;
import java.util.List;
import org.pkl.parser.ParserVisitor;
import org.pkl.parser.Span;
import org.pkl.parser.util.Nullable;
public final class ClassProperty extends AbstractNode {
private final int modifiersOffset;
private final int nameOffset;
public ClassProperty(List<Node> nodes, int modifiersOffset, int nameOffset, Span span) {
super(span, nodes);
this.modifiersOffset = modifiersOffset;
this.nameOffset = nameOffset;
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitClassProperty(this);
}
public @Nullable DocComment getDocComment() {
assert children != null;
return (DocComment) children.get(0);
}
@SuppressWarnings("unchecked")
public List<Annotation> getAnnotations() {
assert children != null;
return (List<Annotation>) children.subList(1, modifiersOffset);
}
@SuppressWarnings("unchecked")
public List<Modifier> getModifiers() {
assert children != null;
return (List<Modifier>) children.subList(modifiersOffset, nameOffset);
}
public Identifier getName() {
assert children != null;
return (Identifier) children.get(nameOffset);
}
public @Nullable TypeAnnotation getTypeAnnotation() {
assert children != null;
return (TypeAnnotation) children.get(nameOffset + 1);
}
public @Nullable Expr getExpr() {
assert children != null;
return (Expr) children.get(nameOffset + 2);
}
@SuppressWarnings("unchecked")
public List<ObjectBody> getBodyList() {
assert children != null;
return (List<ObjectBody>) children.subList(nameOffset + 3, children.size());
}
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.syntax;
import java.util.List;
import org.pkl.parser.ParserVisitor;
import org.pkl.parser.Span;
import org.pkl.parser.util.Nullable;
public final class DocComment extends AbstractNode {
private final List<Span> spans;
public DocComment(List<Span> spans) {
super(spans.get(0).endWith(spans.get(spans.size() - 1)), null);
this.spans = spans;
}
@Override
public Span span() {
return spans.get(0).endWith(spans.get(spans.size() - 1));
}
public List<Span> getSpans() {
return spans;
}
@Override
public <T> @Nullable T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitDocComment(this);
}
@Override
public String text(char[] source) {
var builder = new StringBuilder();
for (var span : spans) {
builder.append(new String(source, span.charIndex(), span.length()));
builder.append('\n');
}
return builder.toString();
}
}

View File

@@ -0,0 +1,731 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.syntax;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import org.pkl.parser.ParserVisitor;
import org.pkl.parser.Span;
import org.pkl.parser.util.Nullable;
public abstract sealed class Expr extends AbstractNode {
public Expr(Span span, @Nullable List<? extends @Nullable Node> children) {
super(span, children);
}
public static final class ThisExpr extends Expr {
public ThisExpr(Span span) {
super(span, null);
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitThisExpr(this);
}
}
public static final class OuterExpr extends Expr {
public OuterExpr(Span span) {
super(span, null);
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitOuterExpr(this);
}
}
public static final class ModuleExpr extends Expr {
public ModuleExpr(Span span) {
super(span, null);
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitModuleExpr(this);
}
}
public static final class NullLiteralExpr extends Expr {
public NullLiteralExpr(Span span) {
super(span, null);
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitNullLiteralExpr(this);
}
}
public static final class BoolLiteralExpr extends Expr {
private final boolean b;
public BoolLiteralExpr(boolean b, Span span) {
super(span, null);
this.b = b;
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitBoolLiteralExpr(this);
}
public boolean isB() {
return b;
}
}
public static final class IntLiteralExpr extends Expr {
private final String number;
public IntLiteralExpr(String number, Span span) {
super(span, null);
this.number = number;
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitIntLiteralExpr(this);
}
public String getNumber() {
return number;
}
}
public static final class FloatLiteralExpr extends Expr {
private final String number;
public FloatLiteralExpr(String number, Span span) {
super(span, null);
this.number = number;
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitFloatLiteralExpr(this);
}
public String getNumber() {
return number;
}
}
public static final class SingleLineStringLiteralExpr extends Expr {
private final Span startDelimiterSpan;
private final Span endDelimiterSpan;
public SingleLineStringLiteralExpr(
List<StringPart> parts, Span startDelimiterSpan, Span endDelimiterSpan, Span span) {
super(span, parts);
this.startDelimiterSpan = startDelimiterSpan;
this.endDelimiterSpan = endDelimiterSpan;
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitSingleLineStringLiteralExpr(this);
}
@SuppressWarnings("unchecked")
public List<StringPart> getParts() {
assert children != null;
return (List<StringPart>) children;
}
public Span getStartDelimiterSpan() {
return startDelimiterSpan;
}
public Span getEndDelimiterSpan() {
return endDelimiterSpan;
}
}
public static final class MultiLineStringLiteralExpr extends Expr {
private final Span startDelimiterSpan;
private final Span endDelimiterSpan;
public MultiLineStringLiteralExpr(
List<StringPart> parts, Span startDelimiterSpan, Span endDelimiterSpan, Span span) {
super(span, parts);
this.startDelimiterSpan = startDelimiterSpan;
this.endDelimiterSpan = endDelimiterSpan;
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitMultiLineStringLiteralExpr(this);
}
@SuppressWarnings("unchecked")
public List<StringPart> getParts() {
assert children != null;
return (List<StringPart>) children;
}
public Span getStartDelimiterSpan() {
return startDelimiterSpan;
}
public Span getEndDelimiterSpan() {
return endDelimiterSpan;
}
}
public static final class ThrowExpr extends Expr {
public ThrowExpr(Expr expr, Span span) {
super(span, List.of(expr));
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitThrowExpr(this);
}
public Expr getExpr() {
assert children != null;
return (Expr) children.get(0);
}
}
public static final class TraceExpr extends Expr {
public TraceExpr(Expr expr, Span span) {
super(span, List.of(expr));
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitTraceExpr(this);
}
public Expr getExpr() {
assert children != null;
return (Expr) children.get(0);
}
}
public static final class ImportExpr extends Expr {
private final boolean isGlob;
public ImportExpr(StringConstant importStr, boolean isGlob, Span span) {
super(span, List.of(importStr));
this.isGlob = isGlob;
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitImportExpr(this);
}
public StringConstant getImportStr() {
assert children != null;
return (StringConstant) children.get(0);
}
public boolean isGlob() {
return isGlob;
}
}
public static final class ReadExpr extends Expr {
private final ReadType readType;
public ReadExpr(Expr expr, ReadType readType, Span span) {
super(span, List.of(expr));
this.readType = readType;
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitReadExpr(this);
}
public Expr getExpr() {
assert children != null;
return (Expr) children.get(0);
}
public ReadType getReadType() {
return readType;
}
}
public enum ReadType {
READ,
GLOB,
NULL
}
public static final class UnqualifiedAccessExpr extends Expr {
public UnqualifiedAccessExpr(
Identifier identifier, @Nullable ArgumentList argumentList, Span span) {
super(span, Arrays.asList(identifier, argumentList));
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitUnqualifiedAccessExpr(this);
}
public Identifier getIdentifier() {
assert children != null;
return (Identifier) children.get(0);
}
public @Nullable ArgumentList getArgumentList() {
assert children != null;
return (ArgumentList) children.get(1);
}
}
public static final class QualifiedAccessExpr extends Expr {
private final boolean isNullable;
public QualifiedAccessExpr(
Expr expr,
Identifier identifier,
boolean isNullable,
@Nullable ArgumentList argumentList,
Span span) {
super(span, Arrays.asList(expr, identifier, argumentList));
this.isNullable = isNullable;
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitQualifiedAccessExpr(this);
}
public Expr getExpr() {
assert children != null;
return (Expr) children.get(0);
}
public Identifier getIdentifier() {
assert children != null;
return (Identifier) children.get(1);
}
public boolean isNullable() {
return isNullable;
}
public @Nullable ArgumentList getArgumentList() {
assert children != null;
return (ArgumentList) children.get(2);
}
}
public static final class SuperAccessExpr extends Expr {
public SuperAccessExpr(Identifier identifier, @Nullable ArgumentList argumentList, Span span) {
super(span, Arrays.asList(identifier, argumentList));
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitSuperAccessExpr(this);
}
public Identifier getIdentifier() {
assert children != null;
return (Identifier) children.get(0);
}
public @Nullable ArgumentList getArgumentList() {
assert children != null;
return (ArgumentList) children.get(1);
}
}
public static final class SuperSubscriptExpr extends Expr {
public SuperSubscriptExpr(Expr arg, Span span) {
super(span, List.of(arg));
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitSuperSubscriptExpr(this);
}
public Expr getArg() {
assert children != null;
return (Expr) children.get(0);
}
}
public static final class SubscriptExpr extends Expr {
public SubscriptExpr(Expr expr, Expr arg, Span span) {
super(span, List.of(expr, arg));
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitSubscriptExpr(this);
}
public Expr getExpr() {
assert children != null;
return (Expr) children.get(0);
}
public Expr getArg() {
assert children != null;
return (Expr) children.get(1);
}
}
public static final class IfExpr extends Expr {
public IfExpr(Expr cond, Expr then, Expr els, Span span) {
super(span, List.of(cond, then, els));
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitIfExpr(this);
}
public Expr getCond() {
assert children != null;
return (Expr) children.get(0);
}
public Expr getThen() {
assert children != null;
return (Expr) children.get(1);
}
public Expr getEls() {
assert children != null;
return (Expr) children.get(2);
}
}
public static final class LetExpr extends Expr {
public LetExpr(Parameter parameter, Expr bindingExpr, Expr expr, Span span) {
super(span, List.of(parameter, bindingExpr, expr));
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitLetExpr(this);
}
public Parameter getParameter() {
assert children != null;
return (Parameter) children.get(0);
}
public Expr getBindingExpr() {
assert children != null;
return (Expr) children.get(1);
}
public Expr getExpr() {
assert children != null;
return (Expr) children.get(2);
}
}
public static final class FunctionLiteralExpr extends Expr {
public FunctionLiteralExpr(ParameterList parameterList, Expr expr, Span span) {
super(span, List.of(parameterList, expr));
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitFunctionLiteralExpr(this);
}
public ParameterList getParameterList() {
assert children != null;
return (ParameterList) children.get(0);
}
public Expr getExpr() {
assert children != null;
return (Expr) children.get(1);
}
}
public static final class ParenthesizedExpr extends Expr {
public ParenthesizedExpr(Expr expr, Span span) {
super(span, List.of(expr));
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitParenthesizedExpr(this);
}
public Expr getExpr() {
assert children != null;
return (Expr) children.get(0);
}
}
public static final class NewExpr extends Expr {
public NewExpr(@Nullable Type type, ObjectBody body, Span span) {
super(span, Arrays.asList(type, body));
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitNewExpr(this);
}
public @Nullable Type getType() {
assert children != null;
return (Type) children.get(0);
}
public ObjectBody getBody() {
assert children != null;
return (ObjectBody) children.get(1);
}
public Span newSpan() {
return new Span(span.charIndex(), 3);
}
}
public static final class AmendsExpr extends Expr {
public AmendsExpr(Expr expr, ObjectBody body, Span span) {
super(span, List.of(expr, body));
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitAmendsExpr(this);
}
public Expr getExpr() {
assert children != null;
return (Expr) children.get(0);
}
public ObjectBody getBody() {
assert children != null;
return (ObjectBody) children.get(1);
}
}
public static final class NonNullExpr extends Expr {
public NonNullExpr(Expr expr, Span span) {
super(span, List.of(expr));
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitNonNullExpr(this);
}
public Expr getExpr() {
assert children != null;
return (Expr) children.get(0);
}
}
public static final class UnaryMinusExpr extends Expr {
public UnaryMinusExpr(Expr expr, Span span) {
super(span, List.of(expr));
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitUnaryMinusExpr(this);
}
public Expr getExpr() {
assert children != null;
return (Expr) children.get(0);
}
}
public static final class LogicalNotExpr extends Expr {
public LogicalNotExpr(Expr expr, Span span) {
super(span, List.of(expr));
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitLogicalNotExpr(this);
}
public Expr getExpr() {
assert children != null;
return (Expr) children.get(0);
}
}
public static final class BinaryOperatorExpr extends Expr {
private final Operator op;
public BinaryOperatorExpr(Expr left, Expr right, Operator op, Span span) {
super(span, List.of(left, right));
this.op = op;
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitBinaryOperatorExpr(this);
}
public Expr getLeft() {
assert children != null;
return (Expr) children.get(0);
}
public Expr getRight() {
assert children != null;
return (Expr) children.get(1);
}
public Operator getOp() {
return op;
}
@Override
public String toString() {
return "BinaryOp{children=" + children + ", op=" + op + ", span=" + span + '}';
}
@SuppressWarnings("ConstantValue")
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
BinaryOperatorExpr binaryOp = (BinaryOperatorExpr) o;
return Objects.deepEquals(children, binaryOp.children)
&& op == binaryOp.op
&& Objects.equals(span, binaryOp.span);
}
@Override
public int hashCode() {
return Objects.hash(children, op, span);
}
}
public static final class TypeCheckExpr extends Expr {
public TypeCheckExpr(Expr expr, Type type, Span span) {
super(span, List.of(expr, type));
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitTypeCheckExpr(this);
}
public Expr getExpr() {
assert children != null;
return (Expr) children.get(0);
}
public Type getType() {
assert children != null;
return (Type) children.get(1);
}
}
public static final class TypeCastExpr extends Expr {
public TypeCastExpr(Expr expr, Type type, Span span) {
super(span, List.of(expr, type));
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitTypeCastExpr(this);
}
public Expr getExpr() {
assert children != null;
return (Expr) children.get(0);
}
public Type getType() {
assert children != null;
return (Type) children.get(1);
}
}
/** This is a synthetic class only used at parse time. */
public static final class OperatorExpr extends Expr {
private final Operator op;
public OperatorExpr(Operator op, Span span) {
super(span, null);
this.op = op;
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
// should never be called
throw new RuntimeException("Unreacheable code");
}
public Operator getOp() {
return op;
}
@Override
public String toString() {
return "OperatorExpr{op=" + op + ", span=" + span + '}';
}
@SuppressWarnings("ConstantValue")
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
OperatorExpr that = (OperatorExpr) o;
return op == that.op && Objects.equals(span, that.span);
}
@Override
public int hashCode() {
return Objects.hash(op, span);
}
}
/** This is a synthetic class only used at parse time. */
public static final class TypeExpr extends Expr {
public TypeExpr(Type type) {
super(type.span(), List.of(type));
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
// should never be called
throw new RuntimeException("Unreacheable code");
}
public Type getType() {
assert children != null;
return (Type) children.get(0);
}
}
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.syntax;
import java.util.List;
import java.util.Objects;
import org.pkl.parser.ParserVisitor;
import org.pkl.parser.Span;
import org.pkl.parser.util.Nullable;
public class ExtendsOrAmendsClause extends AbstractNode {
private final Type type;
public ExtendsOrAmendsClause(StringConstant url, Type type, Span span) {
super(span, List.of(url));
this.type = type;
}
@Override
public <T> @Nullable T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitExtendsOrAmendsClause(this);
}
public StringConstant getUrl() {
assert children != null;
return (StringConstant) children.get(0);
}
public Type getType() {
return type;
}
@Override
public String toString() {
return "ExtendsOrAmendsClause{"
+ "type="
+ type
+ ", span="
+ span
+ ", children="
+ children
+ '}';
}
@SuppressWarnings("ConstantValue")
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
if (!super.equals(o)) {
return false;
}
ExtendsOrAmendsClause that = (ExtendsOrAmendsClause) o;
return type == that.type;
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), type);
}
public enum Type {
EXTENDS,
AMENDS
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.syntax;
import java.util.Objects;
import org.pkl.parser.ParserVisitor;
import org.pkl.parser.Span;
public final class Identifier extends AbstractNode {
private final String value;
public Identifier(String value, Span span) {
super(span, null);
this.value = value;
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitIdentifier(this);
}
public String getValue() {
return removeBackticks(value);
}
public String getRawValue() {
return value;
}
private static String removeBackticks(String text) {
if (!text.isEmpty() && text.charAt(0) == '`') {
// lexer makes sure there's a ` at the end
return text.substring(1, text.length() - 1);
}
return text;
}
@Override
public String toString() {
return "Identifier{value='" + value + '\'' + ", span=" + span + '}';
}
@SuppressWarnings("ConstantValue")
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Identifier identifier = (Identifier) o;
return Objects.equals(value, identifier.value) && Objects.equals(span, identifier.span);
}
@Override
public int hashCode() {
return Objects.hash(value, span);
}
}

View File

@@ -0,0 +1,77 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.syntax;
import java.util.Arrays;
import java.util.Objects;
import org.pkl.parser.ParserVisitor;
import org.pkl.parser.Span;
import org.pkl.parser.util.Nullable;
public final class ImportClause extends AbstractNode {
private final boolean isGlob;
public ImportClause(
StringConstant importStr, boolean isGlob, @Nullable Identifier alias, Span span) {
super(span, Arrays.asList(importStr, alias));
this.isGlob = isGlob;
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitImportClause(this);
}
public StringConstant getImportStr() {
assert children != null;
return (StringConstant) children.get(0);
}
public boolean isGlob() {
return isGlob;
}
public @Nullable Identifier getAlias() {
assert children != null;
return (Identifier) children.get(1);
}
@Override
public String toString() {
return "Import{isGlob=" + isGlob + ", span=" + span + ", children=" + children + '}';
}
@SuppressWarnings("ConstantValue")
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
if (!super.equals(o)) {
return false;
}
ImportClause anImport = (ImportClause) o;
return isGlob == anImport.isGlob;
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), isGlob);
}
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.syntax;
import org.pkl.parser.ParserVisitor;
import org.pkl.parser.Span;
public class Keyword extends AbstractNode {
public Keyword(Span span) {
super(span, null);
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitKeyword(this);
}
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.syntax;
import java.util.Objects;
import org.pkl.parser.ParserVisitor;
import org.pkl.parser.Span;
public final class Modifier extends AbstractNode {
private final ModifierValue value;
public Modifier(ModifierValue value, Span span) {
super(span, null);
this.value = value;
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitModifier(this);
}
public ModifierValue getValue() {
return value;
}
@Override
public String toString() {
return "Modifier{value=" + value + ", span=" + span + '}';
}
@SuppressWarnings("ConstantValue")
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Modifier modifier = (Modifier) o;
return value == modifier.value && Objects.equals(span, modifier.span);
}
@Override
public int hashCode() {
return Objects.hash(value, span);
}
public enum ModifierValue {
EXTERNAL,
ABSTRACT,
OPEN,
LOCAL,
HIDDEN,
FIXED,
CONST
}
}

View File

@@ -0,0 +1,98 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.syntax;
import java.util.ArrayList;
import java.util.List;
import org.pkl.parser.ParserVisitor;
import org.pkl.parser.Span;
import org.pkl.parser.util.Nullable;
public final class Module extends AbstractNode {
public Module(List<Node> nodes, Span span) {
super(span, nodes);
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitModule(this);
}
public @Nullable ModuleDecl getDecl() {
assert children != null;
return (ModuleDecl) children.get(0);
}
public List<ImportClause> getImports() {
assert children != null;
if (children.size() < 2) return List.of();
var res = new ArrayList<ImportClause>();
for (int i = 1; i < children.size(); i++) {
var child = children.get(i);
if (child instanceof ImportClause imp) {
res.add(imp);
} else {
// imports are sequential
break;
}
}
return res;
}
public List<org.pkl.parser.syntax.Class> getClasses() {
var res = new ArrayList<org.pkl.parser.syntax.Class>();
assert children != null;
for (var child : children) {
if (child instanceof Class clazz) {
res.add(clazz);
}
}
return res;
}
public List<TypeAlias> getTypeAliases() {
var res = new ArrayList<TypeAlias>();
assert children != null;
for (var child : children) {
if (child instanceof TypeAlias typeAlias) {
res.add(typeAlias);
}
}
return res;
}
public List<ClassProperty> getProperties() {
var res = new ArrayList<ClassProperty>();
assert children != null;
for (var child : children) {
if (child instanceof ClassProperty classProperty) {
res.add(classProperty);
}
}
return res;
}
public List<ClassMethod> getMethods() {
var res = new ArrayList<ClassMethod>();
assert children != null;
for (var child : children) {
if (child instanceof ClassMethod classMethod) {
res.add(classMethod);
}
}
return res;
}
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.syntax;
import java.util.List;
import org.pkl.parser.ParserVisitor;
import org.pkl.parser.Span;
import org.pkl.parser.util.Nullable;
public final class ModuleDecl extends AbstractNode {
private final int modifiersOffset;
private final int nameOffset;
public ModuleDecl(List<Node> nodes, int modifiersOffset, int nameOffset, Span span) {
super(span, nodes);
this.modifiersOffset = modifiersOffset;
this.nameOffset = nameOffset;
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitModuleDecl(this);
}
public @Nullable DocComment getDocComment() {
assert children != null;
return (DocComment) children.get(0);
}
@SuppressWarnings("unchecked")
public List<Annotation> getAnnotations() {
assert children != null;
return (List<Annotation>) children.subList(1, modifiersOffset);
}
@SuppressWarnings("unchecked")
public List<Modifier> getModifiers() {
assert children != null;
return (List<Modifier>) children.subList(modifiersOffset, nameOffset);
}
public @Nullable Keyword getModuleKeyword() {
assert children != null;
return (Keyword) children.get(nameOffset);
}
public @Nullable QualifiedIdentifier getName() {
assert children != null;
return (QualifiedIdentifier) children.get(nameOffset + 1);
}
public @Nullable ExtendsOrAmendsClause getExtendsOrAmendsDecl() {
assert children != null;
return (ExtendsOrAmendsClause) children.get(nameOffset + 2);
}
@SuppressWarnings("DuplicatedCode")
public Span headerSpan() {
Span start = null;
assert children != null;
for (var i = modifiersOffset; i < children.size(); i++) {
var child = children.get(i);
if (child != null) {
start = child.span();
break;
}
}
var extendsOrAmends = children.get(nameOffset + 2);
assert start != null;
if (extendsOrAmends != null) {
return start.endWith(extendsOrAmends.span());
}
return start.endWith(children.get(nameOffset + 1).span());
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.syntax;
import java.util.List;
import org.pkl.parser.ParserVisitor;
import org.pkl.parser.Span;
import org.pkl.parser.util.Nullable;
public interface Node {
Span span();
@Nullable
Node parent();
void setParent(Node parent);
@Nullable
List<? extends @Nullable Node> children();
<T> T accept(ParserVisitor<? extends T> visitor);
default String text(char[] source) {
return new String(source, span().charIndex(), span().length());
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.syntax;
import java.util.List;
import org.pkl.parser.ParserVisitor;
import org.pkl.parser.Span;
public final class ObjectBody extends AbstractNode {
private final int membersOffset;
public ObjectBody(List<Node> nodes, int membersOffset, Span span) {
super(span, nodes);
this.membersOffset = membersOffset;
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitObjectBody(this);
}
@SuppressWarnings("unchecked")
public List<Parameter> getParameters() {
assert children != null;
return (List<Parameter>) children.subList(0, membersOffset);
}
@SuppressWarnings("unchecked")
public List<ObjectMember> getMembers() {
assert children != null;
return (List<ObjectMember>) children.subList(membersOffset, children.size());
}
}

View File

@@ -0,0 +1,331 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.syntax;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import org.pkl.parser.ParserVisitor;
import org.pkl.parser.Span;
import org.pkl.parser.util.Nullable;
public abstract sealed class ObjectMember extends AbstractNode {
public ObjectMember(Span span, @Nullable List<? extends @Nullable Node> children) {
super(span, children);
}
public static final class ObjectElement extends ObjectMember {
public ObjectElement(Expr expr, Span span) {
super(span, List.of(expr));
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitObjectElement(this);
}
public Expr getExpr() {
assert children != null;
return (Expr) children.get(0);
}
}
public static final class ObjectProperty extends ObjectMember {
private final int identifierOffset;
public ObjectProperty(List<Node> nodes, int identifierOffset, Span span) {
super(span, nodes);
this.identifierOffset = identifierOffset;
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitObjectProperty(this);
}
@SuppressWarnings("unchecked")
public List<Modifier> getModifiers() {
assert children != null;
return (List<Modifier>) children.subList(0, identifierOffset);
}
public Identifier getIdentifier() {
assert children != null;
return (Identifier) children.get(identifierOffset);
}
public @Nullable TypeAnnotation getTypeAnnotation() {
assert children != null;
return (TypeAnnotation) children.get(identifierOffset + 1);
}
public @Nullable Expr getExpr() {
assert children != null;
return (Expr) children.get(identifierOffset + 2);
}
@SuppressWarnings("unchecked")
public List<ObjectBody> getBodyList() {
assert children != null;
return (List<ObjectBody>) children.subList(identifierOffset + 3, children.size());
}
}
public static final class ObjectMethod extends ObjectMember {
private final int identifierOffset;
public ObjectMethod(List<Node> nodes, int identifierOffset, Span span) {
super(span, nodes);
this.identifierOffset = identifierOffset;
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitObjectMethod(this);
}
@SuppressWarnings("unchecked")
public List<Modifier> getModifiers() {
assert children != null;
return (List<Modifier>) children.subList(0, identifierOffset);
}
public Keyword getFunctionKeyword() {
assert children != null;
return (Keyword) children.get(identifierOffset);
}
public Identifier getIdentifier() {
assert children != null;
return (Identifier) children.get(identifierOffset + 1);
}
public @Nullable TypeParameterList getTypeParameterList() {
assert children != null;
return (TypeParameterList) children.get(identifierOffset + 2);
}
public ParameterList getParamList() {
assert children != null;
return (ParameterList) children.get(identifierOffset + 3);
}
public @Nullable TypeAnnotation getTypeAnnotation() {
assert children != null;
return (TypeAnnotation) children.get(identifierOffset + 4);
}
public Expr getExpr() {
assert children != null;
return (Expr) children.get(identifierOffset + 5);
}
@SuppressWarnings("DuplicatedCode")
public Span headerSpan() {
Span start = null;
assert children != null;
for (var child : children) {
if (child != null) {
start = child.span();
break;
}
}
Span end;
var typeAnnotation = children.get(identifierOffset + 4);
if (typeAnnotation == null) {
end = children.get(identifierOffset + 3).span();
} else {
end = typeAnnotation.span();
}
assert start != null;
return start.endWith(end);
}
}
public static final class MemberPredicate extends ObjectMember {
public MemberPredicate(List<Node> nodes, Span span) {
super(span, nodes);
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitMemberPredicate(this);
}
public Expr getPred() {
assert children != null;
return (Expr) children.get(0);
}
public @Nullable Expr getExpr() {
assert children != null;
return (Expr) children.get(1);
}
@SuppressWarnings("unchecked")
public List<ObjectBody> getBodyList() {
assert children != null;
return (List<ObjectBody>) children.subList(2, children.size());
}
}
public static final class ObjectEntry extends ObjectMember {
public ObjectEntry(List<Node> nodes, Span span) {
super(span, nodes);
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitObjectEntry(this);
}
public Expr getKey() {
assert children != null;
return (Expr) children.get(0);
}
public @Nullable Expr getValue() {
assert children != null;
return (Expr) children.get(1);
}
@SuppressWarnings("unchecked")
public List<ObjectBody> getBodyList() {
assert children != null;
return (List<ObjectBody>) children.subList(2, children.size());
}
}
public static final class ObjectSpread extends ObjectMember {
private final boolean isNullable;
public ObjectSpread(Expr expr, boolean isNullable, Span span) {
super(span, List.of(expr));
this.isNullable = isNullable;
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitObjectSpread(this);
}
public Expr getExpr() {
assert children != null;
return (Expr) children.get(0);
}
public boolean isNullable() {
return isNullable;
}
@Override
public String toString() {
return "ObjectSpread{"
+ "isNullable="
+ isNullable
+ ", span="
+ span
+ ", children="
+ children
+ '}';
}
@SuppressWarnings("ConstantValue")
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
if (!super.equals(o)) {
return false;
}
ObjectSpread that = (ObjectSpread) o;
return isNullable == that.isNullable;
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), isNullable);
}
}
public static final class WhenGenerator extends ObjectMember {
public WhenGenerator(
Expr predicate, ObjectBody thenClause, @Nullable ObjectBody elseClause, Span span) {
super(span, Arrays.asList(predicate, thenClause, elseClause));
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitWhenGenerator(this);
}
public Expr getPredicate() {
assert children != null;
return (Expr) children.get(0);
}
public ObjectBody getThenClause() {
assert children != null;
return (ObjectBody) children.get(1);
}
public @Nullable ObjectBody getElseClause() {
assert children != null;
return (ObjectBody) children.get(2);
}
}
public static final class ForGenerator extends ObjectMember {
public ForGenerator(
Parameter p1, @Nullable Parameter p2, Expr expr, ObjectBody body, Span span) {
super(span, Arrays.asList(p1, p2, expr, body));
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitForGenerator(this);
}
public Parameter getP1() {
assert children != null;
return (Parameter) children.get(0);
}
public @Nullable Parameter getP2() {
assert children != null;
return (Parameter) children.get(1);
}
public Expr getExpr() {
assert children != null;
return (Expr) children.get(2);
}
public ObjectBody getBody() {
assert children != null;
return (ObjectBody) children.get(3);
}
public Span forSpan() {
return new Span(span.charIndex(), 3);
}
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.syntax;
public enum Operator {
POW,
MULT,
DIV,
INT_DIV,
MOD,
PLUS,
MINUS,
LT,
GT,
LTE,
GTE,
IS,
AS,
EQ_EQ,
NOT_EQ,
AND,
OR,
PIPE,
NULL_COALESCE,
DOT,
QDOT,
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.syntax;
import java.util.Arrays;
import java.util.List;
import org.pkl.parser.ParserVisitor;
import org.pkl.parser.Span;
import org.pkl.parser.util.Nullable;
public abstract sealed class Parameter extends AbstractNode {
public Parameter(Span span, @Nullable List<? extends @Nullable Node> children) {
super(span, children);
}
@Override
public <T> @Nullable T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitParameter(this);
}
public static final class Underscore extends Parameter {
public Underscore(Span span) {
super(span, null);
}
}
public static final class TypedIdentifier extends Parameter {
public TypedIdentifier(
Identifier identifier, @Nullable TypeAnnotation typeAnnotation, Span span) {
super(span, Arrays.asList(identifier, typeAnnotation));
}
public Identifier getIdentifier() {
assert children != null;
return (Identifier) children.get(0);
}
public @Nullable TypeAnnotation getTypeAnnotation() {
assert children != null;
return (TypeAnnotation) children.get(1);
}
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.syntax;
import java.util.List;
import org.pkl.parser.ParserVisitor;
import org.pkl.parser.Span;
import org.pkl.parser.util.Nullable;
public class ParameterList extends AbstractNode {
public ParameterList(List<Parameter> parameters, Span span) {
super(span, parameters);
}
@Override
public <T> @Nullable T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitParameterList(this);
}
@SuppressWarnings("unchecked")
public List<Parameter> getParameters() {
assert children != null;
return (List<Parameter>) children;
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.syntax;
import java.util.List;
import java.util.stream.Collectors;
import org.pkl.parser.ParserVisitor;
public final class QualifiedIdentifier extends AbstractNode {
public QualifiedIdentifier(List<Identifier> identifiers) {
super(
identifiers.get(0).span.endWith(identifiers.get(identifiers.size() - 1).span), identifiers);
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitQualifiedIdentifier(this);
}
@SuppressWarnings("unchecked")
public List<Identifier> getIdentifiers() {
assert children != null;
return (List<Identifier>) children;
}
public String text() {
return getIdentifiers().stream().map(Identifier::getValue).collect(Collectors.joining("."));
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.syntax;
import java.util.List;
import org.pkl.parser.ParserVisitor;
import org.pkl.parser.Span;
import org.pkl.parser.util.Nullable;
public class ReplInput extends AbstractNode {
public ReplInput(List<Node> nodes, Span span) {
super(span, nodes);
}
@Override
public <T> @Nullable T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitReplInput(this);
}
@SuppressWarnings("unchecked")
public List<Node> getNodes() {
assert children != null;
return (List<Node>) children;
}
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.syntax;
import java.util.Objects;
import org.pkl.parser.ParserVisitor;
import org.pkl.parser.Span;
import org.pkl.parser.util.Nullable;
public class StringConstant extends AbstractNode {
private final String string;
public StringConstant(String string, Span span) {
super(span, null);
this.string = string;
}
@Override
public <T> @Nullable T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitStringConstant(this);
}
public String getString() {
return string;
}
@Override
public String toString() {
return "StringConstant{string='" + string + '\'' + ", span=" + span + '}';
}
@SuppressWarnings("ConstantValue")
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
if (!super.equals(o)) {
return false;
}
StringConstant that = (StringConstant) o;
return Objects.equals(string, that.string);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), string);
}
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.syntax;
import java.util.List;
import java.util.Objects;
import org.pkl.parser.ParserVisitor;
import org.pkl.parser.Span;
import org.pkl.parser.util.Nullable;
public abstract sealed class StringPart extends AbstractNode {
public StringPart(Span span, @Nullable List<? extends @Nullable Node> children) {
super(span, children);
}
@Override
public <T> @Nullable T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitStringPart(this);
}
public static final class StringChars extends StringPart {
private final String string;
public StringChars(String string, Span span) {
super(span, null);
this.string = string;
}
public String getString() {
return string;
}
@Override
public String toString() {
return "StringChars{string='" + string + '\'' + ", span=" + span + '}';
}
@SuppressWarnings("ConstantValue")
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
if (!super.equals(o)) {
return false;
}
StringChars that = (StringChars) o;
return Objects.equals(string, that.string);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), string);
}
}
public static final class StringInterpolation extends StringPart {
public StringInterpolation(Expr expr, Span span) {
super(span, List.of(expr));
}
public Expr getExpr() {
assert children != null;
return (Expr) children.get(0);
}
}
}

View File

@@ -0,0 +1,233 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.syntax;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import org.pkl.parser.ParserVisitor;
import org.pkl.parser.Span;
import org.pkl.parser.util.Nullable;
public abstract sealed class Type extends AbstractNode {
public Type(Span span, @Nullable List<? extends @Nullable Node> children) {
super(span, children);
}
public static final class UnknownType extends Type {
public UnknownType(Span span) {
super(span, null);
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitUnknownType(this);
}
}
public static final class NothingType extends Type {
public NothingType(Span span) {
super(span, null);
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitNothingType(this);
}
}
public static final class ModuleType extends Type {
public ModuleType(Span span) {
super(span, null);
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitModuleType(this);
}
}
public static final class StringConstantType extends Type {
public StringConstantType(StringConstant str, Span span) {
super(span, List.of(str));
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitStringConstantType(this);
}
public StringConstant getStr() {
assert children != null;
return (StringConstant) children.get(0);
}
}
public static final class DeclaredType extends Type {
public DeclaredType(QualifiedIdentifier name, @Nullable TypeArgumentList typeArgs, Span span) {
super(span, Arrays.asList(name, typeArgs));
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitDeclaredType(this);
}
public QualifiedIdentifier getName() {
assert children != null;
return (QualifiedIdentifier) children.get(0);
}
public @Nullable TypeArgumentList getArgs() {
assert children != null;
return (TypeArgumentList) children.get(1);
}
}
public static final class ParenthesizedType extends Type {
public ParenthesizedType(Type type, Span span) {
super(span, List.of(type));
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitParenthesizedType(this);
}
public Type getType() {
assert children != null;
return (Type) children.get(0);
}
}
public static final class NullableType extends Type {
public NullableType(Type type, Span span) {
super(span, List.of(type));
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitNullableType(this);
}
public Type getType() {
assert children != null;
return (Type) children.get(0);
}
}
public static final class ConstrainedType extends Type {
public ConstrainedType(List<Node> nodes, Span span) {
super(span, nodes);
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitConstrainedType(this);
}
public Type getType() {
assert children != null;
return (Type) children.get(0);
}
@SuppressWarnings("unchecked")
public List<Expr> getExprs() {
assert children != null;
return (List<Expr>) children.subList(1, children.size());
}
}
public static final class UnionType extends Type {
private final int defaultIndex;
public UnionType(List<Type> types, int defaultIndex, Span span) {
super(span, types);
this.defaultIndex = defaultIndex;
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitUnionType(this);
}
@SuppressWarnings("unchecked")
public List<Type> getTypes() {
assert children != null;
return (List<Type>) children;
}
public int getDefaultIndex() {
return defaultIndex;
}
@Override
public String toString() {
return "UnionType{"
+ "defaultIndex="
+ defaultIndex
+ ", span="
+ span
+ ", children="
+ children
+ '}';
}
@SuppressWarnings("ConstantValue")
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
if (!super.equals(o)) {
return false;
}
UnionType unionType = (UnionType) o;
return defaultIndex == unionType.defaultIndex;
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), defaultIndex);
}
}
public static final class FunctionType extends Type {
public FunctionType(List<Node> children, Span span) {
super(span, children);
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitFunctionType(this);
}
@SuppressWarnings("unchecked")
public List<Type> getArgs() {
assert children != null;
return (List<Type>) children.subList(0, children.size() - 1);
}
public Type getRet() {
assert children != null;
return (Type) children.get(children.size() - 1);
}
}
}

View File

@@ -0,0 +1,94 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.syntax;
import java.util.List;
import org.pkl.parser.ParserVisitor;
import org.pkl.parser.Span;
import org.pkl.parser.util.Nullable;
public final class TypeAlias extends AbstractNode {
private final int modifiersOffset;
private final int nameOffset;
public TypeAlias(List<Node> children, int modifiersOffset, int nameOffset, Span span) {
super(span, children);
this.modifiersOffset = modifiersOffset;
this.nameOffset = nameOffset;
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitTypeAlias(this);
}
public @Nullable DocComment getDocComment() {
assert children != null;
return (DocComment) children.get(0);
}
@SuppressWarnings("unchecked")
public List<Annotation> getAnnotations() {
assert children != null;
return (List<Annotation>) children.subList(1, modifiersOffset);
}
@SuppressWarnings("unchecked")
public List<Modifier> getModifiers() {
assert children != null;
return (List<Modifier>) children.subList(modifiersOffset, nameOffset);
}
public Keyword getTypealiasKeyword() {
assert children != null;
return (Keyword) children.get(nameOffset);
}
public Identifier getName() {
assert children != null;
return (Identifier) children.get(nameOffset + 1);
}
public @Nullable TypeParameterList getTypeParameterList() {
assert children != null;
return (TypeParameterList) children.get(nameOffset + 2);
}
public Type getType() {
assert children != null;
return (Type) children.get(nameOffset + 3);
}
@SuppressWarnings("DuplicatedCode")
public Span getHeaderSpan() {
Span start = null;
assert children != null;
for (var i = modifiersOffset; i < children.size(); i++) {
var child = children.get(i);
if (child != null) {
start = child.span();
break;
}
}
var end = children.get(nameOffset + 1).span();
var tparList = children.get(nameOffset + 2);
if (tparList != null) {
end = tparList.span();
}
assert start != null;
return start.endWith(end);
}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.syntax;
import java.util.List;
import org.pkl.parser.ParserVisitor;
import org.pkl.parser.Span;
import org.pkl.parser.util.Nullable;
public class TypeAnnotation extends AbstractNode {
public TypeAnnotation(Type type, Span span) {
super(span, List.of(type));
}
@Override
public <T> @Nullable T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitTypeAnnotation(this);
}
public Type getType() {
assert children != null;
return (Type) children.get(0);
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.syntax;
import java.util.List;
import org.pkl.parser.ParserVisitor;
import org.pkl.parser.Span;
public class TypeArgumentList extends AbstractNode {
public TypeArgumentList(List<Type> children, Span span) {
super(span, children);
}
@SuppressWarnings("unchecked")
public List<Type> getTypes() {
assert children != null;
return (List<Type>) children;
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitTypeArgumentList(this);
}
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.syntax;
import java.util.List;
import java.util.Objects;
import org.pkl.parser.ParserVisitor;
import org.pkl.parser.Span;
import org.pkl.parser.util.Nullable;
public final class TypeParameter extends AbstractNode {
private final @Nullable Variance variance;
public TypeParameter(@Nullable Variance variance, Identifier identifier, Span span) {
super(span, List.of(identifier));
this.variance = variance;
}
@Override
public <T> T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitTypeParameter(this);
}
public @Nullable Variance getVariance() {
return variance;
}
public Identifier getIdentifier() {
assert children != null;
return (Identifier) children.get(0);
}
@Override
public String toString() {
return "TypeParameter{"
+ "variance="
+ variance
+ ", children="
+ children
+ ", span="
+ span
+ '}';
}
@SuppressWarnings("ConstantValue")
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
if (!super.equals(o)) {
return false;
}
TypeParameter that = (TypeParameter) o;
return variance == that.variance;
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), variance);
}
public enum Variance {
IN,
OUT
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.syntax;
import java.util.List;
import org.pkl.parser.ParserVisitor;
import org.pkl.parser.Span;
import org.pkl.parser.util.Nullable;
public class TypeParameterList extends AbstractNode {
public TypeParameterList(List<TypeParameter> parameters, Span span) {
super(span, parameters);
}
@Override
public <T> @Nullable T accept(ParserVisitor<? extends T> visitor) {
return visitor.visitTypeParameterList(this);
}
@SuppressWarnings("unchecked")
public List<TypeParameter> getParameters() {
assert children != null;
return (List<TypeParameter>) children;
}
}

View File

@@ -0,0 +1,4 @@
@NonnullByDefault
package org.pkl.parser.syntax;
import org.pkl.parser.util.NonnullByDefault;

View File

@@ -0,0 +1,36 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.util;
import java.text.MessageFormat;
import java.util.Locale;
import java.util.ResourceBundle;
public final class ErrorMessages {
private ErrorMessages() {}
public static String create(String messageName, Object... args) {
var locale = Locale.getDefault();
var errorMessage =
ResourceBundle.getBundle("org.pkl.parser.errorMessages", locale).getString(messageName);
// only format if `errorMessage` is a format string
if (args.length == 0) return errorMessage;
var formatter = new MessageFormat(errorMessage, locale);
return formatter.format(args);
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.util;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.annotation.meta.TypeQualifierDefault;
/**
* Indicates that method return types and method parameters in the annotated package are Nonnull
* unless explicitly annotated with {@link Nullable}.
*
* <p>This annotation is a generalization of {@link javax.annotation.ParametersAreNonnullByDefault}.
* All Pkl packages containing Java code should carry this annotation.
*
* <p>Ideally, this default would apply to every {@link ElementType#TYPE_USE}, but I haven't been
* able to make this work reasonably in <a
* href="https://youtrack.jetbrains.com/issue/IDEA-278618">IntelliJ</a>.
*/
@Documented
@TypeQualifierDefault({ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE_PARAMETER})
@javax.annotation.Nonnull
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PACKAGE)
public @interface NonnullByDefault {}

View File

@@ -0,0 +1,38 @@
/*
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.parser.util;
import static javax.annotation.meta.When.MAYBE;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.annotation.meta.TypeQualifierNickname;
@Target({
ElementType.TYPE_PARAMETER,
ElementType.TYPE_USE,
ElementType.PARAMETER,
ElementType.FIELD,
ElementType.METHOD
})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@javax.annotation.Nonnull(when = MAYBE)
@TypeQualifierNickname
public @interface Nullable {}

View File

@@ -0,0 +1,97 @@
unexpectedCharacter=\
Unexpected character `{0}`. Did you mean `{1}`?
unexpectedCharacter3=\
Unexpected character `{0}`. Did you mean `{1}`, `{2}` or `{3}`?
unexpectedToken=\
Unexpected token `{0}`. Expected `{1}`.
unexpectedToken2=\
Unexpected token `{0}`. Expected `{1}` or `{2}`.
unexpectedTokenForExpression=\
Unexpected token `{0}`.
unexpectedTokenForType=\
Unexpected token `{0}`. Expected a type.
unexpectedTokenForType2=\
Unexpected token `{0}`. Expected a type or `{1}`.
unexpectedCurlyProbablyAmendsExpression=\
Unexpected token: `'{'`.\n\
\n\
If you meant to write an amends expression, wrap the parent in parentheses. Try: `({0}) '{' ... '}'`
unexpectedEndOfFile=\
Unexpected end of file.
invalidCharacter=\
Invalid identifier `{0}`.
invalidTopLevelToken=\
Invalid token at position. Expected a class, typealias, method, or property.
invalidProperty=\
Invalid property definition. Expected a type annotation, `=` or `{`.
invalidSeparatorPosition=\
Unexpected separator character.\n\
\n\
The separator character (`_`) cannot follow `0x`, `0b`, `.`, `e`, or 'E' in a number literal.
invalidCharacterEscapeSequence=\
Invalid character escape sequence `{0}`.\n\
\n\
Valid character escape sequences are: {1}n {1}r {1}t {1}" {1}\\
invalidUnicodeEscapeSequence=\
Invalid Unicode escape sequence `{0}`.\n\
\n\
Valid Unicode escape sequences are {1}'{'0'}' to {1}'{'10FFFF'}' (1-6 hexadecimal characters).
missingDelimiter=\
Missing `{0}` delimiter.
unterminatedUnicodeEscapeSequence=\
Unterminated Unicode escape sequence `{0}`.\n\
\n\
Unicode escape sequences must end with `}`.
keywordNotAllowedHere=\
Keyword `{0}` is not allowed here.\n\
\n\
If you must use this name as identifier, enclose it in backticks.
typeAnnotationInAmends=\
Properties with type annotations cannot have object bodies.\n\
\n\
To define both a type annotation and an object body, try using assignment instead.\n\
For example: `obj: Bird = new { ... }`.
stringContentMustBeginOnNewLine=\
The content of a multi-line string must begin on a new line.
stringIndentationMustMatchLastLine=\
Line must match or exceed indentation of the String's last line.
closingStringDelimiterMustBeginOnNewLine=\
The closing delimiter of a multi-line string must begin on a new line.
interpolationInConstant=\
String constant cannot have interpolated values.
multipleUnionDefaults=\
A type union cannot have more than one default type.
notAUnion=\
Only type unions can have a default marker (*).
wrongHeaders=\
{0} cannot have doc comments, annotations or modifiers.
danglingDocComment=\
Dangling documentation comment.\n\
\n\
Documentation comments must be attached to modules, classes, typealiases, methods, or properties.