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

@@ -3,13 +3,7 @@
# This file is expected to be part of source control.
com.google.code.findbugs:jsr305:3.0.2=compileClasspath,compileOnlyDependenciesMetadata
com.palantir.javapoet:javapoet:0.6.0=generatorCompileClasspath,generatorImplementationDependenciesMetadata,generatorRuntimeClasspath
com.tunnelvisionlabs:antlr4-annotations:4.9.0=antlr
com.tunnelvisionlabs:antlr4-runtime:4.9.0=antlr,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
com.tunnelvisionlabs:antlr4:4.9.0=antlr
net.bytebuddy:byte-buddy:1.15.11=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.abego.treelayout:org.abego.treelayout.core:1.0.1=antlr
org.antlr:ST4:4.3=antlr
org.antlr:antlr-runtime:3.5.2=antlr
org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath,testImplementationDependenciesMetadata,testJdk17CompileClasspath,testJdk17ImplementationDependenciesMetadata,testRuntimeOnlyDependenciesMetadata
org.assertj:assertj-core:3.27.3=testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath
org.graalvm.polyglot:polyglot:24.1.2=compileClasspath,generatorCompileClasspath,generatorImplementationDependenciesMetadata,generatorRuntimeClasspath,implementationDependenciesMetadata,runtimeClasspath,testCompileClasspath,testImplementationDependenciesMetadata,testRuntimeClasspath

View File

@@ -21,42 +21,30 @@ plugins {
pklJavaLibrary
pklPublishLibrary
pklNativeBuild
antlr
idea
}
val generatorSourceSet = sourceSets.register("generator")
sourceSets { test { java { srcDir(file("testgenerated/antlr")) } } }
idea {
module {
// mark src/test/antlr as source dir
// mark generated/antlr as generated source dir
// mark generated/truffle as generated source dir
sourceDirs = sourceDirs + files("generated/truffle")
generatedSourceDirs = generatedSourceDirs + files("testgenerated/antlr", "generated/truffle")
testSources.from(files("src/test/antlr", "testgenerated/antlr"))
generatedSourceDirs = generatedSourceDirs + files("generated/truffle")
}
}
val javaExecutableConfiguration: Configuration = configurations.create("javaExecutable")
// workaround for https://github.com/gradle/gradle/issues/820
configurations.api.get().let { apiConfig ->
apiConfig.setExtendsFrom(apiConfig.extendsFrom.filter { it.name != "antlr" })
}
dependencies {
annotationProcessor(libs.truffleDslProcessor)
annotationProcessor(generatorSourceSet.get().runtimeClasspath)
antlr(libs.antlr)
compileOnly(libs.jsr305)
// pkl-core implements pkl-executor's ExecutorSpi, but the SPI doesn't ship with pkl-core
compileOnly(projects.pklExecutor)
implementation(projects.pklParser)
implementation(libs.msgpack)
implementation(libs.truffleApi)
implementation(libs.graalSdk)
@@ -65,7 +53,6 @@ dependencies {
implementation(libs.snakeYaml)
testImplementation(libs.antlrRuntime)
testImplementation(projects.pklCommonsTest)
add("generatorImplementation", libs.javaPoet)
@@ -93,35 +80,6 @@ publishing {
}
}
tasks.generateTestGrammarSource {
maxHeapSize = "64m"
// generate only visitor
arguments = arguments + listOf("-visitor", "-no-listener")
// Due to https://github.com/antlr/antlr4/issues/2260,
// we can't put .g4 files into src/test/antlr/org/pkl/core/parser/antlr.
// Instead, we put .g4 files into src/test/antlr, adapt output dir below,
// and use @header directives in .g4 files (instead of setting `-package` argument here)
// and task makeIntelliJAntlrPluginHappy to fix up the IDE story.
outputDirectory = file("testgenerated/antlr/org/pkl/core/parser/antlr")
}
tasks.generateGrammarSource { enabled = false }
tasks.named("generateGeneratorGrammarSource") { enabled = false }
tasks.compileTestKotlin { dependsOn(tasks.generateTestGrammarSource) }
// Satisfy expectations of IntelliJ ANTLR plugin,
// which can't otherwise cope with our ANTLR setup.
val makeIntelliJAntlrPluginHappy by
tasks.registering(Copy::class) {
dependsOn(tasks.generateGrammarSource)
into("test/antlr")
from("testgenerated/antlr/org/pkl/core/parser/antlr") { include("PklLexer.tokens") }
}
tasks.processResources {
inputs.property("version", buildInfo.pklVersion)
inputs.property("commitId", buildInfo.commitId)
@@ -245,13 +203,6 @@ tasks.clean {
delete(layout.buildDirectory.dir("test-packages"))
}
spotless {
antlr4 {
licenseHeaderFile(rootProject.file("buildSrc/src/main/resources/license-header.star-block.txt"))
target(files("src/test/antlr/PklParser.g4", "src/test/antlr/PklLexer.g4"))
}
}
private fun Test.configureTest() {
inputs
.dir("src/test/files/LanguageSnippetTests/input")

View File

@@ -19,7 +19,7 @@ import java.io.IOException;
import java.io.Writer;
import java.util.*;
import java.util.regex.Pattern;
import org.pkl.core.parser.Lexer;
import org.pkl.parser.Lexer;
// To instantiate this class, use ValueRenderers.pcf().
final class PcfRenderer implements ValueRenderer {

View File

@@ -18,14 +18,14 @@ package org.pkl.core.ast.builder;
import com.oracle.truffle.api.source.Source;
import com.oracle.truffle.api.source.SourceSection;
import java.util.List;
import org.pkl.core.parser.BaseParserVisitor;
import org.pkl.core.parser.Span;
import org.pkl.core.parser.syntax.DocComment;
import org.pkl.core.parser.syntax.Modifier;
import org.pkl.core.parser.syntax.Modifier.ModifierValue;
import org.pkl.core.parser.syntax.Node;
import org.pkl.core.runtime.VmExceptionBuilder;
import org.pkl.core.util.Nullable;
import org.pkl.parser.BaseParserVisitor;
import org.pkl.parser.Span;
import org.pkl.parser.syntax.DocComment;
import org.pkl.parser.syntax.Modifier;
import org.pkl.parser.syntax.Modifier.ModifierValue;
import org.pkl.parser.syntax.Node;
public abstract class AbstractAstBuilder<T> extends BaseParserVisitor<T> {

View File

@@ -157,81 +157,6 @@ import org.pkl.core.module.ModuleKey;
import org.pkl.core.module.ModuleKeys;
import org.pkl.core.module.ResolvedModuleKey;
import org.pkl.core.packages.PackageLoadError;
import org.pkl.core.parser.Span;
import org.pkl.core.parser.syntax.Annotation;
import org.pkl.core.parser.syntax.ArgumentList;
import org.pkl.core.parser.syntax.Class;
import org.pkl.core.parser.syntax.ClassMethod;
import org.pkl.core.parser.syntax.ClassProperty;
import org.pkl.core.parser.syntax.Expr;
import org.pkl.core.parser.syntax.Expr.AmendsExpr;
import org.pkl.core.parser.syntax.Expr.BinaryOperatorExpr;
import org.pkl.core.parser.syntax.Expr.BoolLiteralExpr;
import org.pkl.core.parser.syntax.Expr.FloatLiteralExpr;
import org.pkl.core.parser.syntax.Expr.FunctionLiteralExpr;
import org.pkl.core.parser.syntax.Expr.IfExpr;
import org.pkl.core.parser.syntax.Expr.ImportExpr;
import org.pkl.core.parser.syntax.Expr.IntLiteralExpr;
import org.pkl.core.parser.syntax.Expr.LetExpr;
import org.pkl.core.parser.syntax.Expr.LogicalNotExpr;
import org.pkl.core.parser.syntax.Expr.ModuleExpr;
import org.pkl.core.parser.syntax.Expr.MultiLineStringLiteralExpr;
import org.pkl.core.parser.syntax.Expr.NewExpr;
import org.pkl.core.parser.syntax.Expr.NonNullExpr;
import org.pkl.core.parser.syntax.Expr.NullLiteralExpr;
import org.pkl.core.parser.syntax.Expr.OuterExpr;
import org.pkl.core.parser.syntax.Expr.ParenthesizedExpr;
import org.pkl.core.parser.syntax.Expr.QualifiedAccessExpr;
import org.pkl.core.parser.syntax.Expr.ReadExpr;
import org.pkl.core.parser.syntax.Expr.SingleLineStringLiteralExpr;
import org.pkl.core.parser.syntax.Expr.SubscriptExpr;
import org.pkl.core.parser.syntax.Expr.SuperAccessExpr;
import org.pkl.core.parser.syntax.Expr.SuperSubscriptExpr;
import org.pkl.core.parser.syntax.Expr.ThisExpr;
import org.pkl.core.parser.syntax.Expr.ThrowExpr;
import org.pkl.core.parser.syntax.Expr.TraceExpr;
import org.pkl.core.parser.syntax.Expr.TypeCastExpr;
import org.pkl.core.parser.syntax.Expr.TypeCheckExpr;
import org.pkl.core.parser.syntax.Expr.UnaryMinusExpr;
import org.pkl.core.parser.syntax.Expr.UnqualifiedAccessExpr;
import org.pkl.core.parser.syntax.ExtendsOrAmendsClause;
import org.pkl.core.parser.syntax.Identifier;
import org.pkl.core.parser.syntax.ImportClause;
import org.pkl.core.parser.syntax.Modifier;
import org.pkl.core.parser.syntax.Modifier.ModifierValue;
import org.pkl.core.parser.syntax.Module;
import org.pkl.core.parser.syntax.Node;
import org.pkl.core.parser.syntax.ObjectBody;
import org.pkl.core.parser.syntax.ObjectMember.ForGenerator;
import org.pkl.core.parser.syntax.ObjectMember.MemberPredicate;
import org.pkl.core.parser.syntax.ObjectMember.ObjectElement;
import org.pkl.core.parser.syntax.ObjectMember.ObjectEntry;
import org.pkl.core.parser.syntax.ObjectMember.ObjectMethod;
import org.pkl.core.parser.syntax.ObjectMember.ObjectProperty;
import org.pkl.core.parser.syntax.ObjectMember.ObjectSpread;
import org.pkl.core.parser.syntax.ObjectMember.WhenGenerator;
import org.pkl.core.parser.syntax.Parameter;
import org.pkl.core.parser.syntax.Parameter.TypedIdentifier;
import org.pkl.core.parser.syntax.ParameterList;
import org.pkl.core.parser.syntax.QualifiedIdentifier;
import org.pkl.core.parser.syntax.StringConstant;
import org.pkl.core.parser.syntax.StringPart;
import org.pkl.core.parser.syntax.StringPart.StringChars;
import org.pkl.core.parser.syntax.StringPart.StringInterpolation;
import org.pkl.core.parser.syntax.Type;
import org.pkl.core.parser.syntax.Type.ConstrainedType;
import org.pkl.core.parser.syntax.Type.DeclaredType;
import org.pkl.core.parser.syntax.Type.FunctionType;
import org.pkl.core.parser.syntax.Type.ModuleType;
import org.pkl.core.parser.syntax.Type.NothingType;
import org.pkl.core.parser.syntax.Type.NullableType;
import org.pkl.core.parser.syntax.Type.ParenthesizedType;
import org.pkl.core.parser.syntax.Type.StringConstantType;
import org.pkl.core.parser.syntax.Type.UnionType;
import org.pkl.core.parser.syntax.Type.UnknownType;
import org.pkl.core.parser.syntax.TypeAlias;
import org.pkl.core.parser.syntax.TypeAnnotation;
import org.pkl.core.parser.syntax.TypeParameterList;
import org.pkl.core.runtime.BaseModule;
import org.pkl.core.runtime.ModuleInfo;
import org.pkl.core.runtime.ModuleResolver;
@@ -256,6 +181,81 @@ import org.pkl.core.util.EconomicMaps;
import org.pkl.core.util.IoUtils;
import org.pkl.core.util.Nullable;
import org.pkl.core.util.Pair;
import org.pkl.parser.Span;
import org.pkl.parser.syntax.Annotation;
import org.pkl.parser.syntax.ArgumentList;
import org.pkl.parser.syntax.Class;
import org.pkl.parser.syntax.ClassMethod;
import org.pkl.parser.syntax.ClassProperty;
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.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.Modifier;
import org.pkl.parser.syntax.Modifier.ModifierValue;
import org.pkl.parser.syntax.Module;
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.Parameter.TypedIdentifier;
import org.pkl.parser.syntax.ParameterList;
import org.pkl.parser.syntax.QualifiedIdentifier;
import org.pkl.parser.syntax.StringConstant;
import org.pkl.parser.syntax.StringPart;
import org.pkl.parser.syntax.StringPart.StringChars;
import org.pkl.parser.syntax.StringPart.StringInterpolation;
import org.pkl.parser.syntax.Type;
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.TypeParameterList;
public class AstBuilder extends AbstractAstBuilder<Object> {
private final VmLanguage language;
@@ -1097,7 +1097,7 @@ public class AstBuilder extends AbstractAstBuilder<Object> {
return Pair.of(elementNodes, isConstantNodes);
}
public GeneratorMemberNode visitObjectMember(org.pkl.core.parser.syntax.ObjectMember member) {
public GeneratorMemberNode visitObjectMember(org.pkl.parser.syntax.ObjectMember member) {
return (GeneratorMemberNode) member.accept(this);
}
@@ -2375,7 +2375,7 @@ public class AstBuilder extends AbstractAstBuilder<Object> {
}
private GeneratorMemberNode[] doVisitGeneratorMemberNodes(
List<? extends org.pkl.core.parser.syntax.ObjectMember> members) {
List<? extends org.pkl.parser.syntax.ObjectMember> members) {
var result = new GeneratorMemberNode[members.size()];
for (var i = 0; i < result.length; i++) {
result[i] = visitObjectMember(members.get(i));
@@ -2666,7 +2666,7 @@ public class AstBuilder extends AbstractAstBuilder<Object> {
}
var forExprCtx = ctx.parent();
while (forExprCtx != null
&& forExprCtx.getClass() != org.pkl.core.parser.syntax.ObjectMember.ForGenerator.class) {
&& forExprCtx.getClass() != org.pkl.parser.syntax.ObjectMember.ForGenerator.class) {
forExprCtx = forExprCtx.parent();
}
assert forExprCtx != null;
@@ -2674,7 +2674,7 @@ public class AstBuilder extends AbstractAstBuilder<Object> {
.evalError(errorMessageKey)
.withSourceSection(
createSourceSection(
((org.pkl.core.parser.syntax.ObjectMember.ForGenerator) forExprCtx).forSpan()))
((org.pkl.parser.syntax.ObjectMember.ForGenerator) forExprCtx).forSpan()))
.build();
}

View File

@@ -24,21 +24,21 @@ import java.util.List;
import org.pkl.core.ast.builder.ImportsAndReadsParser.Entry;
import org.pkl.core.module.ModuleKey;
import org.pkl.core.module.ResolvedModuleKey;
import org.pkl.core.parser.Parser;
import org.pkl.core.parser.ParserError;
import org.pkl.core.parser.syntax.Expr;
import org.pkl.core.parser.syntax.Expr.ImportExpr;
import org.pkl.core.parser.syntax.Expr.ReadExpr;
import org.pkl.core.parser.syntax.Expr.ReadType;
import org.pkl.core.parser.syntax.Expr.SingleLineStringLiteralExpr;
import org.pkl.core.parser.syntax.ExtendsOrAmendsClause;
import org.pkl.core.parser.syntax.ExtendsOrAmendsClause.Type;
import org.pkl.core.parser.syntax.ImportClause;
import org.pkl.core.parser.syntax.StringPart.StringChars;
import org.pkl.core.runtime.VmExceptionBuilder;
import org.pkl.core.runtime.VmUtils;
import org.pkl.core.util.IoUtils;
import org.pkl.core.util.Nullable;
import org.pkl.parser.Parser;
import org.pkl.parser.ParserError;
import org.pkl.parser.syntax.Expr;
import org.pkl.parser.syntax.Expr.ImportExpr;
import org.pkl.parser.syntax.Expr.ReadExpr;
import org.pkl.parser.syntax.Expr.ReadType;
import org.pkl.parser.syntax.Expr.SingleLineStringLiteralExpr;
import org.pkl.parser.syntax.ExtendsOrAmendsClause;
import org.pkl.parser.syntax.ExtendsOrAmendsClause.Type;
import org.pkl.parser.syntax.ImportClause;
import org.pkl.parser.syntax.StringPart.StringChars;
/**
* Collects module uris and resource uris imported within a module.

View File

@@ -24,12 +24,12 @@ import org.pkl.core.ast.ConstantNode;
import org.pkl.core.ast.ExpressionNode;
import org.pkl.core.ast.expression.generator.GeneratorMemberNode;
import org.pkl.core.ast.member.ObjectMember;
import org.pkl.core.parser.Lexer;
import org.pkl.core.runtime.Identifier;
import org.pkl.core.runtime.ModuleInfo;
import org.pkl.core.runtime.VmDataSize;
import org.pkl.core.runtime.VmDuration;
import org.pkl.core.util.Nullable;
import org.pkl.parser.Lexer;
public final class SymbolTable {
private Scope currentScope;

View File

@@ -1,482 +0,0 @@
/*
* 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.core.parser;
import org.pkl.core.parser.syntax.Annotation;
import org.pkl.core.parser.syntax.ArgumentList;
import org.pkl.core.parser.syntax.Class;
import org.pkl.core.parser.syntax.ClassBody;
import org.pkl.core.parser.syntax.ClassMethod;
import org.pkl.core.parser.syntax.ClassProperty;
import org.pkl.core.parser.syntax.DocComment;
import org.pkl.core.parser.syntax.Expr.AmendsExpr;
import org.pkl.core.parser.syntax.Expr.BinaryOperatorExpr;
import org.pkl.core.parser.syntax.Expr.BoolLiteralExpr;
import org.pkl.core.parser.syntax.Expr.FloatLiteralExpr;
import org.pkl.core.parser.syntax.Expr.FunctionLiteralExpr;
import org.pkl.core.parser.syntax.Expr.IfExpr;
import org.pkl.core.parser.syntax.Expr.ImportExpr;
import org.pkl.core.parser.syntax.Expr.IntLiteralExpr;
import org.pkl.core.parser.syntax.Expr.LetExpr;
import org.pkl.core.parser.syntax.Expr.LogicalNotExpr;
import org.pkl.core.parser.syntax.Expr.ModuleExpr;
import org.pkl.core.parser.syntax.Expr.MultiLineStringLiteralExpr;
import org.pkl.core.parser.syntax.Expr.NewExpr;
import org.pkl.core.parser.syntax.Expr.NonNullExpr;
import org.pkl.core.parser.syntax.Expr.NullLiteralExpr;
import org.pkl.core.parser.syntax.Expr.OuterExpr;
import org.pkl.core.parser.syntax.Expr.ParenthesizedExpr;
import org.pkl.core.parser.syntax.Expr.QualifiedAccessExpr;
import org.pkl.core.parser.syntax.Expr.ReadExpr;
import org.pkl.core.parser.syntax.Expr.SingleLineStringLiteralExpr;
import org.pkl.core.parser.syntax.Expr.SubscriptExpr;
import org.pkl.core.parser.syntax.Expr.SuperAccessExpr;
import org.pkl.core.parser.syntax.Expr.SuperSubscriptExpr;
import org.pkl.core.parser.syntax.Expr.ThisExpr;
import org.pkl.core.parser.syntax.Expr.ThrowExpr;
import org.pkl.core.parser.syntax.Expr.TraceExpr;
import org.pkl.core.parser.syntax.Expr.TypeCastExpr;
import org.pkl.core.parser.syntax.Expr.TypeCheckExpr;
import org.pkl.core.parser.syntax.Expr.UnaryMinusExpr;
import org.pkl.core.parser.syntax.Expr.UnqualifiedAccessExpr;
import org.pkl.core.parser.syntax.ExtendsOrAmendsClause;
import org.pkl.core.parser.syntax.Identifier;
import org.pkl.core.parser.syntax.ImportClause;
import org.pkl.core.parser.syntax.Keyword;
import org.pkl.core.parser.syntax.Modifier;
import org.pkl.core.parser.syntax.ModuleDecl;
import org.pkl.core.parser.syntax.Node;
import org.pkl.core.parser.syntax.ObjectBody;
import org.pkl.core.parser.syntax.ObjectMember.ForGenerator;
import org.pkl.core.parser.syntax.ObjectMember.MemberPredicate;
import org.pkl.core.parser.syntax.ObjectMember.ObjectElement;
import org.pkl.core.parser.syntax.ObjectMember.ObjectEntry;
import org.pkl.core.parser.syntax.ObjectMember.ObjectMethod;
import org.pkl.core.parser.syntax.ObjectMember.ObjectProperty;
import org.pkl.core.parser.syntax.ObjectMember.ObjectSpread;
import org.pkl.core.parser.syntax.ObjectMember.WhenGenerator;
import org.pkl.core.parser.syntax.Parameter;
import org.pkl.core.parser.syntax.ParameterList;
import org.pkl.core.parser.syntax.QualifiedIdentifier;
import org.pkl.core.parser.syntax.ReplInput;
import org.pkl.core.parser.syntax.StringConstant;
import org.pkl.core.parser.syntax.StringPart;
import org.pkl.core.parser.syntax.Type.ConstrainedType;
import org.pkl.core.parser.syntax.Type.DeclaredType;
import org.pkl.core.parser.syntax.Type.FunctionType;
import org.pkl.core.parser.syntax.Type.ModuleType;
import org.pkl.core.parser.syntax.Type.NothingType;
import org.pkl.core.parser.syntax.Type.NullableType;
import org.pkl.core.parser.syntax.Type.ParenthesizedType;
import org.pkl.core.parser.syntax.Type.StringConstantType;
import org.pkl.core.parser.syntax.Type.UnionType;
import org.pkl.core.parser.syntax.Type.UnknownType;
import org.pkl.core.parser.syntax.TypeAlias;
import org.pkl.core.parser.syntax.TypeAnnotation;
import org.pkl.core.parser.syntax.TypeArgumentList;
import org.pkl.core.parser.syntax.TypeParameter;
import org.pkl.core.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.core.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

@@ -1,818 +0,0 @@
/*
* 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.core.parser;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Deque;
import org.pkl.core.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

@@ -1,140 +0,0 @@
/*
* 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.core.parser;
import java.util.ArrayList;
import java.util.List;
import org.pkl.core.parser.syntax.Expr;
import org.pkl.core.parser.syntax.Expr.BinaryOperatorExpr;
import org.pkl.core.parser.syntax.Expr.OperatorExpr;
import org.pkl.core.parser.syntax.Expr.TypeCastExpr;
import org.pkl.core.parser.syntax.Expr.TypeCheckExpr;
import org.pkl.core.parser.syntax.Expr.TypeExpr;
import org.pkl.core.parser.syntax.Operator;
import org.pkl.core.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

@@ -1,41 +0,0 @@
/*
* 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.core.parser;
import org.pkl.core.parser.syntax.Module;
import org.pkl.core.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

@@ -1,226 +0,0 @@
/*
* 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.core.parser;
import org.pkl.core.parser.syntax.Annotation;
import org.pkl.core.parser.syntax.ArgumentList;
import org.pkl.core.parser.syntax.Class;
import org.pkl.core.parser.syntax.ClassBody;
import org.pkl.core.parser.syntax.ClassMethod;
import org.pkl.core.parser.syntax.ClassProperty;
import org.pkl.core.parser.syntax.DocComment;
import org.pkl.core.parser.syntax.Expr;
import org.pkl.core.parser.syntax.Expr.AmendsExpr;
import org.pkl.core.parser.syntax.Expr.BinaryOperatorExpr;
import org.pkl.core.parser.syntax.Expr.BoolLiteralExpr;
import org.pkl.core.parser.syntax.Expr.FloatLiteralExpr;
import org.pkl.core.parser.syntax.Expr.FunctionLiteralExpr;
import org.pkl.core.parser.syntax.Expr.IfExpr;
import org.pkl.core.parser.syntax.Expr.IntLiteralExpr;
import org.pkl.core.parser.syntax.Expr.LetExpr;
import org.pkl.core.parser.syntax.Expr.LogicalNotExpr;
import org.pkl.core.parser.syntax.Expr.ModuleExpr;
import org.pkl.core.parser.syntax.Expr.MultiLineStringLiteralExpr;
import org.pkl.core.parser.syntax.Expr.NewExpr;
import org.pkl.core.parser.syntax.Expr.NonNullExpr;
import org.pkl.core.parser.syntax.Expr.NullLiteralExpr;
import org.pkl.core.parser.syntax.Expr.OuterExpr;
import org.pkl.core.parser.syntax.Expr.ParenthesizedExpr;
import org.pkl.core.parser.syntax.Expr.QualifiedAccessExpr;
import org.pkl.core.parser.syntax.Expr.ReadExpr;
import org.pkl.core.parser.syntax.Expr.SingleLineStringLiteralExpr;
import org.pkl.core.parser.syntax.Expr.SubscriptExpr;
import org.pkl.core.parser.syntax.Expr.SuperAccessExpr;
import org.pkl.core.parser.syntax.Expr.SuperSubscriptExpr;
import org.pkl.core.parser.syntax.Expr.ThisExpr;
import org.pkl.core.parser.syntax.Expr.ThrowExpr;
import org.pkl.core.parser.syntax.Expr.TraceExpr;
import org.pkl.core.parser.syntax.Expr.TypeCastExpr;
import org.pkl.core.parser.syntax.Expr.TypeCheckExpr;
import org.pkl.core.parser.syntax.Expr.UnaryMinusExpr;
import org.pkl.core.parser.syntax.Expr.UnqualifiedAccessExpr;
import org.pkl.core.parser.syntax.ExtendsOrAmendsClause;
import org.pkl.core.parser.syntax.Identifier;
import org.pkl.core.parser.syntax.ImportClause;
import org.pkl.core.parser.syntax.Keyword;
import org.pkl.core.parser.syntax.Modifier;
import org.pkl.core.parser.syntax.Module;
import org.pkl.core.parser.syntax.ModuleDecl;
import org.pkl.core.parser.syntax.ObjectBody;
import org.pkl.core.parser.syntax.ObjectMember;
import org.pkl.core.parser.syntax.Parameter;
import org.pkl.core.parser.syntax.ParameterList;
import org.pkl.core.parser.syntax.QualifiedIdentifier;
import org.pkl.core.parser.syntax.ReplInput;
import org.pkl.core.parser.syntax.StringConstant;
import org.pkl.core.parser.syntax.StringPart;
import org.pkl.core.parser.syntax.Type;
import org.pkl.core.parser.syntax.TypeAlias;
import org.pkl.core.parser.syntax.TypeAnnotation;
import org.pkl.core.parser.syntax.TypeArgumentList;
import org.pkl.core.parser.syntax.TypeParameter;
import org.pkl.core.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

@@ -1,45 +0,0 @@
/*
* 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.core.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

@@ -1,200 +0,0 @@
/*
* 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.core.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

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

View File

@@ -1,88 +0,0 @@
/*
* 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.core.parser.syntax;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import org.pkl.core.parser.Span;
import org.pkl.core.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

@@ -1,42 +0,0 @@
/*
* 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.core.parser.syntax;
import java.util.List;
import org.pkl.core.parser.ParserVisitor;
import org.pkl.core.parser.Span;
import org.pkl.core.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

@@ -1,39 +0,0 @@
/*
* 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.core.parser.syntax;
import java.util.List;
import org.pkl.core.parser.ParserVisitor;
import org.pkl.core.parser.Span;
import org.pkl.core.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

@@ -1,102 +0,0 @@
/*
* 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.core.parser.syntax;
import java.util.List;
import org.pkl.core.parser.ParserVisitor;
import org.pkl.core.parser.Span;
import org.pkl.core.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

@@ -1,56 +0,0 @@
/*
* 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.core.parser.syntax;
import java.util.ArrayList;
import java.util.List;
import org.pkl.core.parser.ParserVisitor;
import org.pkl.core.parser.Span;
import org.pkl.core.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

@@ -1,86 +0,0 @@
/*
* 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.core.parser.syntax;
import java.util.List;
import org.pkl.core.parser.ParserVisitor;
import org.pkl.core.parser.Span;
import org.pkl.core.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

@@ -1,75 +0,0 @@
/*
* 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.core.parser.syntax;
import java.util.List;
import org.pkl.core.parser.ParserVisitor;
import org.pkl.core.parser.Span;
import org.pkl.core.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

@@ -1,54 +0,0 @@
/*
* 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.core.parser.syntax;
import java.util.List;
import org.pkl.core.parser.ParserVisitor;
import org.pkl.core.parser.Span;
import org.pkl.core.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

@@ -1,732 +0,0 @@
/*
* 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.core.parser.syntax;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import org.pkl.core.PklBugException;
import org.pkl.core.parser.ParserVisitor;
import org.pkl.core.parser.Span;
import org.pkl.core.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 PklBugException.unreachableCode();
}
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 PklBugException.unreachableCode();
}
public Type getType() {
assert children != null;
return (Type) children.get(0);
}
}
}

View File

@@ -1,83 +0,0 @@
/*
* 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.core.parser.syntax;
import java.util.List;
import java.util.Objects;
import org.pkl.core.parser.ParserVisitor;
import org.pkl.core.parser.Span;
import org.pkl.core.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

@@ -1,73 +0,0 @@
/*
* 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.core.parser.syntax;
import java.util.Objects;
import org.pkl.core.parser.ParserVisitor;
import org.pkl.core.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

@@ -1,77 +0,0 @@
/*
* 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.core.parser.syntax;
import java.util.Arrays;
import java.util.Objects;
import org.pkl.core.parser.ParserVisitor;
import org.pkl.core.parser.Span;
import org.pkl.core.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

@@ -1,31 +0,0 @@
/*
* 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.core.parser.syntax;
import org.pkl.core.parser.ParserVisitor;
import org.pkl.core.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

@@ -1,71 +0,0 @@
/*
* 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.core.parser.syntax;
import java.util.Objects;
import org.pkl.core.parser.ParserVisitor;
import org.pkl.core.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

@@ -1,98 +0,0 @@
/*
* 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.core.parser.syntax;
import java.util.ArrayList;
import java.util.List;
import org.pkl.core.parser.ParserVisitor;
import org.pkl.core.parser.Span;
import org.pkl.core.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<Class> getClasses() {
var res = new ArrayList<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

@@ -1,88 +0,0 @@
/*
* 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.core.parser.syntax;
import java.util.List;
import org.pkl.core.parser.ParserVisitor;
import org.pkl.core.parser.Span;
import org.pkl.core.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

@@ -1,39 +0,0 @@
/*
* 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.core.parser.syntax;
import java.util.List;
import org.pkl.core.parser.ParserVisitor;
import org.pkl.core.parser.Span;
import org.pkl.core.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

@@ -1,46 +0,0 @@
/*
* 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.core.parser.syntax;
import java.util.List;
import org.pkl.core.parser.ParserVisitor;
import org.pkl.core.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

@@ -1,331 +0,0 @@
/*
* 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.core.parser.syntax;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import org.pkl.core.parser.ParserVisitor;
import org.pkl.core.parser.Span;
import org.pkl.core.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

@@ -1,40 +0,0 @@
/*
* 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.core.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

@@ -1,57 +0,0 @@
/*
* 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.core.parser.syntax;
import java.util.Arrays;
import java.util.List;
import org.pkl.core.parser.ParserVisitor;
import org.pkl.core.parser.Span;
import org.pkl.core.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

@@ -1,38 +0,0 @@
/*
* 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.core.parser.syntax;
import java.util.List;
import org.pkl.core.parser.ParserVisitor;
import org.pkl.core.parser.Span;
import org.pkl.core.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

@@ -1,42 +0,0 @@
/*
* 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.core.parser.syntax;
import java.util.List;
import java.util.stream.Collectors;
import org.pkl.core.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

@@ -1,38 +0,0 @@
/*
* 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.core.parser.syntax;
import java.util.List;
import org.pkl.core.parser.ParserVisitor;
import org.pkl.core.parser.Span;
import org.pkl.core.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

@@ -1,65 +0,0 @@
/*
* 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.core.parser.syntax;
import java.util.Objects;
import org.pkl.core.parser.ParserVisitor;
import org.pkl.core.parser.Span;
import org.pkl.core.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

@@ -1,84 +0,0 @@
/*
* 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.core.parser.syntax;
import java.util.List;
import java.util.Objects;
import org.pkl.core.parser.ParserVisitor;
import org.pkl.core.parser.Span;
import org.pkl.core.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

@@ -1,233 +0,0 @@
/*
* 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.core.parser.syntax;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import org.pkl.core.parser.ParserVisitor;
import org.pkl.core.parser.Span;
import org.pkl.core.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

@@ -1,94 +0,0 @@
/*
* 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.core.parser.syntax;
import java.util.List;
import org.pkl.core.parser.ParserVisitor;
import org.pkl.core.parser.Span;
import org.pkl.core.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

@@ -1,37 +0,0 @@
/*
* 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.core.parser.syntax;
import java.util.List;
import org.pkl.core.parser.ParserVisitor;
import org.pkl.core.parser.Span;
import org.pkl.core.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

@@ -1,38 +0,0 @@
/*
* 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.core.parser.syntax;
import java.util.List;
import org.pkl.core.parser.ParserVisitor;
import org.pkl.core.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

@@ -1,83 +0,0 @@
/*
* 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.core.parser.syntax;
import java.util.List;
import java.util.Objects;
import org.pkl.core.parser.ParserVisitor;
import org.pkl.core.parser.Span;
import org.pkl.core.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

@@ -1,38 +0,0 @@
/*
* 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.core.parser.syntax;
import java.util.List;
import org.pkl.core.parser.ParserVisitor;
import org.pkl.core.parser.Span;
import org.pkl.core.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

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

View File

@@ -35,14 +35,6 @@ import org.pkl.core.ast.type.TypeNode;
import org.pkl.core.http.HttpClient;
import org.pkl.core.module.*;
import org.pkl.core.packages.PackageResolver;
import org.pkl.core.parser.Parser;
import org.pkl.core.parser.ParserError;
import org.pkl.core.parser.syntax.Class;
import org.pkl.core.parser.syntax.ClassProperty;
import org.pkl.core.parser.syntax.Expr;
import org.pkl.core.parser.syntax.ImportClause;
import org.pkl.core.parser.syntax.ModuleDecl;
import org.pkl.core.parser.syntax.ReplInput;
import org.pkl.core.project.DeclaredDependencies;
import org.pkl.core.repl.ReplRequest.Eval;
import org.pkl.core.repl.ReplRequest.Load;
@@ -56,6 +48,14 @@ import org.pkl.core.util.EconomicMaps;
import org.pkl.core.util.IoUtils;
import org.pkl.core.util.MutableReference;
import org.pkl.core.util.Nullable;
import org.pkl.parser.Parser;
import org.pkl.parser.ParserError;
import org.pkl.parser.syntax.Class;
import org.pkl.parser.syntax.ClassProperty;
import org.pkl.parser.syntax.Expr;
import org.pkl.parser.syntax.ImportClause;
import org.pkl.parser.syntax.ModuleDecl;
import org.pkl.parser.syntax.ReplInput;
public class ReplServer implements AutoCloseable {
private final IndirectCallNode callNode = Truffle.getRuntime().createIndirectCallNode();
@@ -222,9 +222,9 @@ public class ReplServer implements AutoCloseable {
}
} else if (tree instanceof Class clazz) {
addStaticModuleProperty(builder.visitClass(clazz));
} else if (tree instanceof org.pkl.core.parser.syntax.TypeAlias typeAlias) {
} else if (tree instanceof org.pkl.parser.syntax.TypeAlias typeAlias) {
addStaticModuleProperty(builder.visitTypeAlias(typeAlias));
} else if (tree instanceof org.pkl.core.parser.syntax.ClassMethod classMethod) {
} else if (tree instanceof org.pkl.parser.syntax.ClassMethod classMethod) {
addModuleMethodDef(builder.visitClassMethod(classMethod));
} else if (tree instanceof ModuleDecl) {
// do nothing for now

View File

@@ -18,11 +18,11 @@ package org.pkl.core.runtime;
import com.oracle.truffle.api.nodes.Node;
import org.pkl.core.Release;
import org.pkl.core.Version;
import org.pkl.core.parser.syntax.Module;
import org.pkl.core.parser.syntax.ObjectMember.ObjectProperty;
import org.pkl.core.parser.syntax.Type;
import org.pkl.core.parser.syntax.Type.DeclaredType;
import org.pkl.core.util.Nullable;
import org.pkl.parser.syntax.Module;
import org.pkl.parser.syntax.ObjectMember.ObjectProperty;
import org.pkl.parser.syntax.Type;
import org.pkl.parser.syntax.Type.DeclaredType;
final class MinPklVersionChecker {
private static final Version currentVersion = Release.current().version();

View File

@@ -24,11 +24,11 @@ import com.oracle.truffle.api.source.Source;
import org.pkl.core.ast.builder.AstBuilder;
import org.pkl.core.module.ModuleKey;
import org.pkl.core.module.ResolvedModuleKey;
import org.pkl.core.parser.Parser;
import org.pkl.core.parser.ParserError;
import org.pkl.core.parser.syntax.Module;
import org.pkl.core.util.IoUtils;
import org.pkl.core.util.Nullable;
import org.pkl.parser.Parser;
import org.pkl.parser.ParserError;
import org.pkl.parser.syntax.Module;
@TruffleLanguage.Registration(
id = "pkl",

View File

@@ -22,8 +22,8 @@ import java.util.Deque;
import java.util.List;
import java.util.Map;
import org.pkl.core.StackFrame;
import org.pkl.core.parser.Lexer;
import org.pkl.core.util.Nullable;
import org.pkl.parser.Lexer;
public final class VmUndefinedValueException extends VmEvalException {
private final @Nullable Object receiver;

View File

@@ -56,11 +56,11 @@ import org.pkl.core.ast.type.UnresolvedTypeNode;
import org.pkl.core.module.ModuleKey;
import org.pkl.core.module.ModuleKeys;
import org.pkl.core.module.ResolvedModuleKey;
import org.pkl.core.parser.Parser;
import org.pkl.core.parser.ParserError;
import org.pkl.core.parser.syntax.Expr;
import org.pkl.core.util.EconomicMaps;
import org.pkl.core.util.Nullable;
import org.pkl.parser.Parser;
import org.pkl.parser.ParserError;
import org.pkl.parser.syntax.Expr;
public final class VmUtils {
/** See {@link VmUtils#shouldRunTypeCheck(VirtualFrame)}. */

View File

@@ -18,8 +18,8 @@ package org.pkl.core.runtime;
import java.util.ArrayDeque;
import java.util.Deque;
import org.pkl.core.ValueFormatter;
import org.pkl.core.parser.Lexer;
import org.pkl.core.util.MutableBoolean;
import org.pkl.parser.Lexer;
/**
* Renders values for use in REPL and error messages. Does not force values to avoid consecutive

View File

@@ -16,7 +16,6 @@
package org.pkl.core.stdlib.base;
import org.pkl.core.ValueFormatter;
import org.pkl.core.parser.Lexer;
import org.pkl.core.runtime.Identifier;
import org.pkl.core.runtime.VmDataSize;
import org.pkl.core.runtime.VmDuration;
@@ -37,6 +36,7 @@ import org.pkl.core.runtime.VmUtils;
import org.pkl.core.stdlib.AbstractRenderer;
import org.pkl.core.stdlib.PklConverter;
import org.pkl.core.util.LateInit;
import org.pkl.parser.Lexer;
public final class PcfRenderer extends AbstractRenderer {
private final ValueFormatter valueFormatter;

View File

@@ -99,11 +99,6 @@ A local property definition cannot be amended.\n\
\n\
Use definition syntax instead, for example `local person = new { ... }` instead of `local person { ... }`.
unexpectedCurlyProbablyAmendsExpression=\
Unexpected token: `'{'`.\n\
\n\
If you meant to write an amends expression, wrap the parent in parentheses. Try: `({0}) '{' ... '}'`
moduleCannotExtendSelf=\
Module `{0}` cannot extend itself.
@@ -217,35 +212,6 @@ Expected {0} type argument(s) but got {1}.
duplicateDefinition=\
Duplicate definition of member `{0}`.
invalidCharacterEscapeSequence=\
Invalid character escape sequence `{0}`.\n\
\n\
Valid character escape sequences are: {1}n {1}r {1}t {1}" {1}\\
unterminatedUnicodeEscapeSequence=\
Unterminated Unicode escape sequence `{0}`.\n\
\n\
Unicode escape sequences must end with `}`.
invalidUnicodeEscapeSequence=\
Invalid Unicode escape sequence `{0}`.\n\
\n\
Valid Unicode escape sequences are {1}'{'0'}' to {1}'{'10FFFF'}' (1-6 hexadecimal characters).
invalidSeparatorPosition=\
Unexpected separator character.\n\
\n\
The separator character (`_`) cannot follow `0x`, `0b`, `.`, `e`, or 'E' in a number literal.
stringContentMustBeginOnNewLine=\
The content of a multi-line string must begin on a new line.
closingStringDelimiterMustBeginOnNewLine=\
The closing delimiter of a multi-line string must begin on a new line.
stringIndentationMustMatchLastLine=\
Line must match or exceed indentation of the String's last line.
floatTooLarge=\
Float literal `{0}` is too large.
@@ -704,11 +670,6 @@ Cannot resolve a triple-dot import from module URI `{0}`.\n\
\n\
Triple-dot imports may only be resolved by module schemes that are considered local, and have hierarchical URIs.
moduleDoesNotSupportDependencies=\
Module `{0}` does not support importing dependencies.\n\
\n\
Dependencies can only be imported in modules that belong to a project, or within a package.
cannotHaveRelativeImport=\
Module `{0}` cannot have a relative import URI.
@@ -764,18 +725,6 @@ A value of type `{0}` cannot be exported.
incompatiblePklVersion=\
Module `{0}` requires Pkl version {1} or higher, but your Pkl version is {2}.
missingDelimiter=\
Missing `{0}` delimiter.
wrongDelimiter=\
Expected delimiter `{0}`, but got `{1}`.
danglingDelimiter=\
Unmatched delimiter `{0}`.
missingCommaSeparator=\
Missing `,` separator.
missingFixedModifier=\
Missing modifier `fixed`.\n\
\n\
@@ -855,12 +804,6 @@ The problematic cycles are those declared as local dependencies.\n\
\n\
{0}
multipleUnionDefaults=\
A type union cannot have more than one default type.
notAUnion=\
Only type unions can have a default marker (*).
invalidModuleOutput=\
Expected `{0}` of module `{3}` to be of type `{1}`, but got type `{2}`.
@@ -878,11 +821,6 @@ Cannot find a dependency named `{0}`, because it is not declared in the current
\n\
To fix this, add it to the `dependencies` section of your `PklProject` file, and resolve your dependencies.
cannotResolveDependencyFromReaderWithOpaqueUris=\
Cannot resolve dependencies from module reader with opaque URIs.\n\
\n\
Module reader for scheme `{0}` does not support hierarchical URIs.
cannotFindDependencyInPackage=\
Cannot find dependency named `{0}`, because it was not declared in package `{1}`.
@@ -1080,14 +1018,6 @@ The only supported checksum algorithm is sha256.
testsFailed=\
Tests failed.
expectedJarOrFileUrl=\
Certificates can only be loaded from `jar:` or `file:` URLs, but got:\n\
{0}
cannotFindBuiltInCertificates=\
Cannot find Pkl's trusted CA certificates on the class path.\n\
To fix this problem, add dependency `org.pkl:pkl-certs`.
# suppress inspection "HttpUrlsUsage"
malformedProxyAddress=\
Malformed proxy URI (expecting `http://<host>[:<port>]`): `{0}`.
@@ -1127,58 +1057,3 @@ External {0} reader does not support scheme `{1}`.
externalReaderAlreadyTerminated=\
External reader process has already terminated.
keywordNotAllowedHere=\
Keyword `{0}` is not allowed here.\n\
\n\
If you must use this name as identifier, enclose it in backticks.
unexpectedEndOfFile=\
Unexpected end of file.
wrongHeaders=\
{0} cannot have doc comments, annotations or modifiers.
invalidTopLevelToken=\
Invalid token at position. Expected a class, typealias, method, or property.
interpolationInConstant=\
String constant cannot have interpolated values.
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}`.
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 { ... }`.
invalidProperty=\
Invalid property definition. Expected a type annotation, `=` or `{`.
unexpectedCharacter=\
Unexpected character `{0}`. Did you mean `{1}`?
unexpectedCharacter3=\
Unexpected character `{0}`. Did you mean `{1}`, `{2}` or `{3}`?
invalidCharacter=\
Invalid identifier `{0}`.
danglingDocComment=\
Dangling documentation comment.\n\
\n\
Documentation comments must be attached to modules, classes, typealiases, methods, or properties.

View File

@@ -1,387 +0,0 @@
/*
* 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.
*/
lexer grammar PklLexer;
@header {
package org.pkl.core.parser.antlr;
}
@members {
class StringInterpolationScope {
int parenLevel = 0;
int poundLength = 0;
}
java.util.Deque<StringInterpolationScope> interpolationScopes = new java.util.ArrayDeque<>();
StringInterpolationScope interpolationScope;
{ pushInterpolationScope(); }
void pushInterpolationScope() {
interpolationScope = new StringInterpolationScope();
interpolationScopes.push(interpolationScope);
}
void incParenLevel() {
interpolationScope.parenLevel += 1;
}
void decParenLevel() {
if (interpolationScope.parenLevel == 0) {
// guard against syntax errors
if (interpolationScopes.size() > 1) {
interpolationScopes.pop();
interpolationScope = interpolationScopes.peek();
popMode();
}
} else {
interpolationScope.parenLevel -= 1;
}
}
boolean isPounds() {
// optimize for common cases (0, 1)
switch (interpolationScope.poundLength) {
case 0: return true;
case 1: return _input.LA(1) == '#';
default:
int poundLength = interpolationScope.poundLength;
for (int i = 1; i <= poundLength; i++) {
if (_input.LA(i) != '#') return false;
}
return true;
}
}
boolean isQuote() {
return _input.LA(1) == '"';
}
boolean endsWithPounds(String text) {
assert text.length() >= 2;
// optimize for common cases (0, 1)
switch (interpolationScope.poundLength) {
case 0: return true;
case 1: return text.charAt(text.length() - 1) == '#';
default:
int poundLength = interpolationScope.poundLength;
int textLength = text.length();
if (textLength < poundLength) return false;
int stop = textLength - poundLength;
for (int i = textLength - 1; i >= stop; i--) {
if (text.charAt(i) != '#') return false;
}
return true;
}
}
void removeBackTicks() {
String text = getText();
setText(text.substring(1, text.length() - 1));
}
// look ahead in predicate rather than consume in grammar so that newlines
// go to NewlineSemicolonChannel, which is important for consumers of that channel
boolean isNewlineOrEof() {
int input = _input.LA(1);
return input == '\n' || input == '\r' || input == IntStream.EOF;
}
}
channels {
NewlineSemicolonChannel,
WhitespaceChannel,
CommentsChannel,
ShebangChannel
}
ABSTRACT : 'abstract';
AMENDS : 'amends';
AS : 'as';
CLASS : 'class';
CONST : 'const';
ELSE : 'else';
EXTENDS : 'extends';
EXTERNAL : 'external';
FALSE : 'false';
FIXED : 'fixed';
FOR : 'for';
FUNCTION : 'function';
HIDDEN_ : 'hidden';
IF : 'if';
IMPORT : 'import';
IMPORT_GLOB : 'import*';
IN : 'in';
IS : 'is';
LET : 'let';
LOCAL : 'local';
MODULE : 'module';
NEW : 'new';
NOTHING : 'nothing';
NULL : 'null';
OPEN : 'open';
OUT : 'out';
OUTER : 'outer';
READ : 'read';
READ_GLOB : 'read*';
READ_OR_NULL : 'read?';
SUPER : 'super';
THIS : 'this';
THROW : 'throw';
TRACE : 'trace';
TRUE : 'true';
TYPE_ALIAS : 'typealias';
UNKNOWN : 'unknown';
WHEN : 'when';
// reserved for future use, but not used today
PROTECTED : 'protected';
OVERRIDE : 'override';
RECORD : 'record';
DELETE : 'delete';
CASE : 'case';
SWITCH : 'switch';
VARARG : 'vararg';
LPAREN : '(' { incParenLevel(); };
RPAREN : ')' { decParenLevel(); };
LBRACE : '{';
RBRACE : '}';
LBRACK : '[';
RBRACK : ']';
LPRED : '[['; // No RPRED, because that lexes too eager to allow nested index expressions, e.g. foo[bar[baz]]
COMMA : ',';
DOT : '.';
QDOT : '?.';
COALESCE : '??';
NON_NULL : '!!';
AT : '@';
ASSIGN : '=';
GT : '>';
LT : '<';
NOT : '!';
QUESTION : '?';
COLON : ':';
ARROW : '->';
EQUAL : '==';
NOT_EQUAL : '!=';
LTE : '<=';
GTE : '>=';
AND : '&&';
OR : '||';
PLUS : '+';
MINUS : '-';
POW : '**';
STAR : '*';
DIV : '/';
INT_DIV : '~/';
MOD : '%';
UNION : '|';
PIPE : '|>';
SPREAD : '...';
QSPREAD : '...?';
UNDERSCORE : '_';
SLQuote : '#'* '"' { interpolationScope.poundLength = getText().length() - 1; } -> pushMode(SLString);
MLQuote : '#'* '"""' { interpolationScope.poundLength = getText().length() - 3; } -> pushMode(MLString);
IntLiteral
: DecimalLiteral
| HexadecimalLiteral
| BinaryLiteral
| OctalLiteral
;
// leading zeros are allowed (cf. Swift)
fragment DecimalLiteral
: DecimalDigit DecimalDigitCharacters?
;
fragment DecimalDigitCharacters
: DecimalDigitCharacter+
;
fragment DecimalDigitCharacter
: DecimalDigit
| '_'
;
fragment DecimalDigit
: [0-9]
;
fragment HexadecimalLiteral
: '0x' HexadecimalCharacter+ // intentionally allow underscore after '0x'; e.g. `0x_ab`. We will throw an error in AstBuilder.
;
fragment HexadecimalCharacter
: [0-9a-fA-F_]
;
fragment BinaryLiteral
: '0b' BinaryCharacter+ // intentionally allow underscore after '0b'; e.g. `0b_11`. We will throw an error in AstBuilder.
;
fragment BinaryCharacter
: [01_]
;
fragment OctalLiteral
: '0o' OctalCharacter+ // intentionally allow underscore after '0o'; e.g. `0o_34`. We will throw an error in AstBuilder.
;
fragment OctalCharacter
: [0-7_]
;
FloatLiteral
: DecimalLiteral? '.' '_'? DecimalLiteral Exponent? // intentionally allow underscore. We will throw an error in AstBuilder.
| DecimalLiteral Exponent
;
fragment Exponent
: [eE] [+-]? '_'? DecimalLiteral // intentionally allow underscore. We will throw an error in AstBuilder.
;
Identifier
: RegularIdentifier
| QuotedIdentifier { removeBackTicks(); }
;
// Note: Keep in sync with Lexer.isRegularIdentifier()
fragment RegularIdentifier
: IdentifierStart IdentifierPart*
;
fragment QuotedIdentifier
: '`' (~'`')+ '`'
;
fragment
IdentifierStart
: [a-zA-Z$_] // handle common cases without a predicate
| . {Character.isUnicodeIdentifierStart(_input.LA(-1))}?
;
fragment
IdentifierPart
: [a-zA-Z0-9$_] // handle common cases without a predicate
| . {Character.isUnicodeIdentifierPart(_input.LA(-1))}?
;
NewlineSemicolon
: [\r\n;]+ -> channel(NewlineSemicolonChannel)
;
// Note: Java, Scala, and Swift treat \f as whitespace; Dart doesn't.
// Python and C also include vertical tab.
// C# also includes Unicode class Zs (separator, space).
Whitespace
: [ \t\f]+ -> channel(WhitespaceChannel)
;
DocComment
: ([ \t\f]* '///' .*? (Newline|EOF))+
;
BlockComment
: '/*' (BlockComment | .)*? '*/' -> channel(CommentsChannel)
;
LineComment
: '//' .*? {isNewlineOrEof()}? -> channel(CommentsChannel)
;
ShebangComment
: '#!' .*? {isNewlineOrEof()}? -> channel(ShebangChannel)
;
// strict: '\\' Pounds 'u{' HexDigit (HexDigit (HexDigit (HexDigit (HexDigit (HexDigit (HexDigit HexDigit? )?)?)?)?)?)? '}'
fragment UnicodeEscape
: '\\' Pounds 'u{' ~[}\r\n "]* '}'?
;
// strict: '\\' Pounds [tnr"\\]
fragment CharacterEscape
: '\\' Pounds .
;
fragment Pounds
: { interpolationScope.poundLength == 0 }?
| '#' { interpolationScope.poundLength == 1 }?
| '#'+ { endsWithPounds(getText()) }?
;
fragment Newline
: '\n' | '\r' '\n'?
;
mode SLString;
// strict: '"' Pounds
SLEndQuote
: ('"' Pounds | Newline ) -> popMode
;
SLInterpolation
: '\\' Pounds '(' { pushInterpolationScope(); } -> pushMode(DEFAULT_MODE)
;
SLUnicodeEscape
: UnicodeEscape
;
SLCharacterEscape
: CharacterEscape
;
SLCharacters
: ~["\\\r\n]+ SLCharacters?
| ["\\] {!isPounds()}? SLCharacters?
;
mode MLString;
MLEndQuote
: '"""' Pounds -> popMode
;
MLInterpolation
: '\\' Pounds '(' { pushInterpolationScope(); } -> pushMode(DEFAULT_MODE)
;
MLUnicodeEscape
: UnicodeEscape
;
MLCharacterEscape
: CharacterEscape
;
MLNewline
: Newline
;
MLCharacters
: ~["\\\r\n]+ MLCharacters?
| ('\\' | '"""') {!isPounds()}? MLCharacters?
| '"' '"'? {!isQuote()}? MLCharacters?
;

View File

@@ -1,254 +0,0 @@
/*
* 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.
*/
parser grammar PklParser;
@header {
package org.pkl.core.parser.antlr;
}
@members {
/**
* Returns true if and only if the next token to be consumed is not preceded by a newline or semicolon.
*/
boolean noNewlineOrSemicolon() {
for (int i = _input.index() - 1; i >= 0; i--) {
Token token = _input.get(i);
int channel = token.getChannel();
if (channel == PklLexer.DEFAULT_TOKEN_CHANNEL) return true;
if (channel == PklLexer.NewlineSemicolonChannel) return false;
}
return true;
}
}
options {
tokenVocab = PklLexer;
}
replInput
: ((moduleDecl
| importClause
| clazz
| typeAlias
| classProperty
| classMethod
| expr))* EOF
;
exprInput
: expr EOF
;
module
: moduleDecl? (is+=importClause)* ((cs+=clazz | ts+=typeAlias | ps+=classProperty | ms+=classMethod))* EOF
;
moduleDecl
: t=DocComment? annotation* moduleHeader
;
moduleHeader
: modifier* 'module' qualifiedIdentifier moduleExtendsOrAmendsClause?
| moduleExtendsOrAmendsClause
;
moduleExtendsOrAmendsClause
: t=('extends' | 'amends') stringConstant
;
importClause
: t=('import' | 'import*') stringConstant ('as' Identifier)?
;
clazz
: t=DocComment? annotation* classHeader classBody?
;
classHeader
: modifier* 'class' Identifier typeParameterList? ('extends' type)?
;
modifier
: t=('external' | 'abstract' | 'open' | 'local' | 'hidden' | 'fixed' | 'const')
;
classBody
: '{' ((ps+=classProperty | ms+=classMethod))* err='}'?
;
typeAlias
: t=DocComment? annotation* typeAliasHeader '=' type
;
typeAliasHeader
: modifier* 'typealias' Identifier typeParameterList?
;
// allows `foo: Bar { ... }` s.t. AstBuilder can provide better error message
classProperty
: t=DocComment? annotation* modifier* Identifier (typeAnnotation | typeAnnotation? ('=' expr | objectBody+))
;
classMethod
: t=DocComment? annotation* methodHeader ('=' expr)?
;
methodHeader
: modifier* 'function' Identifier typeParameterList? parameterList typeAnnotation?
;
parameterList
: '(' (ts+=parameter (errs+=','? ts+=parameter)*)? err=')'?
;
argumentList
: {noNewlineOrSemicolon()}? '(' (es+=expr (errs+=','? es+=expr)*)? err=')'?
;
annotation
: '@' type objectBody?
;
qualifiedIdentifier
: ts+=Identifier ('.' ts+=Identifier)*
;
typeAnnotation
: ':' type
;
typeParameterList
: '<' ts+=typeParameter (errs+=','? ts+=typeParameter)* err='>'?
;
typeParameter
: t=('in' | 'out')? Identifier
;
typeArgumentList
: '<' ts+=type (errs+=','? ts+=type)* err='>'?
;
type
: 'unknown' # unknownType
| 'nothing' # nothingType
| 'module' # moduleType
| stringConstant # stringLiteralType
| qualifiedIdentifier typeArgumentList? # declaredType
| '(' type err=')'? # parenthesizedType
| type '?' # nullableType
| type {noNewlineOrSemicolon()}? t='(' es+=expr (errs+=','? es+=expr)* err=')'? # constrainedType
| '*' u=type # defaultUnionType
| l=type '|' r=type # unionType
| t='(' (ps+=type (errs+=','? ps+=type)*)? err=')'? '->' r=type # functionType
;
typedIdentifier
: Identifier typeAnnotation?
;
parameter
: '_'
| typedIdentifier
;
// Many languages (e.g., Python) give `**` higher precedence than unary minus.
// The reason is that in Math, `-a^2` means `-(a^2)`.
// To avoid confusion, JS rejects `-a**2` and requires explicit parens.
// `-3.abs()` is a similar problem, handled differently by different languages.
expr
: 'this' # thisExpr
| 'outer' # outerExpr
| 'module' # moduleExpr
| 'null' # nullLiteral
| 'true' # trueLiteral
| 'false' # falseLiteral
| IntLiteral # intLiteral
| FloatLiteral # floatLiteral
| 'throw' '(' expr err=')'? # throwExpr
| 'trace' '(' expr err=')'? # traceExpr
| t=('import' | 'import*') '(' stringConstant err=')'? # importExpr
| t=('read' | 'read?' | 'read*') '(' expr err=')'? # readExpr
| Identifier argumentList? # unqualifiedAccessExpr
| t=SLQuote singleLineStringPart* t2=SLEndQuote # singleLineStringLiteral
| t=MLQuote multiLineStringPart* t2=MLEndQuote # multiLineStringLiteral
| t='new' type? objectBody # newExpr
| expr objectBody # amendExpr
| 'super' '.' Identifier argumentList? # superAccessExpr
| 'super' t='[' e=expr err=']'? # superSubscriptExpr
| expr t=('.' | '?.') Identifier argumentList? # qualifiedAccessExpr
| l=expr {noNewlineOrSemicolon()}? t='[' r=expr err=']'? # subscriptExpr
| expr '!!' # nonNullExpr
| '-' expr # unaryMinusExpr
| '!' expr # logicalNotExpr
| <assoc=right> l=expr t='**' r=expr # exponentiationExpr
// for some reason, moving rhs of rules starting with `l=expr` into a
// separate rule (to avoid repeated parsing of `expr`) messes up precedence
| l=expr t=('*' | '/' | '~/' | '%') r=expr # multiplicativeExpr
| l=expr (t='+' | {noNewlineOrSemicolon()}? t='-') r=expr # additiveExpr
| l=expr t=('<' | '>' | '<=' | '>=') r=expr # comparisonExpr
| l=expr t=('is' | 'as') r=type # typeTestExpr
| l=expr t=('==' | '!=') r=expr # equalityExpr
| l=expr t='&&' r=expr # logicalAndExpr
| l=expr t='||' r=expr # logicalOrExpr
| l=expr t='|>' r=expr # pipeExpr
| <assoc=right> l=expr t='??' r=expr # nullCoalesceExpr
| 'if' '(' c=expr err=')'? l=expr 'else' r=expr # ifExpr
| 'let' '(' parameter '=' l=expr err=')'? r=expr # letExpr
| parameterList '->' expr # functionLiteral
| '(' expr err=')'? # parenthesizedExpr
;
objectBody
: '{' (ps+=parameter (errs+=','? ps+=parameter)* '->')? objectMember* err='}'?
;
objectMember
: modifier* Identifier (typeAnnotation? '=' expr | objectBody+) # objectProperty
| methodHeader '=' expr # objectMethod
| t='[[' k=expr err1=']'? err2=']'? ('=' v=expr | objectBody+) # memberPredicate
| t='[' k=expr err1=']'? err2=']'? ('=' v=expr | objectBody+) # objectEntry
| expr # objectElement
| ('...' | '...?') expr # objectSpread
| 'when' '(' e=expr err=')'? (b1=objectBody ('else' b2=objectBody)?) # whenGenerator
| 'for' '(' t1=parameter (',' t2=parameter)? 'in' e=expr err=')'? objectBody # forGenerator
;
stringConstant
: t=SLQuote (ts+=SLCharacters | ts+=SLCharacterEscape | ts+=SLUnicodeEscape)* t2=SLEndQuote
;
singleLineStringPart
: SLInterpolation e=expr ')'
| (ts+=SLCharacters | ts+=SLCharacterEscape | ts+=SLUnicodeEscape)+
;
multiLineStringPart
: MLInterpolation e=expr ')'
| (ts+=MLCharacters | ts+=MLNewline | ts+=MLCharacterEscape | ts+=MLUnicodeEscape)+
;
// intentionally unused
//TODO: we get a "Mismatched Input" error unless we introduce this parser rule. Why?
reservedKeyword
: 'protected'
| 'override'
| 'record'
| 'delete'
| 'case'
| 'switch'
| 'vararg'
;

View File

@@ -1,54 +0,0 @@
/*
* 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.core.parser
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
class LexerTest {
@Test
fun isRegularIdentifier() {
assertThat(Lexer.isRegularIdentifier("pigeon")).isTrue
assertThat(Lexer.isRegularIdentifier("_pigeon")).isTrue
assertThat(Lexer.isRegularIdentifier("f_red")).isTrue
assertThat(Lexer.isRegularIdentifier("\$pigeon")).isTrue
assertThat(Lexer.isRegularIdentifier("f\$red")).isTrue
assertThat(Lexer.isRegularIdentifier("जावास्क्रिप्ट")).isTrue
assertThat(Lexer.isRegularIdentifier("this")).isFalse
assertThat(Lexer.isRegularIdentifier("😀")).isFalse
}
@Test
fun maybeQuoteIdentifier() {
assertThat(Lexer.maybeQuoteIdentifier("pigeon")).isEqualTo("pigeon")
assertThat(Lexer.maybeQuoteIdentifier("_pigeon")).isEqualTo("_pigeon")
assertThat(Lexer.maybeQuoteIdentifier("\$pigeon")).isEqualTo("\$pigeon")
assertThat(Lexer.maybeQuoteIdentifier("जावास्क्रिप्ट")).isEqualTo("जावास्क्रिप्ट")
assertThat(Lexer.maybeQuoteIdentifier("this")).isEqualTo("`this`")
assertThat(Lexer.maybeQuoteIdentifier("😀")).isEqualTo("`😀`")
}
@Test
fun `lexer keywords are sorted`() {
assertThat(Lexer.KEYWORDS).isSortedAccordingTo { a, b -> a.compareTo(b.name) }
}
}

View File

@@ -1,103 +0,0 @@
/*
* 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.core.parser
import java.nio.file.Path
import kotlin.io.path.Path
import kotlin.io.path.extension
import org.junit.jupiter.api.Test
import org.pkl.commons.walk
class ParserComparisonTest : ParserComparisonTestInterface {
@Test
fun testAsPrecedence() {
compare("prop = 3 + bar as Int * 5")
}
@Test
fun testStringInterpolation() {
compare(
"""
prop = "\(bar)"
prop2 = "foo \(bar)"
prop3 = "\(bar) foo"
prop4 = "foo \(bar + baz) foo"
"""
.trimIndent()
)
compare(
"""
prop = ""${'"'}
\(bar)
""${'"'}
prop2 = ""${'"'}
foo \(bar)
""${'"'}
prop3 = ""${'"'}
\(bar) foo
""${'"'}
prop4 = ""${'"'}
foo \(bar + baz) foo
""${'"'}
"""
.trimIndent()
)
}
override fun getSnippets(): List<Path> {
return Path("src/test/files/LanguageSnippetTests/input")
.walk()
.filter { path ->
val pathStr = path.toString().replace("\\", "/")
path.extension == "pkl" &&
!exceptions.any { pathStr.endsWith(it) } &&
!regexExceptions.any { it.matches(pathStr) }
}
.toList()
}
companion object {
// tests that are not syntactically valid Pkl
private val exceptions =
setOf(
"stringError1.pkl",
"annotationIsNotExpression2.pkl",
"amendsRequiresParens.pkl",
"errors/parser18.pkl",
"errors/nested1.pkl",
"errors/invalidCharacterEscape.pkl",
"errors/invalidUnicodeEscape.pkl",
"errors/unterminatedUnicodeEscape.pkl",
"errors/keywordNotAllowedHere1.pkl",
"errors/keywordNotAllowedHere2.pkl",
"errors/keywordNotAllowedHere3.pkl",
"errors/keywordNotAllowedHere4.pkl",
"errors/moduleWithHighMinPklVersionAndParseErrors.pkl",
"errors/underscore.pkl",
"notAUnionDefault.pkl",
"multipleDefaults.pkl",
)
private val regexExceptions =
setOf(
Regex(".*/errors/delimiters/.*"),
Regex(".*/errors/parser\\d+\\.pkl"),
Regex(".*/parser/.*"),
)
}
}

View File

@@ -1,112 +0,0 @@
/*
* 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.core.parser
import java.nio.file.Path
import kotlin.io.path.pathString
import kotlin.io.path.readText
import org.antlr.v4.runtime.ANTLRInputStream
import org.antlr.v4.runtime.CommonTokenStream
import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.SoftAssertions
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.parallel.Execution
import org.junit.jupiter.api.parallel.ExecutionMode
import org.pkl.core.parser.antlr.PklLexer
import org.pkl.core.parser.antlr.PklParser
@Execution(ExecutionMode.CONCURRENT)
interface ParserComparisonTestInterface {
@Test
@Execution(ExecutionMode.CONCURRENT)
fun compareSnippetTests() {
SoftAssertions.assertSoftly { softly ->
getSnippets()
.parallelStream()
.map { Pair(it.pathString, it.readText()) }
.forEach { (path, snippet) ->
try {
compare(snippet, path, softly)
} catch (e: ParserError) {
softly.fail("path: $path. Message: ${e.message}", e)
}
}
}
}
@Test
@Execution(ExecutionMode.CONCURRENT)
fun compareSnippetTestsSpans() {
SoftAssertions.assertSoftly { softly ->
getSnippets()
.parallelStream()
.map { Pair(it.pathString, it.readText()) }
.forEach { (path, snippet) ->
try {
compareSpans(snippet, path, softly)
} catch (e: ParserError) {
softly.fail("path: $path. Message: ${e.message}", e)
}
}
}
}
fun getSnippets(): List<Path>
fun compare(code: String, path: String? = null, softly: SoftAssertions? = null) {
val (sexp, antlrExp) = renderBoth(code)
when {
(path != null && softly != null) ->
softly.assertThat(sexp).`as`("path: $path").isEqualTo(antlrExp)
else -> assertThat(sexp).isEqualTo(antlrExp)
}
}
fun compareSpans(code: String, path: String, softly: SoftAssertions) {
// Our ANTLR grammar always start doc comment spans in the beginning of the line,
// even though they may have leading spaces.
// This is a regression, but it's a bugfix
if (path.endsWith("annotation1.pkl")) return
val parser = Parser()
val mod = parser.parseModule(code)
val lexer = PklLexer(ANTLRInputStream(code))
val antlr = PklParser(CommonTokenStream(lexer))
val antlrMod = antlr.module()
val comparer = SpanComparison(path, softly)
comparer.compare(mod, antlrMod)
}
fun renderBoth(code: String): Pair<String, String> = Pair(renderCode(code), renderANTLRCode(code))
companion object {
private fun renderCode(code: String): String {
val parser = Parser()
val mod = parser.parseModule(code)
val renderer = SexpRenderer()
return renderer.render(mod)
}
private fun renderANTLRCode(code: String): String {
val lexer = PklLexer(ANTLRInputStream(code))
val parser = PklParser(CommonTokenStream(lexer))
val mod = parser.module()
val renderer = ANTLRSexpRenderer()
return renderer.render(mod)
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,464 +0,0 @@
/*
* 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.core.parser
import org.antlr.v4.runtime.ParserRuleContext
import org.antlr.v4.runtime.tree.TerminalNode
import org.assertj.core.api.SoftAssertions
import org.pkl.core.parser.antlr.PklParser.*
import org.pkl.core.parser.syntax.*
import org.pkl.core.parser.syntax.Annotation
import org.pkl.core.parser.syntax.Expr.AmendsExpr
import org.pkl.core.parser.syntax.Expr.BinaryOperatorExpr
import org.pkl.core.parser.syntax.Expr.FunctionLiteralExpr
import org.pkl.core.parser.syntax.Expr.IfExpr
import org.pkl.core.parser.syntax.Expr.ImportExpr
import org.pkl.core.parser.syntax.Expr.LetExpr
import org.pkl.core.parser.syntax.Expr.LogicalNotExpr
import org.pkl.core.parser.syntax.Expr.MultiLineStringLiteralExpr
import org.pkl.core.parser.syntax.Expr.NewExpr
import org.pkl.core.parser.syntax.Expr.NonNullExpr
import org.pkl.core.parser.syntax.Expr.ParenthesizedExpr
import org.pkl.core.parser.syntax.Expr.QualifiedAccessExpr
import org.pkl.core.parser.syntax.Expr.ReadExpr
import org.pkl.core.parser.syntax.Expr.SingleLineStringLiteralExpr
import org.pkl.core.parser.syntax.Expr.SubscriptExpr
import org.pkl.core.parser.syntax.Expr.SuperAccessExpr
import org.pkl.core.parser.syntax.Expr.SuperSubscriptExpr
import org.pkl.core.parser.syntax.Expr.ThrowExpr
import org.pkl.core.parser.syntax.Expr.TraceExpr
import org.pkl.core.parser.syntax.Expr.TypeCastExpr
import org.pkl.core.parser.syntax.Expr.TypeCheckExpr
import org.pkl.core.parser.syntax.Expr.UnaryMinusExpr
import org.pkl.core.parser.syntax.Expr.UnqualifiedAccessExpr
import org.pkl.core.parser.syntax.ObjectMember.ForGenerator
import org.pkl.core.parser.syntax.ObjectMember.MemberPredicate
import org.pkl.core.parser.syntax.ObjectMember.ObjectElement
import org.pkl.core.parser.syntax.ObjectMember.ObjectEntry
import org.pkl.core.parser.syntax.ObjectMember.ObjectMethod
import org.pkl.core.parser.syntax.ObjectMember.ObjectProperty
import org.pkl.core.parser.syntax.ObjectMember.ObjectSpread
import org.pkl.core.parser.syntax.ObjectMember.WhenGenerator
import org.pkl.core.parser.syntax.Parameter.TypedIdentifier
import org.pkl.core.parser.syntax.Type.ConstrainedType
import org.pkl.core.parser.syntax.Type.DeclaredType
import org.pkl.core.parser.syntax.Type.FunctionType
import org.pkl.core.parser.syntax.Type.NullableType
import org.pkl.core.parser.syntax.Type.ParenthesizedType
import org.pkl.core.parser.syntax.Type.StringConstantType
import org.pkl.core.parser.syntax.Type.UnionType
class SpanComparison(val path: String, private val softly: SoftAssertions) {
fun compare(module: Module, modCtx: ModuleContext) {
compareSpan(module, modCtx)
if (module.decl !== null) {
compareModuleDecl(module.decl!!, modCtx.moduleDecl())
}
module.imports.zip(modCtx.importClause()).forEach { (i1, i2) -> compareImport(i1, i2) }
module.classes.zip(modCtx.clazz()).forEach { (class1, class2) -> compareClass(class1, class2) }
module.typeAliases.zip(modCtx.typeAlias()).forEach { (ta1, ta2) -> compareTypealias(ta1, ta2) }
module.properties.zip(modCtx.classProperty()).forEach { (prop1, prop2) ->
compareProperty(prop1, prop2)
}
module.methods.zip(modCtx.classMethod()).forEach { (m1, m2) -> compareMethod(m1, m2) }
}
private fun compareModuleDecl(node: ModuleDecl, ctx: ModuleDeclContext) {
compareSpan(node, ctx)
compareDocComment(node.docComment, ctx.DocComment())
node.annotations.zip(ctx.annotation()).forEach { (a1, a2) -> compareAnnotation(a1, a2) }
val header = ctx.moduleHeader()
node.modifiers.zip(header.modifier()).forEach { (m1, m2) -> compareSpan(m1, m2) }
compareQualifiedIdentifier(node.name, header.qualifiedIdentifier())
compareExtendsOrAmendsClause(node.extendsOrAmendsDecl, header.moduleExtendsOrAmendsClause())
}
private fun compareImport(node: ImportClause, ctx: ImportClauseContext) {
compareSpan(node, ctx)
compareSpan(node.importStr, ctx.stringConstant())
compareSpan(node.alias, ctx.Identifier())
}
private fun compareClass(node: Class, ctx: ClazzContext) {
compareSpan(node, ctx)
compareDocComment(node.docComment, ctx.DocComment())
node.annotations.zip(ctx.annotation()).forEach { (a1, a2) -> compareAnnotation(a1, a2) }
val header = ctx.classHeader()
node.modifiers.zip(header.modifier()).forEach { (m1, m2) -> compareSpan(m1, m2) }
compareSpan(node.classKeyword, header.CLASS())
compareSpan(node.name, header.Identifier())
compareTypeParameterList(node.typeParameterList, header.typeParameterList())
compareType(node.superClass, header.type())
compareClassBody(node.body, ctx.classBody())
compareSpan(node.headerSpan, header)
}
private fun compareTypealias(node: TypeAlias, ctx: TypeAliasContext) {
compareSpan(node, ctx)
compareDocComment(node.docComment, ctx.DocComment())
node.annotations.zip(ctx.annotation()).forEach { (a1, a2) -> compareAnnotation(a1, a2) }
val header = ctx.typeAliasHeader()
node.modifiers.zip(header.modifier()).forEach { (m1, m2) -> compareSpan(m1, m2) }
compareSpan(node.typealiasKeyword, header.TYPE_ALIAS())
compareSpan(node.name, header.Identifier())
compareTypeParameterList(node.typeParameterList, header.typeParameterList())
compareType(node.type, ctx.type())
compareSpan(node.headerSpan, header)
}
private fun compareProperty(node: ClassProperty, ctx: ClassPropertyContext) {
if (node.docComment === null) {
compareSpan(node, ctx)
}
compareDocComment(node.docComment, ctx.DocComment())
node.annotations.zip(ctx.annotation()).forEach { (a1, a2) -> compareAnnotation(a1, a2) }
node.modifiers.zip(ctx.modifier()).forEach { (m1, m2) -> compareSpan(m1, m2) }
compareSpan(node.name, ctx.Identifier())
compareTypeAnnotation(node.typeAnnotation, ctx.typeAnnotation())
compareExpr(node.expr, ctx.expr())
node.bodyList.zip(ctx.objectBody()).forEach { (b1, b2) -> compareObjectBody(b1, b2) }
}
private fun compareMethod(node: ClassMethod, ctx: ClassMethodContext) {
compareSpan(node, ctx)
compareDocComment(node.docComment, ctx.DocComment())
node.annotations.zip(ctx.annotation()).forEach { (a1, a2) -> compareAnnotation(a1, a2) }
val header = ctx.methodHeader()
compareSpan(node.headerSpan, header)
node.modifiers.zip(header.modifier()).forEach { (m1, m2) -> compareSpan(m1, m2) }
compareSpan(node.name, header.Identifier())
compareTypeParameterList(node.typeParameterList, header.typeParameterList())
compareParameterList(node.parameterList, header.parameterList())
compareTypeAnnotation(node.typeAnnotation, header.typeAnnotation())
compareExpr(node.expr, ctx.expr())
}
private fun compareAnnotation(node: Annotation, ctx: AnnotationContext) {
compareSpan(node, ctx)
compareType(node.type, ctx.type())
compareObjectBody(node.body, ctx.objectBody())
}
private fun compareParameterList(node: ParameterList?, ctx: ParameterListContext?) {
if (node === null) return
compareSpan(node, ctx!!)
node.parameters.zip(ctx.parameter()).forEach { (p1, p2) -> compareParameter(p1, p2) }
}
private fun compareParameter(node: Parameter?, ctx: ParameterContext?) {
if (node === null) return
compareSpan(node, ctx!!)
if (node is TypedIdentifier) {
val tident = ctx.typedIdentifier()
compareSpan(node.identifier, tident.Identifier())
compareTypeAnnotation(node.typeAnnotation, tident.typeAnnotation())
}
}
private fun compareTypeParameterList(node: TypeParameterList?, ctx: TypeParameterListContext?) {
if (node === null) return
compareSpan(node, ctx!!)
node.parameters.zip(ctx.typeParameter()).forEach { (p1, p2) -> compareTypeParameter(p1, p2) }
}
private fun compareTypeParameter(node: TypeParameter, ctx: TypeParameterContext) {
compareSpan(node, ctx)
compareSpan(node.identifier, ctx.Identifier())
}
private fun compareClassBody(node: ClassBody?, ctx: ClassBodyContext?) {
if (node === null) return
compareSpan(node, ctx!!)
node.properties.zip(ctx.classProperty()).forEach { (p1, p2) -> compareProperty(p1, p2) }
node.methods.zip(ctx.classMethod()).forEach { (m1, m2) -> compareMethod(m1, m2) }
}
private fun compareTypeAnnotation(node: TypeAnnotation?, ctx: TypeAnnotationContext?) {
if (node === null) return
compareSpan(node, ctx!!)
compareSpan(node.type, ctx.type())
}
private fun compareObjectBody(node: ObjectBody?, ctx: ObjectBodyContext?) {
if (node === null) return
compareSpan(node, ctx!!)
node.parameters.zip(ctx.parameter()).forEach { (p1, p2) -> compareParameter(p1, p2) }
node.members.zip(ctx.objectMember()).forEach { (m1, m2) -> compareObjectMember(m1, m2) }
}
private fun compareType(node: Type?, actx: TypeContext?) {
if (node === null) return
val ctx = if (actx is DefaultUnionTypeContext) actx.type() else actx
compareSpan(node, ctx!!)
when (node) {
is StringConstantType ->
compareSpan(node.str, (ctx as StringLiteralTypeContext).stringConstant())
is DeclaredType -> {
val decl = ctx as DeclaredTypeContext
compareQualifiedIdentifier(node.name, decl.qualifiedIdentifier())
compareTypeArgumentList(node.args, ctx.typeArgumentList())
}
is ParenthesizedType -> compareType(node.type, (ctx as ParenthesizedTypeContext).type())
is NullableType -> compareType(node.type, (ctx as NullableTypeContext).type())
is ConstrainedType -> {
val cons = ctx as ConstrainedTypeContext
compareType(node.type, cons.type())
node.exprs.zip(cons.expr()).forEach { (e1, e2) -> compareExpr(e1, e2) }
}
is UnionType -> {
val flattened = ANTLRSexpRenderer.flattenUnion(ctx as UnionTypeContext)
node.types.zip(flattened).forEach { (t1, t2) -> compareType(t1, t2) }
}
is FunctionType -> {
val func = ctx as FunctionTypeContext
node.args.zip(func.ps).forEach { (t1, t2) -> compareType(t1, t2) }
compareType(node.ret, func.r)
}
else -> {}
}
}
private fun compareObjectMember(node: ObjectMember, ctx: ObjectMemberContext) {
compareSpan(node, ctx)
when (node) {
is ObjectElement -> compareExpr(node.expr, (ctx as ObjectElementContext).expr())
is ObjectProperty -> {
ctx as ObjectPropertyContext
node.modifiers.zip(ctx.modifier()).forEach { (m1, m2) -> compareSpan(m1, m2) }
compareSpan(node.identifier, ctx.Identifier())
compareTypeAnnotation(node.typeAnnotation, ctx.typeAnnotation())
compareExpr(node.expr, ctx.expr())
if (node.bodyList.isNotEmpty()) {
node.bodyList.zip(ctx.objectBody()).forEach { (b1, b2) -> compareObjectBody(b1, b2) }
}
}
is ObjectMethod -> {
ctx as ObjectMethodContext
val header = ctx.methodHeader()
node.modifiers.zip(header.modifier()).forEach { (m1, m2) -> compareSpan(m1, m2) }
compareSpan(node.functionKeyword, header.FUNCTION())
compareSpan(node.identifier, header.Identifier())
compareTypeParameterList(node.typeParameterList, header.typeParameterList())
compareParameterList(node.paramList, header.parameterList())
compareTypeAnnotation(node.typeAnnotation, header.typeAnnotation())
compareExpr(node.expr, ctx.expr())
compareSpan(node.headerSpan(), header)
}
is MemberPredicate -> {
ctx as MemberPredicateContext
compareExpr(node.pred, ctx.k)
compareExpr(node.expr, ctx.v)
if (node.bodyList.isNotEmpty()) {
node.bodyList.zip(ctx.objectBody()).forEach { (b1, b2) -> compareObjectBody(b1, b2) }
}
}
is ObjectEntry -> {
ctx as ObjectEntryContext
compareExpr(node.key, ctx.k)
compareExpr(node.value, ctx.v)
if (node.bodyList.isNotEmpty()) {
node.bodyList.zip(ctx.objectBody()).forEach { (b1, b2) -> compareObjectBody(b1, b2) }
}
}
is ObjectSpread -> compareExpr(node.expr, (ctx as ObjectSpreadContext).expr())
is WhenGenerator -> {
ctx as WhenGeneratorContext
compareExpr(node.predicate, ctx.expr())
compareObjectBody(node.thenClause, ctx.b1)
compareObjectBody(node.elseClause, ctx.b2)
}
is ForGenerator -> {
ctx as ForGeneratorContext
compareParameter(node.p1, ctx.t1)
compareParameter(node.p2, ctx.t2)
compareExpr(node.expr, ctx.expr())
compareObjectBody(node.body, ctx.objectBody())
}
}
}
private fun compareExpr(node: Expr?, ctx: ExprContext?) {
if (node === null) return
compareSpan(node, ctx!!)
when (node) {
is SingleLineStringLiteralExpr -> {
node.parts.zip((ctx as SingleLineStringLiteralContext).singleLineStringPart()).forEach {
(s1, s2) ->
compareSpan(s1, s2)
}
}
is MultiLineStringLiteralExpr -> {
// only compare interpolated expressions
val exprs = node.parts.filterIsInstance<StringPart.StringInterpolation>()
val antlrExprs =
(ctx as MultiLineStringLiteralContext).multiLineStringPart().mapNotNull { it.expr() }
exprs.zip(antlrExprs).forEach { (s1, s2) -> compareExpr(s1.expr, s2) }
}
is ThrowExpr -> compareExpr(node.expr, (ctx as ThrowExprContext).expr())
is TraceExpr -> compareExpr(node.expr, (ctx as TraceExprContext).expr())
is ImportExpr -> compareSpan(node.importStr, (ctx as ImportExprContext).stringConstant())
is ReadExpr -> compareExpr(node.expr, (ctx as ReadExprContext).expr())
is UnqualifiedAccessExpr -> {
ctx as UnqualifiedAccessExprContext
compareSpan(node.identifier, ctx.Identifier())
compareArgumentList(node.argumentList, ctx.argumentList())
}
is QualifiedAccessExpr -> {
ctx as QualifiedAccessExprContext
compareExpr(node.expr, ctx.expr())
compareSpan(node.identifier, ctx.Identifier())
compareArgumentList(node.argumentList, ctx.argumentList())
}
is SuperAccessExpr -> {
ctx as SuperAccessExprContext
compareSpan(node.identifier, ctx.Identifier())
compareArgumentList(node.argumentList, ctx.argumentList())
}
is SuperSubscriptExpr -> compareExpr(node.arg, (ctx as SuperSubscriptExprContext).expr())
is SubscriptExpr -> {
ctx as SubscriptExprContext
compareExpr(node.expr, ctx.l)
compareExpr(node.arg, ctx.r)
}
is IfExpr -> {
ctx as IfExprContext
compareExpr(node.cond, ctx.c)
compareExpr(node.then, ctx.l)
compareExpr(node.els, ctx.r)
}
is LetExpr -> {
ctx as LetExprContext
compareParameter(node.parameter, ctx.parameter())
compareExpr(node.bindingExpr, ctx.l)
compareExpr(node.expr, ctx.r)
}
is FunctionLiteralExpr -> {
ctx as FunctionLiteralContext
compareParameterList(node.parameterList, ctx.parameterList())
compareExpr(node.expr, ctx.expr())
}
is ParenthesizedExpr -> compareExpr(node.expr, (ctx as ParenthesizedExprContext).expr())
is NewExpr -> {
ctx as NewExprContext
compareType(node.type, ctx.type())
compareObjectBody(node.body, ctx.objectBody())
}
is AmendsExpr -> {
ctx as AmendExprContext
compareExpr(node.expr, ctx.expr())
compareObjectBody(node.body, ctx.objectBody())
}
is NonNullExpr -> compareExpr(node.expr, (ctx as NonNullExprContext).expr())
is UnaryMinusExpr -> compareExpr(node.expr, (ctx as UnaryMinusExprContext).expr())
is LogicalNotExpr -> compareExpr(node.expr, (ctx as LogicalNotExprContext).expr())
is BinaryOperatorExpr -> {
val (l, r) =
when (ctx) {
is ExponentiationExprContext -> ctx.l to ctx.r
is MultiplicativeExprContext -> ctx.l to ctx.r
is AdditiveExprContext -> ctx.l to ctx.r
is ComparisonExprContext -> ctx.l to ctx.r
is EqualityExprContext -> ctx.l to ctx.r
is LogicalAndExprContext -> ctx.l to ctx.r
is LogicalOrExprContext -> ctx.l to ctx.r
is PipeExprContext -> ctx.l to ctx.r
is NullCoalesceExprContext -> ctx.l to ctx.r
else -> throw RuntimeException("unreacheable code")
}
compareExpr(node.left, l)
compareExpr(node.right, r)
}
is TypeCheckExpr -> {
ctx as TypeTestExprContext
compareExpr(node.expr, ctx.expr())
compareType(node.type, ctx.type())
}
is TypeCastExpr -> {
ctx as TypeTestExprContext
compareExpr(node.expr, ctx.expr())
compareType(node.type, ctx.type())
}
else -> {}
}
}
private fun compareArgumentList(node: ArgumentList?, ctx: ArgumentListContext?) {
if (node === null) return
compareSpan(node, ctx!!)
node.arguments.zip(ctx.expr()).forEach { (e1, e2) -> compareExpr(e1, e2) }
}
private fun compareTypeArgumentList(node: TypeArgumentList?, ctx: TypeArgumentListContext?) {
if (node === null) return
compareSpan(node, ctx!!)
node.types.zip(ctx.type()).forEach { (t1, t2) -> compareType(t1, t2) }
}
private fun compareQualifiedIdentifier(
node: QualifiedIdentifier?,
ctx: QualifiedIdentifierContext?,
) {
if (node === null) return
compareSpan(node, ctx!!)
node.identifiers.zip(ctx.Identifier()).forEach { (id1, id2) -> compareSpan(id1, id2) }
}
private fun compareExtendsOrAmendsClause(
node: ExtendsOrAmendsClause?,
ctx: ModuleExtendsOrAmendsClauseContext?,
) {
if (node === null) return
compareSpan(node, ctx!!)
compareSpan(node.url, ctx.stringConstant())
}
private fun compareSpan(node: Node?, ctx: ParserRuleContext) {
if (node != null) {
compareSpan(node, ctx.start.startIndex, ctx.stop.stopIndex)
}
}
private fun compareSpan(node: Node?, ctx: TerminalNode?) {
if (node != null) {
compareSpan(node, ctx!!.symbol.startIndex, ctx.symbol.stopIndex)
}
}
private fun compareSpan(node: Node, charIndex: Int, tokenStop: Int) {
compareSpan(node.span(), charIndex, tokenStop)
}
private fun compareSpan(span: Span, ctx: ParserRuleContext) {
compareSpan(span, ctx.start.startIndex, ctx.stop.stopIndex)
}
private fun compareSpan(span: Span, charIndex: Int, tokenStop: Int) {
val length = tokenStop - charIndex + 1
softly.assertThat(span.charIndex).`as`("$span, index for path: $path").isEqualTo(charIndex)
softly.assertThat(span.length).`as`("$span, length for path: $path").isEqualTo(length)
}
private fun compareDocComment(node: Node?, ctx: TerminalNode?) {
if (node == null) return
val charIndex = ctx!!.symbol.startIndex
// for some reason antlr's doc coments are off by one
val length = ctx.symbol.stopIndex - charIndex
val span = node.span()
softly.assertThat(span.charIndex).`as`("$span, index for path: $path").isEqualTo(charIndex)
softly.assertThat(span.length).`as`("$span, length for path: $path").isEqualTo(length)
}
}

View File

@@ -1,41 +0,0 @@
/*
* 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.core.parser
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
class SpanTest {
@Test
fun `endWith test`() {
var span1 = Span(10, 20)
var span2 = Span(20, 20)
assertThat(span1.endWith(span2)).isEqualTo(Span(10, 30))
span1 = Span(10, 20)
span2 = Span(0, 40)
assertThat(span1.endWith(span2)).isEqualTo(Span(10, 30))
span1 = Span(10, 30)
span2 = Span(20, 20)
assertThat(span1.endWith(span2)).isEqualTo(Span(10, 30))
span1 = Span(10, 30)
span2 = Span(20, 5)
assertThat(span1.endWith(span2)).isEqualTo(Span(10, 15))
}
}