Skip to content

Commit

Permalink
Split up source files
Browse files Browse the repository at this point in the history
  • Loading branch information
propensive committed Jun 24, 2024
1 parent 76307ee commit 66b6ec1
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 90 deletions.
23 changes: 23 additions & 0 deletions src/plugin/larceny-plugin.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
Larceny, version [unreleased]. Copyright 2024 Jon Pretty, Propensive OÜ.
The primary distribution site is: https://propensive.com/
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
http://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 larceny

def demilitarize(code: Matchable): List[CompileError] = code match
case xs: List[CompileError] @unchecked => xs
case _ => Nil

def procrastinate(errors: List[CompileError]): List[CompileError] = errors
21 changes: 21 additions & 0 deletions src/plugin/larceny.CompileError.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
Larceny, version [unreleased]. Copyright 2024 Jon Pretty, Propensive OÜ.
The primary distribution site is: https://propensive.com/
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
http://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 larceny

case class CompileError(ordinal: Int, message: String, code: String, start: Int, offset: Int):
def id: CompileErrorId = CompileErrorId.fromOrdinal(ordinal + 1)
def point: Int = start + offset
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,6 @@

package larceny

def demilitarize(code: Matchable): List[CompileError] = code match
case xs: List[CompileError] @unchecked => xs
case _ => Nil

def procrastinate(errors: List[CompileError]): List[CompileError] = errors

case class CompileError(ordinal: Int, message: String, code: String, start: Int, offset: Int):
def id: CompileErrorId = CompileErrorId.fromOrdinal(ordinal + 1)
def point: Int = start + offset

object CompileErrorId:
def unapply(compileError: CompileError): Some[CompileErrorId] = Some(compileError.id)

Expand Down
27 changes: 27 additions & 0 deletions src/plugin/larceny.LarcenyPlugin.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
Larceny, version [unreleased]. Copyright 2024 Jon Pretty, Propensive OÜ.
The primary distribution site is: https://propensive.com/
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
http://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 larceny

import dotty.tools.*, dotc.*, core.*, Contexts.*, plugins.*

import language.adhocExtensions

class LarcenyPlugin() extends StandardPlugin:
val name: String = "larceny"
override val description: String = "capture errors"
override def initialize(options: List[String])(using Context): List[PluginPhase] =
List(LarcenyTransformer())
93 changes: 93 additions & 0 deletions src/plugin/larceny.LarcenyTransformer.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
Larceny, version [unreleased]. Copyright 2024 Jon Pretty, Propensive OÜ.
The primary distribution site is: https://propensive.com/
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
http://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 larceny

import dotty.tools.*, dotc.*, util.*, ast.Trees.*, ast.tpd, core.*,
Constants.Constant, Contexts.*, Decorators.*, StdNames.*, plugins.*

import scala.collection.mutable as scm

import language.adhocExtensions

class LarcenyTransformer() extends PluginPhase:
import tpd.*

val phaseName = "errorcap"
override val runsAfter = Set("parser")
override val runsBefore = Set("typer")

override def transformUnit(tree: Tree)(using Context): Tree =
import ast.untpd.*
val classpath = ctx.settings.classpath.value

object collector extends UntypedTreeMap:
val regions: scm.ListBuffer[(Int, Int)] = scm.ListBuffer()

override def transform(tree: Tree)(using Context): Tree = tree match
case Apply(Ident(name), List(body)) if name.toString == "demilitarize" =>
try regions += (body.span.start -> body.span.end) catch case err: AssertionError => ()
tree

case _ =>
super.transform(tree)

collector.transform(ctx.compilationUnit.untpdTree)
val regions = collector.regions.to(Set)
val source = String(ctx.compilationUnit.source.content)

val errors: List[CompileError] =
Subcompiler.compile(ctx.settings.classpath.value, source, regions)

object transformer extends UntypedTreeMap:

override def transform(tree: Tree)(using Context): Tree = tree match
case Apply(Ident(name), List(content)) if name.toString == "procrastinate" =>
val source2 = source.substring(content.span.start, content.span.end)
val javaClasspath = System.getProperty("java.class.path").nn
Apply(Select(Select(Select(Ident(nme.ROOTPKG), "larceny".toTermName),
"Subcompiler".toTermName), "compile".toTermName), List(
Literal(Constant(javaClasspath+":"+ctx.settings.classpath.value)),
Literal(Constant(source2))
))

case Apply(Ident(name), List(content)) if name.toString == "demilitarize" =>
val captured = errors.filter: error =>
try error.point >= content.span.start && error.point <= content.span.end
catch case err: AssertionError => false

val msgs = captured.map: error =>
Apply(
Select(Select(Ident(nme.ROOTPKG), "larceny".toTermName), "CompileError".toTermName),
List(
Literal(Constant(error.ordinal)),
Literal(Constant(error.message)),
Literal(Constant(error.code)),
Literal(Constant(error.start)),
Literal(Constant(error.offset))
)
)

Apply
(Ident(name),
List
(Block(List(), Apply(Select(Select(Ident(nme.ROOTPKG), nme.scala), nme.List), msgs))))

case _ =>
super.transform(tree)

ctx.compilationUnit.untpdTree = transformer.transform(ctx.compilationUnit.untpdTree)
super.transformUnit(tree)
79 changes: 1 addition & 78 deletions src/plugin/plugin.scala → src/plugin/larceny.Subcompiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,97 +16,20 @@

package larceny

import dotty.tools.*, dotc.*, util.*, reporting.*, ast.Trees.*, ast.tpd, core.*,
Constants.Constant, Contexts.*, Decorators.*, StdNames.*, plugins.*
import dotty.tools.*, dotc.*, util.*, reporting.*, core.*, Contexts.*

import scala.util.chaining.*
import scala.collection.mutable as scm

import language.adhocExtensions

class LarcenyPlugin() extends StandardPlugin:
val name: String = "larceny"
override val description: String = "capture errors"
override def initialize(options: List[String])(using Context): List[PluginPhase] =
List(LarcenyTransformer())

class LarcenyTransformer() extends PluginPhase:
import tpd.*

val phaseName = "errorcap"
override val runsAfter = Set("parser")
override val runsBefore = Set("typer")

override def transformUnit(tree: Tree)(using Context): Tree =
import ast.untpd.*
val classpath = ctx.settings.classpath.value

object collector extends UntypedTreeMap:
val regions: scm.ListBuffer[(Int, Int)] = scm.ListBuffer()

override def transform(tree: Tree)(using Context): Tree = tree match
case Apply(Ident(name), List(body)) if name.toString == "demilitarize" =>
try regions += (body.span.start -> body.span.end) catch case err: AssertionError => ()
tree

case _ =>
super.transform(tree)

collector.transform(ctx.compilationUnit.untpdTree)
val regions = collector.regions.to(Set)
val source = String(ctx.compilationUnit.source.content)

val errors: List[CompileError] =
Subcompiler.compile(ctx.settings.classpath.value, source, regions)

object transformer extends UntypedTreeMap:

override def transform(tree: Tree)(using Context): Tree = tree match
case Apply(Ident(name), List(content)) if name.toString == "procrastinate" =>
val source2 = source.substring(content.span.start, content.span.end)
val javaClasspath = System.getProperty("java.class.path").nn
Apply(Select(Select(Select(Ident(nme.ROOTPKG), "larceny".toTermName),
"Subcompiler".toTermName), "compile".toTermName), List(
Literal(Constant(javaClasspath+":"+ctx.settings.classpath.value)),
Literal(Constant(source2))
))

case Apply(Ident(name), List(content)) if name.toString == "demilitarize" =>
val captured = errors.filter: error =>
try error.point >= content.span.start && error.point <= content.span.end
catch case err: AssertionError => false

val msgs = captured.map: error =>
Apply(
Select(Select(Ident(nme.ROOTPKG), "larceny".toTermName), "CompileError".toTermName),
List(
Literal(Constant(error.ordinal)),
Literal(Constant(error.message)),
Literal(Constant(error.code)),
Literal(Constant(error.start)),
Literal(Constant(error.offset))
)
)

Apply
(Ident(name),
List
(Block(List(), Apply(Select(Select(Ident(nme.ROOTPKG), nme.scala), nme.List), msgs))))

case _ =>
super.transform(tree)

ctx.compilationUnit.untpdTree = transformer.transform(ctx.compilationUnit.untpdTree)
super.transformUnit(tree)

object Subcompiler:
val Scala3: Compiler = new Compiler()

class CustomReporter() extends Reporter, UniqueMessagePositions, HideNonSensicalMessages:
val errors: scm.ListBuffer[CompileError] = scm.ListBuffer()

def doReport(diagnostic: Diagnostic)(using Context): Unit =
println(diagnostic)
try
val pos = diagnostic.pos
val code = String(ctx.compilationUnit.source.content.slice(pos.start, pos.end))
Expand Down
3 changes: 3 additions & 0 deletions src/plugin/soundness+larceny-plugin.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package soundness

export larceny.{demilitarize, procrastinate, CompileError, CompileErrorId}
2 changes: 0 additions & 2 deletions src/test/example.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import larceny.*

import CompileErrorId.*

@main def run(): Unit =
val errors = demilitarize:
compiletime.error("it failed")
Expand Down

0 comments on commit 66b6ec1

Please sign in to comment.