Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Supported -tycheck:update-ignore #115

Merged
merged 1 commit into from
Nov 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .completion
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ _esmeta_completions() {
extractOpt="-extract:target -extract:log -extract:repl"
compileOpt="-compile:log -compile:log-with-loc"
buildcfgOpt="-build-cfg:log -build-cfg:dot -build-cfg:pdf"
tycheckOpt="-tycheck:target -tycheck:repl -tycheck:ignore -tycheck:log"
tycheckOpt="-tycheck:target -tycheck:repl -tycheck:ignore -tycheck:update-ignore -tycheck:log"
parseOpt="-parse:debug"
evalOpt="-eval:timeout -eval:tycheck -eval:multiple -eval:log"
webOpt="-web:port"
Expand Down
54 changes: 36 additions & 18 deletions src/main/scala/esmeta/analyzer/TypeAnalyzer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ import esmeta.util.SystemUtils.*
private class TypeAnalyzer(
cfg: CFG,
targets: List[Func],
ignorePath: Option[String],
ignoreSet: Set[String],
ignore: TypeAnalyzer.Ignore,
log: Boolean = false,
silent: Boolean = false,
) {
Expand All @@ -24,12 +23,13 @@ private class TypeAnalyzer(
withSem(sem) {
sem.fixpoint
if (log) logging
var unusedSet = ignoreSet
val mismatches = sem.getMismatches.filter {
var unusedSet = ignore.names
val origMismatches = sem.getMismatches
val mismatches = origMismatches.filter {
case mismatch =>
val name = mismatch.name
unusedSet -= name
!ignoreSet.contains(name)
!ignore.names.contains(name)
}
if (!mismatches.isEmpty || !unusedSet.isEmpty)
val app = new Appender
Expand All @@ -43,13 +43,21 @@ private class TypeAnalyzer(
app >> " names are not used to ignore mismatches."
mismatches.toList.map(_.toString).sorted.map(app :> _)
// show help message about how to use the ignorance system
ignorePath.map(path =>
app :> "=" * 80
app :> "To suppress this error message, "
app >> "add/remove the following names to `" >> path >> "`:"
mismatches.map(_.name).toList.sorted.map(app :> " + " >> _)
unusedSet.toList.sorted.map(app :> " - " >> _)
app :> "=" * 80,
ignore.filename.map(path =>
if (ignore.update)
dumpJson(
name = "algorithm names for the ignorance system",
data = origMismatches.map(_.name).toList.sorted,
filename = path,
noSpace = false,
)
else
app :> "=" * 80
app :> "To suppress this error message, "
app >> "add/remove the following names to `" >> path >> "`:"
mismatches.map(_.name).toList.sorted.map(app :> " + " >> _)
unusedSet.toList.sorted.map(app :> " - " >> _)
app :> "=" * 80,
)
throw TypeCheckFail(if (silent) None else Some(app.toString))
sem
Expand Down Expand Up @@ -109,7 +117,7 @@ private class TypeAnalyzer(
)
}
}
object TypeAnalyzer:
object TypeAnalyzer {
// set type domains
initDomain(
stateDomain = state.TypeDomain,
Expand All @@ -127,20 +135,16 @@ object TypeAnalyzer:
def apply(
cfg: CFG,
target: Option[String] = None,
ignore: Option[String] = None,
ignore: Ignore = Ignore(),
log: Boolean = false,
silent: Boolean = false,
): TypeSemantics =
val targets = TypeAnalyzer.getInitTargets(cfg, target, silent)
if (!silent) println(s"- ${targets.size} functions are initial targets.")
val ignoreSet = optional {
readJson[Set[String]](ignore.get)
}.getOrElse(Set())
new TypeAnalyzer(
cfg,
targets,
ignore,
ignoreSet,
log,
silent,
).result
Expand All @@ -159,3 +163,17 @@ object TypeAnalyzer:
warn(s"failed to find functions matched with the pattern `$pattern`.")
funcs
})

/** algorithm names used in ignoring type mismatches */
case class Ignore(
filename: Option[String] = None,
names: Set[String] = Set(),
update: Boolean = false,
)
object Ignore:
def apply(filename: String, update: Boolean): Ignore = Ignore(
filename = Some(filename),
names = optional { readJson[Set[String]](filename) }.getOrElse(Set()),
update = update,
)
}
31 changes: 20 additions & 11 deletions src/main/scala/esmeta/phase/TypeCheck.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package esmeta.phase

import esmeta.*
import esmeta.analyzer.*
import esmeta.analyzer.TypeAnalyzer.Ignore
import esmeta.analyzer.domain
import esmeta.cfg.{CFG, Func}
import esmeta.util.*
Expand All @@ -16,15 +17,17 @@ case object TypeCheck extends Phase[CFG, AbsSemantics] {
cfg: CFG,
cmdConfig: CommandConfig,
config: Config,
): AbsSemantics = TypeAnalyzer(
cfg = cfg,
target = config.target,
ignore = config.ignore match
case None => cfg.spec.manualInfo.tycheckIgnore
case ignore => ignore
,
log = config.log,
)
): AbsSemantics =
val ignorePath = config.ignorePath match
case None => cfg.spec.manualInfo.tycheckIgnore
case path => path
val ignore = ignorePath.fold(Ignore())(Ignore(_, config.ignoreUpdate))
TypeAnalyzer(
cfg = cfg,
target = config.target,
ignore = ignore,
log = config.log,
)

def defaultConfig: Config = Config()
val options: List[PhaseOption[Config]] = List(
Expand All @@ -40,9 +43,14 @@ case object TypeCheck extends Phase[CFG, AbsSemantics] {
),
(
"ignore",
StrOption((c, s) => c.ignore = Some(s)),
StrOption((c, s) => c.ignorePath = Some(s)),
"ignore type mismatches in algorithms listed in a given JSON file.",
),
(
"update-ignore",
BoolOption(c => c.ignoreUpdate = true),
"update the given JSON file used in ignoring type mismatches.",
),
(
"log",
BoolOption(c => c.log = true),
Expand All @@ -51,7 +59,8 @@ case object TypeCheck extends Phase[CFG, AbsSemantics] {
)
case class Config(
var target: Option[String] = None,
var ignore: Option[String] = None,
var ignorePath: Option[String] = None,
var ignoreUpdate: Boolean = false,
var log: Boolean = false,
)
}