Lean2Js.JsSem
The semantics of the generated JavaScript, held inside Lean #
Holds the semantics of the generated JavaScript inside Lean.
What this model assumes #
Numbers are held as Int, with no Number rounding. That is legitimate because the generated code never
handles a bare Number: integer addition, subtraction and multiplication always go through __i53 or
>>> 0, and division goes through BigInt. On top of that we assume the following about IEEE double
precision.
- If the true result is a safe integer, the double-precision result agrees with it
- If the true result is not a safe integer, the double-precision result is not a safe integer either
So "exact integer arithmetic + a range check" returns the same result as real JS's "double-precision
arithmetic + Number.isSafeInteger".
-0 cannot be represented in this model. Agreement on negative zero is the differential test's job.
The guarantee therefore comes in two layers. On the Lean side we check that this model and the reference semantics agree; the differential test on Node checks that the model and the real JS agree.
Lean2Js.Js.JsValue
sourceInstances For
Used by
Lean2Js.Js.instReprJsValue
sourceEquations
- Lean2Js.Js.instReprJsValue = { reprPrec := Lean2Js.Js.instReprJsValue.repr }
Used by
Lean2Js.Js.instReprJsValue.repr
sourceUsed by
Lean2Js.Js.instInhabitedJsValue
sourceEquations
Used by
Lean2Js.Js.JsEnv
sourceEquations
Instances For
Used by
Lean2Js.Js.JsResult
sourceOnly the code of a thrown exception is observed. The generated code throws from nowhere but
__fail.
Equations
Instances For
Used by
Lean2Js.Js.JsValue.beq
sourceEquations
- (Lean2Js.Js.JsValue.num a).beq (Lean2Js.Js.JsValue.num b) = (a == b)
- (Lean2Js.Js.JsValue.bigint a).beq (Lean2Js.Js.JsValue.bigint b) = (a == b)
- (Lean2Js.Js.JsValue.str a).beq (Lean2Js.Js.JsValue.str b) = (a == b)
- (Lean2Js.Js.JsValue.bool a).beq (Lean2Js.Js.JsValue.bool b) = (a == b)
- (Lean2Js.Js.JsValue.obj a).beq (Lean2Js.Js.JsValue.obj b) = Lean2Js.Js.JsValue.beqFields a b
- (Lean2Js.Js.JsValue.arr a).beq (Lean2Js.Js.JsValue.arr b) = Lean2Js.Js.JsValue.beqList a b
- (Lean2Js.Js.JsValue.dict a).beq (Lean2Js.Js.JsValue.dict b) = Lean2Js.Js.JsValue.beqFields a b
- (Lean2Js.Js.JsValue.fn a).beq (Lean2Js.Js.JsValue.fn b) = (a == b)
- x✝¹.beq x✝ = false
Instances For
Used by
Lean2Js.Js.JsValue.beqFields
sourceEquations
Instances For
Used by
Lean2Js.Js.JsValue.beqList
sourceEquations
- Lean2Js.Js.JsValue.beqList [] [] = true
- Lean2Js.Js.JsValue.beqList (a :: as) (b :: bs) = (a.beq b && Lean2Js.Js.JsValue.beqList as bs)
- Lean2Js.Js.JsValue.beqList x✝¹ x✝ = false
Instances For
Used by
Lean2Js.Js.instBEqJsValue
sourceEquations
Used by
Lean2Js.Js.Runtime.safeMax
sourceEquations
- Lean2Js.Js.Runtime.safeMax = 9007199254740991
Instances For
Used by
Lean2Js.Js.Runtime.safeMin
sourceEquations
- Lean2Js.Js.Runtime.safeMin = -9007199254740991
Instances For
Used by
Lean2Js.Js.Runtime.wrap32
sourceEquations
- Lean2Js.Js.Runtime.wrap32 = 4294967296
Instances For
Used by
Lean2Js.Js.Runtime.fail
sourceEquations
- Lean2Js.Js.Runtime.fail code = Except.error code
Instances For
Used by
Lean2Js.Js.Runtime.i53
sourceEquations
- One or more equations did not get rendered due to their size.
Instances For
Used by
Lean2Js.Js.Runtime.i53div
sourceEquations
- Lean2Js.Js.Runtime.i53div a b = if (b == 0) = true then Lean2Js.Js.Runtime.fail "divByZero" else Lean2Js.Js.Runtime.i53 (a.tdiv b)
Instances For
Used by
Lean2Js.Js.Runtime.i53mod
sourceEquations
- Lean2Js.Js.Runtime.i53mod a b = if (b == 0) = true then Lean2Js.Js.Runtime.fail "divByZero" else Lean2Js.Js.Runtime.i53 (a.tmod b)
Instances For
Used by
Lean2Js.Js.Runtime.u32
source>>> 0 is ToUint32: the non-negative representative modulo 2^32.
Equations
Instances For
Used by
Lean2Js.Js.Runtime.u32mul
sourceEquations
Instances For
Used by
Lean2Js.Js.Runtime.u32div
sourceEquations
- Lean2Js.Js.Runtime.u32div a b = if (b == 0) = true then Lean2Js.Js.Runtime.fail "divByZero" else Except.ok (Lean2Js.Js.JsValue.num (Lean2Js.Js.Runtime.u32 (a.tdiv b)))
Instances For
Used by
Lean2Js.Js.Runtime.u32mod
sourceEquations
- Lean2Js.Js.Runtime.u32mod a b = if (b == 0) = true then Lean2Js.Js.Runtime.fail "divByZero" else Except.ok (Lean2Js.Js.JsValue.num (Lean2Js.Js.Runtime.u32 (a.tmod b)))
Instances For
Used by
Lean2Js.Js.Runtime.bigdiv
sourceEquations
- Lean2Js.Js.Runtime.bigdiv a b = if (b == 0) = true then Lean2Js.Js.Runtime.fail "divByZero" else Except.ok (Lean2Js.Js.JsValue.bigint (a.tdiv b))
Instances For
Used by
Lean2Js.Js.Runtime.bigmod
sourceEquations
- Lean2Js.Js.Runtime.bigmod a b = if (b == 0) = true then Lean2Js.Js.Runtime.fail "divByZero" else Except.ok (Lean2Js.Js.JsValue.bigint (a.tmod b))
Instances For
Used by
Lean2Js.Js.Runtime.strcmp
sourceArray.from splits by code point, not by the UTF-16 units JS's < uses.
Equations
- Lean2Js.Js.Runtime.strcmp a b = match compare a.toList b.toList with | Ordering.lt => -1 | Ordering.eq => 0 | Ordering.gt => 1
Instances For
Used by
Lean2Js.Js.Runtime.isSpace
sourceInstances For
Used by
Lean2Js.Js.Runtime.strTrim
sourceEquations
Instances For
Used by
Lean2Js.Js.Runtime.strUpper
sourceEquations
Instances For
Used by
Lean2Js.Js.Runtime.strLower
sourceEquations
Instances For
Used by
Lean2Js.Js.Runtime.digitsValue
sourceThe digits read as a number, with no bound on the answer. A character that is not a digit
contributes its code point less 48; strToInt throws that away by printing the answer back.
Equations
- Lean2Js.Js.Runtime.digitsValue cs = List.foldl (fun (acc : Int) (c : Char) => acc * 10 + (↑c.toNat - 48)) 0 cs
Instances For
Used by
Lean2Js.Js.Runtime.strToInt
sourceWhat __toInt answers: the value, read back and printed again, has to be the string it was handed.
That admits exactly the strings String(n) prints for an Int53, so "007", "+5", " 5" and "-0"
are all refused.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Used by
Lean2Js.Js.Runtime.strIncludes
sourceEquations
- Lean2Js.Js.Runtime.strIncludes needle [] = needle.isEmpty
- Lean2Js.Js.Runtime.strIncludes needle (c :: rest) = (needle.isPrefixOf (c :: rest) || Lean2Js.Js.Runtime.strIncludes needle rest)
Instances For
Used by
Lean2Js.Js.Runtime.strIndexOfChars
sourceWhere needle first sits in the haystack, counted in code points. The empty needle sits at 0.
Equations
- Lean2Js.Js.Runtime.strIndexOfChars [] x✝ = if x✝.isPrefixOf [] = true then some 0 else none
- Lean2Js.Js.Runtime.strIndexOfChars (c :: rest) x✝ = if x✝.isPrefixOf (c :: rest) = true then some 0 else Option.map (fun (x : Nat) => x + 1) (Lean2Js.Js.Runtime.strIndexOfChars rest x✝)
Instances For
Used by
Lean2Js.Js.Runtime.strIndexOf
sourceA position past the safe integers is what __i53 refuses, exactly as a length is.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Used by
Lean2Js.Js.Runtime.strJoinFrom
sourceEquations
- Lean2Js.Js.Runtime.strJoinFrom sep acc [] = acc
- Lean2Js.Js.Runtime.strJoinFrom sep acc (s :: rest) = Lean2Js.Js.Runtime.strJoinFrom sep (acc ++ sep ++ s) rest
Instances For
Used by
Lean2Js.Js.Runtime.strJoin
sourceEquations
- Lean2Js.Js.Runtime.strJoin [] sep = ""
- Lean2Js.Js.Runtime.strJoin (s :: rest) sep = Lean2Js.Js.Runtime.strJoinFrom sep s rest
Instances For
Used by
Lean2Js.Js.Runtime.strRepeatFrom
sources written n times over, one copy at a time.
Equations
Instances For
Used by
Lean2Js.Js.Runtime.strRepeat
sourceA result longer than the safe integers is what __i53 refuses, exactly as a length is. An empty
string answers before the bound is consulted, because no count makes it longer.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Used by
Lean2Js.Js.Runtime.strsOf
sourceAn array holding anything but Strings is past what the compiler builds, so the table leaves it unanswered rather than modelling what JS would print for it.
Equations
- Lean2Js.Js.Runtime.strsOf [] = some []
- Lean2Js.Js.Runtime.strsOf (Lean2Js.Js.JsValue.str s :: rest) = Option.map (fun (x : List String) => s :: x) (Lean2Js.Js.Runtime.strsOf rest)
- Lean2Js.Js.Runtime.strsOf x✝ = none
Instances For
Used by
Lean2Js.Js.Runtime.strsOf_map_str
sourceUsed by
Lean2Js.Js.Runtime.strsOf_eq
sourceUsed by
Lean2Js.Js.Runtime.strSplit
sourceEquations
Instances For
Used by
Lean2Js.Js.Runtime.strSlice
sourceEquations
- One or more equations did not get rendered due to their size.
Instances For
Used by
Lean2Js.Js.Runtime.mapSet
sourceMap.set overwrites in place and appends a key it has not seen, so iteration order survives both.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Used by
Lean2Js.Js.Runtime.mapSetAll
sourceWhat a Map filled from a list of entries holds: each one set in the order the list carries them.
This model holds an object as an association list, which can carry a key twice where a real object
cannot; a Map keeps the last of such a pair, at the place the first took, and saying so here is what
lets a dictionary rebuilt out of an object need nothing of the object's keys.
Equations
- Lean2Js.Js.Runtime.mapSetAll x✝ [] = x✝
- Lean2Js.Js.Runtime.mapSetAll x✝ ((k, v) :: rest) = Lean2Js.Js.Runtime.mapSetAll (Lean2Js.Js.Runtime.mapSet x✝ k v) rest
Instances For
Used by
Lean2Js.Js.Runtime.arrSlice
sourceEquations
- One or more equations did not get rendered due to their size.
Instances For
Used by
Lean2Js.Js.Runtime.at?
sourceEquations
- One or more equations did not get rendered due to their size.
Instances For
Used by
Lean2Js.Js.Runtime.rangeNums
sourceThe whole numbers below n, as the model's numbers.
Equations
- Lean2Js.Js.Runtime.rangeNums n = List.map (fun (k : Nat) => Lean2Js.Js.JsValue.num (Int.ofNat k)) (List.range n.toNat)
Instances For
Used by
Lean2Js.Js.helper
sourceThe runtime helpers the generated code calls. Guarded by the reserved prefix every helper name carries, which is what tells a call to a declaration apart from a call to a helper.
The raised budget is what lets a proof case-split on this table: split builds the splitter with the
options this declaration was elaborated under, not the ones in force where it is called.
Equations
- One or more equations did not get rendered due to their size.
- Lean2Js.Js.helper "__i53" [Lean2Js.Js.JsValue.num a] = if (!Lean2Js.isReserved "__i53") = true then none else some (Lean2Js.Js.Runtime.i53 a)
- Lean2Js.Js.helper "__i53div" [Lean2Js.Js.JsValue.num a, Lean2Js.Js.JsValue.num b] = if (!Lean2Js.isReserved "__i53div") = true then none else some (Lean2Js.Js.Runtime.i53div a b)
- Lean2Js.Js.helper "__i53mod" [Lean2Js.Js.JsValue.num a, Lean2Js.Js.JsValue.num b] = if (!Lean2Js.isReserved "__i53mod") = true then none else some (Lean2Js.Js.Runtime.i53mod a b)
- Lean2Js.Js.helper "__u32mul" [Lean2Js.Js.JsValue.num a, Lean2Js.Js.JsValue.num b] = if (!Lean2Js.isReserved "__u32mul") = true then none else some (Lean2Js.Js.Runtime.u32mul a b)
- Lean2Js.Js.helper "__u32div" [Lean2Js.Js.JsValue.num a, Lean2Js.Js.JsValue.num b] = if (!Lean2Js.isReserved "__u32div") = true then none else some (Lean2Js.Js.Runtime.u32div a b)
- Lean2Js.Js.helper "__u32mod" [Lean2Js.Js.JsValue.num a, Lean2Js.Js.JsValue.num b] = if (!Lean2Js.isReserved "__u32mod") = true then none else some (Lean2Js.Js.Runtime.u32mod a b)
- Lean2Js.Js.helper "__bigdiv" [Lean2Js.Js.JsValue.bigint a, Lean2Js.Js.JsValue.bigint b] = if (!Lean2Js.isReserved "__bigdiv") = true then none else some (Lean2Js.Js.Runtime.bigdiv a b)
- Lean2Js.Js.helper "__bigmod" [Lean2Js.Js.JsValue.bigint a, Lean2Js.Js.JsValue.bigint b] = if (!Lean2Js.isReserved "__bigmod") = true then none else some (Lean2Js.Js.Runtime.bigmod a b)
- Lean2Js.Js.helper "__abs" [Lean2Js.Js.JsValue.num a] = if (!Lean2Js.isReserved "__abs") = true then none else some (Except.ok (Lean2Js.Js.JsValue.num (if a < 0 then -a else a)))
- Lean2Js.Js.helper "__abs" [Lean2Js.Js.JsValue.bigint a] = if (!Lean2Js.isReserved "__abs") = true then none else some (Except.ok (Lean2Js.Js.JsValue.bigint (if a < 0 then -a else a)))
- Lean2Js.Js.helper "__eq" [a, b] = if (!Lean2Js.isReserved "__eq") = true then none else some (Except.ok (Lean2Js.Js.JsValue.bool (a == b)))
- Lean2Js.Js.helper "__at" [Lean2Js.Js.JsValue.arr xs, Lean2Js.Js.JsValue.num i] = if (!Lean2Js.isReserved "__at") = true then none else some (Lean2Js.Js.Runtime.at? xs i)
- Lean2Js.Js.helper "__aconcat" [Lean2Js.Js.JsValue.arr a, Lean2Js.Js.JsValue.arr b] = if (!Lean2Js.isReserved "__aconcat") = true then none else some (Except.ok (Lean2Js.Js.JsValue.arr (a ++ b)))
- Lean2Js.Js.helper "__areverse" [Lean2Js.Js.JsValue.arr xs] = if (!Lean2Js.isReserved "__areverse") = true then none else some (Except.ok (Lean2Js.Js.JsValue.arr xs.reverse))
- Lean2Js.Js.helper "__range" [Lean2Js.Js.JsValue.num n] = if (!Lean2Js.isReserved "__range") = true then none else some (Except.ok (Lean2Js.Js.JsValue.arr (Lean2Js.Js.Runtime.rangeNums n)))
- Lean2Js.Js.helper "__str" [Lean2Js.Js.JsValue.num a] = if (!Lean2Js.isReserved "__str") = true then none else some (Except.ok (Lean2Js.Js.JsValue.str (toString a)))
- Lean2Js.Js.helper "__strlen" [Lean2Js.Js.JsValue.str s] = if (!Lean2Js.isReserved "__strlen") = true then none else some (Except.ok (Lean2Js.Js.JsValue.num ↑s.toList.length))
- Lean2Js.Js.helper "__trim" [Lean2Js.Js.JsValue.str s] = if (!Lean2Js.isReserved "__trim") = true then none else some (Except.ok (Lean2Js.Js.JsValue.str (Lean2Js.Js.Runtime.strTrim s)))
- Lean2Js.Js.helper "__upper" [Lean2Js.Js.JsValue.str s] = if (!Lean2Js.isReserved "__upper") = true then none else some (Except.ok (Lean2Js.Js.JsValue.str (Lean2Js.Js.Runtime.strUpper s)))
- Lean2Js.Js.helper "__lower" [Lean2Js.Js.JsValue.str s] = if (!Lean2Js.isReserved "__lower") = true then none else some (Except.ok (Lean2Js.Js.JsValue.str (Lean2Js.Js.Runtime.strLower s)))
- Lean2Js.Js.helper "__indexOf" [Lean2Js.Js.JsValue.str s, Lean2Js.Js.JsValue.str t] = if (!Lean2Js.isReserved "__indexOf") = true then none else some (Lean2Js.Js.Runtime.strIndexOf s t)
- Lean2Js.Js.helper "__repeat" [Lean2Js.Js.JsValue.str s, Lean2Js.Js.JsValue.num n] = if (!Lean2Js.isReserved "__repeat") = true then none else some (Lean2Js.Js.Runtime.strRepeat s n)
- Lean2Js.Js.helper name args = if (!Lean2Js.isReserved name) = true then none else none
Instances For
Used by
Lean2Js.Js.helper_join
sourceUsed by
Lean2Js.Js.HelperRow
sourceThe calls the table above answers. Stated as an inductive rather than read off helper at the use
site because split builds its splitter in whatever module asks, under options that module cannot
raise, and this table is past what they allow; here the matcher is at hand. A row added to helper
without a constructor here fails helper_row.
Instances For
Used by
Lean2Js.Js.helper_row
sourceUsed by
Lean2Js.Js.helper_of_isBodyName
sourceA declaration's body function is no runtime helper. Every row of the table names a literal, and none
of them carries _ where the body prefix does, so a call the compiler redirects to a body reaches the
module's own function and not the table. Read off HelperRow rather than off helper, for the reason
HelperRow exists.
Used by
Lean2Js.Js.arith
sourceEquations
- Lean2Js.Js.arith "+" (Lean2Js.Js.JsValue.num x) (Lean2Js.Js.JsValue.num y) = Except.ok (Lean2Js.Js.JsValue.num (x + y))
- Lean2Js.Js.arith "-" (Lean2Js.Js.JsValue.num x) (Lean2Js.Js.JsValue.num y) = Except.ok (Lean2Js.Js.JsValue.num (x - y))
- Lean2Js.Js.arith "*" (Lean2Js.Js.JsValue.num x) (Lean2Js.Js.JsValue.num y) = Except.ok (Lean2Js.Js.JsValue.num (x * y))
- Lean2Js.Js.arith ">>>" (Lean2Js.Js.JsValue.num x) (Lean2Js.Js.JsValue.num 0) = Except.ok (Lean2Js.Js.JsValue.num (Lean2Js.Js.Runtime.u32 x))
- Lean2Js.Js.arith "+" (Lean2Js.Js.JsValue.bigint x) (Lean2Js.Js.JsValue.bigint y) = Except.ok (Lean2Js.Js.JsValue.bigint (x + y))
- Lean2Js.Js.arith "-" (Lean2Js.Js.JsValue.bigint x) (Lean2Js.Js.JsValue.bigint y) = Except.ok (Lean2Js.Js.JsValue.bigint (x - y))
- Lean2Js.Js.arith "*" (Lean2Js.Js.JsValue.bigint x) (Lean2Js.Js.JsValue.bigint y) = Except.ok (Lean2Js.Js.JsValue.bigint (x * y))
- Lean2Js.Js.arith "+" (Lean2Js.Js.JsValue.str x) (Lean2Js.Js.JsValue.str y) = Except.ok (Lean2Js.Js.JsValue.str (x ++ y))
- Lean2Js.Js.arith "===" a b = Except.ok (Lean2Js.Js.JsValue.bool (Lean2Js.Js.arith.sameValue a b))
- Lean2Js.Js.arith "!==" a b = Except.ok (Lean2Js.Js.JsValue.bool !Lean2Js.Js.arith.sameValue a b)
- Lean2Js.Js.arith "<" a b = Lean2Js.Js.arith.order a b fun (x : Ordering) => x == Ordering.lt
- Lean2Js.Js.arith "<=" a b = Lean2Js.Js.arith.order a b fun (x : Ordering) => x != Ordering.gt
- Lean2Js.Js.arith ">" a b = Lean2Js.Js.arith.order a b fun (x : Ordering) => x == Ordering.gt
- Lean2Js.Js.arith ">=" a b = Lean2Js.Js.arith.order a b fun (x : Ordering) => x != Ordering.lt
- Lean2Js.Js.arith op a b = Except.error "typeError"
Instances For
Used by
Lean2Js.Js.arith.sameValue
source=== compares values on scalars and references on everything else. The generated code calls
__eq in the latter case, so the model admits only the former.
Equations
- Lean2Js.Js.arith.sameValue (Lean2Js.Js.JsValue.num x_2) (Lean2Js.Js.JsValue.num y) = (x_2 == y)
- Lean2Js.Js.arith.sameValue (Lean2Js.Js.JsValue.bigint x_2) (Lean2Js.Js.JsValue.bigint y) = (x_2 == y)
- Lean2Js.Js.arith.sameValue (Lean2Js.Js.JsValue.str x_2) (Lean2Js.Js.JsValue.str y) = (x_2 == y)
- Lean2Js.Js.arith.sameValue (Lean2Js.Js.JsValue.bool x_2) (Lean2Js.Js.JsValue.bool y) = (x_2 == y)
- Lean2Js.Js.arith.sameValue a✝¹ a✝ = false
Instances For
Used by
Lean2Js.Js.arith.order
sourceEquations
- Lean2Js.Js.arith.order (Lean2Js.Js.JsValue.num a) (Lean2Js.Js.JsValue.num b) keep = Except.ok (Lean2Js.Js.JsValue.bool (keep (compare a b)))
- Lean2Js.Js.arith.order (Lean2Js.Js.JsValue.bigint a) (Lean2Js.Js.JsValue.bigint b) keep = Except.ok (Lean2Js.Js.JsValue.bool (keep (compare a b)))
- Lean2Js.Js.arith.order (Lean2Js.Js.JsValue.str a) (Lean2Js.Js.JsValue.str b) keep = Except.ok (Lean2Js.Js.JsValue.bool (keep (compare a.toList b.toList)))
- Lean2Js.Js.arith.order x y keep = Except.error "typeError"
Instances For
Used by
Reading a field by name #
Everything below asks an object for a key rather than for a position: the order a JavaScript object carries its keys in is not something a caller can be held to.
Lean2Js.Js.lookupField
sourceEquations
- Lean2Js.Js.lookupField fields k = Option.map (fun (x : String × Lean2Js.Js.JsValue) => x.snd) (List.find? (fun (x : String × Lean2Js.Js.JsValue) => x.fst == k) fields)
Instances For
Used by
Lean2Js.Js.sizeOf_lookupField
sourceUsed by
Lean2Js.Js.descRank
sourceWhat a step that does not descend into the value shrinks instead. Entering a mu lands on the
ctors node it binds, and resolving a ref lands on the one its binder holds, so both reach rank one
and every step after that is measured by the value.
Equations
- Lean2Js.Js.descRank (Lean2Js.Js.TyDesc.mu key alts) = 2
- Lean2Js.Js.descRank (Lean2Js.Js.TyDesc.ref up) = 2
- Lean2Js.Js.descRank x✝ = 1
Instances For
Used by
Lean2Js.Js.checkTy
sourceWhether a value matches the type its declaration promised. This mirrors Value.hasTy on every
value a caller can hand over; the two are held together by the vectors that call an exported function
with an argument of the wrong shape. The one value they disagree on is a dictionary holding the same
key twice, which hasTy refuses and this accepts — a Map cannot hold one, and
dictKeysDistinctList is the hypothesis that fences it out of the statements that need the two to
coincide.
A constructor's fields are read by name, so the order they arrive in does not matter and a key the
descriptor does not name is ignored. normTy below is what puts such a value back into the shape
encodeValue writes.
Equations
- One or more equations did not get rendered due to their size.
- Lean2Js.Js.checkTy env (Lean2Js.Js.JsValue.bool b) Lean2Js.Js.TyDesc.bool = true
- Lean2Js.Js.checkTy env (Lean2Js.Js.JsValue.num i) Lean2Js.Js.TyDesc.int53 = (decide (Lean2Js.Js.Runtime.safeMin ≤ i) && decide (i ≤ Lean2Js.Js.Runtime.safeMax))
- Lean2Js.Js.checkTy env (Lean2Js.Js.JsValue.num i) Lean2Js.Js.TyDesc.uint32 = (decide (0 ≤ i) && decide (i < Lean2Js.Js.Runtime.wrap32))
- Lean2Js.Js.checkTy env (Lean2Js.Js.JsValue.str s) Lean2Js.Js.TyDesc.string = true
- Lean2Js.Js.checkTy env (Lean2Js.Js.JsValue.bigint i) Lean2Js.Js.TyDesc.bigint = true
- Lean2Js.Js.checkTy env (Lean2Js.Js.JsValue.arr xs) t.array = Lean2Js.Js.checkList env xs t
- Lean2Js.Js.checkTy env (Lean2Js.Js.JsValue.dict entries) t.dict = Lean2Js.Js.checkEntries env entries t
- Lean2Js.Js.checkTy env (Lean2Js.Js.JsValue.obj fields) t.dictObj = Lean2Js.Js.checkEntries env fields t
- Lean2Js.Js.checkTy env (Lean2Js.Js.JsValue.dict entries) t.dictObj = Lean2Js.Js.checkEntries env entries t
- Lean2Js.Js.checkTy env x✝ (Lean2Js.Js.TyDesc.mu key alts) = Lean2Js.Js.checkTy ((key, alts) :: env) x✝ (Lean2Js.Js.TyDesc.ctors key alts)
- Lean2Js.Js.checkTy env x✝ (Lean2Js.Js.TyDesc.ref up) = match env[up]? with | some b => Lean2Js.Js.checkTy (List.drop up env) x✝ (Lean2Js.Js.TyDesc.ctors b.fst b.snd) | none => false
- Lean2Js.Js.checkTy env x✝¹ x✝ = false
Instances For
Used by
Lean2Js.Js.checkFields
sourceEquations
- One or more equations did not get rendered due to their size.
- Lean2Js.Js.checkFields env fields [] = true
Instances For
Used by
Lean2Js.Js.checkList
sourceEquations
- Lean2Js.Js.checkList env [] x✝ = true
- Lean2Js.Js.checkList env (x_2 :: rest) x✝ = (Lean2Js.Js.checkTy env x_2 x✝ && Lean2Js.Js.checkList env rest x✝)
Instances For
Used by
Lean2Js.Js.checkEntries
sourceEquations
- Lean2Js.Js.checkEntries env [] x✝ = true
- Lean2Js.Js.checkEntries env ((fst, v) :: rest) x✝ = (Lean2Js.Js.checkTy env v x✝ && Lean2Js.Js.checkEntries env rest x✝)
Instances For
Used by
Descriptors a compiled type renders #
Field names a constructor may carry: distinct, and none of them the key the constructor's own name is
carried under. Compile.lean rejects a field named that key, and Decl.lean proves the names distinct
for a well-formed type. Without both, the object this reads by name and the Value the reference
semantics reads by position are different readings.
Lean2Js.Js.namesOk
sourceEquations
Instances For
Used by
Lean2Js.Js.descOk
sourceEquations
- Lean2Js.Js.descOk depth Lean2Js.Js.TyDesc.bool = true
- Lean2Js.Js.descOk depth Lean2Js.Js.TyDesc.int53 = true
- Lean2Js.Js.descOk depth Lean2Js.Js.TyDesc.uint32 = true
- Lean2Js.Js.descOk depth Lean2Js.Js.TyDesc.string = true
- Lean2Js.Js.descOk depth Lean2Js.Js.TyDesc.bigint = true
- Lean2Js.Js.descOk depth t.option = Lean2Js.Js.descOk depth t
- Lean2Js.Js.descOk depth t.array = Lean2Js.Js.descOk depth t
- Lean2Js.Js.descOk depth t.dict = Lean2Js.Js.descOk depth t
- Lean2Js.Js.descOk depth t.dictObj = Lean2Js.Js.descOk depth t
- Lean2Js.Js.descOk depth (ok.result err) = (Lean2Js.Js.descOk depth ok && Lean2Js.Js.descOk depth err)
- Lean2Js.Js.descOk depth (Lean2Js.Js.TyDesc.ctors key alts) = Lean2Js.Js.altsOk depth key alts
- Lean2Js.Js.descOk depth (Lean2Js.Js.TyDesc.mu key alts) = Lean2Js.Js.altsOk (depth + 1) key alts
- Lean2Js.Js.descOk depth (Lean2Js.Js.TyDesc.ref up) = decide (up < depth)
Instances For
Used by
Lean2Js.Js.fieldsOk
sourceEquations
- Lean2Js.Js.fieldsOk depth [] = true
- Lean2Js.Js.fieldsOk depth ((n, t) :: rest) = (Lean2Js.Js.descOk depth t && Lean2Js.Js.fieldsOk depth rest)
Instances For
Used by
Lean2Js.Js.altsOk
sourceEquations
- Lean2Js.Js.altsOk depth key [] = true
- Lean2Js.Js.altsOk depth key ((fst, fields) :: rest) = (Lean2Js.Js.namesOk key fields && Lean2Js.Js.fieldsOk depth fields && Lean2Js.Js.altsOk depth key rest)
Instances For
Used by
Lean2Js.Js.envOk
sourceWhat an environment a ref may be resolved in has to be: each binder's alternatives well formed at
the depth that binder sits at, which is its own plus everything outside it.
Equations
- Lean2Js.Js.envOk [] = true
- Lean2Js.Js.envOk ((key, alts) :: rest) = (Lean2Js.Js.altsOk (rest.length + 1) key alts && Lean2Js.Js.envOk rest)
Instances For
Used by
Lean2Js.Js.envOk_drop
sourceThe environment from a binder outwards is an environment: a ref resolved in it is resolved in one
whose entries are still well formed at the depth they sit at.
Used by
Lean2Js.Js.envOk_getElem
sourceWhat a binder holds is well formed at the depth of the environment it opens.
Used by
Descriptors that reach no dictionary crossing as an object #
The predicates themselves are in Js.lean, beside the descriptor they read, because the compiler
consults them to decide whether a declaration's entry needs a walk out at all. What is here is what a
proof needs of them.
Lean2Js.Js.envNoDictObj_drop
sourceUsed by
Lean2Js.Js.envNoDictObj_getElem
sourceUsed by
Lean2Js.Js.altsNoDictObj_find
sourceUsed by
The canonical shape #
checkTy reads a constructor's fields by name, so a value it accepts may carry them in any order and may
carry keys the descriptor does not name. normTy rebuilds it with the key the constructor's name is
carried under first and the constructor's fields in declared order, dropping the keys the descriptor does
not name, so what reaches the body is the value encodeValue writes.
Lean2Js.Js.normTy
sourceEquations
- One or more equations did not get rendered due to their size.
- Lean2Js.Js.normTy env (Lean2Js.Js.JsValue.arr xs) t.array = Lean2Js.Js.JsValue.arr (Lean2Js.Js.normList env xs t)
- Lean2Js.Js.normTy env (Lean2Js.Js.JsValue.dict entries) t.dict = Lean2Js.Js.JsValue.dict (Lean2Js.Js.normEntries env entries t)
- Lean2Js.Js.normTy env (Lean2Js.Js.JsValue.obj fields) t.dictObj = Lean2Js.Js.JsValue.dict (Lean2Js.Js.Runtime.mapSetAll [] (Lean2Js.Js.normEntries env fields t))
- Lean2Js.Js.normTy env (Lean2Js.Js.JsValue.dict entries) t.dictObj = Lean2Js.Js.JsValue.dict (Lean2Js.Js.normEntries env entries t)
- Lean2Js.Js.normTy env x✝ (Lean2Js.Js.TyDesc.mu key alts) = Lean2Js.Js.normTy ((key, alts) :: env) x✝ (Lean2Js.Js.TyDesc.ctors key alts)
- Lean2Js.Js.normTy env x✝ (Lean2Js.Js.TyDesc.ref up) = match env[up]? with | some b => Lean2Js.Js.normTy (List.drop up env) x✝ (Lean2Js.Js.TyDesc.ctors b.fst b.snd) | none => x✝
- Lean2Js.Js.normTy env x✝¹ x✝ = x✝¹
Instances For
Used by
Lean2Js.Js.normList
sourceEquations
- Lean2Js.Js.normList env [] x✝ = []
- Lean2Js.Js.normList env (x_2 :: rest) x✝ = Lean2Js.Js.normTy env x_2 x✝ :: Lean2Js.Js.normList env rest x✝
Instances For
Used by
Lean2Js.Js.normEntries
sourceEquations
- Lean2Js.Js.normEntries env [] x✝ = []
- Lean2Js.Js.normEntries env ((fst, v) :: rest) x✝ = (fst, Lean2Js.Js.normTy env v x✝) :: Lean2Js.Js.normEntries env rest x✝
Instances For
Used by
Lean2Js.Js.normFields
sourceEquations
Instances For
Used by
The shape a result leaves in #
A dictionary is a Map everywhere inside the module, whatever its declared type says it crosses the
boundary as. outTy is what the entry reads its result through: the walk normTy does, differing at
exactly one node — a dictObj becomes the plain object a consumer can stringify, where normTy on the
way in made the Map the body runs on.
Everywhere else the two agree, so a return type reaching no dictObj is handed back untouched and the
entry emits no wrapper at all.
Lean2Js.Js.outTy
sourceEquations
- One or more equations did not get rendered due to their size.
- Lean2Js.Js.outTy env (Lean2Js.Js.JsValue.arr xs) t.array = Lean2Js.Js.JsValue.arr (Lean2Js.Js.outList env xs t)
- Lean2Js.Js.outTy env (Lean2Js.Js.JsValue.dict entries) t.dict = Lean2Js.Js.JsValue.dict (Lean2Js.Js.outEntries env entries t)
- Lean2Js.Js.outTy env (Lean2Js.Js.JsValue.dict entries) t.dictObj = Lean2Js.Js.JsValue.obj (Lean2Js.Js.outEntries env entries t)
- Lean2Js.Js.outTy env x✝ (Lean2Js.Js.TyDesc.mu key alts) = Lean2Js.Js.outTy ((key, alts) :: env) x✝ (Lean2Js.Js.TyDesc.ctors key alts)
- Lean2Js.Js.outTy env x✝ (Lean2Js.Js.TyDesc.ref up) = match env[up]? with | some b => Lean2Js.Js.outTy (List.drop up env) x✝ (Lean2Js.Js.TyDesc.ctors b.fst b.snd) | none => x✝
- Lean2Js.Js.outTy env x✝¹ x✝ = x✝¹
Instances For
Used by
Lean2Js.Js.outList
sourceEquations
- Lean2Js.Js.outList env [] x✝ = []
- Lean2Js.Js.outList env (x_2 :: rest) x✝ = Lean2Js.Js.outTy env x_2 x✝ :: Lean2Js.Js.outList env rest x✝
Instances For
Used by
Lean2Js.Js.outEntries
sourceEquations
- Lean2Js.Js.outEntries env [] x✝ = []
- Lean2Js.Js.outEntries env ((fst, v) :: rest) x✝ = (fst, Lean2Js.Js.outTy env v x✝) :: Lean2Js.Js.outEntries env rest x✝
Instances For
Used by
Lean2Js.Js.outFields
sourceEquations
Instances For
Used by
Dictionaries a Map could have produced #
checkTy never looks at a dictionary's keys, because the value it is handed is a Map and a Map
cannot hold one key twice. This model holds a dictionary as an association list, which can carry what no
Map can, so a claim about what the generated code accepts has to say it is looking at the values the
runtime actually hands it.
Lean2Js.Js.keysDistinct
sourceEquations
- Lean2Js.Js.keysDistinct [] = true
- Lean2Js.Js.keysDistinct (s :: rest) = (!rest.contains s && Lean2Js.Js.keysDistinct rest)
Instances For
Used by
Lean2Js.Js.dictKeysDistinct
sourceEquations
- One or more equations did not get rendered due to their size.
- Lean2Js.Js.dictKeysDistinct (Lean2Js.Js.JsValue.obj fields) = Lean2Js.Js.dictKeysDistinctFields fields
- Lean2Js.Js.dictKeysDistinct (Lean2Js.Js.JsValue.arr xs) = Lean2Js.Js.dictKeysDistinctList xs
- Lean2Js.Js.dictKeysDistinct x✝ = true
Instances For
Used by
Lean2Js.Js.dictKeysDistinctFields
sourceEquations
Instances For
Used by
Lean2Js.Js.dictKeysDistinctList
sourceEquations
Instances For
Used by
Lean2Js.Js.bindAll
sourceEquations
- Lean2Js.Js.bindAll (n :: ns) (v :: vs) = (n, v) :: Lean2Js.Js.bindAll ns vs
- Lean2Js.Js.bindAll x✝¹ x✝ = []
Instances For
Used by
Lean2Js.Js.calleeName
sourceThe function a call lands on. A binding holding a function shadows the module's own, the way a local name shadows a function declaration in real JavaScript; anything else bound to the name is not something the compiler emits a call through.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Used by
Lean2Js.Js.keyLe
sourceThe order __sortBy puts its keys in. A number is compared with <= and a string through
__strcmp, which is the code-point order the rest of the model already uses for < on two strings.
Equations
- Lean2Js.Js.keyLe (Lean2Js.Js.JsValue.num a) (Lean2Js.Js.JsValue.num b) = decide (a ≤ b)
- Lean2Js.Js.keyLe (Lean2Js.Js.JsValue.str a) (Lean2Js.Js.JsValue.str b) = (compare a.toList b.toList != Ordering.gt)
- Lean2Js.Js.keyLe x✝¹ x✝ = false
Instances For
Used by
Lean2Js.Js.isNumKey
sourceEquations
Instances For
Used by
Lean2Js.Js.isStrKey
sourceEquations
Instances For
Used by
Lean2Js.Js.keysOk
sourceEquations
- One or more equations did not get rendered due to their size.
Instances For
Used by
Lean2Js.Js.sortPairs
sourceThe keys are asked to be all numbers or all strings, which is more than the helper asks and exactly
what the key type gives. Mixing them would put __strcmp on a number, which the model has no answer
for.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Used by
Lean2Js.Js.eval
sourceEvaluation of the generated code. && and || short-circuit as they do in JS.
Equations
- One or more equations did not get rendered due to their size.
- Lean2Js.Js.eval m 0 env e = Except.error "outOfFuel"
- Lean2Js.Js.eval m n.succ env (Lean2Js.Js.Expr.num i) = Except.ok (Lean2Js.Js.JsValue.num i)
- Lean2Js.Js.eval m n.succ env (Lean2Js.Js.Expr.bigLit i) = Except.ok (Lean2Js.Js.JsValue.bigint i)
- Lean2Js.Js.eval m n.succ env (Lean2Js.Js.Expr.str s) = Except.ok (Lean2Js.Js.JsValue.str s)
- Lean2Js.Js.eval m n.succ env (Lean2Js.Js.Expr.bool b) = Except.ok (Lean2Js.Js.JsValue.bool b)
- Lean2Js.Js.eval m n.succ env (Lean2Js.Js.Expr.unary op e_2) = Except.error "typeError"
- Lean2Js.Js.eval m n.succ env (Lean2Js.Js.Expr.binary op lhs rhs) = do let a ← Lean2Js.Js.eval m n env lhs let b ← Lean2Js.Js.eval m n env rhs Lean2Js.Js.arith op a b
- Lean2Js.Js.eval m n.succ env (Lean2Js.Js.Expr.arrayLit items) = do let __do_lift ← Lean2Js.Js.evalList m n env items Except.ok (Lean2Js.Js.JsValue.arr __do_lift)
- Lean2Js.Js.eval m n.succ env (Lean2Js.Js.Expr.out d x_1) = do let v ← Lean2Js.Js.eval m n env x_1 Except.ok (Lean2Js.Js.outTy [] v d)
- Lean2Js.Js.eval m n.succ env (scrut.foldJs key spec binder body) = do let __do_lift ← Lean2Js.Js.eval m n env scrut Lean2Js.Js.evalFoldJs m n env key spec binder body __do_lift
Instances For
Used by
Lean2Js.Js.evalList
sourceEquations
- Lean2Js.Js.evalList m fuel env [] = Except.ok []
- Lean2Js.Js.evalList m fuel env (e :: rest) = do let v ← Lean2Js.Js.eval m fuel env e let vs ← Lean2Js.Js.evalList m fuel env rest Except.ok (v :: vs)
Instances For
Used by
Lean2Js.Js.evalMapJs
sourceThe combinators are walked here rather than modelled as a function value handed to a helper, so that nothing in the model is ever a closure.
Equations
Instances For
Used by
Lean2Js.Js.evalFilterJs
sourceEquations
Instances For
Used by
Lean2Js.Js.evalFindJs
sourceEquations
- One or more equations did not get rendered due to their size.
- Lean2Js.Js.evalFindJs m fuel env binder body [] = Except.ok (Lean2Js.Js.JsValue.obj [("tag", Lean2Js.Js.JsValue.str "none")])
Instances For
Used by
Lean2Js.Js.evalQuantJs
sourceEquations
- One or more equations did not get rendered due to their size.
- Lean2Js.Js.evalQuantJs m fuel env op binder body [] = Except.ok (Lean2Js.Js.JsValue.bool (op == Lean2Js.Core.QuantOp.all))
Instances For
Used by
Lean2Js.Js.evalReduceJs
sourceEquations
- One or more equations did not get rendered due to their size.
- Lean2Js.Js.evalReduceJs m fuel env accName elemName body acc [] = Except.ok acc
Instances For
Used by
Lean2Js.Js.evalFoldJs
sourceWhat __fold computes, walked here rather than reached as a call to the helper, the way mapJs is:
the node is rebuilt out of the fields the spec names, with each field that came round replaced by the
answer for it, and body runs on the rebuilt node with binder bound to it.
A field the spec names and the node does not carry is a missing property read, which this model refuses
exactly as member does — real JavaScript reads undefined there, and a node the entry check accepted
carries every field its constructor declares.
Equations
- One or more equations did not get rendered due to their size.
- Lean2Js.Js.evalFoldJs m fuel env key spec binder body v = Except.error "typeError"
Instances For
Used by
Lean2Js.Js.evalFoldList
sourceEquations
Instances For
Used by
Lean2Js.Js.evalFoldListAt
sourceA field the spec says holds a list of the type coming round. Anything but an array is a value the entry check would not have let through, so the walk refuses it rather than guessing.
Equations
- Lean2Js.Js.evalFoldListAt m fuel env key spec binder body (Lean2Js.Js.JsValue.arr xs) = Lean2Js.Js.evalFoldList m fuel env key spec binder body xs
- Lean2Js.Js.evalFoldListAt m fuel env key spec binder body v = Except.error "typeError"
Instances For
Used by
Lean2Js.Js.evalFoldPairs
sourceEquations
Instances For
Used by
Lean2Js.Js.evalStmts
sourceEquations
- Lean2Js.Js.evalStmts m fuel env [] = Except.error "typeError"
- Lean2Js.Js.evalStmts m fuel env (Lean2Js.Js.Stmt.ret e :: tail) = Lean2Js.Js.eval m fuel env e
- Lean2Js.Js.evalStmts m fuel env (Lean2Js.Js.Stmt.const name val :: rest) = do let v ← Lean2Js.Js.eval m fuel env val Lean2Js.Js.evalStmts m fuel ((name, v) :: env) rest
Instances For
Used by
Unfolding the fold walk #
The fold family recurses on the value rather than on the fuel, under the same five-component measure
eval is defined by, so Lean does not hand back its equations as definitional unfoldings the way it
does for a definition structural in its argument like evalMapJs. These state them once, so the
agreement proof rewrites with a lemma where the map proofs rewrite with Js.evalMapJs itself.
They are the twins of Eval.evalFold_obj and the five under it, against JsValue rather than Value
and reading the spec the compiler emitted rather than the declaration the spec came from.
Lean2Js.Js.evalFoldJs_obj
sourceUsed by
Lean2Js.Js.evalFoldList_nil
sourceUsed by
Lean2Js.Js.evalFoldList_cons
sourceUsed by
Lean2Js.Js.evalFoldListAt_arr
sourceUsed by
Lean2Js.Js.evalFoldPairs_nil
sourceUsed by
Lean2Js.Js.evalFoldPairs_cons_none
sourceUsed by
Lean2Js.Js.evalFoldPairs_cons_some
sourceUsed by
Lean2Js.Js.callFunctionAt
sourceCalling an exported function at a stated amount of fuel. The model's fuel is what makes eval total;
real JavaScript has none, so a claim about the generated code is stated for every large enough amount and
callFunction fixes the one the shipped artifact is checked at.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Used by
Lean2Js.Js.eval_call
sourceA call evaluates its arguments and then runs the callee, which is what callFunctionAt does.
Used by
Lean2Js.Js.callFunction
sourceEquations
- Lean2Js.Js.callFunction m name args = Lean2Js.Js.callFunctionAt m 10000 name args