From 50d69c3c86bd30f212194ce129c76dd37efab8fa Mon Sep 17 00:00:00 2001 From: jhnaldo Date: Tue, 29 Nov 2022 16:20:46 +0900 Subject: [PATCH] Supported -tycheck:update-ignore --- .completion | 2 +- .../scala/esmeta/analyzer/TypeAnalyzer.scala | 54 ++++++++++++------- src/main/scala/esmeta/phase/TypeCheck.scala | 31 +++++++---- 3 files changed, 57 insertions(+), 30 deletions(-) diff --git a/.completion b/.completion index 63b02bb9f3..fa82205ec4 100644 --- a/.completion +++ b/.completion @@ -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" diff --git a/src/main/scala/esmeta/analyzer/TypeAnalyzer.scala b/src/main/scala/esmeta/analyzer/TypeAnalyzer.scala index 978bbc57bb..ae66bf01b4 100644 --- a/src/main/scala/esmeta/analyzer/TypeAnalyzer.scala +++ b/src/main/scala/esmeta/analyzer/TypeAnalyzer.scala @@ -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, ) { @@ -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 @@ -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 @@ -109,7 +117,7 @@ private class TypeAnalyzer( ) } } -object TypeAnalyzer: +object TypeAnalyzer { // set type domains initDomain( stateDomain = state.TypeDomain, @@ -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 @@ -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, + ) +} diff --git a/src/main/scala/esmeta/phase/TypeCheck.scala b/src/main/scala/esmeta/phase/TypeCheck.scala index 998f52255d..5333e94638 100644 --- a/src/main/scala/esmeta/phase/TypeCheck.scala +++ b/src/main/scala/esmeta/phase/TypeCheck.scala @@ -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.* @@ -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( @@ -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), @@ -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, ) }