Skip to content

Commit

Permalink
Advanced Type Analysis (#261)
Browse files Browse the repository at this point in the history
  • Loading branch information
jhnaldo authored Oct 31, 2024
1 parent d2c7ab8 commit 1c04850
Show file tree
Hide file tree
Showing 359 changed files with 11,441 additions and 14,743 deletions.
11 changes: 3 additions & 8 deletions .completion
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,19 @@ _esmeta_completions() {
local cur prev opts lastc informats outformats datafiles
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
cmdList="help extract compile build-cfg tycheck parse eval web test262-test inject mutate analyze"
cmdList="help extract compile build-cfg tycheck parse eval web test262-test inject mutate"
globalOpt="-silent -error -status -time -test262dir"
helpOpt=""
extractOpt="-extract:target -extract:log -extract:eval -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:repl-continue -tycheck:ignore -tycheck:update-ignore -tycheck:log -tycheck:detail-log -tycheck:tysens"
tycheckOpt="-tycheck:target -tycheck:repl -tycheck:repl-continue -tycheck:ignore -tycheck:update-ignore -tycheck:log -tycheck:detail-log -tycheck:type-sens -tycheck:infer-guard"
parseOpt="-parse:debug"
evalOpt="-eval:timeout -eval:multiple -eval:log -eval:detail-log"
webOpt="-web:port"
test262testOpt="-test262-test:target -test262-test:features -test262-test:progress -test262-test:coverage -test262-test:timeout -test262-test:with-yet -test262-test:log -test262-test:concurrent -test262-test:verbose"
test262testOpt="-test262-test:target -test262-test:features -test262-test:progress -test262-test:coverage -test262-test:timeout -test262-test:with-yet -test262-test:log -test262-test:detail-log -test262-test:concurrent"
injectOpt="-inject:defs -inject:out -inject:log"
mutateOpt="-mutate:out -mutate:mutator -mutate:untilValid"
analyzeOpt="-analyze:repl"
# completion for commands
case "${COMP_CWORD}" in
1)
Expand Down Expand Up @@ -81,10 +80,6 @@ _esmeta_completions() {
COMPREPLY=($(compgen -W "${globalOpt} ${extractOpt} ${compileOpt} ${buildcfgOpt} ${mutateOpt}"))
return 0
;;
analyze)
COMPREPLY=($(compgen -W "${globalOpt} ${extractOpt} ${compileOpt} ${buildcfgOpt} ${analyzeOpt}"))
return 0
;;
esac
return 0
;;
Expand Down
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ automatically generates language-based tools.
+ [Interactive Execution with ECMAScript Double Debugger](#interactive-execution-with-ecmascript-double-debugger)
+ [Conformance Test Synthesizer from ECMA-262](#conformance-test-synthesizer-from-ecma-262)
+ [Type Analysis on ECMA-262](#type-analysis-on-ecma-262)
+ [Meta-Level Static Analyzer for ECMAScript](#meta-level-static-analyzer-for-ecmascript)
+ [Meta-Level Static Analyzer for ECMAScript](#meta-level-static-analyzer-for-ecmascript) (temporarily removed)
* [Academic Achievement](#academic-achievement)
+ [Publications](#publications)
+ [PLDI 2022 Tutorial](#pldi-2022-tutorial)
Expand Down Expand Up @@ -92,7 +92,7 @@ It supports the following commands:
- `test262-test` tests Test262 tests with harness files (default: tests/test262).
- `inject` injects assertions to check final state of an ECMAScript file.
- `mutate` mutates an ECMAScript program.
- `analyze` analyzes an ECMAScript file using meta-level static analysis.
- `analyze` analyzes an ECMAScript file using meta-level static analysis. (temporarily removed)

and global options:
- `-silent` does not show final results.
Expand Down Expand Up @@ -325,6 +325,12 @@ $ esmeta tycheck -extract:target=2c78e6f

### Meta-Level Static Analyzer for ECMAScript

> :NOTE:
> The meta-level static analyzer is temporarily removed from the current version
> of ESMeta. We are working on the improvement of the meta-level static analyzer
> for ECMAScript/JavaScript programs. We will re-introduce this feature in the
> future version of ESMeta.
ESMeta also supports a meta-level static analyzer for ECMAScript/JavaScript
programs based on mechanized specifications extracted from ECMA-262. A
mechanized specification is an interpreter that can parse and execute JavaScript
Expand Down
17 changes: 6 additions & 11 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ ThisBuild / organization := "esmeta"
ThisBuild / scalacOptions := Seq(
"-language:implicitConversions", // allow implicit conversions
"-deprecation", // emit warning and location for usages of deprecated APIs
"-explain", // explain errors in more detail
"-explain-types", // explain type errors in more detail
"-feature", // emit warning for features that should be imported explicitly
"-unchecked", // enable warnings where generated code depends on assumptions
)
Expand Down Expand Up @@ -75,6 +73,7 @@ lazy val tyContainsTest = taskKey[Unit]("Launch contains tests for ty (tiny)")
lazy val tyStringifyTest =
taskKey[Unit]("Launch stringify tests for ty (tiny)")
lazy val tyJsonTest = taskKey[Unit]("Launch JSON tests for ty (tiny)")
lazy val tyOpTest = taskKey[Unit]("Launch operation tests for ty (tiny)")

// compiler
lazy val compilerTest = taskKey[Unit]("Launch compiler tests")
Expand Down Expand Up @@ -108,10 +107,8 @@ lazy val stateStringifyTest =

// analyzer
lazy val analyzerTest = taskKey[Unit]("Launch analyzer tests")
lazy val analyzerStringifyTest =
taskKey[Unit]("Launch stringify tests for analyzer (tiny)")
lazy val analyzerTypeCheckTest =
taskKey[Unit]("Launch typecheck tests for analyzer (small)")
lazy val analyzerTyCheckTest =
taskKey[Unit]("Launch tycheck tests for analyzer (small)")

// es
lazy val esTest = taskKey[Unit]("Launch ECMAScript tests")
Expand Down Expand Up @@ -230,6 +227,7 @@ lazy val root = project
tyContainsTest := (Test / testOnly).toTask(" *.ty.Contains*Test").value,
tyStringifyTest := (Test / testOnly).toTask(" *.ty.Stringify*Test").value,
tyJsonTest := (Test / testOnly).toTask(" *.ty.Json*Test").value,
tyOpTest := (Test / testOnly).toTask(" *.ty.Op*Test").value,
// compiler
compilerTest := (Test / testOnly).toTask(" *.compiler.*Test").value,
compilerValidityTest := (Test / testOnly)
Expand Down Expand Up @@ -259,11 +257,8 @@ lazy val root = project
.value,
// analyzer
analyzerTest := (Test / testOnly).toTask(" *.analyzer.*Test").value,
analyzerStringifyTest := (Test / testOnly)
.toTask(" *.analyzer.Stringify*Test")
.value,
analyzerTypeCheckTest := (Test / testOnly)
.toTask(" *.analyzer.TypeCheck*Test")
analyzerTyCheckTest := (Test / testOnly)
.toTask(" *.analyzer.TyCheck*Test")
.value,
// es
esTest := (Test / testOnly).toTask(" *.es.*Test").value,
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/manuals/algos/RunJobs.algo
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
1. Perform ? InitializeHostDefinedRealm().
1. Let _scriptEvaluationJob_ be a new Abstract Closure with no parameters that captures nothing and performs the following steps when called:
1. Let _sourceText_ be the source code of a script.
1. Let _script_ be ParseScript(_sourceText_, the current Realm Record, *undefined*).
1. Let _script_ be ParseScript(_sourceText_, the current Realm Record, ~empty~).
1. Perform ? ScriptEvaluation(_script_).
1. Return *undefined*.
1. Perform HostEnqueuePromiseJob(_scriptEvaluationJob_, the current Realm Record).
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,33 @@
diff --git a/spec.html b/spec.html
index dc31c1a3..43d994b9 100644
index dc31c1a3..38978a55 100644
--- a/spec.html
+++ b/spec.html
@@ -42050,7 +42050,7 @@ THH:mm:ss.sss
@@ -23970,6 +23970,7 @@
1. Perform ? FunctionDeclarationInstantiation(_functionObject_, _argumentsList_).
1. Let _G_ be ? OrdinaryCreateFromConstructor(_functionObject_, *"%GeneratorFunction.prototype.prototype%"*, « [[GeneratorState]], [[GeneratorContext]], [[GeneratorBrand]] »).
1. Set _G_.[[GeneratorBrand]] to ~empty~.
+ 1. Set _G_.[[GeneratorState]] to *undefined*.
1. Perform GeneratorStart(_G_, |FunctionBody|).
1. Return Completion Record { [[Type]]: ~return~, [[Value]]: _G_, [[Target]]: ~empty~ }.
</emu-alg>
@@ -24197,6 +24198,7 @@
1. Perform ? FunctionDeclarationInstantiation(_functionObject_, _argumentsList_).
1. Let _generator_ be ? OrdinaryCreateFromConstructor(_functionObject_, *"%AsyncGeneratorFunction.prototype.prototype%"*, « [[AsyncGeneratorState]], [[AsyncGeneratorContext]], [[AsyncGeneratorQueue]], [[GeneratorBrand]] »).
1. Set _generator_.[[GeneratorBrand]] to ~empty~.
+ 1. Set _generator_.[[AsyncGeneratorState]] to *undefined*.
1. Perform AsyncGeneratorStart(_generator_, |FunctionBody|).
1. Return Completion Record { [[Type]]: ~return~, [[Value]]: _generator_, [[Target]]: ~empty~ }.
</emu-alg>
@@ -28928,7 +28930,7 @@
1. Let _F_ be _thisEnvRec_.[[FunctionObject]].
1. Set _inFunction_ to *true*.
1. Set _inMethod_ to _thisEnvRec_.HasSuperBinding().
- 1. If _F_.[[ConstructorKind]] is ~derived~, set _inDerivedConstructor_ to *true*.
+ 1. If IsConstructor(_F_) is *true* and _F_.[[ConstructorKind]] is ~derived~, set _inDerivedConstructor_ to *true*.
1. Let _classFieldInitializerName_ be _F_.[[ClassFieldInitializerName]].
1. If _classFieldInitializerName_ is not ~empty~, set _inClassFieldInitializer_ to *true*.
1. Perform the following substeps in an implementation-defined order, possibly interleaving parsing and error detection:
@@ -42050,7 +42052,7 @@ THH:mm:ss.sss
1. Perform ? GeneratorYield(CreateIterResultObject(_result_, *false*)).
1. NOTE: The number of elements in _entries_ may have increased while execution of this abstract operation was paused by Yield.
1. Set _numEntries_ to the number of elements in _entries_.
Expand All @@ -11,7 +36,7 @@ index dc31c1a3..43d994b9 100644
1. Return CreateIteratorFromClosure(_closure_, *"%MapIteratorPrototype%"*, %MapIteratorPrototype%).
</emu-alg>
</emu-clause>
@@ -42339,7 +42339,7 @@ THH:mm:ss.sss
@@ -42339,7 +42341,7 @@ THH:mm:ss.sss
1. Perform ? GeneratorYield(CreateIterResultObject(_e_, *false*)).
1. NOTE: The number of elements in _entries_ may have increased while execution of this abstract operation was paused by Yield.
1. Set _numEntries_ to the number of elements in _entries_.
Expand Down

This file was deleted.

10 changes: 6 additions & 4 deletions src/main/resources/manuals/funcs/BigInt::exponentiate.ir
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ def <NUM>:BigInt::exponentiate(
exponent: BigInt,
): Normal[BigInt] | Abrupt[throw] = {
if (< exponent 0n) {
call %0 = clo<__NEW_ERROR_OBJ__>("%RangeError.prototype%")
call %1 = clo<ThrowCompletion>(%0)
call %0 = clo<"__NEW_ERROR_OBJ__">("%RangeError.prototype%")
call %1 = clo<"ThrowCompletion">(%0)
return %1
}
if (&& (= base 0n) (= exponent 0n)) {
return 1n
call %2 = clo<"NormalCompletion">(1n)
return %2
}
return (** base exponent)
call %3 = clo<"NormalCompletion">((** base exponent))
return %3
}
5 changes: 3 additions & 2 deletions src/main/resources/manuals/funcs/BigInt::toString.ir
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ def <NUM>:BigInt::toString(
x: BigInt,
radix?: Math,
): String = {
if (= radix absent) return ([str] x) else return ([str radix] x)
}
if (exists radix) return ([str radix] x)
return ([str] x)
}
10 changes: 7 additions & 3 deletions src/main/resources/manuals/funcs/HostEnqueuePromiseJob.ir
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
def HostEnqueuePromiseJob(
job: Clo,
realm: RealmRecord | Null,
realm: Record[RealmRecord] | Null,
): Enum[~unused~] = {
call %0 = clo<GetActiveScriptOrModule>()
let newJob = (record [PendingJob] { "Job" : job, "Realm" : realm, "ScriptOrModule" : %0 })
call %0 = clo<"GetActiveScriptOrModule">()
let newJob = (record {
"Job" : job,
"Realm" : realm,
"ScriptOrModule" : %0,
})
push @JOB_QUEUE < newJob
return ~unused~
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
def HostEnsureCanCompileStrings(
calleeRealm: RealmRecord,
calleeRealm: Record[RealmRecord],
parameterStrings: List[String],
bodyString: String,
direct: Boolean,
): Normal[Enum[~unused~]] | Abrupt[throw] = {
call %0 = clo<NormalCompletion>(~unused~)
call %0 = clo<"NormalCompletion">(~unused~)
return %0
}
}
6 changes: 3 additions & 3 deletions src/main/resources/manuals/funcs/HostFinalizeImportMeta.ir
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
def HostFinalizeImportMeta(
importMeta: Object,
moduleRecord: ModuleRecord,
importMeta: Record[Object],
moduleRecord: Record[ModuleRecord],
): Enum[~unused~] = {
return ~unused~
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
def HostGetImportMetaProperties(
moduleRecord: ModuleRecord,
): List[{ [[Key]]: Symbol | String, [[Value]]: ESValue }] = {
moduleRecord: Record[ModuleRecord],
): List[Record[{ Key: Record[Symbol] | String, Value: ESValue }]] = {
return (list [])
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
def HostPromiseRejectionTracker(
promise: Promise,
promise: Record[Promise],
operation: String["handle", "reject"],
): Enum[~unused~] = {
return ~unused~
}
}
46 changes: 30 additions & 16 deletions src/main/resources/manuals/funcs/INTRINSICS.EvalError.ir
Original file line number Diff line number Diff line change
@@ -1,26 +1,40 @@
def <BUILTIN>:INTRINSICS.EvalError(
this: ESValue,
ArgumentsList: List[ESValue],
NewTarget: Object | Undefined,
NewTarget: Record[Constructor] | Undefined,
): Unknown = {
if (< 0 ArgumentsList.length) let message = (pop < ArgumentsList) else let message = absent
if (< 0 ArgumentsList.length) let options = (pop < ArgumentsList) else let options = absent
%0 = (= NewTarget undefined)
if %0 {
let __args__ = (record)
if (< 0 (sizeof ArgumentsList)) {
pop message < ArgumentsList
expand __args__.message
} else let message = undefined
if (< 0 (sizeof ArgumentsList)) {
pop options < ArgumentsList
expand __args__.options
} else let options = undefined
if (= NewTarget undefined) {
let newTarget = @EXECUTION_STACK[0].Function
} else {
let newTarget = NewTarget
}
call %1 = clo<OrdinaryCreateFromConstructor>(newTarget, "%EvalError.prototype%", (list ["ErrorData"]))
let O = [? %1]
%2 = (! (= message undefined))
if %2 {
call %3 = clo<ToString>(message)
let msg = [? %3]
call %4 = clo<CreateNonEnumerableDataPropertyOrThrow>(O, "message", msg)
[! %4]
call %0 = clo<"OrdinaryCreateFromConstructor">(newTarget, "%EvalError.prototype%", (list ["ErrorData"]))
assert (? %0: Completion)
if (? %0: Abrupt) return %0
else %0 = %0.Value
let O = %0
%1 = (exists __args__.message)
if %1 {
call %2 = clo<"ToString">(message)
assert (? %2: Completion)
if (? %2: Abrupt) return %2
else %2 = %2.Value
let msg = %2
call %3 = clo<"CreateNonEnumerableDataPropertyOrThrow">(O, "message", msg)
}
call %5 = clo<InstallErrorCause>(O, options)
[? %5]
return O
call %4 = clo<"InstallErrorCause">(O, options)
assert (? %4: Completion)
if (? %4: Abrupt) return %4
else %4 = %4.Value
call %5 = clo<"NormalCompletion">(O)
return %5
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
def <BUILTIN>:INTRINSICS.Function.prototype(
this: ESValue,
ArgumentsList: List[ESValue],
NewTarget: Object | Undefined,
NewTarget: Record[Object] | Undefined,
): Unknown = {
return undefined
}
call %0 = clo<"NormalCompletion">(undefined)
return %0
}
Loading

0 comments on commit 1c04850

Please sign in to comment.