Skip to content

Commit

Permalink
Stateless parser API
Browse files Browse the repository at this point in the history
Stateless (static) parser interface. Buffer-reuse optimization is now hidden
behind JNI FFI implementation. Fixes #11121 and prevents similar bugs.
  • Loading branch information
kazcw committed Sep 21, 2024
1 parent c996707 commit ce95e4e
Show file tree
Hide file tree
Showing 19 changed files with 102 additions and 326 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.nio.file.Path;
import java.util.LinkedHashSet;
import java.util.TreeSet;
import org.enso.compiler.core.EnsoParser;
import org.enso.compiler.core.ir.module.scope.imports.Polyglot;
import org.enso.pkg.PackageManager$;
import org.graalvm.nativeimage.hosted.Feature;
Expand Down Expand Up @@ -45,14 +46,14 @@ public void beforeAnalysis(BeforeAnalysisAccess access) {
*/

var classes = new TreeSet<String>();
try (var parser = new org.enso.compiler.core.EnsoParser()) {
try {
for (var p : libs) {
var result = PackageManager$.MODULE$.Default().loadPackage(p.toFile());
if (result.isSuccess()) {
var pkg = result.get();
for (var src : pkg.listSourcesJava()) {
var code = Files.readString(src.file().toPath());
var ir = parser.compile(code);
var ir = EnsoParser.compile(code);
for (var imp : asJava(ir.imports())) {
if (imp instanceof Polyglot poly && poly.entity() instanceof Polyglot.Java entity) {
var name = new StringBuilder(entity.getJavaName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import org.enso.compiler.phase.exports.{
ExportsResolution
}
import org.enso.syntax2.Tree
import org.enso.syntax2.Parser

import java.io.PrintStream
import java.util.concurrent.{
Expand Down Expand Up @@ -69,7 +70,6 @@ class Compiler(
if (config.outputRedirect.isDefined)
new PrintStream(config.outputRedirect.get)
else context.getOut
private lazy val ensoCompiler: EnsoParser = new EnsoParser()

/** Java accessor */
def getConfig(): CompilerConfig = config
Expand Down Expand Up @@ -598,11 +598,8 @@ class Compiler(
)

val src = context.getCharacters(module)
val idMap = context.getIdMap(module)
val tree = ensoCompiler.parse(src)
val expr =
if (idMap == null) ensoCompiler.generateIR(tree)
else ensoCompiler.generateModuleIr(tree, idMap.values)
val idMap = Option(context.getIdMap(module))
val expr = EnsoParser.compile(src, idMap.map(_.values).orNull)

val exprWithModuleExports =
if (context.isSynthetic(module))
Expand Down Expand Up @@ -685,9 +682,8 @@ class Compiler(
inlineContext: InlineContext
): Option[(InlineContext, Expression)] = {
val newContext = inlineContext.copy(freshNameSupply = Some(freshNameSupply))
val tree = ensoCompiler.parse(srcString)

ensoCompiler.generateIRInline(tree).map { ir =>
EnsoParser.compileInline(srcString).map { ir =>
val compilerOutput = runCompilerPhasesInline(ir, newContext)
runErrorHandlingInline(compilerOutput, newContext)
(newContext, compilerOutput)
Expand All @@ -700,7 +696,7 @@ class Compiler(
* @return A Tree representation of `source`
*/
def parseInline(source: CharSequence): Tree =
ensoCompiler.parse(source)
Parser.parse(source)

/** Enhances the provided IR with import/export statements for the provided list
* of fully qualified names of modules. The statements are considered to be "synthetic" i.e. compiler-generated.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ import org.enso.compiler.data.CompilerConfig
import org.enso.common.CompilationStage
import org.enso.compiler.phase.exports.ExportsResolution

import scala.util.Using

/** A phase responsible for initializing the builtins' IR from the provided
* source.
*/
Expand Down Expand Up @@ -44,9 +42,7 @@ object BuiltinsIrBuilder {
freshNameSupply = Some(freshNameSupply),
compilerConfig = CompilerConfig(warningsEnabled = false)
)
val initialIr = Using(new EnsoParser) { compiler =>
compiler.compile(module.getCharacters)
}.get
val initialIr = EnsoParser.compile(module.getCharacters)
val irAfterModDiscovery = passManager.runPassesOnModule(
initialIr,
moduleContext,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import org.enso.text.editing.{IndexedSource, TextEditor}

import java.util.UUID
import scala.collection.mutable
import scala.util.Using

/** The changeset of a module containing the computed list of invalidated
* expressions.
Expand Down Expand Up @@ -97,14 +96,12 @@ final class ChangesetBuilder[A: TextEditor: IndexedSource](
}

val source = Source.newBuilder("enso", value, null).build
Using(new EnsoParser) { compiler =>
compiler
.generateIRInline(compiler.parse(source.getCharacters()))
.flatMap(_ match {
case ir: Literal => Some(ir.setLocation(oldIr.location))
case _ => None
})
}.get
EnsoParser
.compileInline(source.getCharacters())
.flatMap(_ match {
case ir: Literal => Some(ir.setLocation(oldIr.location))
case _ => None
})
}

oldIr match {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,42 +21,6 @@ import org.enso.common.CompilationStage
trait CompilerTestSetup {
// === IR Utilities =========================================================

/** An extension method to allow converting string source code to IR as a
* module.
*
* @param source the source code to convert
*/
implicit private class ToIrModule(source: String) {

/** Converts program text to a top-level Enso module.
*
* @return the [[IR]] representing [[source]]
*/
def toIrModule: Module = {
val compiler = new EnsoParser()
try compiler.compile(source)
finally compiler.close()
}
}

/** An extension method to allow converting string source code to IR as an
* expression.
*
* @param source the source code to convert
*/
implicit private class ToIrExpression(source: String) {

/** Converts the program text to an Enso expression.
*
* @return the [[IR]] representing [[source]], if it is a valid expression
*/
def toIrExpression: Option[Expression] = {
val compiler = new EnsoParser()
try compiler.generateIRInline(compiler.parse(source))
finally compiler.close()
}
}

/** Provides an extension method allowing the running of a specified list of
* passes on the provided IR.
*
Expand Down Expand Up @@ -112,7 +76,7 @@ trait CompilerTestSetup {
* @return IR appropriate for testing the alias analysis pass as a module
*/
def preprocessModule(implicit moduleContext: ModuleContext): Module = {
source.toIrModule.runPasses(passManager, moduleContext)
EnsoParser.compile(source).runPasses(passManager, moduleContext)
}

/** Translates the source code into appropriate IR for testing this pass
Expand All @@ -123,7 +87,9 @@ trait CompilerTestSetup {
def preprocessExpression(implicit
inlineContext: InlineContext
): Option[Expression] = {
source.toIrExpression.map(_.runPasses(passManager, inlineContext))
EnsoParser
.compileInline(source)
.map(_.runPasses(passManager, inlineContext))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,10 @@
import org.enso.compiler.core.EnsoParser;
import org.enso.compiler.core.IR;
import org.enso.compiler.core.ir.Module;
import org.junit.AfterClass;
import org.junit.BeforeClass;

public abstract class CompilerTests {

protected static EnsoParser ensoCompiler;

@BeforeClass
public static void initEnsoParser() {
ensoCompiler = new EnsoParser();
}

@AfterClass
public static void closeEnsoParser() throws Exception {
ensoCompiler.close();
}

protected static Module parse(CharSequence code) {
Module ir = ensoCompiler.compile(code);
Module ir = EnsoParser.compile(code);
assertNotNull("IR was generated", ir);
return ir;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,10 @@
import org.enso.compiler.core.ir.Name;
import org.enso.compiler.core.ir.expression.Comment;
import org.enso.compiler.core.ir.module.scope.Definition;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import scala.Function1;

public class VectorArraySignatureTest {
private static EnsoParser ensoCompiler;

@BeforeClass
public static void initEnsoParser() {
ensoCompiler = new EnsoParser();
}

@AfterClass
public static void closeEnsoParser() throws Exception {
ensoCompiler.close();
ensoCompiler = null;
}

@Test
public void testParseVectorAndArray() throws Exception {
var p = Paths.get("../../distribution/").toFile().getCanonicalFile();
Expand Down Expand Up @@ -81,8 +66,7 @@ public FileVisitResult postVisitDirectory(Path t, IOException ioe) throws IOExce
var vectorSrc = Files.readString(vectorAndArray[1]);

var arrayIR =
ensoCompiler
.compile(arraySrc)
EnsoParser.compile(arraySrc)
.preorder()
.filter(
(v) -> {
Expand All @@ -95,8 +79,7 @@ public FileVisitResult postVisitDirectory(Path t, IOException ioe) throws IOExce
})
.head();
var vectorIR =
ensoCompiler
.compile(vectorSrc)
EnsoParser.compile(vectorSrc)
.preorder()
.filter(
(v) -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,42 +31,6 @@ trait CompilerTest extends AnyWordSpecLike with Matchers with CompilerRunner
trait CompilerRunner {
// === IR Utilities =========================================================

/** An extension method to allow converting string source code to IR as a
* module.
*
* @param source the source code to convert
*/
implicit class ToIrModule(source: String) {

/** Converts program text to a top-level Enso module.
*
* @return the [[IR]] representing [[source]]
*/
def toIrModule: Module = {
val compiler = new EnsoParser()
try compiler.compile(source)
finally compiler.close()
}
}

/** An extension method to allow converting string source code to IR as an
* expression.
*
* @param source the source code to convert
*/
implicit class ToIrExpression(source: String) {

/** Converts the program text to an Enso expression.
*
* @return the [[IR]] representing [[source]], if it is a valid expression
*/
def toIrExpression: Option[Expression] = {
val compiler = new EnsoParser()
try compiler.generateIRInline(compiler.parse(source))
finally compiler.close()
}
}

/** Provides an extension method allowing the running of a specified list of
* passes on the provided IR.
*
Expand Down Expand Up @@ -137,7 +101,7 @@ trait CompilerRunner {
* @return IR appropriate for testing the alias analysis pass as a module
*/
def preprocessModule(implicit moduleContext: ModuleContext): Module = {
source.toIrModule.runPasses(passManager, moduleContext)
EnsoParser.compile(source).runPasses(passManager, moduleContext)
}

/** Translates the source code into appropriate IR for testing this pass
Expand All @@ -148,7 +112,9 @@ trait CompilerRunner {
def preprocessExpression(implicit
inlineContext: InlineContext
): Option[Expression] = {
source.toIrExpression.map(_.runPasses(passManager, inlineContext))
EnsoParser
.compileInline(source)
.map(_.runPasses(passManager, inlineContext))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package org.enso.compiler.test.pass.resolve

import org.enso.compiler.Passes
import org.enso.compiler.context.{FreshNameSupply, ModuleContext}
import org.enso.compiler.core.IR
import org.enso.compiler.core.{EnsoParser, IR}
import org.enso.compiler.core.Implicits.AsMetadata
import org.enso.compiler.core.ir.Expression
import org.enso.compiler.core.ir.Function
Expand Down Expand Up @@ -84,7 +84,7 @@ class GlobalNamesTest extends CompilerTest {
|add_one x = x + 1
|
|""".stripMargin
val parsed = code.toIrModule
val parsed = EnsoParser.compile(code)
val moduleMapped = passManager.runPassesOnModule(parsed, ctx, group1)
ModuleTestUtils.unsafeSetIr(both._2, moduleMapped)

Expand Down
Loading

0 comments on commit ce95e4e

Please sign in to comment.