Merge branch 'master' into merge

This commit is contained in:
Arseny Kapoulkine 2022-03-04 08:19:44 -08:00
commit 600b8a483a
54 changed files with 1960 additions and 336 deletions

View File

@ -1,25 +1,10 @@
name: prototyping
on:
push:
branches:
- 'master'
- 'prototyping-*'
paths:
- '.github/workflows/**'
- 'prototyping/**'
- 'Analysis/**'
- 'Ast/**'
- 'CLI/Ast.cpp'
- 'CLI/FileUtils.*'
pull_request:
paths:
- '.github/workflows/**'
- '.github/workflows/prototyping.yml'
- 'prototyping/**'
- 'Analysis/**'
- 'Ast/**'
- 'CLI/Ast.cpp'
- 'CLI/FileUtils.*'
jobs:
linux:
@ -52,8 +37,7 @@ jobs:
- name: check targets
working-directory: prototyping
run: |
~/.cabal/bin/agda Examples.agda
~/.cabal/bin/agda Properties.agda
~/.cabal/bin/agda Everything.agda
- name: build executables
working-directory: prototyping
run: |

View File

@ -64,7 +64,7 @@ Makefile builds combine both into a single target and can be ran via `make test`
Luau uses C++ as its implementation language. The runtime requires C++11, whereas the compiler and analysis components require C++17. It should build without issues using Microsoft Visual Studio 2017 or later, or gcc-7 or clang-7 or later.
Other than the STL/CRT, Luau library components don't have external dependencies. The test suite depends on [doctest](https://github.com/onqtam/doctest) testing framework, and the REPL command-line depends on [cpp-linenoise](https://github.com/yhirose/cpp-linenoise).
Other than the STL/CRT, Luau library components don't have external dependencies. The test suite depends on [doctest](https://github.com/onqtam/doctest) testing framework, and the REPL command-line depends on [isocline](https://github.com/daanx/isocline).
# License

View File

@ -0,0 +1,164 @@
---
layout: single
title: "Luau Recap: February 2022"
---
Luau is our new language that you can read more about at [https://luau-lang.org](https://luau-lang.org).
[Cross-posted to the [Roblox Developer Forum](https://devforum.roblox.com/t/luau-recap-february-2022/).]
## Default type alias type parameters
We have introduced a syntax to provide default type arguments inside the type alias type parameter list.
It is now possible to have type functions where the instantiation can omit some type arguments.
You can provide concrete types:
```lua
--!strict
type FieldResolver<T, Data = {[string]: any}> = (T, Data) -> number
local a: FieldResolver<number> = ...
local b: FieldResolver<number, {name: string}> = ...
```
Or reference parameters defined earlier in the list:
```lua
--!strict
type EqComp<T, U = T> = (l: T, r: U) -> boolean
local a: EqComp<number> = ... -- (l: number, r: number) -> boolean
local b: EqComp<number, string> = ... -- (l: number, r: string) -> boolean
```
Type pack parameters can also have a default type pack:
```lua
--!strict
type Process<T, U... = ...string> = (T) -> U...
local a: Process<number> = ... -- (number) -> ...string
local b: Process<number, (boolean, string)> = ... -- (number) -> (boolean, string)
```
If all type parameters have a default type, it is now possible to reference that without providing any type arguments:
```lua
--!strict
type All<T = string, U = number> = (T) -> U
local a: All -- ok
local b: All<> -- ok as well
```
For more details, you can read the original [RFC proposal](https://github.com/Roblox/luau/blob/master/rfcs/syntax-default-type-alias-type-parameters.md).
## Typechecking improvements
This month we had many fixes to improve our type inference and reduce false positive errors.
if-then-else expression can now have different types in each branch:
```lua
--!strict
local a = if x then 5 else nil -- 'a' will have type 'number?'
local b = if x then 1 else '2' -- 'b' will have type 'number | string'
```
And if the expected result type is known, you will not get an error in cases like these:
```lua
--!strict
type T = {number | string}
-- different array element types don't give an error if that is expected
local c: T = if x then {1, "x", 2, "y"} else {0}
```
---
`assert` result is now known to not be 'falsy' (`false` or `nil`):
```lua
--!strict
local function f(x: number?): number
return assert(x) -- no longer an error
end
```
---
We fixed cases where length operator `#` reported an error when used on a compatible type:
```lua
--!strict
local union: {number} | {string}
local a = #union -- no longer an error
```
---
Functions with different variadic argument/return types are no longer compatible:
```lua
--!strict
local function f(): (number, ...string)
return 2, "a", "b"
end
local g: () -> (number, ...boolean) = f -- error
```
---
We have also fixed:
* false positive errors caused by incorrect reuse of generic types across different function declarations
* issues with forward-declared intersection types
* wrong return type annotation for table.move
* various crashes reported by developers
## Linter improvements
A new static analysis warning was introduced to mark incorrect use of a '`a and b or c`' pattern. When 'b' is 'falsy' (`false` or `nil`), result will always be 'c', even if the expression 'a' was true:
```lua
local function f(x: number)
-- The and-or expression always evaluates to the second alternative because the first alternative is false; consider using if-then-else expression instead
return x < 0.5 and false or 42
end
```
Like we say in the warning, new if-then-else expression doesn't have this pitfall:
```lua
local function g(x: number)
return if x < 0.5 then false else 42
end
```
---
We have also introduced a check for misspelled comment directives:
```lua
--!non-strict
-- ^ Unknown comment directive 'non-strict'; did you mean 'nonstrict'?
```
## Performance improvements
For performance, we have changed how our Garbage Collector collects unreachable memory.
This rework makes it possible to free memory 2.5x faster and also comes with a small change to how we store Luau objects in memory. For example, each table now uses 16 fewer bytes on 64-bit platforms.
Another optimization was made for `select(_, ...)` call.
It is now using a special fast path that has constant-time complexity in number of arguments (~3x faster with 10 arguments).
## Thanks
A special thanks to all the fine folks who contributed PRs this month!
* [mikejsavage](https://github.com/mikejsavage)
* [TheGreatSageEqualToHeaven](https://github.com/TheGreatSageEqualToHeaven)
* [petrihakkinen](https://github.com/petrihakkinen)

View File

@ -2,10 +2,8 @@
*.agdai
Main
MAlonzo
Examples
PrettyPrinter
Interpreter
Properties
!Tests/Interpreter
!Tests/PrettyPrinter
.ghc.*

View File

@ -0,0 +1,8 @@
{-# OPTIONS --rewriting #-}
module Everything where
import Examples
import Properties
import PrettyPrinter
import Interpreter

View File

@ -1,8 +1,10 @@
{-# OPTIONS --rewriting #-}
module Examples.OpSem where
open import Luau.OpSem using (_⊢_⟶ᴱ_⊣_; _⊢_⟶ᴮ_⊣_; subst)
open import Luau.Syntax using (Block; var; nil; local_←_; _∙_; done; return; block_is_end)
open import Luau.Syntax using (Block; var; val; nil; local_←_; _∙_; done; return; block_is_end)
open import Luau.Heap using ()
ex1 : (local (var "x") nil return (var "x") done) ⟶ᴮ (return nil done)
ex1 = subst
ex1 : (local (var "x") val nil return (var "x") done) ⟶ᴮ (return (val nil) done)
ex1 = subst nil

View File

@ -4,22 +4,20 @@ module Examples.Run where
open import Agda.Builtin.Equality using (_≡_; refl)
open import Agda.Builtin.Bool using (true; false)
open import Luau.Syntax using (nil; var; _$_; function_is_end; return; _∙_; done; _⟨_⟩; number; binexp; +; <; true; false)
open import Luau.Value using (nil; number; bool)
open import Luau.Syntax using (nil; var; _$_; function_is_end; return; _∙_; done; _⟨_⟩; number; binexp; +; <; val; bool; ~=; string)
open import Luau.Run using (run; return)
open import Luau.Heap using (lookup-next; next-emp; lookup-next-emp)
import Agda.Builtin.Equality.Rewrite
{-# REWRITE lookup-next next-emp lookup-next-emp #-}
ex1 : (run (function "id" var "x" is return (var "x") done end return (var "id" $ nil) done) return nil _)
ex1 : (run (function "id" var "x" is return (var "x") done end return (var "id" $ val nil) done) return nil _)
ex1 = refl
ex2 : (run (function "fn" var "x" is return (number 123.0) done end return (var "fn" $ nil) done) return (number 123.0) _)
ex2 : (run (function "fn" var "x" is return (val (number 123.0)) done end return (var "fn" $ val nil) done) return (number 123.0) _)
ex2 = refl
ex3 : (run (function "fn" var "x" is return (binexp (number 1.0) + (number 2.0)) done end return (var "fn" $ nil) done) return (number 3.0) _)
ex3 : (run (function "fn" var "x" is return (binexp (val (number 1.0)) + (val (number 2.0))) done end return (var "fn" $ val nil) done) return (number 3.0) _)
ex3 = refl
ex4 : (run (function "fn" var "x" is return (binexp (number 1.0) < (number 2.0)) done end return (var "fn" $ nil) done) return (bool true) _)
ex4 : (run (function "fn" var "x" is return (binexp (val (number 1.0)) < (val (number 2.0))) done end return (var "fn" $ val nil) done) return (bool true) _)
ex4 = refl
ex5 : (run (function "fn" var "x" is return (binexp (val (string "foo")) ~= (val (string "bar"))) done end return (var "fn" $ val nil) done) return (bool true) _)
ex5 = refl

View File

@ -2,7 +2,7 @@ module Examples.Syntax where
open import Agda.Builtin.Equality using (_≡_; refl)
open import FFI.Data.String using (_++_)
open import Luau.Syntax using (var; _$_; return; nil; function_is_end; local_←_; done; _∙_; _⟨_⟩)
open import Luau.Syntax using (var; _$_; return; val; nil; function_is_end; local_←_; done; _∙_; _⟨_⟩)
open import Luau.Syntax.ToString using (exprToString; blockToString)
ex1 : exprToString(function "" var "x" is return (var "f" $ var "x") done end)
@ -11,7 +11,7 @@ ex1 : exprToString(function "" ⟨ var "x" ⟩ is return (var "f" $ var "x") ∙
"end"
ex1 = refl
ex2 : blockToString(local var "x" nil return (var "x") done)
ex2 : blockToString(local var "x" (val nil) return (var "x") done)
"local x = nil\n" ++
"return x"
ex2 = refl

View File

@ -25,3 +25,4 @@ ex6 = refl
ex7 : typeToString((nil nil) ((nil (nil nil)) nil)) "((nil) -> nil | (nil) -> (nil) -> nil)?"
ex7 = refl

View File

@ -1,15 +1,21 @@
{-# OPTIONS --rewriting #-}
module FFI.Data.Aeson where
open import Agda.Builtin.Equality using (_≡_)
open import Agda.Builtin.Equality.Rewrite using ()
open import Agda.Builtin.Bool using (Bool)
open import Agda.Builtin.String using (String)
open import FFI.Data.ByteString using (ByteString)
open import FFI.Data.HaskellString using (HaskellString; pack)
open import FFI.Data.Maybe using (Maybe)
open import FFI.Data.Maybe using (Maybe; just; nothing)
open import FFI.Data.Either using (Either; mapLeft)
open import FFI.Data.Scientific using (Scientific)
open import FFI.Data.Vector using (Vector)
open import Properties.Equality using (_≢_)
{-# FOREIGN GHC import qualified Data.Aeson #-}
{-# FOREIGN GHC import qualified Data.Aeson.Key #-}
{-# FOREIGN GHC import qualified Data.Aeson.KeyMap #-}
@ -19,14 +25,35 @@ postulate
Key : Set
fromString : String Key
toString : Key String
empty : {A} KeyMap A
singleton : {A} Key A (KeyMap A)
insert : {A} Key A (KeyMap A) (KeyMap A)
delete : {A} Key (KeyMap A) (KeyMap A)
unionWith : {A} (A A A) (KeyMap A) (KeyMap A) (KeyMap A)
lookup : {A} Key -> KeyMap A -> Maybe A
{-# POLARITY KeyMap ++ #-}
{-# COMPILE GHC KeyMap = type Data.Aeson.KeyMap.KeyMap #-}
{-# COMPILE GHC Key = type Data.Aeson.Key.Key #-}
{-# COMPILE GHC fromString = Data.Aeson.Key.fromText #-}
{-# COMPILE GHC toString = Data.Aeson.Key.toText #-}
{-# COMPILE GHC empty = \_ -> Data.Aeson.KeyMap.empty #-}
{-# COMPILE GHC singleton = \_ -> Data.Aeson.KeyMap.singleton #-}
{-# COMPILE GHC insert = \_ -> Data.Aeson.KeyMap.insert #-}
{-# COMPILE GHC delete = \_ -> Data.Aeson.KeyMap.delete #-}
{-# COMPILE GHC unionWith = \_ -> Data.Aeson.KeyMap.unionWith #-}
{-# COMPILE GHC lookup = \_ -> Data.Aeson.KeyMap.lookup #-}
postulate lookup-insert : {A} k v (m : KeyMap A) (lookup k (insert k v m) just v)
postulate lookup-empty : {A} k (lookup {A} k empty nothing)
postulate lookup-insert-not : {A} j k v (m : KeyMap A) (j k) (lookup k m lookup k (insert j v m))
postulate singleton-insert-empty : {A} k (v : A) (singleton k v insert k v empty)
postulate insert-swap : {A} j k (v w : A) m (j k) insert j v (insert k w m) insert k w (insert j v m)
postulate insert-over : {A} j k (v w : A) m (j k) insert j v (insert k w m) insert j v m
postulate to-from : k toString(fromString k) k
postulate from-to : k fromString(toString k) k
{-# REWRITE lookup-insert lookup-empty singleton-insert-empty #-}
data Value : Set where
object : KeyMap Value Value
array : Vector Value Value

View File

@ -1,8 +1,14 @@
module FFI.Data.Maybe where
open import Agda.Builtin.Equality using (_≡_; refl)
{-# FOREIGN GHC import qualified Data.Maybe #-}
data Maybe (A : Set) : Set where
nothing : Maybe A
just : A Maybe A
{-# COMPILE GHC Maybe = data Data.Maybe.Maybe (Data.Maybe.Nothing|Data.Maybe.Just) #-}
just-inv : {A} {x y : A} (just x just y) (x y)
just-inv refl = refl

View File

@ -1,11 +1,15 @@
{-# OPTIONS --rewriting #-}
module FFI.Data.Vector where
open import Agda.Builtin.Equality using (_≡_)
open import Agda.Builtin.Equality.Rewrite using ()
open import Agda.Builtin.Int using (Int; pos; negsuc)
open import Agda.Builtin.Nat using (Nat)
open import Agda.Builtin.Bool using (Bool; false; true)
open import FFI.Data.HaskellInt using (HaskellInt; haskellIntToInt; intToHaskellInt)
open import FFI.Data.Maybe using (Maybe; just; nothing)
open import Properties.Equality using (_≢_)
{-# FOREIGN GHC import qualified Data.Vector #-}
@ -30,8 +34,13 @@ postulate
{-# COMPILE GHC snoc = \_ -> Data.Vector.snoc #-}
postulate length-empty : {A} (length (empty {A}) 0)
postulate lookup-empty : {A} n (lookup (empty {A}) n nothing)
postulate lookup-snoc : {A} (x : A) (v : Vector A) (lookup (snoc v x) (length v) just x)
postulate lookup-length : {A} (v : Vector A) (lookup v (length v) nothing)
postulate lookup-snoc-empty : {A} (x : A) (lookup (snoc empty x) 0 just x)
postulate lookup-snoc-not : {A n} (x : A) (v : Vector A) (n length v) (lookup v n lookup (snoc v x) n)
{-# REWRITE length-empty lookup-snoc lookup-length lookup-snoc-empty lookup-empty #-}
head : {A} (Vector A) (Maybe A)
head vec with null vec

View File

@ -1,3 +1,5 @@
{-# OPTIONS --rewriting #-}
module Interpreter where
open import Agda.Builtin.IO using (IO)
@ -7,31 +9,41 @@ open import Agda.Builtin.Unit using ()
open import FFI.IO using (getContents; putStrLn; _>>=_; _>>_)
open import FFI.Data.Aeson using (Value; eitherDecode)
open import FFI.Data.Either using (Left; Right)
open import FFI.Data.Maybe using (just; nothing)
open import FFI.Data.String using (String; _++_)
open import FFI.Data.Text.Encoding using (encodeUtf8)
open import FFI.System.Exit using (exitWith; ExitFailure)
open import Luau.Syntax using (Block)
open import Luau.StrictMode.ToString using (warningToStringᴮ)
open import Luau.Syntax using (Block; yes; maybe; isAnnotatedᴮ)
open import Luau.Syntax.FromJSON using (blockFromJSON)
open import Luau.Syntax.ToString using (blockToString)
open import Luau.Syntax.ToString using (blockToString; valueToString)
open import Luau.Run using (run; return; done; error)
open import Luau.RuntimeError.ToString using (errToStringᴮ)
open import Luau.Value.ToString using (valueToString)
runBlock : {a} Block a IO
runBlock block with run block
runBlock block | return V D = putStrLn (valueToString V)
runBlock block | done D = putStrLn "nil"
runBlock block | error E D = putStrLn (errToStringᴮ E)
open import Properties.StrictMode using (wellTypedProgramsDontGoWrong)
runBlock : a Block a IO
runBlock a block with run block
runBlock a block | return V D = putStrLn ("\nRAN WITH RESULT: " ++ valueToString V)
runBlock a block | done D = putStrLn ("\nRAN")
runBlock maybe block | error E D = putStrLn ("\nRUNTIME ERROR:\n" ++ errToStringᴮ _ E)
runBlock yes block | error E D with wellTypedProgramsDontGoWrong _ block _ D E
runBlock yes block | error E D | W = putStrLn ("\nRUNTIME ERROR:\n" ++ errToStringᴮ _ E ++ "\n\nTYPE ERROR:\n" ++ warningToStringᴮ _ W)
runBlock : Block maybe IO
runBlock B with isAnnotatedᴮ B
runBlock B | nothing = putStrLn ("UNANNOTATED PROGRAM:\n" ++ blockToString B) >> runBlock maybe B
runBlock B | just B = putStrLn ("ANNOTATED PROGRAM:\n" ++ blockToString B) >> runBlock yes B
runJSON : Value IO
runJSON value with blockFromJSON(value)
runJSON value | (Left err) = putStrLn ("Luau error: " ++ err) >> exitWith (ExitFailure (pos 1))
runJSON value | (Left err) = putStrLn ("LUAU ERROR: " ++ err) >> exitWith (ExitFailure (pos 1))
runJSON value | (Right block) = runBlock block
runString : String IO
runString txt with eitherDecode (encodeUtf8 txt)
runString txt | (Left err) = putStrLn ("JSON error: " ++ err) >> exitWith (ExitFailure (pos 1))
runString txt | (Left err) = putStrLn ("JSON ERROR: " ++ err) >> exitWith (ExitFailure (pos 1))
runString txt | (Right value) = runJSON value
main : IO

View File

@ -5,13 +5,14 @@ open import Agda.Builtin.Equality using (_≡_)
open import Agda.Builtin.Nat using (Nat; _==_)
open import Agda.Builtin.String using (String)
open import Agda.Builtin.TrustMe using (primTrustMe)
open import Properties.Dec using (Dec; yes; no; )
open import Properties.Dec using (Dec; yes; no)
open import Properties.Equality using (_≢_)
Addr : Set
Addr = Nat
_≡ᴬ_ : (a b : Addr) Dec (a b)
a ≡ᴬ b with a == b
a ≡ᴬ b | false = no p where postulate p : (a b)
a ≡ᴬ b | false = no p where postulate p : (a b)
a ≡ᴬ b | true = yes primTrustMe

View File

@ -1,32 +1,39 @@
{-# OPTIONS --rewriting #-}
module Luau.Heap where
open import Agda.Builtin.Equality using (_≡_)
open import FFI.Data.Maybe using (Maybe; just)
open import FFI.Data.Vector using (Vector; length; snoc; empty)
open import Luau.Addr using (Addr)
open import Agda.Builtin.Equality using (_≡_; refl)
open import FFI.Data.Maybe using (Maybe; just; nothing)
open import FFI.Data.Vector using (Vector; length; snoc; empty; lookup-snoc-not)
open import Luau.Addr using (Addr; _≡ᴬ_)
open import Luau.Var using (Var)
open import Luau.Syntax using (Block; Expr; Annotated; FunDec; nil; addr; function_is_end)
open import Luau.Syntax using (Block; Expr; Annotated; FunDec; nil; function_is_end)
open import Properties.Equality using (_≢_; trans)
open import Properties.Remember using (remember; _,_)
open import Properties.Dec using (yes; no)
data HeapValue (a : Annotated) : Set where
function_is_end : FunDec a Block a HeapValue a
-- Heap-allocated objects
data Object (a : Annotated) : Set where
function_is_end : FunDec a Block a Object a
Heap : Annotated Set
Heap a = Vector (HeapValue a)
Heap a = Vector (Object a)
data _≡_⊕_↦_ {a} : Heap a Heap a Addr HeapValue a Set where
data _≡_⊕_↦_ {a} : Heap a Heap a Addr Object a Set where
defn : {H val}
-----------------------------------
(snoc H val) H (length H) val
_[_] : {a} Heap a Addr Maybe (HeapValue a)
_[_] : {a} Heap a Addr Maybe (Object a)
_[_] = FFI.Data.Vector.lookup
: {a} Heap a
= empty
data AllocResult a (H : Heap a) (V : HeapValue a) : Set where
data AllocResult a (H : Heap a) (V : Object a) : Set where
ok : b H (H H b V) AllocResult a H V
alloc : {a} H V AllocResult a H V
@ -35,15 +42,8 @@ alloc H V = ok (length H) (snoc H V) defn
next : {a} Heap a Addr
next = length
allocated : {a} Heap a HeapValue a Heap a
allocated : {a} Heap a Object a Heap a
allocated = snoc
-- next-emp : (length ∅ ≡ 0)
next-emp = FFI.Data.Vector.length-empty
-- lookup-next : ∀ V H → (lookup (allocated H V) (next H) ≡ just V)
lookup-next = FFI.Data.Vector.lookup-snoc
-- lookup-next-emp : ∀ V → (lookup (allocated emp V) 0 ≡ just V)
lookup-next-emp = FFI.Data.Vector.lookup-snoc-empty
lookup-not-allocated : {a} {H H : Heap a} {b c O} (H H b O) (c b) (H [ c ] H [ c ])
lookup-not-allocated {H = H} {O = O} defn p = lookup-snoc-not O H p

View File

@ -1,66 +1,55 @@
{-# OPTIONS --rewriting #-}
module Luau.OpSem where
open import Agda.Builtin.Equality using (_≡_)
open import Agda.Builtin.Float using (Float; primFloatPlus; primFloatMinus; primFloatTimes; primFloatDiv; primFloatEquality; primFloatLess; primFloatInequality)
open import Agda.Builtin.Bool using (Bool; true; false)
open import Agda.Builtin.String using (primStringEquality; primStringAppend)
open import Utility.Bool using (not; _or_; _and_)
open import Agda.Builtin.Nat using (_==_)
open import FFI.Data.Maybe using (just)
open import Agda.Builtin.Nat using () renaming (_==_ to _==ᴬ_)
open import FFI.Data.Maybe using (Maybe; just; nothing)
open import Luau.Heap using (Heap; _≡_⊕_↦_; _[_]; function_is_end)
open import Luau.Substitution using (_[_/_]ᴮ)
open import Luau.Syntax using (Expr; Stat; Block; nil; addr; var; function_is_end; _$_; block_is_end; local_←_; _∙_; done; return; name; fun; arg; binexp; BinaryOperator; +; -; *; /; <; >; ≡; ≅; ≤; ≥; number)
open import Luau.Value using (addr; val; number; Value; bool)
open import Luau.Syntax using (Value; Expr; Stat; Block; nil; addr; val; var; function_is_end; _$_; block_is_end; local_←_; _∙_; done; return; name; fun; arg; binexp; BinaryOperator; +; -; *; /; <; >; ==; ~=; <=; >=; ··; number; bool; string)
open import Luau.RuntimeType using (RuntimeType; valueType)
open import Properties.Product using (_×_; _,_)
evalNumOp : Float BinaryOperator Float Value
evalNumOp x + y = number (primFloatPlus x y)
evalNumOp x - y = number (primFloatMinus x y)
evalNumOp x * y = number (primFloatTimes x y)
evalNumOp x / y = number (primFloatDiv x y)
evalNumOp x < y = bool (primFloatLess x y)
evalNumOp x > y = bool (primFloatLess y x)
evalNumOp x y = bool (primFloatEquality x y)
evalNumOp x y = bool (primFloatInequality x y)
evalNumOp x y = bool ((primFloatLess x y) or (primFloatEquality x y))
evalNumOp x y = bool ((primFloatLess y x) or (primFloatEquality x y))
evalEqOp : Value Value Bool
evalEqOp Value.nil Value.nil = true
evalEqOp (addr x) (addr y) = (x == y)
evalEqOp (number x) (number y) = primFloatEquality x y
evalEqOp (bool true) (bool y) = y
evalEqOp (bool false) (bool y) = not y
evalEqOp _ _ = false
evalEqOp : Value Value Value
evalEqOp Value.nil Value.nil = bool true
evalEqOp (addr x) (addr y) = bool (x == y)
evalEqOp (number x) (number y) = bool (primFloatEquality x y)
evalEqOp (bool true) (bool y) = bool y
evalEqOp (bool false) (bool y) = bool (not y)
evalEqOp _ _ = bool false
evalNeqOp : Value Value Bool
evalNeqOp (number x) (number y) = primFloatInequality x y
evalNeqOp x y = not (evalEqOp x y)
evalNeqOp : Value Value Value
evalNeqOp Value.nil Value.nil = bool false
evalNeqOp (addr x) (addr y) = bool (not (x == y))
evalNeqOp (number x) (number y) = bool (primFloatInequality x y)
evalNeqOp (bool true) (bool y) = bool (not y)
evalNeqOp (bool false) (bool y) = bool y
evalNeqOp _ _ = bool true
coerceToBool : Value Bool
coerceToBool Value.nil = false
coerceToBool (addr x) = true
coerceToBool (number x) = true
coerceToBool (bool x) = x
data _⟦_⟧_⟶_ : Value BinaryOperator Value Value Set where
+ : m n (number m) + (number n) number (primFloatPlus m n)
- : m n (number m) - (number n) number (primFloatMinus m n)
/ : m n (number m) / (number n) number (primFloatTimes m n)
* : m n (number m) * (number n) number (primFloatDiv m n)
< : m n (number m) < (number n) bool (primFloatLess m n)
> : m n (number m) > (number n) bool (primFloatLess n m)
<= : m n (number m) <= (number n) bool ((primFloatLess m n) or (primFloatEquality m n))
>= : m n (number m) >= (number n) bool ((primFloatLess n m) or (primFloatEquality m n))
== : v w v == w bool (evalEqOp v w)
~= : v w v ~= w bool (evalNeqOp v w)
·· : x y (string x) ·· (string y) string (primStringAppend x y)
data _⊢_⟶ᴮ_⊣_ {a} : Heap a Block a Block a Heap a Set
data _⊢_⟶ᴱ_⊣_ {a} : Heap a Expr a Expr a Heap a Set
data _⊢_⟶ᴱ_⊣_ where
nil : {H}
-------------------
H nil ⟶ᴱ nil H
function : {H H a F B}
function : a {H H F B}
H H a (function F is B end)
-------------------------------------------
H (function F is B end) ⟶ᴱ (addr a) H
H (function F is B end) ⟶ᴱ val(addr a) H
app₁ : {H H M M N}
@ -68,17 +57,18 @@ data _⊢_⟶ᴱ_⊣_ where
-----------------------------
H (M $ N) ⟶ᴱ (M $ N) H
app₂ : {H H V N N}
app₂ : v {H H N N}
H N ⟶ᴱ N H
-----------------------------
H (val V $ N) ⟶ᴱ (val V $ N) H
H (val v $ N) ⟶ᴱ (val v $ N) H
beta : {H a F B V}
beta : O v {H a F B}
H [ a ] just(function F is B end)
(O function F is B end)
H [ a ] just(O)
-----------------------------------------------------------------------------
H (addr a $ val V) ⟶ᴱ (block (fun F) is (B [ V / name(arg F) ]ᴮ) end) H
H (val (addr a) $ val v) ⟶ᴱ (block (fun F) is (B [ v / name(arg F) ]ᴮ) end) H
block : {H H B B b}
@ -86,44 +76,34 @@ data _⊢_⟶ᴱ_⊣_ where
----------------------------------------------------
H (block b is B end) ⟶ᴱ (block b is B end) H
return : {H V B b}
return : v {H B b}
--------------------------------------------------------
H (block b is return (val V) B end) ⟶ᴱ (val V) H
H (block b is return (val v) B end) ⟶ᴱ val v H
done : {H b}
---------------------------------
H (block b is done end) ⟶ᴱ nil H
--------------------------------------------
H (block b is done end) ⟶ᴱ (val nil) H
binOpEquality :
{H x y}
---------------------------------------------------------------------------
H (binexp (val x) BinaryOperator.≡ (val y)) ⟶ᴱ (val (evalEqOp x y)) H
binOp₀ : {H op v₁ v₂ w}
binOpInequality :
{H x y}
----------------------------------------------------------------------------
H (binexp (val x) BinaryOperator.≅ (val y)) ⟶ᴱ (val (evalNeqOp x y)) H
v₁ op v₂ w
--------------------------------------------------
H (binexp (val v₁) op (val v₂)) ⟶ᴱ (val w) H
binOpNumbers :
{H x op y}
-----------------------------------------------------------------------
H (binexp (number x) op (number y)) ⟶ᴱ (val (evalNumOp x op y)) H
binOp₁ : {H H x x op y}
binOp₁ :
{H H x x op y}
H x ⟶ᴱ x H
---------------------------------------------
H (binexp x op y) ⟶ᴱ (binexp x op y) H
binOp₂ :
{H H x op y y}
binOp₂ : {H H x op y y}
H y ⟶ᴱ y H
---------------------------------------------
H (binexp x op y) ⟶ᴱ (binexp x op y) H
data _⊢_⟶ᴮ_⊣_ where
local : {H H x M M B}
@ -132,16 +112,16 @@ data _⊢_⟶ᴮ_⊣_ where
-------------------------------------------------
H (local x M B) ⟶ᴮ (local x M B) H
subst : {H x v B}
subst : v {H x B}
------------------------------------------------------
H (local x val v B) ⟶ᴮ (B [ v / name x ]ᴮ) H
function : {H H a F B C}
function : a {H H F B C}
H H a (function F is C end)
--------------------------------------------------------------
H (function F is C end B) ⟶ᴮ (B [ addr a / fun F ]ᴮ) H
H (function F is C end B) ⟶ᴮ (B [ addr a / name(fun F) ]ᴮ) H
return : {H H M M B}

View File

@ -1,15 +1,16 @@
{-# OPTIONS --rewriting #-}
module Luau.Run where
open import Agda.Builtin.Equality using (_≡_; refl)
open import Luau.Heap using (Heap; )
open import Luau.Syntax using (Block; return; _∙_; done)
open import Luau.Syntax using (Block; val; return; _∙_; done)
open import Luau.OpSem using (_⊢_⟶*_⊣_; refl; step)
open import Luau.Value using (val)
open import Properties.Step using (stepᴮ; step; return; done; error)
open import Luau.RuntimeError using (RuntimeErrorᴮ)
data RunResult {a} (H : Heap a) (B : Block a) : Set where
return : V {B H} (H B ⟶* (return (val V) B) H) RunResult H B
return : v {B H} (H B ⟶* (return (val v) B) H) RunResult H B
done : {H} (H B ⟶* done H) RunResult H B
error : {B H} (RuntimeErrorᴮ H B) (H B ⟶* B H) RunResult H B

View File

@ -1,27 +1,41 @@
{-# OPTIONS --rewriting #-}
module Luau.RuntimeError where
open import Agda.Builtin.Equality using (_≡_)
open import Luau.Heap using (Heap; _[_])
open import FFI.Data.Maybe using (just; nothing)
open import FFI.Data.String using (String)
open import Luau.Syntax using (Block; Expr; nil; var; addr; block_is_end; _$_; local_←_; return; done; _∙_; number; binexp)
open import Luau.RuntimeType using (RuntimeType; valueType)
open import Luau.Value using (val)
open import Luau.Syntax using (BinaryOperator; Block; Expr; nil; var; val; addr; block_is_end; _$_; local_←_; return; done; _∙_; number; string; binexp; +; -; *; /; <; >; <=; >=; ··)
open import Luau.RuntimeType using (RuntimeType; valueType; function; number; string)
open import Properties.Equality using (_≢_)
data BinOpError : BinaryOperator RuntimeType Set where
+ : {t} (t number) BinOpError + t
- : {t} (t number) BinOpError - t
* : {t} (t number) BinOpError * t
/ : {t} (t number) BinOpError / t
< : {t} (t number) BinOpError < t
> : {t} (t number) BinOpError > t
<= : {t} (t number) BinOpError <= t
>= : {t} (t number) BinOpError >= t
·· : {t} (t string) BinOpError ·· t
data RuntimeErrorᴮ {a} (H : Heap a) : Block a Set
data RuntimeErrorᴱ {a} (H : Heap a) : Expr a Set
data RuntimeErrorᴱ H where
TypeMismatch : t v (t valueType v) RuntimeErrorᴱ H (val v)
UnboundVariable : x RuntimeErrorᴱ H (var x)
SEGV : a (H [ a ] nothing) RuntimeErrorᴱ H (addr a)
FunctionMismatch : v w (function valueType v) RuntimeErrorᴱ H (val v $ val w)
BinOpMismatch₁ : v w {op} (BinOpError op (valueType v)) RuntimeErrorᴱ H (binexp (val v) op (val w))
BinOpMismatch₂ : v w {op} (BinOpError op (valueType w)) RuntimeErrorᴱ H (binexp (val v) op (val w))
UnboundVariable : {x} RuntimeErrorᴱ H (var x)
SEGV : {a} (H [ a ] nothing) RuntimeErrorᴱ H (val (addr a))
app₁ : {M N} RuntimeErrorᴱ H M RuntimeErrorᴱ H (M $ N)
app₂ : {M N} RuntimeErrorᴱ H N RuntimeErrorᴱ H (M $ N)
block : b {B} RuntimeErrorᴮ H B RuntimeErrorᴱ H (block b is B end)
block : {b B} RuntimeErrorᴮ H B RuntimeErrorᴱ H (block b is B end)
bin₁ : {M N op} RuntimeErrorᴱ H M RuntimeErrorᴱ H (binexp M op N)
bin₂ : {M N op} RuntimeErrorᴱ H N RuntimeErrorᴱ H (binexp M op N)
data RuntimeErrorᴮ H where
local : x {M B} RuntimeErrorᴱ H M RuntimeErrorᴮ H (local x M B)
local : {x M B} RuntimeErrorᴱ H M RuntimeErrorᴮ H (local x M B)
return : {M B} RuntimeErrorᴱ H M RuntimeErrorᴮ H (return M B)

View File

@ -1,27 +1,31 @@
{-# OPTIONS --rewriting #-}
module Luau.RuntimeError.ToString where
open import Agda.Builtin.Float using (primShowFloat)
open import FFI.Data.String using (String; _++_)
open import Luau.RuntimeError using (RuntimeErrorᴮ; RuntimeErrorᴱ; local; return; TypeMismatch; UnboundVariable; SEGV; app₁; app₂; block; bin₁; bin₂)
open import Luau.RuntimeError using (RuntimeErrorᴮ; RuntimeErrorᴱ; local; return; FunctionMismatch; BinOpMismatch₁; BinOpMismatch₂; UnboundVariable; SEGV; app₁; app₂; block; bin₁; bin₂)
open import Luau.RuntimeType.ToString using (runtimeTypeToString)
open import Luau.Addr.ToString using (addrToString)
open import Luau.Syntax.ToString using (exprToString)
open import Luau.Syntax.ToString using (valueToString; exprToString)
open import Luau.Var.ToString using (varToString)
open import Luau.Value.ToString using (valueToString)
open import Luau.Syntax using (name; _$_)
open import Luau.Syntax using (var; val; addr; binexp; block_is_end; local_←_; return; _∙_; name; _$_; ··)
errToStringᴱ : {a H B} RuntimeErrorᴱ {a} H B String
errToStringᴮ : {a H B} RuntimeErrorᴮ {a} H B String
errToStringᴱ : {a H} M RuntimeErrorᴱ {a} H M String
errToStringᴮ : {a H} B RuntimeErrorᴮ {a} H B String
errToStringᴱ (UnboundVariable x) = "variable " ++ varToString x ++ " is unbound"
errToStringᴱ (SEGV a x) = "address " ++ addrToString a ++ " is unallocated"
errToStringᴱ (app₁ E) = errToStringᴱ E
errToStringᴱ (app₂ E) = errToStringᴱ E
errToStringᴱ (bin₁ E) = errToStringᴱ E
errToStringᴱ (bin₂ E) = errToStringᴱ E
errToStringᴱ (block b E) = errToStringᴮ E ++ "\n in call of function " ++ varToString b
errToStringᴱ (TypeMismatch t v _) = "value " ++ valueToString v ++ " is not a " ++ runtimeTypeToString t
errToStringᴮ (local x E) = errToStringᴱ E ++ "\n in definition of " ++ varToString (name x)
errToStringᴮ (return E) = errToStringᴱ E ++ "\n in return statement"
errToStringᴱ (var x) (UnboundVariable) = "variable " ++ varToString x ++ " is unbound"
errToStringᴱ (val (addr a)) (SEGV p) = "address " ++ addrToString a ++ " is unallocated"
errToStringᴱ (M $ N) (FunctionMismatch v w p) = "value " ++ (valueToString v) ++ " is not a function"
errToStringᴱ (M $ N) (app₁ E) = errToStringᴱ M E
errToStringᴱ (M $ N) (app₂ E) = errToStringᴱ N E
errToStringᴱ (binexp M ·· N) (BinOpMismatch₁ v w p) = "value " ++ (valueToString v) ++ " is not a string"
errToStringᴱ (binexp M ·· N) (BinOpMismatch₂ v w p) = "value " ++ (valueToString w) ++ " is not a string"
errToStringᴱ (binexp M op N) (BinOpMismatch₁ v w p) = "value " ++ (valueToString v) ++ " is not a number"
errToStringᴱ (binexp M op N) (BinOpMismatch₂ v w p) = "value " ++ (valueToString w) ++ " is not a number"
errToStringᴱ (binexp M op N) (bin₁ E) = errToStringᴱ M E
errToStringᴱ (binexp M op N) (bin₂ E) = errToStringᴱ N E
errToStringᴱ (block b is B end) (block E) = errToStringᴮ B E ++ "\n in call of function " ++ varToString (name b)
errToStringᴮ (local x M B) (local E) = errToStringᴱ M E ++ "\n in definition of " ++ varToString (name x)
errToStringᴮ (return M B) (return E) = errToStringᴱ M E ++ "\n in return statement"

View File

@ -1,15 +1,17 @@
module Luau.RuntimeType where
open import Luau.Value using (Value; nil; addr; number; bool)
open import Luau.Syntax using (Value; nil; addr; number; bool; string)
data RuntimeType : Set where
function : RuntimeType
number : RuntimeType
nil : RuntimeType
boolean : RuntimeType
string : RuntimeType
valueType : Value RuntimeType
valueType nil = nil
valueType (addr x) = function
valueType (number x) = number
valueType (bool _) = boolean
valueType (addr a) = function
valueType (number n) = number
valueType (bool b) = boolean
valueType (string x) = string

View File

@ -1,10 +1,11 @@
module Luau.RuntimeType.ToString where
open import FFI.Data.String using (String)
open import Luau.RuntimeType using (RuntimeType; function; number; nil; boolean)
open import Luau.RuntimeType using (RuntimeType; function; number; nil; boolean; string)
runtimeTypeToString : RuntimeType String
runtimeTypeToString function = "function"
runtimeTypeToString number = "number"
runtimeTypeToString nil = "nil"
runtimeTypeToString boolean = "boolean"
runtimeTypeToString string = "string"

View File

@ -0,0 +1,206 @@
{-# OPTIONS --rewriting #-}
module Luau.StrictMode where
open import Agda.Builtin.Equality using (_≡_)
open import FFI.Data.Maybe using (just; nothing)
open import Luau.Syntax using (Expr; Stat; Block; BinaryOperator; yes; nil; addr; var; binexp; var_∈_; _⟨_⟩∈_; function_is_end; _$_; block_is_end; local_←_; _∙_; done; return; name; +; -; *; /; <; >; <=; >=; ··)
open import Luau.Type using (Type; strict; nil; number; string; _⇒_; tgt)
open import Luau.Heap using (Heap; function_is_end) renaming (_[_] to _[_]ᴴ)
open import Luau.VarCtxt using (VarCtxt; ∅; _⋒_; _↦_; _⊕_↦_; _⊝_) renaming (_[_] to _[_]ⱽ)
open import Luau.TypeCheck(strict) using (_⊢ᴮ_∈_; _⊢ᴱ_∈_; ⊢ᴴ_; ⊢ᴼ_; _⊢ᴴᴱ_▷_∈_; _⊢ᴴᴮ_▷_∈_; var; addr; app; binexp; block; return; local; function)
open import Properties.Equality using (_≢_)
open import Properties.TypeCheck(strict) using (typeCheckᴮ)
open import Properties.Product using (_,_)
src : Type Type
src = Luau.Type.src strict
data BinOpWarning : BinaryOperator Type Set where
+ : {T} (T number) BinOpWarning + T
- : {T} (T number) BinOpWarning - T
* : {T} (T number) BinOpWarning * T
/ : {T} (T number) BinOpWarning / T
< : {T} (T number) BinOpWarning < T
> : {T} (T number) BinOpWarning > T
<= : {T} (T number) BinOpWarning <= T
>= : {T} (T number) BinOpWarning >= T
·· : {T} (T string) BinOpWarning ·· T
data Warningᴱ (H : Heap yes) {Γ} : {M T} (Γ ⊢ᴱ M T) Set
data Warningᴮ (H : Heap yes) {Γ} : {B T} (Γ ⊢ᴮ B T) Set
data Warningᴱ H {Γ} where
UnallocatedAddress : {a T}
(H [ a ]ᴴ nothing)
---------------------
Warningᴱ H (addr {a} T)
UnboundVariable : {x T p}
(Γ [ x ]ⱽ nothing)
------------------------
Warningᴱ H (var {x} {T} p)
FunctionCallMismatch : {M N T U} {D₁ : Γ ⊢ᴱ M T} {D₂ : Γ ⊢ᴱ N U}
(src T U)
-----------------
Warningᴱ H (app D₁ D₂)
app₁ : {M N T U} {D₁ : Γ ⊢ᴱ M T} {D₂ : Γ ⊢ᴱ N U}
Warningᴱ H D₁
-----------------
Warningᴱ H (app D₁ D₂)
app₂ : {M N T U} {D₁ : Γ ⊢ᴱ M T} {D₂ : Γ ⊢ᴱ N U}
Warningᴱ H D₂
-----------------
Warningᴱ H (app D₁ D₂)
BinOpMismatch₁ : {op M N T U} {D₁ : Γ ⊢ᴱ M T} {D₂ : Γ ⊢ᴱ N U}
BinOpWarning op T
------------------------------
Warningᴱ H (binexp {op} D₁ D₂)
BinOpMismatch₂ : {op M N T U} {D₁ : Γ ⊢ᴱ M T} {D₂ : Γ ⊢ᴱ N U}
BinOpWarning op U
------------------------------
Warningᴱ H (binexp {op} D₁ D₂)
bin₁ : {op M N T U} {D₁ : Γ ⊢ᴱ M T} {D₂ : Γ ⊢ᴱ N U}
Warningᴱ H D₁
------------------------------
Warningᴱ H (binexp {op} D₁ D₂)
bin₂ : {op M N T U} {D₁ : Γ ⊢ᴱ M T} {D₂ : Γ ⊢ᴱ N U}
Warningᴱ H D₂
------------------------------
Warningᴱ H (binexp {op} D₁ D₂)
FunctionDefnMismatch : {f x B T U V} {D : (Γ x T) ⊢ᴮ B V}
(U V)
-------------------------
Warningᴱ H (function {f} {U = U} D)
function₁ : {f x B T U V} {D : (Γ x T) ⊢ᴮ B V}
Warningᴮ H D
-------------------------
Warningᴱ H (function {f} {U = U} D)
BlockMismatch : {b B T U} {D : Γ ⊢ᴮ B U}
(T U)
------------------------------
Warningᴱ H (block {b} {T = T} D)
block₁ : {b B T U} {D : Γ ⊢ᴮ B U}
Warningᴮ H D
------------------------------
Warningᴱ H (block {b} {T = T} D)
data Warningᴮ H {Γ} where
return : {M B T U} {D₁ : Γ ⊢ᴱ M T} {D₂ : Γ ⊢ᴮ B U}
Warningᴱ H D₁
------------------
Warningᴮ H (return D₁ D₂)
LocalVarMismatch : {x M B T U V} {D₁ : Γ ⊢ᴱ M U} {D₂ : (Γ x T) ⊢ᴮ B V}
(T U)
--------------------
Warningᴮ H (local D₁ D₂)
local₁ : {x M B T U V} {D₁ : Γ ⊢ᴱ M U} {D₂ : (Γ x T) ⊢ᴮ B V}
Warningᴱ H D₁
--------------------
Warningᴮ H (local D₁ D₂)
local₂ : {x M B T U V} {D₁ : Γ ⊢ᴱ M U} {D₂ : (Γ x T) ⊢ᴮ B V}
Warningᴮ H D₂
--------------------
Warningᴮ H (local D₁ D₂)
FunctionDefnMismatch : {f x B C T U V W} {D₁ : (Γ x T) ⊢ᴮ C V} {D₂ : (Γ f (T U)) ⊢ᴮ B W}
(U V)
-------------------------------------
Warningᴮ H (function D₁ D₂)
function₁ : {f x B C T U V W} {D₁ : (Γ x T) ⊢ᴮ C V} {D₂ : (Γ f (T U)) ⊢ᴮ B W}
Warningᴮ H D₁
--------------------
Warningᴮ H (function D₁ D₂)
function₂ : {f x B C T U V W} {D₁ : (Γ x T) ⊢ᴮ C V} {D₂ : (Γ f (T U)) ⊢ᴮ B W}
Warningᴮ H D₂
--------------------
Warningᴮ H (function D₁ D₂)
data Warningᴼ (H : Heap yes) : {V} (⊢ᴼ V) Set where
FunctionDefnMismatch : {f x B T U V} {D : (x T) ⊢ᴮ B V}
(U V)
---------------------------------
Warningᴼ H (function {f} {U = U} D)
function₁ : {f x B T U V} {D : (x T) ⊢ᴮ B V}
Warningᴮ H D
---------------------------------
Warningᴼ H (function {f} {U = U} D)
data Warningᴴ H (D : ⊢ᴴ H) : Set where
addr : a {O}
(p : H [ a ]ᴴ O)
Warningᴼ H (D a p)
---------------
Warningᴴ H D
data Warningᴴᴱ H {Γ M T} : (Γ ⊢ᴴᴱ H M T) Set where
heap : {D₁ : ⊢ᴴ H} {D₂ : Γ ⊢ᴱ M T}
Warningᴴ H D₁
-----------------
Warningᴴᴱ H (D₁ , D₂)
expr : {D₁ : ⊢ᴴ H} {D₂ : Γ ⊢ᴱ M T}
Warningᴱ H D₂
---------------------
Warningᴴᴱ H (D₁ , D₂)
data Warningᴴᴮ H {Γ B T} : (Γ ⊢ᴴᴮ H B T) Set where
heap : {D₁ : ⊢ᴴ H} {D₂ : Γ ⊢ᴮ B T}
Warningᴴ H D₁
-----------------
Warningᴴᴮ H (D₁ , D₂)
block : {D₁ : ⊢ᴴ H} {D₂ : Γ ⊢ᴮ B T}
Warningᴮ H D₂
---------------------
Warningᴴᴮ H (D₁ , D₂)

View File

@ -0,0 +1,39 @@
{-# OPTIONS --rewriting #-}
module Luau.StrictMode.ToString where
open import FFI.Data.String using (String; _++_)
open import Luau.StrictMode using (Warningᴱ; Warningᴮ; UnallocatedAddress; UnboundVariable; FunctionCallMismatch; FunctionDefnMismatch; BlockMismatch; app₁; app₂; BinOpMismatch₁; BinOpMismatch₂; bin₁; bin₂; block₁; return; LocalVarMismatch; local₁; local₂; function₁; function₂; heap; expr; block; addr)
open import Luau.Syntax using (Expr; val; yes; var; var_∈_; _⟨_⟩∈_; _$_; addr; number; binexp; nil; function_is_end; block_is_end; done; return; local_←_; _∙_; fun; arg; name)
open import Luau.Type using (strict)
open import Luau.TypeCheck(strict) using (_⊢ᴮ_∈_; _⊢ᴱ_∈_)
open import Luau.Addr.ToString using (addrToString)
open import Luau.Var.ToString using (varToString)
open import Luau.Type.ToString using (typeToString)
open import Luau.Syntax.ToString using (binOpToString)
warningToStringᴱ : {H Γ T} M {D : Γ ⊢ᴱ M T} Warningᴱ H D String
warningToStringᴮ : {H Γ T} B {D : Γ ⊢ᴮ B T} Warningᴮ H D String
warningToStringᴱ (var x) (UnboundVariable p) = "Unbound variable " ++ varToString x
warningToStringᴱ (val (addr a)) (UnallocatedAddress p) = "Unallocated adress " ++ addrToString a
warningToStringᴱ (M $ N) (FunctionCallMismatch {T = T} {U = U} p) = "Function has type " ++ typeToString T ++ " but argument has type " ++ typeToString U
warningToStringᴱ (M $ N) (app₁ W) = warningToStringᴱ M W
warningToStringᴱ (M $ N) (app₂ W) = warningToStringᴱ N W
warningToStringᴱ (function f var x T ⟩∈ U is B end) (FunctionDefnMismatch {V = V} p) = "Function expresion " ++ varToString f ++ " has return type " ++ typeToString U ++ " but body returns " ++ typeToString V
warningToStringᴱ (function f var x T ⟩∈ U is B end) (function₁ W) = warningToStringᴮ B W ++ "\n in function expression " ++ varToString f
warningToStringᴱ block var b T is B end (BlockMismatch {U = U} p) = "Block " ++ varToString b ++ " has type " ++ typeToString T ++ " but body returns " ++ typeToString U
warningToStringᴱ block var b T is B end (block₁ W) = warningToStringᴮ B W ++ "\n in block " ++ varToString b
warningToStringᴱ (binexp M op N) (BinOpMismatch₁ {T = T} p) = "Binary operator " ++ binOpToString op ++ " lhs has type " ++ typeToString T
warningToStringᴱ (binexp M op N) (BinOpMismatch₂ {U = U} p) = "Binary operator " ++ binOpToString op ++ " rhs has type " ++ typeToString U
warningToStringᴱ (binexp M op N) (bin₁ W) = warningToStringᴱ M W
warningToStringᴱ (binexp M op N) (bin₂ W) = warningToStringᴱ N W
warningToStringᴮ (function f var x T ⟩∈ U is C end B) (FunctionDefnMismatch {V = V} p) = "Function declaration " ++ varToString f ++ " has return type " ++ typeToString U ++ " but body returns " ++ typeToString V
warningToStringᴮ (function f var x T ⟩∈ U is C end B) (function₁ W) = warningToStringᴮ C W ++ "\n in function declaration " ++ varToString f
warningToStringᴮ (function f var x T ⟩∈ U is C end B) (function₂ W) = warningToStringᴮ B W
warningToStringᴮ (local var x T M B) (LocalVarMismatch {U = U} p) = "Local variable " ++ varToString x ++ " has type " ++ typeToString T ++ " but expression has type " ++ typeToString U
warningToStringᴮ (local var x T M B) (local₁ W) = warningToStringᴱ M W ++ "\n in local variable declaration " ++ varToString x
warningToStringᴮ (local var x T M B) (local₂ W) = warningToStringᴮ B W
warningToStringᴮ (return M B) (return W) = warningToStringᴱ M W ++ "\n in return statement"

View File

@ -1,7 +1,6 @@
module Luau.Substitution where
open import Luau.Syntax using (Expr; Stat; Block; nil; true; false; addr; var; function_is_end; _$_; block_is_end; local_←_; _∙_; done; return; _⟨_⟩ ; name; fun; arg; number; binexp)
open import Luau.Value using (Value; val)
open import Luau.Syntax using (Value; Expr; Stat; Block; val; nil; bool; addr; var; function_is_end; _$_; block_is_end; local_←_; _∙_; done; return; _⟨_⟩ ; name; fun; arg; number; binexp)
open import Luau.Var using (Var; _≡ⱽ_)
open import Properties.Dec using (Dec; yes; no)
@ -10,18 +9,14 @@ _[_/_]ᴮ : ∀ {a} → Block a → Value → Var → Block a
var_[_/_]ᴱwhenever_ : {a P} Var Value Var (Dec P) Expr a
_[_/_]ᴮunless_ : {a P} Block a Value Var (Dec P) Block a
nil [ v / x ]ᴱ = nil
true [ v / x ]ᴱ = true
false [ v / x ]ᴱ = false
val w [ v / x ]ᴱ = val w
var y [ v / x ]ᴱ = var y [ v / x ]ᴱwhenever (x ≡ⱽ y)
addr a [ v / x ]ᴱ = addr a
(number y) [ v / x ]ᴱ = number y
(M $ N) [ v / x ]ᴱ = (M [ v / x ]ᴱ) $ (N [ v / x ]ᴱ)
function F is C end [ v / x ]ᴱ = function F is C [ v / x ]ᴮunless (x ≡ⱽ name(arg F)) end
block b is C end [ v / x ]ᴱ = block b is C [ v / x ]ᴮ end
(binexp e₁ op e₂) [ v / x ]ᴱ = binexp (e₁ [ v / x ]ᴱ) op (e₂ [ v / x ]ᴱ)
(function F is C end B) [ v / x ]ᴮ = function F is (C [ v / x ]ᴮunless (x ≡ⱽ name(arg F))) end (B [ v / x ]ᴮunless (x ≡ⱽ fun F))
(function F is C end B) [ v / x ]ᴮ = function F is (C [ v / x ]ᴮunless (x ≡ⱽ name(arg F))) end (B [ v / x ]ᴮunless (x ≡ⱽ name(fun F)))
(local y M B) [ v / x ]ᴮ = local y (M [ v / x ]ᴱ) (B [ v / x ]ᴮunless (x ≡ⱽ name y))
(return M B) [ v / x ]ᴮ = return (M [ v / x ]ᴱ) (B [ v / x ]ᴮ)
done [ v / x ]ᴮ = done

View File

@ -1,11 +1,13 @@
module Luau.Syntax where
open import Agda.Builtin.Equality using (_≡_)
open import Agda.Builtin.Bool using (Bool; true; false)
open import Agda.Builtin.Float using (Float)
open import Properties.Dec using ()
open import Agda.Builtin.String using (String)
open import Luau.Var using (Var)
open import Luau.Addr using (Addr)
open import Luau.Type using (Type)
open import FFI.Data.Maybe using (Maybe; just; nothing)
infixr 5 _∙_
@ -25,9 +27,9 @@ data FunDec : Annotated → Set where
_⟨_⟩∈_ : {a} Var VarDec a Type FunDec a
_⟨_⟩ : Var VarDec maybe FunDec maybe
fun : {a} FunDec a Var
fun (f x ⟩∈ T) = f
fun (f x ) = f
fun : {a} FunDec a VarDec a
fun (f x ⟩∈ T) = (var f T)
fun (f x ) = (var f)
arg : {a} FunDec a VarDec a
arg (f x ⟩∈ T) = x
@ -40,10 +42,18 @@ data BinaryOperator : Set where
/ : BinaryOperator
< : BinaryOperator
> : BinaryOperator
: BinaryOperator
: BinaryOperator
: BinaryOperator
: BinaryOperator
== : BinaryOperator
~= : BinaryOperator
<= : BinaryOperator
>= : BinaryOperator
·· : BinaryOperator
data Value : Set where
nil : Value
addr : Addr Value
number : Float Value
bool : Bool Value
string : String Value
data Block (a : Annotated) : Set
data Stat (a : Annotated) : Set
@ -59,13 +69,42 @@ data Stat a where
return : Expr a Stat a
data Expr a where
nil : Expr a
true : Expr a
false : Expr a
var : Var Expr a
addr : Addr Expr a
val : Value Expr a
_$_ : Expr a Expr a Expr a
function_is_end : FunDec a Block a Expr a
block_is_end : Var Block a Expr a
number : Float Expr a
block_is_end : VarDec a Block a Expr a
binexp : Expr a BinaryOperator Expr a Expr a
isAnnotatedᴱ : {a} Expr a Maybe (Expr yes)
isAnnotatedᴮ : {a} Block a Maybe (Block yes)
isAnnotatedᴱ (var x) = just (var x)
isAnnotatedᴱ (val v) = just (val v)
isAnnotatedᴱ (M $ N) with isAnnotatedᴱ M | isAnnotatedᴱ N
isAnnotatedᴱ (M $ N) | just M | just N = just (M $ N)
isAnnotatedᴱ (M $ N) | _ | _ = nothing
isAnnotatedᴱ (function f var x T ⟩∈ U is B end) with isAnnotatedᴮ B
isAnnotatedᴱ (function f var x T ⟩∈ U is B end) | just B = just (function f var x T ⟩∈ U is B end)
isAnnotatedᴱ (function f var x T ⟩∈ U is B end) | _ = nothing
isAnnotatedᴱ (function _ is B end) = nothing
isAnnotatedᴱ (block var b T is B end) with isAnnotatedᴮ B
isAnnotatedᴱ (block var b T is B end) | just B = just (block var b T is B end)
isAnnotatedᴱ (block var b T is B end) | _ = nothing
isAnnotatedᴱ (block _ is B end) = nothing
isAnnotatedᴱ (binexp M op N) with isAnnotatedᴱ M | isAnnotatedᴱ N
isAnnotatedᴱ (binexp M op N) | just M | just N = just (binexp M op N)
isAnnotatedᴱ (binexp M op N) | _ | _ = nothing
isAnnotatedᴮ (function f var x T ⟩∈ U is C end B) with isAnnotatedᴮ B | isAnnotatedᴮ C
isAnnotatedᴮ (function f var x T ⟩∈ U is C end B) | just B | just C = just (function f var x T ⟩∈ U is C end B)
isAnnotatedᴮ (function f var x T ⟩∈ U is C end B) | _ | _ = nothing
isAnnotatedᴮ (function _ is C end B) = nothing
isAnnotatedᴮ (local var x T M B) with isAnnotatedᴱ M | isAnnotatedᴮ B
isAnnotatedᴮ (local var x T M B) | just M | just B = just (local var x T M B)
isAnnotatedᴮ (local var x T M B) | _ | _ = nothing
isAnnotatedᴮ (local _ M B) = nothing
isAnnotatedᴮ (return M B) with isAnnotatedᴱ M | isAnnotatedᴮ B
isAnnotatedᴮ (return M B) | just M | just B = just (return M B)
isAnnotatedᴮ (return M B) | _ | _ = nothing
isAnnotatedᴮ done = just done

View File

@ -1,6 +1,8 @@
{-# OPTIONS --rewriting #-}
module Luau.Syntax.FromJSON where
open import Luau.Syntax using (Block; Stat ; Expr; nil; _$_; var; var_∈_; function_is_end; _⟨_⟩; local_←_; return; done; _∙_; maybe; VarDec; number; binexp; BinaryOperator; +; -; *; /; ≡; ≅; <; >; ≤; )
open import Luau.Syntax using (Block; Stat ; Expr; _$_; val; nil; bool; number; var; var_∈_; function_is_end; _⟨_⟩; _⟨_⟩∈_; local_←_; return; done; _∙_; maybe; VarDec; binexp; BinaryOperator; +; -; *; /; ==; ~=; <; >; <=; >=; ··; string)
open import Luau.Type.FromJSON using (typeFromJSON)
open import Agda.Builtin.List using (List; _∷_; [])
@ -26,6 +28,8 @@ vars = fromString "vars"
op = fromString "op"
left = fromString "left"
right = fromString "right"
returnAnnotation = fromString "returnAnnotation"
types = fromString "types"
data Lookup : Set where
_,_ : String Value Lookup
@ -49,22 +53,23 @@ blockFromJSON : Value → Either String (Block maybe)
blockFromArray : Array Either String (Block maybe)
binOpFromJSON (string s) = binOpFromString s
binOpFromJSON val = Left "Binary operator not a string"
binOpFromJSON _ = Left "Binary operator not a string"
binOpFromString "Add" = Right +
binOpFromString "Sub" = Right -
binOpFromString "Mul" = Right *
binOpFromString "Div" = Right /
binOpFromString "CompareEq" = Right
binOpFromString "CompareNe" = Right
binOpFromString "CompareEq" = Right ==
binOpFromString "CompareNe" = Right ~=
binOpFromString "CompareLt" = Right <
binOpFromString "CompareLe" = Right
binOpFromString "CompareLe" = Right <=
binOpFromString "CompareGt" = Right >
binOpFromString "CompareGe" = Right
binOpFromString "CompareGe" = Right >=
binOpFromString "Concat" = Right ··
binOpFromString s = Left ("'" ++ s ++ "' is not a valid operator")
varDecFromJSON (object arg) = varDecFromObject arg
varDecFromJSON val = Left "VarDec not an object"
varDecFromJSON _ = Left "VarDec not an object"
varDecFromObject obj with lookup name obj | lookup type obj
varDecFromObject obj | just (string name) | nothing = Right (var name)
@ -76,7 +81,7 @@ varDecFromObject obj | just _ | _ = Left "AstLocal name is not a string"
varDecFromObject obj | nothing | _ = Left "AstLocal missing name"
exprFromJSON (object obj) = exprFromObject obj
exprFromJSON val = Left "AstExpr not an object"
exprFromJSON _ = Left "AstExpr not an object"
exprFromObject obj with lookup type obj
exprFromObject obj | just (string "AstExprCall") with lookup func obj | lookup args obj
@ -89,29 +94,41 @@ exprFromObject obj | just (string "AstExprCall") | just value | just (array arr)
exprFromObject obj | just (string "AstExprCall") | just value | just _ = Left ("AstExprCall args not an array")
exprFromObject obj | just (string "AstExprCall") | nothing | _ = Left ("AstExprCall missing func")
exprFromObject obj | just (string "AstExprCall") | _ | nothing = Left ("AstExprCall missing args")
exprFromObject obj | just (string "AstExprConstantNil") = Right nil
exprFromObject obj | just (string "AstExprFunction") with lookup args obj | lookup body obj
exprFromObject obj | just (string "AstExprFunction") | just (array arr) | just blockValue with head arr | blockFromJSON blockValue
exprFromObject obj | just (string "AstExprFunction") | just (array arr) | just blockValue | just argValue | Right B with varDecFromJSON argValue
exprFromObject obj | just (string "AstExprFunction") | just (array arr) | just blockValue | just argValue | Right B | Right arg = Right (function "" arg is B end)
exprFromObject obj | just (string "AstExprFunction") | just (array arr) | just blockValue | just argValue | Right B | Left err = Left err
exprFromObject obj | just (string "AstExprFunction") | just (array arr) | just blockValue | nothing | Right B = Left "Unsupported AstExprFunction empty args"
exprFromObject obj | just (string "AstExprFunction") | just (array arr) | just blockValue | _ | Left err = Left err
exprFromObject obj | just (string "AstExprFunction") | just _ | just _ = Left "AstExprFunction args not an array"
exprFromObject obj | just (string "AstExprFunction") | nothing | _ = Left "AstExprFunction missing args"
exprFromObject obj | just (string "AstExprFunction") | _ | nothing = Left "AstExprFunction missing body"
exprFromObject obj | just (string "AstExprConstantNil") = Right (val nil)
exprFromObject obj | just (string "AstExprFunction") with lookup args obj | lookup body obj | lookup returnAnnotation obj
exprFromObject obj | just (string "AstExprFunction") | just (array arr) | just blockValue | rtn with head arr | blockFromJSON blockValue
exprFromObject obj | just (string "AstExprFunction") | just (array arr) | just blockValue | rtn | just argValue | Right B with varDecFromJSON argValue
exprFromObject obj | just (string "AstExprFunction") | just (array arr) | just blockValue | just (object rtnObj) | just argValue | Right B | Right arg with lookup types rtnObj
exprFromObject obj | just (string "AstExprFunction") | just (array arr) | just blockValue | just (object rtnObj) | just argValue | Right B | Right arg | just (array rtnTypes) with head rtnTypes
exprFromObject obj | just (string "AstExprFunction") | just (array arr) | just blockValue | just (object rtnObj) | just argValue | Right B | Right arg | just (array rtnTypes) | just rtnType with typeFromJSON rtnType
exprFromObject obj | just (string "AstExprFunction") | just (array arr) | just blockValue | just (object rtnObj) | just argValue | Right B | Right arg | just (array rtnTypes) | just rtnType | Left err = Left err
exprFromObject obj | just (string "AstExprFunction") | just (array arr) | just blockValue | just (object rtnObj) | just argValue | Right B | Right arg | just (array rtnTypes) | just rtnType | Right T = Right (function "" arg ⟩∈ T is B end)
exprFromObject obj | just (string "AstExprFunction") | just (array arr) | just blockValue | just (object rtnObj) | just argValue | Right B | Right arg | just (array rtnTypes) | nothing = Right (function "" arg is B end)
exprFromObject obj | just (string "AstExprFunction") | just (array arr) | just blockValue | just (object rtnObj) | just argValue | Right B | Right arg | just _ = Left "returnAnnotation types not an array"
exprFromObject obj | just (string "AstExprFunction") | just (array arr) | just blockValue | just (object rtnObj) | just argValue | Right B | Right arg | nothing = Left "returnAnnotation missing types"
exprFromObject obj | just (string "AstExprFunction") | just (array arr) | just blockValue | just _ | just argValue | Right B | Right arg = Left "returnAnnotation not an object"
exprFromObject obj | just (string "AstExprFunction") | just (array arr) | just blockValue | nothing | just argValue | Right B | Right arg = Right (function "" arg is B end)
exprFromObject obj | just (string "AstExprFunction") | just (array arr) | just blockValue | rtn | just argValue | Right B | Left err = Left err
exprFromObject obj | just (string "AstExprFunction") | just (array arr) | just blockValue | rtn | nothing | Right B = Left "Unsupported AstExprFunction empty args"
exprFromObject obj | just (string "AstExprFunction") | just (array arr) | just blockValue | rtn | _ | Left err = Left err
exprFromObject obj | just (string "AstExprFunction") | just _ | just _ | rtn = Left "AstExprFunction args not an array"
exprFromObject obj | just (string "AstExprFunction") | nothing | _ | rtn = Left "AstExprFunction missing args"
exprFromObject obj | just (string "AstExprFunction") | _ | nothing | rtn = Left "AstExprFunction missing body"
exprFromObject obj | just (string "AstExprLocal") with lookup lokal obj
exprFromObject obj | just (string "AstExprLocal") | just x with varDecFromJSON x
exprFromObject obj | just (string "AstExprLocal") | just x | Right x = Right (var (Luau.Syntax.name x))
exprFromObject obj | just (string "AstExprLocal") | just x | Left err = Left err
exprFromObject obj | just (string "AstExprLocal") | nothing = Left "AstExprLocal missing local"
exprFromObject obj | just (string "AstExprConstantNumber") with lookup value obj
exprFromObject obj | just (string "AstExprConstantNumber") | just (FFI.Data.Aeson.Value.number x) = Right (number (toFloat x))
exprFromObject obj | just (string "AstExprConstantNumber") | just (FFI.Data.Aeson.Value.number x) = Right (val (number (toFloat x)))
exprFromObject obj | just (string "AstExprConstantNumber") | just _ = Left "AstExprConstantNumber value is not a number"
exprFromObject obj | just (string "AstExprConstantNumber") | nothing = Left "AstExprConstantNumber missing value"
exprFromObject obj | just (string "AstExprConstantString") with lookup value obj
exprFromObject obj | just (string "AstExprConstantString") | just (string x) = Right (val (string x))
exprFromObject obj | just (string "AstExprConstantString") | just _ = Left "AstExprConstantString value is not a string"
exprFromObject obj | just (string "AstExprConstantString") | nothing = Left "AstExprConstantString missing value"
exprFromObject obj | just (string "AstExprConstantBool") with lookup value obj
exprFromObject obj | just (string "AstExprConstantBool") | just (FFI.Data.Aeson.Value.bool true) = Right Expr.true
exprFromObject obj | just (string "AstExprConstantBool") | just (FFI.Data.Aeson.Value.bool false) = Right Expr.false
exprFromObject obj | just (string "AstExprConstantBool") | just (FFI.Data.Aeson.Value.bool b) = Right (val (bool b))
exprFromObject obj | just (string "AstExprConstantBool") | just _ = Left "AstExprConstantBool value is not a bool"
exprFromObject obj | just (string "AstExprConstantBool") | nothing = Left "AstExprConstantBool missing value"
exprFromObject obj | just (string "AstExprBinary") with lookup op obj | lookup left obj | lookup right obj
@ -147,6 +164,7 @@ statFromObject obj | just(string "AstStatLocal") | nothing | _ = Left "AstStatLo
statFromObject obj | just(string "AstStatLocalFunction") with lookup name obj | lookup func obj
statFromObject obj | just(string "AstStatLocalFunction") | just fnName | just value with varDecFromJSON fnName | exprFromJSON value
statFromObject obj | just(string "AstStatLocalFunction") | just fnName | just value | Right fnVar | Right (function "" x is B end) = Right (function (Luau.Syntax.name fnVar) x is B end)
statFromObject obj | just(string "AstStatLocalFunction") | just fnName | just value | Right fnVar | Right (function "" x ⟩∈ T is B end) = Right (function (Luau.Syntax.name fnVar) x ⟩∈ T is B end)
statFromObject obj | just(string "AstStatLocalFunction") | just fnName | just value | Left err | _ = Left err
statFromObject obj | just(string "AstStatLocalFunction") | just fnName | just value | _ | Left err = Left err
statFromObject obj | just(string "AstStatLocalFunction") | just _ | just _ | Right _ | Right _ = Left "AstStatLocalFunction func is not an AstExprFunction"

View File

@ -1,7 +1,9 @@
module Luau.Syntax.ToString where
open import Agda.Builtin.Bool using (true; false)
open import Agda.Builtin.Float using (primShowFloat)
open import Luau.Syntax using (Block; Stat; Expr; VarDec; FunDec; nil; var; var_∈_; addr; _$_; function_is_end; return; local_←_; _∙_; done; block_is_end; _⟨_⟩; _⟨_⟩∈_; number; BinaryOperator; +; -; *; /; <; >; ≡; ≅; ≤; ≥; binexp; true; false)
open import Agda.Builtin.String using (primShowString)
open import Luau.Syntax using (Value; Block; Stat; Expr; VarDec; FunDec; nil; bool; val; var; var_∈_; addr; _$_; function_is_end; return; local_←_; _∙_; done; block_is_end; _⟨_⟩; _⟨_⟩∈_; number; BinaryOperator; +; -; *; /; <; >; ==; ~=; <=; >=; ··; binexp; string)
open import FFI.Data.String using (String; _++_)
open import Luau.Addr.ToString using (addrToString)
open import Luau.Type.ToString using (typeToString)
@ -24,19 +26,26 @@ binOpToString * = "*"
binOpToString / = "/"
binOpToString < = "<"
binOpToString > = ">"
binOpToString = "=="
binOpToString = "~="
binOpToString = "<="
binOpToString = ">="
binOpToString == = "=="
binOpToString ~= = "~="
binOpToString <= = "<="
binOpToString >= = ">="
binOpToString ·· = ".."
valueToString : Value String
valueToString nil = "nil"
valueToString (addr a) = addrToString a
valueToString (number x) = primShowFloat x
valueToString (bool false) = "false"
valueToString (bool true) = "true"
valueToString (string x) = primShowString x
exprToString : {a} String Expr a String
statToString : {a} String Stat a String
blockToString : {a} String Block a String
exprToString lb nil =
"nil"
exprToString lb (addr a) =
addrToString(a)
exprToString lb (val v) =
valueToString(v)
exprToString lb (var x) =
varToString(x)
exprToString lb (M $ N) =
@ -46,13 +55,10 @@ exprToString lb (function F is B end) =
" " ++ (blockToString (lb ++ " ") B) ++ lb ++
"end"
exprToString lb (block b is B end) =
"(" ++ b ++ "()" ++ lb ++
"(" ++ varDecToString b ++ "()" ++ lb ++
" " ++ (blockToString (lb ++ " ") B) ++ lb ++
"end)()"
exprToString lb (number x) = primShowFloat x
exprToString lb (binexp x op y) = exprToString lb x ++ " " ++ binOpToString op ++ " " ++ exprToString lb y
exprToString lb true = "true"
exprToString lb false = "false"
statToString lb (function F is B end) =
"local " ++ funDecToString F ++ lb ++

View File

@ -1,5 +1,9 @@
module Luau.Type where
open import FFI.Data.Maybe using (Maybe; just; nothing; just-inv)
open import Agda.Builtin.Equality using (_≡_; refl)
open import Properties.Dec using (Dec; yes; no)
open import Properties.Equality using (cong)
open import FFI.Data.Maybe using (Maybe; just; nothing)
data Type : Set where
@ -7,18 +11,153 @@ data Type : Set where
_⇒_ : Type Type Type
none : Type
any : Type
boolean : Type
number : Type
string : Type
__ : Type Type Type
_∩_ : Type Type Type
src : Type Type
src nil = none
src (S T) = S
src none = none
src any = any
src number = none
src (S T) = (src S) (src T)
src (S T) = (src S) (src T)
lhs : Type Type
lhs (T _) = T
lhs (T _) = T
lhs (T _) = T
lhs nil = nil
lhs none = none
lhs any = any
lhs number = number
lhs boolean = boolean
lhs string = string
rhs : Type Type
rhs (_ T) = T
rhs (_ T) = T
rhs (_ T) = T
rhs nil = nil
rhs none = none
rhs any = any
rhs number = number
rhs boolean = boolean
rhs string = string
_≡ᵀ_ : (T U : Type) Dec(T U)
nil ≡ᵀ nil = yes refl
nil ≡ᵀ (S T) = no (λ ())
nil ≡ᵀ none = no (λ ())
nil ≡ᵀ any = no (λ ())
nil ≡ᵀ number = no (λ ())
nil ≡ᵀ boolean = no (λ ())
nil ≡ᵀ (S T) = no (λ ())
nil ≡ᵀ (S T) = no (λ ())
nil ≡ᵀ string = no (λ ())
(S T) ≡ᵀ string = no (λ ())
none ≡ᵀ string = no (λ ())
any ≡ᵀ string = no (λ ())
boolean ≡ᵀ string = no (λ ())
number ≡ᵀ string = no (λ ())
(S T) ≡ᵀ string = no (λ ())
(S T) ≡ᵀ string = no (λ ())
(S T) ≡ᵀ nil = no (λ ())
(S T) ≡ᵀ (U V) with (S ≡ᵀ U) | (T ≡ᵀ V)
(S T) ≡ᵀ (S T) | yes refl | yes refl = yes refl
(S T) ≡ᵀ (U V) | _ | no p = no (λ q p (cong rhs q))
(S T) ≡ᵀ (U V) | no p | _ = no (λ q p (cong lhs q))
(S T) ≡ᵀ none = no (λ ())
(S T) ≡ᵀ any = no (λ ())
(S T) ≡ᵀ number = no (λ ())
(S T) ≡ᵀ boolean = no (λ ())
(S T) ≡ᵀ (U V) = no (λ ())
(S T) ≡ᵀ (U V) = no (λ ())
none ≡ᵀ nil = no (λ ())
none ≡ᵀ (U V) = no (λ ())
none ≡ᵀ none = yes refl
none ≡ᵀ any = no (λ ())
none ≡ᵀ number = no (λ ())
none ≡ᵀ boolean = no (λ ())
none ≡ᵀ (U V) = no (λ ())
none ≡ᵀ (U V) = no (λ ())
any ≡ᵀ nil = no (λ ())
any ≡ᵀ (U V) = no (λ ())
any ≡ᵀ none = no (λ ())
any ≡ᵀ any = yes refl
any ≡ᵀ number = no (λ ())
any ≡ᵀ boolean = no (λ ())
any ≡ᵀ (U V) = no (λ ())
any ≡ᵀ (U V) = no (λ ())
number ≡ᵀ nil = no (λ ())
number ≡ᵀ (T U) = no (λ ())
number ≡ᵀ none = no (λ ())
number ≡ᵀ any = no (λ ())
number ≡ᵀ number = yes refl
number ≡ᵀ boolean = no (λ ())
number ≡ᵀ (T U) = no (λ ())
number ≡ᵀ (T U) = no (λ ())
boolean ≡ᵀ nil = no (λ ())
boolean ≡ᵀ (T U) = no (λ ())
boolean ≡ᵀ none = no (λ ())
boolean ≡ᵀ any = no (λ ())
boolean ≡ᵀ boolean = yes refl
boolean ≡ᵀ number = no (λ ())
boolean ≡ᵀ (T U) = no (λ ())
boolean ≡ᵀ (T U) = no (λ ())
string ≡ᵀ nil = no (λ ())
string ≡ᵀ (x x₁) = no (λ ())
string ≡ᵀ none = no (λ ())
string ≡ᵀ any = no (λ ())
string ≡ᵀ boolean = no (λ ())
string ≡ᵀ number = no (λ ())
string ≡ᵀ string = yes refl
string ≡ᵀ (U V) = no (λ ())
string ≡ᵀ (U V) = no (λ ())
(S T) ≡ᵀ nil = no (λ ())
(S T) ≡ᵀ (U V) = no (λ ())
(S T) ≡ᵀ none = no (λ ())
(S T) ≡ᵀ any = no (λ ())
(S T) ≡ᵀ number = no (λ ())
(S T) ≡ᵀ boolean = no (λ ())
(S T) ≡ᵀ (U V) with (S ≡ᵀ U) | (T ≡ᵀ V)
(S T) ≡ᵀ (S T) | yes refl | yes refl = yes refl
(S T) ≡ᵀ (U V) | _ | no p = no (λ q p (cong rhs q))
(S T) ≡ᵀ (U V) | no p | _ = no (λ q p (cong lhs q))
(S T) ≡ᵀ (U V) = no (λ ())
(S T) ≡ᵀ nil = no (λ ())
(S T) ≡ᵀ (U V) = no (λ ())
(S T) ≡ᵀ none = no (λ ())
(S T) ≡ᵀ any = no (λ ())
(S T) ≡ᵀ number = no (λ ())
(S T) ≡ᵀ boolean = no (λ ())
(S T) ≡ᵀ (U V) = no (λ ())
(S T) ≡ᵀ (U V) with (S ≡ᵀ U) | (T ≡ᵀ V)
(S T) ≡ᵀ (U V) | yes refl | yes refl = yes refl
(S T) ≡ᵀ (U V) | _ | no p = no (λ q p (cong rhs q))
(S T) ≡ᵀ (U V) | no p | _ = no (λ q p (cong lhs q))
_≡ᴹᵀ_ : (T U : Maybe Type) Dec(T U)
nothing ≡ᴹᵀ nothing = yes refl
nothing ≡ᴹᵀ just U = no (λ ())
just T ≡ᴹᵀ nothing = no (λ ())
just T ≡ᴹᵀ just U with T ≡ᵀ U
(just T ≡ᴹᵀ just T) | yes refl = yes refl
(just T ≡ᴹᵀ just U) | no p = no (λ q p (just-inv q))
data Mode : Set where
strict : Mode
nonstrict : Mode
src : Mode Type Type
src m nil = none
src m number = none
src m boolean = none
src m string = none
src m (S T) = S
-- In nonstrict mode, functions are covaraiant, in strict mode they're contravariant
src strict (S T) = (src strict S) (src strict T)
src nonstrict (S T) = (src nonstrict S) (src nonstrict T)
src strict (S T) = (src strict S) (src strict T)
src nonstrict (S T) = (src nonstrict S) (src nonstrict T)
src strict none = any
src nonstrict none = none
src strict any = none
src nonstrict any = any
tgt : Type Type
tgt nil = none
@ -26,6 +165,8 @@ tgt (S ⇒ T) = T
tgt none = none
tgt any = any
tgt number = none
tgt boolean = none
tgt string = none
tgt (S T) = (tgt S) (tgt T)
tgt (S T) = (tgt S) (tgt T)

View File

@ -1,6 +1,8 @@
{-# OPTIONS --rewriting #-}
module Luau.Type.FromJSON where
open import Luau.Type using (Type; nil; _⇒_; __; _∩_; any; number)
open import Luau.Type using (Type; nil; _⇒_; __; _∩_; any; number; string)
open import Agda.Builtin.List using (List; _∷_; [])
open import Agda.Builtin.Bool using (true; false)
@ -42,6 +44,7 @@ typeFromJSON (object o) | just (string "AstTypeReference") with lookup name o
typeFromJSON (object o) | just (string "AstTypeReference") | just (string "nil") = Right nil
typeFromJSON (object o) | just (string "AstTypeReference") | just (string "any") = Right any
typeFromJSON (object o) | just (string "AstTypeReference") | just (string "number") = Right number
typeFromJSON (object o) | just (string "AstTypeReference") | just (string "string") = Right string
typeFromJSON (object o) | just (string "AstTypeReference") | _ = Left "Unknown referenced type"
typeFromJSON (object o) | just (string "AstTypeUnion") with lookup types o

View File

@ -1,7 +1,7 @@
module Luau.Type.ToString where
open import FFI.Data.String using (String; _++_)
open import Luau.Type using (Type; nil; _⇒_; none; any; number; __; _∩_; normalizeOptional)
open import Luau.Type using (Type; nil; _⇒_; none; any; number; boolean; string; __; _∩_; normalizeOptional)
{-# TERMINATING #-}
typeToString : Type String
@ -13,6 +13,8 @@ typeToString (S ⇒ T) = "(" ++ (typeToString S) ++ ") -> " ++ (typeToString T)
typeToString none = "none"
typeToString any = "any"
typeToString number = "number"
typeToString boolean = "boolean"
typeToString string = "string"
typeToString (S T) with normalizeOptional(S T)
typeToString (S T) | ((S T) nil) = "(" ++ typeToString (S T) ++ ")?"
typeToString (S T) | (S nil) = typeToString S ++ "?"

View File

@ -0,0 +1,149 @@
{-# OPTIONS --rewriting #-}
open import Luau.Type using (Mode)
module Luau.TypeCheck (m : Mode) where
open import Agda.Builtin.Equality using (_≡_)
open import FFI.Data.Maybe using (Maybe; just)
open import Luau.Syntax using (Expr; Stat; Block; BinaryOperator; yes; nil; addr; number; bool; string; val; var; var_∈_; _⟨_⟩∈_; function_is_end; _$_; block_is_end; binexp; local_←_; _∙_; done; return; name; +; -; *; /; <; >; ==; ~=; <=; >=; ··)
open import Luau.Var using (Var)
open import Luau.Addr using (Addr)
open import Luau.Heap using (Heap; Object; function_is_end) renaming (_[_] to _[_]ᴴ)
open import Luau.Type using (Type; Mode; nil; none; number; boolean; string; _⇒_; tgt)
open import Luau.VarCtxt using (VarCtxt; ∅; _⋒_; _↦_; _⊕_↦_; _⊝_) renaming (_[_] to _[_]ⱽ)
open import FFI.Data.Vector using (Vector)
open import FFI.Data.Maybe using (Maybe; just; nothing)
open import Properties.Product using (_×_; _,_)
src : Type Type
src = Luau.Type.src m
orNone : Maybe Type Type
orNone nothing = none
orNone (just T) = T
tgtBinOp : BinaryOperator Type
tgtBinOp + = number
tgtBinOp - = number
tgtBinOp * = number
tgtBinOp / = number
tgtBinOp < = boolean
tgtBinOp > = boolean
tgtBinOp == = boolean
tgtBinOp ~= = boolean
tgtBinOp <= = boolean
tgtBinOp >= = boolean
tgtBinOp ·· = string
data _⊢ᴮ_∈_ : VarCtxt Block yes Type Set
data _⊢ᴱ_∈_ : VarCtxt Expr yes Type Set
data _⊢ᴮ_∈_ where
done : {Γ}
---------------
Γ ⊢ᴮ done nil
return : {M B T U Γ}
Γ ⊢ᴱ M T
Γ ⊢ᴮ B U
---------------------
Γ ⊢ᴮ return M B T
local : {x M B T U V Γ}
Γ ⊢ᴱ M U
(Γ x T) ⊢ᴮ B V
--------------------------------
Γ ⊢ᴮ local var x T M B V
function : {f x B C T U V W Γ}
(Γ x T) ⊢ᴮ C V
(Γ f (T U)) ⊢ᴮ B W
-------------------------------------------------
Γ ⊢ᴮ function f var x T ⟩∈ U is C end B W
data _⊢ᴱ_∈_ where
nil : {Γ}
--------------------
Γ ⊢ᴱ (val nil) nil
var : {x T Γ}
T orNone(Γ [ x ]ⱽ)
----------------
Γ ⊢ᴱ (var x) T
addr : {a Γ} T
-----------------
Γ ⊢ᴱ val(addr a) T
number : {n Γ}
---------------------------
Γ ⊢ᴱ val(number n) number
bool : {b Γ}
--------------------------
Γ ⊢ᴱ val(bool b) boolean
string : {x Γ}
---------------------------
Γ ⊢ᴱ val(string x) string
app : {M N T U Γ}
Γ ⊢ᴱ M T
Γ ⊢ᴱ N U
----------------------
Γ ⊢ᴱ (M $ N) (tgt T)
function : {f x B T U V Γ}
(Γ x T) ⊢ᴮ B V
-----------------------------------------------------
Γ ⊢ᴱ (function f var x T ⟩∈ U is B end) (T U)
block : {b B T U Γ}
Γ ⊢ᴮ B U
------------------------------------
Γ ⊢ᴱ (block var b T is B end) T
binexp : {op Γ M N T U}
Γ ⊢ᴱ M T
Γ ⊢ᴱ N U
----------------------------------
Γ ⊢ᴱ (binexp M op N) tgtBinOp op
data ⊢ᴼ_ : Maybe(Object yes) Set where
nothing :
---------
⊢ᴼ nothing
function : {f x T U V B}
(x T) ⊢ᴮ B V
----------------------------------------------
⊢ᴼ (just function f var x T ⟩∈ U is B end)
⊢ᴴ_ : Heap yes Set
⊢ᴴ H = a {O} (H [ a ]ᴴ O) (⊢ᴼ O)
_⊢ᴴᴱ_▷_∈_ : VarCtxt Heap yes Expr yes Type Set
(Γ ⊢ᴴᴱ H M T) = (⊢ᴴ H) × (Γ ⊢ᴱ M T)
_⊢ᴴᴮ_▷_∈_ : VarCtxt Heap yes Block yes Type Set
(Γ ⊢ᴴᴮ H B T) = (⊢ᴴ H) × (Γ ⊢ᴮ B T)

View File

@ -1,20 +0,0 @@
module Luau.Value where
open import Agda.Builtin.Bool using (Bool; true; false)
open import Agda.Builtin.Float using (Float)
open import Luau.Addr using (Addr)
open import Luau.Syntax using (Block; Expr; nil; addr; number; true; false)
open import Luau.Var using (Var)
data Value : Set where
nil : Value
addr : Addr Value
number : Float Value
bool : Bool Value
val : {a} Value Expr a
val nil = nil
val (addr a) = addr a
val (number x) = number x
val (bool false) = false
val (bool true) = true

View File

@ -1,14 +0,0 @@
module Luau.Value.ToString where
open import Agda.Builtin.String using (String)
open import Agda.Builtin.Float using (primShowFloat)
open import Agda.Builtin.Bool using (true; false)
open import Luau.Value using (Value; nil; addr; number; bool)
open import Luau.Addr.ToString using (addrToString)
valueToString : Value String
valueToString nil = "nil"
valueToString (addr a) = addrToString a
valueToString (number x) = primShowFloat x
valueToString (bool false) = "false"
valueToString (bool true) = "true"

View File

@ -4,13 +4,13 @@ open import Agda.Builtin.Bool using (true; false)
open import Agda.Builtin.Equality using (_≡_)
open import Agda.Builtin.String using (String; primStringEquality)
open import Agda.Builtin.TrustMe using (primTrustMe)
open import Properties.Dec using (Dec; yes; no; )
open import Properties.Dec using (Dec; yes; no)
open import Properties.Equality using (_≢_)
Var : Set
Var = String
_≡ⱽ_ : (a b : Var) Dec (a b)
a ≡ⱽ b with primStringEquality a b
a ≡ⱽ b | false = no p where postulate p : (a b)
a ≡ⱽ b | false = no p where postulate p : (a b)
a ≡ⱽ b | true = yes primTrustMe

View File

@ -0,0 +1,43 @@
{-# OPTIONS --rewriting #-}
module Luau.VarCtxt where
open import Agda.Builtin.Equality using (_≡_)
open import Luau.Type using (Type; __; _∩_)
open import Luau.Var using (Var)
open import FFI.Data.Aeson using (KeyMap; Key; empty; unionWith; singleton; insert; delete; lookup; toString; fromString; lookup-insert; lookup-insert-not; lookup-empty; to-from; insert-swap; insert-over)
open import FFI.Data.Maybe using (Maybe; just; nothing)
open import Properties.Equality using (_≢_; cong; sym; trans)
VarCtxt : Set
VarCtxt = KeyMap Type
: VarCtxt
= empty
_⋒_ : VarCtxt VarCtxt VarCtxt
_⋒_ = unionWith _∩_
_⋓_ : VarCtxt VarCtxt VarCtxt
_⋓_ = unionWith __
_[_] : VarCtxt Var Maybe Type
Γ [ x ] = lookup (fromString x) Γ
_⊝_ : VarCtxt Var VarCtxt
Γ x = delete (fromString x) Γ
_↦_ : Var Type VarCtxt
x T = singleton (fromString x) T
_⊕_↦_ : VarCtxt Var Type VarCtxt
Γ x T = insert (fromString x) T Γ
⊕-over : {Γ x y T U} (x y) ((Γ x T) y U) (Γ y U)
⊕-over p = insert-over _ _ _ _ _ (cong fromString (sym p))
⊕-swap : {Γ x y T U} (x y) ((Γ x T) y U) ((Γ y U) x T)
⊕-swap p = insert-swap _ _ _ _ _ (λ q p (trans (sym (to-from _)) (trans (cong toString (sym q) ) (to-from _))) )
⊕-lookup-miss : x y T Γ (x y) (Γ [ y ] (Γ x T) [ y ])
⊕-lookup-miss x y T Γ p = lookup-insert-not (fromString x) (fromString y) T Γ λ q p (trans (sym (to-from x)) (trans (cong toString q) (to-from y)))

View File

@ -1,3 +1,5 @@
{-# OPTIONS --rewriting #-}
module PrettyPrinter where
open import Agda.Builtin.IO using (IO)

View File

@ -1,7 +1,11 @@
{-# OPTIONS --rewriting #-}
module Properties where
import Properties.Contradiction
import Properties.Dec
import Properties.Equality
import Properties.Step
import Properties.Remember
import Properties.Step
import Properties.StrictMode
import Properties.TypeCheck

View File

@ -1,8 +1,7 @@
module Properties.Dec where
data : Set where
open import Properties.Contradiction using (¬)
data Dec(A : Set) : Set where
yes : A Dec A
no : (A ) Dec A
no : ¬ A Dec A

View File

@ -0,0 +1,14 @@
module Properties.Product where
infixr 5 _×_ _,_
record Σ {A : Set} (B : A Set) : Set where
constructor _,_
field fst : A
field snd : B fst
open Σ public
_×_ : Set Set Set
A × B = Σ (λ (a : A) B)

View File

@ -1,24 +1,119 @@
{-# OPTIONS --rewriting #-}
module Properties.Step where
open import Agda.Builtin.Equality using (_≡_; refl)
open import Agda.Builtin.Float using (primFloatPlus; primFloatMinus; primFloatTimes; primFloatDiv)
open import Agda.Builtin.Float using (primFloatPlus; primFloatMinus; primFloatTimes; primFloatDiv; primFloatEquality; primFloatLess)
open import Agda.Builtin.Bool using (true; false)
open import Agda.Builtin.String using (primStringAppend)
open import FFI.Data.Maybe using (just; nothing)
open import Luau.Heap using (Heap; _[_]; alloc; ok; function_is_end)
open import Luau.Syntax using (Block; Expr; nil; var; addr; true; false; function_is_end; block_is_end; _$_; local_←_; return; done; _∙_; name; fun; arg; number; binexp; +; )
open import Luau.OpSem using (_⊢_⟶ᴱ_⊣_; _⊢_⟶ᴮ_⊣_; app₁ ; app₂ ; beta; function; block; return; done; local; subst; binOpNumbers; evalNumOp; binOp₁; binOp₂; evalEqOp; evalNeqOp; binOpEquality; binOpInequality)
open import Luau.RuntimeError using (RuntimeErrorᴱ; RuntimeErrorᴮ; TypeMismatch; UnboundVariable; SEGV; app₁; app₂; block; local; return; bin₁; bin₂)
open import Luau.RuntimeType using (function; number)
open import Luau.Syntax using (Block; Expr; nil; var; val; addr; bool; function_is_end; block_is_end; _$_; local_←_; return; done; _∙_; name; fun; arg; number; binexp; +; -; *; /; <; >; <=; >=; ==; ~=; ··; string)
open import Luau.OpSem using (_⟦_⟧_⟶_; _⊢_⟶ᴱ_⊣_; _⊢_⟶ᴮ_⊣_; app₁ ; app₂ ; beta; function; block; return; done; local; subst; binOp₀; binOp₁; binOp₂; +; -; *; /; <; >; <=; >=; ==; ~=; ··; evalEqOp; evalNeqOp)
open import Luau.RuntimeError using (BinOpError; RuntimeErrorᴱ; RuntimeErrorᴮ; FunctionMismatch; BinOpMismatch₁; BinOpMismatch₂; UnboundVariable; SEGV; app₁; app₂; block; local; return; bin₁; bin₂; +; -; *; /; <; >; <=; >=; ··)
open import Luau.RuntimeType using (valueType; function; number)
open import Luau.Substitution using (_[_/_]ᴮ)
open import Luau.Value using (nil; addr; val; number; bool)
open import Properties.Remember using (remember; _,_)
open import Utility.Bool using (not; _or_)
data BinOpStepResult v op w : Set where
step : x (v op w x) BinOpStepResult v op w
error₁ : BinOpError op (valueType(v)) BinOpStepResult v op w
error₂ : BinOpError op (valueType(w)) BinOpStepResult v op w
binOpStep : v op w BinOpStepResult v op w
binOpStep nil + w = error₁ (+ (λ ()))
binOpStep (addr a) + w = error₁ (+ (λ ()))
binOpStep (number m) + nil = error₂ (+ (λ ()))
binOpStep (number m) + (addr a) = error₂ (+ (λ ()))
binOpStep (number m) + (number n) = step (number (primFloatPlus m n)) (+ m n)
binOpStep (number m) + (bool b) = error₂ (+ (λ ()))
binOpStep (number m) + (string x) = error₂ (+ (λ ()))
binOpStep (number m) - (string x) = error₂ (- (λ ()))
binOpStep (number m) * (string x) = error₂ (* (λ ()))
binOpStep (number m) / (string x) = error₂ (/ (λ ()))
binOpStep (number m) < (string x) = error₂ (< (λ ()))
binOpStep (number m) > (string x) = error₂ (> (λ ()))
binOpStep (number m) == (string x) = step (bool false) (== (number m) (string x))
binOpStep (number m) ~= (string x) = step (bool true) (~= (number m) (string x))
binOpStep (number m) <= (string x) = error₂ (<= (λ ()))
binOpStep (number m) >= (string x) = error₂ (>= (λ ()))
binOpStep (bool b) + w = error₁ (+ (λ ()))
binOpStep nil - w = error₁ (- (λ ()))
binOpStep (addr a) - w = error₁ (- (λ ()))
binOpStep (number x) - nil = error₂ (- (λ ()))
binOpStep (number x) - (addr a) = error₂ (- (λ ()))
binOpStep (number x) - (number n) = step (number (primFloatMinus x n)) (- x n)
binOpStep (number x) - (bool b) = error₂ (- (λ ()))
binOpStep (bool b) - w = error₁ (- (λ ()))
binOpStep nil * w = error₁ (* (λ ()))
binOpStep (addr a) * w = error₁ (* (λ ()))
binOpStep (number m) * nil = error₂ (* (λ ()))
binOpStep (number m) * (addr a) = error₂ (* (λ ()))
binOpStep (number m) * (number n) = step (number (primFloatDiv m n)) (* m n)
binOpStep (number m) * (bool b) = error₂ (* (λ ()))
binOpStep (bool b) * w = error₁ (* (λ ()))
binOpStep nil / w = error₁ (/ (λ ()))
binOpStep (addr a) / w = error₁ (/ (λ ()))
binOpStep (number m) / nil = error₂ (/ (λ ()))
binOpStep (number m) / (addr a) = error₂ (/ (λ ()))
binOpStep (number m) / (number n) = step (number (primFloatTimes m n)) (/ m n)
binOpStep (number m) / (bool b) = error₂ (/ (λ ()))
binOpStep (bool b) / w = error₁ (/ (λ ()))
binOpStep nil < w = error₁ (< (λ ()))
binOpStep (addr a) < w = error₁ (< (λ ()))
binOpStep (number m) < nil = error₂ (< (λ ()))
binOpStep (number m) < (addr a) = error₂ (< (λ ()))
binOpStep (number m) < (number n) = step (bool (primFloatLess m n)) (< m n)
binOpStep (number m) < (bool b) = error₂ (< (λ ()))
binOpStep (bool b) < w = error₁ (< (λ ()))
binOpStep nil > w = error₁ (> (λ ()))
binOpStep (addr a) > w = error₁ (> (λ ()))
binOpStep (number m) > nil = error₂ (> (λ ()))
binOpStep (number m) > (addr a) = error₂ (> (λ ()))
binOpStep (number m) > (number n) = step (bool (primFloatLess n m)) (> m n)
binOpStep (number m) > (bool b) = error₂ (> (λ ()))
binOpStep (bool b) > w = error₁ (> (λ ()))
binOpStep v == w = step (bool (evalEqOp v w)) (== v w)
binOpStep v ~= w = step (bool (evalNeqOp v w)) (~= v w)
binOpStep nil <= w = error₁ (<= (λ ()))
binOpStep (addr a) <= w = error₁ (<= (λ ()))
binOpStep (number m) <= nil = error₂ (<= (λ ()))
binOpStep (number m) <= (addr a) = error₂ (<= (λ ()))
binOpStep (number m) <= (number n) = step (bool (primFloatLess m n or primFloatEquality m n)) (<= m n)
binOpStep (number m) <= (bool b) = error₂ (<= (λ ()))
binOpStep (bool b) <= w = error₁ (<= (λ ()))
binOpStep nil >= w = error₁ (>= (λ ()))
binOpStep (addr a) >= w = error₁ (>= (λ ()))
binOpStep (number m) >= nil = error₂ (>= (λ ()))
binOpStep (number m) >= (addr a) = error₂ (>= (λ ()))
binOpStep (number m) >= (number n) = step (bool (primFloatLess n m or primFloatEquality m n)) (>= m n)
binOpStep (number m) >= (bool b) = error₂ (>= (λ ()))
binOpStep (bool b) >= w = error₁ (>= (λ ()))
binOpStep (string x) + w = error₁ (+ (λ ()))
binOpStep (string x) - w = error₁ (- (λ ()))
binOpStep (string x) * w = error₁ (* (λ ()))
binOpStep (string x) / w = error₁ (/ (λ ()))
binOpStep (string x) < w = error₁ (< (λ ()))
binOpStep (string x) > w = error₁ (> (λ ()))
binOpStep (string x) <= w = error₁ (<= (λ ()))
binOpStep (string x) >= w = error₁ (>= (λ ()))
binOpStep nil ·· y = error₁ (·· (λ ()))
binOpStep (addr x) ·· y = error₁ (BinOpError.·· (λ ()))
binOpStep (number x) ·· y = error₁ (BinOpError.·· (λ ()))
binOpStep (bool x) ·· y = error₁ (BinOpError.·· (λ ()))
binOpStep (string x) ·· nil = error₂ (·· (λ ()))
binOpStep (string x) ·· (addr y) = error₂ (·· (λ ()))
binOpStep (string x) ·· (number y) = error₂ (·· (λ ()))
binOpStep (string x) ·· (bool y) = error₂ (·· (λ ()))
binOpStep (string x) ·· (string y) = step (string (primStringAppend x y)) (·· x y)
data StepResultᴮ {a} (H : Heap a) (B : Block a) : Set
data StepResultᴱ {a} (H : Heap a) (M : Expr a) : Set
data StepResultᴮ H B where
step : H B (H B ⟶ᴮ B H) StepResultᴮ H B
return : V {B} (B (return (val V) B)) StepResultᴮ H B
return : v {B} (B (return (val v) B)) StepResultᴮ H B
done : (B done) StepResultᴮ H B
error : (RuntimeErrorᴮ H B) StepResultᴮ H B
@ -30,56 +125,48 @@ data StepResultᴱ H M where
stepᴱ : {a} H M StepResultᴱ {a} H M
stepᴮ : {a} H B StepResultᴮ {a} H B
stepᴱ H nil = value nil refl
stepᴱ H (var x) = error (UnboundVariable x)
stepᴱ H (addr a) = value (addr a) refl
stepᴱ H (number x) = value (number x) refl
stepᴱ H (true) = value (bool true) refl
stepᴱ H (false) = value (bool false) refl
stepᴱ H (val v) = value v refl
stepᴱ H (var x) = error UnboundVariable
stepᴱ H (M $ N) with stepᴱ H M
stepᴱ H (M $ N) | step H M D = step H (M $ N) (app₁ D)
stepᴱ H (_ $ N) | value V refl with stepᴱ H N
stepᴱ H (_ $ N) | value V refl | step H N s = step H (val V $ N) (app₂ s)
stepᴱ H (_ $ _) | value nil refl | value W refl = error (app₁ (TypeMismatch function nil λ()))
stepᴱ H (_ $ _) | value (number n) refl | value W refl = error (app₁ (TypeMismatch function (number n) λ()))
stepᴱ H (_ $ _) | value (bool x) refl | value W refl = error (app₁ (TypeMismatch function (bool x) λ()))
stepᴱ H (_ $ _) | value (addr a) refl | value W refl with remember (H [ a ])
stepᴱ H (_ $ _) | value (addr a) refl | value W refl | (nothing , p) = error (app₁ (SEGV a p))
stepᴱ H (_ $ _) | value (addr a) refl | value W refl | (just(function F is B end) , p) = step H (block fun F is B [ W / name (arg F) ]ᴮ end) (beta p)
stepᴱ H (_ $ N) | value v refl with stepᴱ H N
stepᴱ H (_ $ N) | value v refl | step H N s = step H (val v $ N) (app₂ v s)
stepᴱ H (_ $ _) | value (addr a) refl | value w refl with remember (H [ a ])
stepᴱ H (_ $ _) | value (addr a) refl | value w refl | (nothing , p) = error (app₁ (SEGV p))
stepᴱ H (_ $ _) | value (addr a) refl | value w refl | (just(function F is B end) , p) = step H (block (fun F) is B [ w / name (arg F) ]ᴮ end) (beta function F is B end w refl p)
stepᴱ H (_ $ _) | value nil refl | value w refl = error (FunctionMismatch nil w (λ ()))
stepᴱ H (_ $ _) | value (number m) refl | value w refl = error (FunctionMismatch (number m) w (λ ()))
stepᴱ H (_ $ _) | value (bool b) refl | value w refl = error (FunctionMismatch (bool b) w (λ ()))
stepᴱ H (_ $ _) | value (string x) refl | value w refl = error (FunctionMismatch (string x) w (λ ()))
stepᴱ H (M $ N) | value V p | error E = error (app₂ E)
stepᴱ H (M $ N) | error E = error (app₁ E)
stepᴱ H (block b is B end) with stepᴮ H B
stepᴱ H (block b is B end) | step H B D = step H (block b is B end) (block D)
stepᴱ H (block b is (return _ B) end) | return V refl = step H (val V) return
stepᴱ H (block b is done end) | done refl = step H nil done
stepᴱ H (block b is B end) | error E = error (block b E)
stepᴱ H (block b is (return _ B) end) | return v refl = step H (val v) (return v)
stepᴱ H (block b is done end) | done refl = step H (val nil) done
stepᴱ H (block b is B end) | error E = error (block E)
stepᴱ H (function F is C end) with alloc H (function F is C end)
stepᴱ H function F is C end | ok a H p = step H (addr a) (function p)
stepᴱ H (binexp x op y) with stepᴱ H x
stepᴱ H (binexp x op y) | value x refl with stepᴱ H y
-- Have to use explicit form for ≡ here because it's a heavily overloaded symbol
stepᴱ H (binexp x Luau.Syntax.≡ y) | value x refl | value y refl = step H (val (evalEqOp x y)) binOpEquality
stepᴱ H (binexp x y) | value x refl | value y refl = step H (val (evalNeqOp x y)) binOpInequality
stepᴱ H (binexp x op y) | value (number x) refl | value (number y) refl = step H (val (evalNumOp x op y)) binOpNumbers
stepᴱ H (binexp x op y) | value (number x) refl | step H y s = step H (binexp (number x) op y) (binOp₂ s)
stepᴱ H (binexp x op y) | value (number x) refl | error E = error (bin₂ E)
stepᴱ H (binexp x op y) | value nil refl | _ = error (bin₁ (TypeMismatch number nil λ()))
stepᴱ H (binexp x op y) | _ | value nil refl = error (bin₂ (TypeMismatch number nil λ()))
stepᴱ H (binexp x op y) | value (addr a) refl | _ = error (bin₁ (TypeMismatch number (addr a) λ()))
stepᴱ H (binexp x op y) | _ | value (addr a) refl = error (bin₂ (TypeMismatch number (addr a) λ()))
stepᴱ H (binexp x op y) | value (bool x) refl | _ = error (bin₁ (TypeMismatch number (bool x) λ()))
stepᴱ H (binexp x op y) | _ | value (bool y) refl = error (bin₂ (TypeMismatch number (bool y) λ()))
stepᴱ H (binexp x op y) | step H x s = step H (binexp x op y) (binOp₁ s)
stepᴱ H (binexp x op y) | error E = error (bin₁ E)
stepᴱ H function F is C end | ok a H p = step H (val (addr a)) (function a p)
stepᴱ H (binexp M op N) with stepᴱ H M
stepᴱ H (binexp M op N) | step H M s = step H (binexp M op N) (binOp₁ s)
stepᴱ H (binexp M op N) | error E = error (bin₁ E)
stepᴱ H (binexp M op N) | value v refl with stepᴱ H N
stepᴱ H (binexp M op N) | value v refl | step H N s = step H (binexp (val v) op N) (binOp₂ s)
stepᴱ H (binexp M op N) | value v refl | error E = error (bin₂ E)
stepᴱ H (binexp M op N) | value v refl | value w refl with binOpStep v op w
stepᴱ H (binexp M op N) | value v refl | value w refl | step x p = step H (val x) (binOp₀ p)
stepᴱ H (binexp M op N) | value v refl | value w refl | error₁ E = error (BinOpMismatch₁ v w E)
stepᴱ H (binexp M op N) | value v refl | value w refl | error₂ E = error (BinOpMismatch₂ v w E)
stepᴮ H (function F is C end B) with alloc H (function F is C end)
stepᴮ H (function F is C end B) | ok a H p = step H (B [ addr a / fun F ]ᴮ) (function p)
stepᴮ H (function F is C end B) | ok a H p = step H (B [ addr a / name (fun F) ]ᴮ) (function a p)
stepᴮ H (local x M B) with stepᴱ H M
stepᴮ H (local x M B) | step H M D = step H (local x M B) (local D)
stepᴮ H (local x _ B) | value V refl = step H (B [ V / name x ]ᴮ) subst
stepᴮ H (local x M B) | error E = error (local x E)
stepᴮ H (local x _ B) | value v refl = step H (B [ v / name x ]ᴮ) (subst v)
stepᴮ H (local x M B) | error E = error (local E)
stepᴮ H (return M B) with stepᴱ H M
stepᴮ H (return M B) | step H M D = step H (return M B) (return D)
stepᴮ H (return _ B) | value V refl = return V refl
stepᴮ H (return M B) | error E = error (return E)
stepᴮ H done = done refl

View File

@ -0,0 +1,474 @@
{-# OPTIONS --rewriting #-}
module Properties.StrictMode where
import Agda.Builtin.Equality.Rewrite
open import Agda.Builtin.Equality using (_≡_; refl)
open import FFI.Data.Maybe using (Maybe; just; nothing)
open import Luau.Heap using (Heap; Object; function_is_end; defn; alloc; ok; next; lookup-not-allocated) renaming (_≡_⊕_↦_ to _≡ᴴ_⊕_↦_; _[_] to _[_]ᴴ; to ∅ᴴ)
open import Luau.StrictMode using (Warningᴱ; Warningᴮ; Warningᴼ; Warningᴴᴱ; Warningᴴᴮ; UnallocatedAddress; UnboundVariable; FunctionCallMismatch; app₁; app₂; BinOpWarning; BinOpMismatch₁; BinOpMismatch₂; bin₁; bin₂; BlockMismatch; block₁; return; LocalVarMismatch; local₁; local₂; FunctionDefnMismatch; function₁; function₂; heap; expr; block; addr; +; -; *; /; <; >; <=; >=; ··)
open import Luau.Substitution using (_[_/_]ᴮ; _[_/_]ᴱ; _[_/_]ᴮunless_; var_[_/_]ᴱwhenever_)
open import Luau.Syntax using (Expr; yes; var; val; var_∈_; _⟨_⟩∈_; _$_; addr; number; bool; string; binexp; nil; function_is_end; block_is_end; done; return; local_←_; _∙_; fun; arg; name; ==; ~=)
open import Luau.Type using (Type; strict; nil; _⇒_; none; tgt; _≡ᵀ_; _≡ᴹᵀ_)
open import Luau.TypeCheck(strict) using (_⊢ᴮ_∈_; _⊢ᴱ_∈_; _⊢ᴴᴮ_▷_∈_; _⊢ᴴᴱ_▷_∈_; nil; var; addr; app; function; block; done; return; local; orNone; tgtBinOp)
open import Luau.Var using (_≡ⱽ_)
open import Luau.Addr using (_≡ᴬ_)
open import Luau.VarCtxt using (VarCtxt; ∅; _⋒_; _↦_; _⊕_↦_; _⊝_; ⊕-lookup-miss; ⊕-swap; ⊕-over) renaming (_[_] to _[_]ⱽ)
open import Luau.VarCtxt using (VarCtxt; )
open import Properties.Remember using (remember; _,_)
open import Properties.Equality using (_≢_; sym; cong; trans; subst₁)
open import Properties.Dec using (Dec; yes; no)
open import Properties.Contradiction using (CONTRADICTION)
open import Properties.TypeCheck(strict) using (typeOfᴼ; typeOfᴹᴼ; typeOfⱽ; typeOfᴱ; typeOfᴮ; typeCheckᴱ; typeCheckᴮ; typeCheckᴼ; typeCheckᴴᴱ; typeCheckᴴᴮ; mustBeFunction; mustBeNumber; mustBeString)
open import Luau.OpSem using (_⟦_⟧_⟶_; _⊢_⟶*_⊣_; _⊢_⟶ᴮ_⊣_; _⊢_⟶ᴱ_⊣_; app₁; app₂; function; beta; return; block; done; local; subst; binOp₀; binOp₁; binOp₂; refl; step; +; -; *; /; <; >; ==; ~=; <=; >=; ··)
open import Luau.RuntimeError using (BinOpError; RuntimeErrorᴱ; RuntimeErrorᴮ; FunctionMismatch; BinOpMismatch₁; BinOpMismatch₂; UnboundVariable; SEGV; app₁; app₂; bin₁; bin₂; block; local; return; +; -; *; /; <; >; <=; >=; ··)
open import Luau.RuntimeType using (valueType)
src = Luau.Type.src strict
data _⊑_ (H : Heap yes) : Heap yes Set where
refl : (H H)
snoc : {H a V} (H ≡ᴴ H a V) (H H)
rednᴱ⊑ : {H H M M} (H M ⟶ᴱ M H) (H H)
rednᴮ⊑ : {H H B B} (H B ⟶ᴮ B H) (H H)
rednᴱ⊑ (function a p) = snoc p
rednᴱ⊑ (app₁ s) = rednᴱ⊑ s
rednᴱ⊑ (app₂ p s) = rednᴱ⊑ s
rednᴱ⊑ (beta O v p q) = refl
rednᴱ⊑ (block s) = rednᴮ⊑ s
rednᴱ⊑ (return v) = refl
rednᴱ⊑ done = refl
rednᴱ⊑ (binOp₀ p) = refl
rednᴱ⊑ (binOp₁ s) = rednᴱ⊑ s
rednᴱ⊑ (binOp₂ s) = rednᴱ⊑ s
rednᴮ⊑ (local s) = rednᴱ⊑ s
rednᴮ⊑ (subst v) = refl
rednᴮ⊑ (function a p) = snoc p
rednᴮ⊑ (return s) = rednᴱ⊑ s
data LookupResult (H : Heap yes) a V : Set where
just : (H [ a ]ᴴ just V) LookupResult H a V
nothing : (H [ a ]ᴴ nothing) LookupResult H a V
lookup-⊑-nothing : {H H} a (H H) (H [ a ]ᴴ nothing) (H [ a ]ᴴ nothing)
lookup-⊑-nothing {H} a refl p = p
lookup-⊑-nothing {H} a (snoc defn) p with a ≡ᴬ next H
lookup-⊑-nothing {H} a (snoc defn) p | yes refl = refl
lookup-⊑-nothing {H} a (snoc o) p | no q = trans (lookup-not-allocated o q) p
data OrWarningᴱ {Γ M T} (H : Heap yes) (D : Γ ⊢ᴱ M T) A : Set where
ok : A OrWarningᴱ H D A
warning : Warningᴱ H D OrWarningᴱ H D A
data OrWarningᴮ {Γ B T} (H : Heap yes) (D : Γ ⊢ᴮ B T) A : Set where
ok : A OrWarningᴮ H D A
warning : Warningᴮ H D OrWarningᴮ H D A
data OrWarningᴴᴱ {Γ M T} H (D : Γ ⊢ᴴᴱ H M T) A : Set where
ok : A OrWarningᴴᴱ H D A
warning : Warningᴴᴱ H D OrWarningᴴᴱ H D A
data OrWarningᴴᴮ {Γ B T} H (D : Γ ⊢ᴴᴮ H B T) A : Set where
ok : A OrWarningᴴᴮ H D A
warning : Warningᴴᴮ H D OrWarningᴴᴮ H D A
heap-weakeningᴱ : H M {H Γ} (H H) OrWarningᴱ H (typeCheckᴱ H Γ M) (typeOfᴱ H Γ M typeOfᴱ H Γ M)
heap-weakeningᴮ : H B {H Γ} (H H) OrWarningᴮ H (typeCheckᴮ H Γ B) (typeOfᴮ H Γ B typeOfᴮ H Γ B)
heap-weakeningᴱ H (var x) h = ok refl
heap-weakeningᴱ H (val nil) h = ok refl
heap-weakeningᴱ H (val (addr a)) refl = ok refl
heap-weakeningᴱ H (val (addr a)) (snoc {a = b} defn) with a ≡ᴬ b
heap-weakeningᴱ H (val (addr a)) (snoc {a = a} defn) | yes refl = warning (UnallocatedAddress refl)
heap-weakeningᴱ H (val (addr a)) (snoc {a = b} p) | no q = ok (cong orNone (cong typeOfᴹᴼ (lookup-not-allocated p q)))
heap-weakeningᴱ H (val (number n)) h = ok refl
heap-weakeningᴱ H (val (bool b)) h = ok refl
heap-weakeningᴱ H (val (string x)) h = ok refl
heap-weakeningᴱ H (binexp M op N) h = ok refl
heap-weakeningᴱ H (M $ N) h with heap-weakeningᴱ H M h
heap-weakeningᴱ H (M $ N) h | ok p = ok (cong tgt p)
heap-weakeningᴱ H (M $ N) h | warning W = warning (app₁ W)
heap-weakeningᴱ H (function f var x T ⟩∈ U is B end) h = ok refl
heap-weakeningᴱ H (block var b T is B end) h = ok refl
heap-weakeningᴮ H (function f var x T ⟩∈ U is C end B) h with heap-weakeningᴮ H B h
heap-weakeningᴮ H (function f var x T ⟩∈ U is C end B) h | ok p = ok p
heap-weakeningᴮ H (function f var x T ⟩∈ U is C end B) h | warning W = warning (function₂ W)
heap-weakeningᴮ H (local var x T M B) h with heap-weakeningᴮ H B h
heap-weakeningᴮ H (local var x T M B) h | ok p = ok p
heap-weakeningᴮ H (local var x T M B) h | warning W = warning (local₂ W)
heap-weakeningᴮ H (return M B) h with heap-weakeningᴱ H M h
heap-weakeningᴮ H (return M B) h | ok p = ok p
heap-weakeningᴮ H (return M B) h | warning W = warning (return W)
heap-weakeningᴮ H (done) h = ok refl
none-not-obj : O none typeOfᴼ O
none-not-obj (function f var x T ⟩∈ U is B end) ()
typeOf-val-not-none : {H Γ} v OrWarningᴱ H (typeCheckᴱ H Γ (val v)) (none typeOfᴱ H Γ (val v))
typeOf-val-not-none nil = ok (λ ())
typeOf-val-not-none (number n) = ok (λ ())
typeOf-val-not-none (bool b) = ok (λ ())
typeOf-val-not-none (string x) = ok (λ ())
typeOf-val-not-none {H = H} (addr a) with remember (H [ a ]ᴴ)
typeOf-val-not-none {H = H} (addr a) | (just O , p) = ok (λ q none-not-obj O (trans q (cong orNone (cong typeOfᴹᴼ p))))
typeOf-val-not-none {H = H} (addr a) | (nothing , p) = warning (UnallocatedAddress p)
substitutivityᴱ : {Γ T} H M v x (just T typeOfⱽ H v) (typeOfᴱ H (Γ x T) M typeOfᴱ H Γ (M [ v / x ]ᴱ))
substitutivityᴱ-whenever-yes : {Γ T} H v x y (p : x y) (just T typeOfⱽ H v) (typeOfᴱ H (Γ x T) (var y) typeOfᴱ H Γ (var y [ v / x ]ᴱwhenever (yes p)))
substitutivityᴱ-whenever-no : {Γ T} H v x y (p : x y) (just T typeOfⱽ H v) (typeOfᴱ H (Γ x T) (var y) typeOfᴱ H Γ (var y [ v / x ]ᴱwhenever (no p)))
substitutivityᴮ : {Γ T} H B v x (just T typeOfⱽ H v) (typeOfᴮ H (Γ x T) B typeOfᴮ H Γ (B [ v / x ]ᴮ))
substitutivityᴮ-unless-yes : {Γ Γ′ T} H B v x y (p : x y) (just T typeOfⱽ H v) (Γ′ Γ) (typeOfᴮ H Γ′ B typeOfᴮ H Γ (B [ v / x ]ᴮunless (yes p)))
substitutivityᴮ-unless-no : {Γ Γ′ T} H B v x y (p : x y) (just T typeOfⱽ H v) (Γ′ Γ x T) (typeOfᴮ H Γ′ B typeOfᴮ H Γ (B [ v / x ]ᴮunless (no p)))
substitutivityᴱ H (var y) v x p with x ≡ⱽ y
substitutivityᴱ H (var y) v x p | yes q = substitutivityᴱ-whenever-yes H v x y q p
substitutivityᴱ H (var y) v x p | no q = substitutivityᴱ-whenever-no H v x y q p
substitutivityᴱ H (val w) v x p = refl
substitutivityᴱ H (binexp M op N) v x p = refl
substitutivityᴱ H (M $ N) v x p = cong tgt (substitutivityᴱ H M v x p)
substitutivityᴱ H (function f var y T ⟩∈ U is B end) v x p = refl
substitutivityᴱ H (block var b T is B end) v x p = refl
substitutivityᴱ-whenever-yes H v x x refl q = cong orNone q
substitutivityᴱ-whenever-no H v x y p q = cong orNone ( sym (⊕-lookup-miss x y _ _ p))
substitutivityᴮ H (function f var y T ⟩∈ U is C end B) v x p with x ≡ⱽ f
substitutivityᴮ H (function f var y T ⟩∈ U is C end B) v x p | yes q = substitutivityᴮ-unless-yes H B v x f q p (⊕-over q)
substitutivityᴮ H (function f var y T ⟩∈ U is C end B) v x p | no q = substitutivityᴮ-unless-no H B v x f q p (⊕-swap q)
substitutivityᴮ H (local var y T M B) v x p with x ≡ⱽ y
substitutivityᴮ H (local var y T M B) v x p | yes q = substitutivityᴮ-unless-yes H B v x y q p (⊕-over q)
substitutivityᴮ H (local var y T M B) v x p | no q = substitutivityᴮ-unless-no H B v x y q p (⊕-swap q)
substitutivityᴮ H (return M B) v x p = substitutivityᴱ H M v x p
substitutivityᴮ H done v x p = refl
substitutivityᴮ-unless-yes H B v x x refl q refl = refl
substitutivityᴮ-unless-no H B v x y p q refl = substitutivityᴮ H B v x q
binOpPreservation : H {op v w x} (v op w x) (tgtBinOp op typeOfᴱ H (val x))
binOpPreservation H (+ m n) = refl
binOpPreservation H (- m n) = refl
binOpPreservation H (/ m n) = refl
binOpPreservation H (* m n) = refl
binOpPreservation H (< m n) = refl
binOpPreservation H (> m n) = refl
binOpPreservation H (<= m n) = refl
binOpPreservation H (>= m n) = refl
binOpPreservation H (== v w) = refl
binOpPreservation H (~= v w) = refl
binOpPreservation H (·· v w) = refl
preservationᴱ : H M {H M} (H M ⟶ᴱ M H) OrWarningᴴᴱ H (typeCheckᴴᴱ H M) (typeOfᴱ H M typeOfᴱ H M)
preservationᴮ : H B {H B} (H B ⟶ᴮ B H) OrWarningᴴᴮ H (typeCheckᴴᴮ H B) (typeOfᴮ H B typeOfᴮ H B)
preservationᴱ H (function f var x T ⟩∈ U is B end) (function a defn) = ok refl
preservationᴱ H (M $ N) (app₁ s) with preservationᴱ H M s
preservationᴱ H (M $ N) (app₁ s) | ok p = ok (cong tgt p)
preservationᴱ H (M $ N) (app₁ s) | warning (expr W) = warning (expr (app₁ W))
preservationᴱ H (M $ N) (app₁ s) | warning (heap W) = warning (heap W)
preservationᴱ H (M $ N) (app₂ p s) with heap-weakeningᴱ H M (rednᴱ⊑ s)
preservationᴱ H (M $ N) (app₂ p s) | ok q = ok (cong tgt q)
preservationᴱ H (M $ N) (app₂ p s) | warning W = warning (expr (app₁ W))
preservationᴱ H (val (addr a) $ N) (beta (function f var x S ⟩∈ T is B end) v refl p) with remember (typeOfⱽ H v)
preservationᴱ H (val (addr a) $ N) (beta (function f var x S ⟩∈ T is B end) v refl p) | (just U , q) with S ≡ᵀ U | T ≡ᵀ typeOfᴮ H (x S) B
preservationᴱ H (val (addr a) $ N) (beta (function f var x S ⟩∈ T is B end) v refl p) | (just U , q) | yes refl | yes refl = ok (cong tgt (cong orNone (cong typeOfᴹᴼ p)))
preservationᴱ H (val (addr a) $ N) (beta (function f var x S ⟩∈ T is B end) v refl p) | (just U , q) | yes refl | no r = warning (heap (addr a p (FunctionDefnMismatch r)))
preservationᴱ H (val (addr a) $ N) (beta (function f var x S ⟩∈ T is B end) v refl p) | (just U , q) | no r | _ = warning (expr (FunctionCallMismatch (λ s r (trans (trans (sym (cong src (cong orNone (cong typeOfᴹᴼ p)))) s) (cong orNone q)))))
preservationᴱ H (val (addr a) $ N) (beta (function f var x S ⟩∈ T is B end) v refl p) | (nothing , q) with typeOf-val-not-none v
preservationᴱ H (val (addr a) $ N) (beta (function f var x S ⟩∈ T is B end) v refl p) | (nothing , q) | ok r = CONTRADICTION (r (sym (cong orNone q)))
preservationᴱ H (val (addr a) $ N) (beta (function f var x S ⟩∈ T is B end) v refl p) | (nothing , q) | warning W = warning (expr (app₂ W))
preservationᴱ H (block var b T is B end) (block s) = ok refl
preservationᴱ H (block var b T is return M B end) (return v) with T ≡ᵀ typeOfᴱ H (val v)
preservationᴱ H (block var b T is return M B end) (return v) | yes p = ok p
preservationᴱ H (block var b T is return M B end) (return v) | no p = warning (expr (BlockMismatch p))
preservationᴱ H (block var b T is done end) (done) with T ≡ᵀ nil
preservationᴱ H (block var b T is done end) (done) | yes p = ok p
preservationᴱ H (block var b T is done end) (done) | no p = warning (expr (BlockMismatch p))
preservationᴱ H (binexp M op N) (binOp₀ s) = ok (binOpPreservation H s)
preservationᴱ H (binexp M op N) (binOp₁ s) = ok refl
preservationᴱ H (binexp M op N) (binOp₂ s) = ok refl
preservationᴮ H (local var x T M B) (local s) with heap-weakeningᴮ H B (rednᴱ⊑ s)
preservationᴮ H (local var x T M B) (local s) | ok p = ok p
preservationᴮ H (local var x T M B) (local s) | warning W = warning (block (local₂ W))
preservationᴮ H (local var x T M B) (subst v) with remember (typeOfⱽ H v)
preservationᴮ H (local var x T M B) (subst v) | (just U , p) with T ≡ᵀ U
preservationᴮ H (local var x T M B) (subst v) | (just T , p) | yes refl = ok (substitutivityᴮ H B v x (sym p))
preservationᴮ H (local var x T M B) (subst v) | (just U , p) | no q = warning (block (LocalVarMismatch (λ r q (trans r (cong orNone p)))))
preservationᴮ H (local var x T M B) (subst v) | (nothing , p) with typeOf-val-not-none v
preservationᴮ H (local var x T M B) (subst v) | (nothing , p) | ok q = CONTRADICTION (q (sym (cong orNone p)))
preservationᴮ H (local var x T M B) (subst v) | (nothing , p) | warning W = warning (block (local₁ W))
preservationᴮ H (function f var x T ⟩∈ U is C end B) (function a defn) with heap-weakeningᴮ H B (snoc defn)
preservationᴮ H (function f var x T ⟩∈ U is C end B) (function a defn) | ok r = ok (trans r (substitutivityᴮ _ B (addr a) f refl))
preservationᴮ H (function f var x T ⟩∈ U is C end B) (function a defn) | warning W = warning (block (function₂ W))
preservationᴮ H (return M B) (return s) with preservationᴱ H M s
preservationᴮ H (return M B) (return s) | ok p = ok p
preservationᴮ H (return M B) (return s) | warning (expr W) = warning (block (return W))
preservationᴮ H (return M B) (return s) | warning (heap W) = warning (heap W)
reflect-substitutionᴱ : {Γ T} H M v x (just T typeOfⱽ H v) Warningᴱ H (typeCheckᴱ H Γ (M [ v / x ]ᴱ)) Warningᴱ H (typeCheckᴱ H (Γ x T) M)
reflect-substitutionᴱ-whenever-yes : {Γ T} H v x y (p : x y) (just T typeOfⱽ H v) Warningᴱ H (typeCheckᴱ H Γ (var y [ v / x ]ᴱwhenever yes p)) Warningᴱ H (typeCheckᴱ H (Γ x T) (var y))
reflect-substitutionᴱ-whenever-no : {Γ T} H v x y (p : x y) (just T typeOfⱽ H v) Warningᴱ H (typeCheckᴱ H Γ (var y [ v / x ]ᴱwhenever no p)) Warningᴱ H (typeCheckᴱ H (Γ x T) (var y))
reflect-substitutionᴮ : {Γ T} H B v x (just T typeOfⱽ H v) Warningᴮ H (typeCheckᴮ H Γ (B [ v / x ]ᴮ)) Warningᴮ H (typeCheckᴮ H (Γ x T) B)
reflect-substitutionᴮ-unless-yes : {Γ Γ′ T} H B v x y (r : x y) (just T typeOfⱽ H v) (Γ′ Γ) Warningᴮ H (typeCheckᴮ H Γ (B [ v / x ]ᴮunless yes r)) Warningᴮ H (typeCheckᴮ H Γ′ B)
reflect-substitutionᴮ-unless-no : {Γ Γ′ T} H B v x y (r : x y) (just T typeOfⱽ H v) (Γ′ Γ x T) Warningᴮ H (typeCheckᴮ H Γ (B [ v / x ]ᴮunless no r)) Warningᴮ H (typeCheckᴮ H Γ′ B)
reflect-substitutionᴱ H (var y) v x p W with x ≡ⱽ y
reflect-substitutionᴱ H (var y) v x p W | yes r = reflect-substitutionᴱ-whenever-yes H v x y r p W
reflect-substitutionᴱ H (var y) v x p W | no r = reflect-substitutionᴱ-whenever-no H v x y r p W
reflect-substitutionᴱ H (val (addr a)) v x p (UnallocatedAddress r) = UnallocatedAddress r
reflect-substitutionᴱ H (M $ N) v x p (FunctionCallMismatch q) = FunctionCallMismatch (λ s q (trans (cong src (sym (substitutivityᴱ H M v x p))) (trans s (substitutivityᴱ H N v x p))))
reflect-substitutionᴱ H (M $ N) v x p (app₁ W) = app₁ (reflect-substitutionᴱ H M v x p W)
reflect-substitutionᴱ H (M $ N) v x p (app₂ W) = app₂ (reflect-substitutionᴱ H N v x p W)
reflect-substitutionᴱ H (function f var y T ⟩∈ U is B end) v x p (FunctionDefnMismatch q) with (x ≡ⱽ y)
reflect-substitutionᴱ H (function f var y T ⟩∈ U is B end) v x p (FunctionDefnMismatch q) | yes r = FunctionDefnMismatch (λ s q (trans s (substitutivityᴮ-unless-yes H B v x y r p (⊕-over r))))
reflect-substitutionᴱ H (function f var y T ⟩∈ U is B end) v x p (FunctionDefnMismatch q) | no r = FunctionDefnMismatch (λ s q (trans s (substitutivityᴮ-unless-no H B v x y r p (⊕-swap r))))
reflect-substitutionᴱ H (function f var y T ⟩∈ U is B end) v x p (function₁ W) with (x ≡ⱽ y)
reflect-substitutionᴱ H (function f var y T ⟩∈ U is B end) v x p (function₁ W) | yes r = function₁ (reflect-substitutionᴮ-unless-yes H B v x y r p (⊕-over r) W)
reflect-substitutionᴱ H (function f var y T ⟩∈ U is B end) v x p (function₁ W) | no r = function₁ (reflect-substitutionᴮ-unless-no H B v x y r p (⊕-swap r) W)
reflect-substitutionᴱ H (block var b T is B end) v x p (BlockMismatch q) = BlockMismatch (λ r q (trans r (substitutivityᴮ H B v x p)))
reflect-substitutionᴱ H (block var b T is B end) v x p (block₁ W) = block₁ (reflect-substitutionᴮ H B v x p W)
reflect-substitutionᴱ H (binexp M op N) x v p (BinOpMismatch₁ q) = BinOpMismatch₁ (subst₁ (BinOpWarning op) (sym (substitutivityᴱ H M x v p)) q)
reflect-substitutionᴱ H (binexp M op N) x v p (BinOpMismatch₂ q) = BinOpMismatch₂ (subst₁ (BinOpWarning op) (sym (substitutivityᴱ H N x v p)) q)
reflect-substitutionᴱ H (binexp M op N) x v p (bin₁ W) = bin₁ (reflect-substitutionᴱ H M x v p W)
reflect-substitutionᴱ H (binexp M op N) x v p (bin₂ W) = bin₂ (reflect-substitutionᴱ H N x v p W)
reflect-substitutionᴱ-whenever-no H v x y p q (UnboundVariable r) = UnboundVariable (trans (sym (⊕-lookup-miss x y _ _ p)) r)
reflect-substitutionᴱ-whenever-yes H (addr a) x x refl p (UnallocatedAddress q) with trans p (cong typeOfᴹᴼ q)
reflect-substitutionᴱ-whenever-yes H (addr a) x x refl p (UnallocatedAddress q) | ()
reflect-substitutionᴮ H (function f var y T ⟩∈ U is C end B) v x p (FunctionDefnMismatch q) with (x ≡ⱽ y)
reflect-substitutionᴮ H (function f var y T ⟩∈ U is C end B) v x p (FunctionDefnMismatch q) | yes r = FunctionDefnMismatch (λ s q (trans s (substitutivityᴮ-unless-yes H C v x y r p (⊕-over r))))
reflect-substitutionᴮ H (function f var y T ⟩∈ U is C end B) v x p (FunctionDefnMismatch q) | no r = FunctionDefnMismatch (λ s q (trans s (substitutivityᴮ-unless-no H C v x y r p (⊕-swap r))))
reflect-substitutionᴮ H (function f var y T ⟩∈ U is C end B) v x p (function₁ W) with (x ≡ⱽ y)
reflect-substitutionᴮ H (function f var y T ⟩∈ U is C end B) v x p (function₁ W) | yes r = function₁ (reflect-substitutionᴮ-unless-yes H C v x y r p (⊕-over r) W)
reflect-substitutionᴮ H (function f var y T ⟩∈ U is C end B) v x p (function₁ W) | no r = function₁ (reflect-substitutionᴮ-unless-no H C v x y r p (⊕-swap r) W)
reflect-substitutionᴮ H (function f var y T ⟩∈ U is C end B) v x p (function₂ W) with (x ≡ⱽ f)
reflect-substitutionᴮ H (function f var y T ⟩∈ U is C end B) v x p (function₂ W)| yes r = function₂ (reflect-substitutionᴮ-unless-yes H B v x f r p (⊕-over r) W)
reflect-substitutionᴮ H (function f var y T ⟩∈ U is C end B) v x p (function₂ W)| no r = function₂ (reflect-substitutionᴮ-unless-no H B v x f r p (⊕-swap r) W)
reflect-substitutionᴮ H (local var y T M B) v x p (LocalVarMismatch q) = LocalVarMismatch (λ r q (trans r (substitutivityᴱ H M v x p)))
reflect-substitutionᴮ H (local var y T M B) v x p (local₁ W) = local₁ (reflect-substitutionᴱ H M v x p W)
reflect-substitutionᴮ H (local var y T M B) v x p (local₂ W) with (x ≡ⱽ y)
reflect-substitutionᴮ H (local var y T M B) v x p (local₂ W) | yes r = local₂ (reflect-substitutionᴮ-unless-yes H B v x y r p (⊕-over r) W)
reflect-substitutionᴮ H (local var y T M B) v x p (local₂ W) | no r = local₂ (reflect-substitutionᴮ-unless-no H B v x y r p (⊕-swap r) W)
reflect-substitutionᴮ H (return M B) v x p (return W) = return (reflect-substitutionᴱ H M v x p W)
reflect-substitutionᴮ-unless-yes H B v x y r p refl W = W
reflect-substitutionᴮ-unless-no H B v x y r p refl W = reflect-substitutionᴮ H B v x p W
reflect-weakeningᴱ : H M {H Γ} (H H) Warningᴱ H (typeCheckᴱ H Γ M) Warningᴱ H (typeCheckᴱ H Γ M)
reflect-weakeningᴮ : H B {H Γ} (H H) Warningᴮ H (typeCheckᴮ H Γ B) Warningᴮ H (typeCheckᴮ H Γ B)
reflect-weakeningᴱ H (var x) h (UnboundVariable p) = (UnboundVariable p)
reflect-weakeningᴱ H (val (addr a)) h (UnallocatedAddress p) = UnallocatedAddress (lookup-⊑-nothing a h p)
reflect-weakeningᴱ H (M $ N) h (FunctionCallMismatch p) with heap-weakeningᴱ H M h | heap-weakeningᴱ H N h
reflect-weakeningᴱ H (M $ N) h (FunctionCallMismatch p) | ok q₁ | ok q₂ = FunctionCallMismatch (λ r p (trans (cong src (sym q₁)) (trans r q₂)))
reflect-weakeningᴱ H (M $ N) h (FunctionCallMismatch p) | warning W | _ = app₁ W
reflect-weakeningᴱ H (M $ N) h (FunctionCallMismatch p) | _ | warning W = app₂ W
reflect-weakeningᴱ H (M $ N) h (app₁ W) = app₁ (reflect-weakeningᴱ H M h W)
reflect-weakeningᴱ H (M $ N) h (app₂ W) = app₂ (reflect-weakeningᴱ H N h W)
reflect-weakeningᴱ H (binexp M op N) h (BinOpMismatch₁ p) with heap-weakeningᴱ H M h
reflect-weakeningᴱ H (binexp M op N) h (BinOpMismatch₁ p) | ok q = BinOpMismatch₁ (subst₁ (BinOpWarning op) (sym q) p)
reflect-weakeningᴱ H (binexp M op N) h (BinOpMismatch₁ p) | warning W = bin₁ W
reflect-weakeningᴱ H (binexp M op N) h (BinOpMismatch₂ p) with heap-weakeningᴱ H N h
reflect-weakeningᴱ H (binexp M op N) h (BinOpMismatch₂ p) | ok q = BinOpMismatch₂ (subst₁ (BinOpWarning op) (sym q) p)
reflect-weakeningᴱ H (binexp M op N) h (BinOpMismatch₂ p) | warning W = bin₂ W
reflect-weakeningᴱ H (binexp M op N) h (bin₁ W) = bin₁ (reflect-weakeningᴱ H M h W)
reflect-weakeningᴱ H (binexp M op N) h (bin₂ W) = bin₂ (reflect-weakeningᴱ H N h W)
reflect-weakeningᴱ H (function f var y T ⟩∈ U is B end) h (FunctionDefnMismatch p) with heap-weakeningᴮ H B h
reflect-weakeningᴱ H (function f var y T ⟩∈ U is B end) h (FunctionDefnMismatch p) | ok q = FunctionDefnMismatch (λ r p (trans r q))
reflect-weakeningᴱ H (function f var y T ⟩∈ U is B end) h (FunctionDefnMismatch p) | warning W = function₁ W
reflect-weakeningᴱ H (function f var y T ⟩∈ U is B end) h (function₁ W) = function₁ (reflect-weakeningᴮ H B h W)
reflect-weakeningᴱ H (block var b T is B end) h (BlockMismatch p) with heap-weakeningᴮ H B h
reflect-weakeningᴱ H (block var b T is B end) h (BlockMismatch p) | ok q = BlockMismatch (λ r p (trans r q))
reflect-weakeningᴱ H (block var b T is B end) h (BlockMismatch p) | warning W = block₁ W
reflect-weakeningᴱ H (block var b T is B end) h (block₁ W) = block₁ (reflect-weakeningᴮ H B h W)
reflect-weakeningᴮ H (return M B) h (return W) = return (reflect-weakeningᴱ H M h W)
reflect-weakeningᴮ H (local var y T M B) h (LocalVarMismatch p) with heap-weakeningᴱ H M h
reflect-weakeningᴮ H (local var y T M B) h (LocalVarMismatch p) | ok q = LocalVarMismatch (λ r p (trans r q))
reflect-weakeningᴮ H (local var y T M B) h (LocalVarMismatch p) | warning W = local₁ W
reflect-weakeningᴮ H (local var y T M B) h (local₁ W) = local₁ (reflect-weakeningᴱ H M h W)
reflect-weakeningᴮ H (local var y T M B) h (local₂ W) = local₂ (reflect-weakeningᴮ H B h W)
reflect-weakeningᴮ H (function f var x T ⟩∈ U is C end B) h (FunctionDefnMismatch p) with heap-weakeningᴮ H C h
reflect-weakeningᴮ H (function f var x T ⟩∈ U is C end B) h (FunctionDefnMismatch p) | ok q = FunctionDefnMismatch (λ r p (trans r q))
reflect-weakeningᴮ H (function f var x T ⟩∈ U is C end B) h (FunctionDefnMismatch p) | warning W = function₁ W
reflect-weakeningᴮ H (function f var x T ⟩∈ U is C end B) h (function₁ W) = function₁ (reflect-weakeningᴮ H C h W)
reflect-weakeningᴮ H (function f var x T ⟩∈ U is C end B) h (function₂ W) = function₂ (reflect-weakeningᴮ H B h W)
reflect-weakeningᴼ : H O {H} (H H) Warningᴼ H (typeCheckᴼ H O) Warningᴼ H (typeCheckᴼ H O)
reflect-weakeningᴼ H (just (function f var x T ⟩∈ U is B end)) h (FunctionDefnMismatch p) with heap-weakeningᴮ H B h
reflect-weakeningᴼ H (just (function f var x T ⟩∈ U is B end)) h (FunctionDefnMismatch p) | ok q = FunctionDefnMismatch (λ r p (trans r q))
reflect-weakeningᴼ H (just (function f var x T ⟩∈ U is B end)) h (FunctionDefnMismatch p) | warning W = function₁ W
reflect-weakeningᴼ H (just (function f var x T ⟩∈ U is B end)) h (function₁ W) = function₁ (reflect-weakeningᴮ H B h W)
reflectᴱ : H M {H M} (H M ⟶ᴱ M H) Warningᴱ H (typeCheckᴱ H M) Warningᴴᴱ H (typeCheckᴴᴱ H M)
reflectᴮ : H B {H B} (H B ⟶ᴮ B H) Warningᴮ H (typeCheckᴮ H B) Warningᴴᴮ H (typeCheckᴴᴮ H B)
reflectᴱ H (M $ N) (app₁ s) (FunctionCallMismatch p) with preservationᴱ H M s | heap-weakeningᴱ H N (rednᴱ⊑ s)
reflectᴱ H (M $ N) (app₁ s) (FunctionCallMismatch p) | ok q | ok q = expr (FunctionCallMismatch (λ r p (trans (trans (cong src (sym q)) r) q)))
reflectᴱ H (M $ N) (app₁ s) (FunctionCallMismatch p) | warning (expr W) | _ = expr (app₁ W)
reflectᴱ H (M $ N) (app₁ s) (FunctionCallMismatch p) | warning (heap W) | _ = heap W
reflectᴱ H (M $ N) (app₁ s) (FunctionCallMismatch p) | _ | warning W = expr (app₂ W)
reflectᴱ H (M $ N) (app₁ s) (app₁ W) with reflectᴱ H M s W
reflectᴱ H (M $ N) (app₁ s) (app₁ W) | heap W = heap W
reflectᴱ H (M $ N) (app₁ s) (app₁ W) | expr W = expr (app₁ W)
reflectᴱ H (M $ N) (app₁ s) (app₂ W) = expr (app₂ (reflect-weakeningᴱ H N (rednᴱ⊑ s) W))
reflectᴱ H (M $ N) (app₂ p s) (FunctionCallMismatch p) with heap-weakeningᴱ H (val p) (rednᴱ⊑ s) | preservationᴱ H N s
reflectᴱ H (M $ N) (app₂ p s) (FunctionCallMismatch p) | ok q | ok q = expr (FunctionCallMismatch (λ r p (trans (trans (cong src (sym q)) r) q)))
reflectᴱ H (M $ N) (app₂ p s) (FunctionCallMismatch p) | warning W | _ = expr (app₁ W)
reflectᴱ H (M $ N) (app₂ p s) (FunctionCallMismatch p) | _ | warning (expr W) = expr (app₂ W)
reflectᴱ H (M $ N) (app₂ p s) (FunctionCallMismatch p) | _ | warning (heap W) = heap W
reflectᴱ H (M $ N) (app₂ p s) (app₁ W) = expr (app₁ (reflect-weakeningᴱ H M (rednᴱ⊑ s) W))
reflectᴱ H (M $ N) (app₂ p s) (app₂ W) with reflectᴱ H N s W
reflectᴱ H (M $ N) (app₂ p s) (app₂ W) | heap W = heap W
reflectᴱ H (M $ N) (app₂ p s) (app₂ W) | expr W = expr (app₂ W)
reflectᴱ H (val (addr a) $ N) (beta (function f var x T ⟩∈ U is B end) v refl p) (BlockMismatch q) with remember (typeOfⱽ H v)
reflectᴱ H (val (addr a) $ N) (beta (function f var x T ⟩∈ U is B end) v refl p) (BlockMismatch q) | (just S , r) with S ≡ᵀ T
reflectᴱ H (val (addr a) $ N) (beta (function f var x T ⟩∈ U is B end) v refl p) (BlockMismatch q) | (just T , r) | yes refl = heap (addr a p (FunctionDefnMismatch (λ s q (trans s (substitutivityᴮ H B v x (sym r))))))
reflectᴱ H (val (addr a) $ N) (beta (function f var x T ⟩∈ U is B end) v refl p) (BlockMismatch q) | (just S , r) | no s = expr (FunctionCallMismatch (λ t s (trans (cong orNone (sym r)) (trans (sym t) (cong src (cong orNone (cong typeOfᴹᴼ p)))))))
reflectᴱ H (val (addr a) $ N) (beta (function f var x T ⟩∈ U is B end) v refl p) (BlockMismatch q) | (nothing , r) with typeOf-val-not-none v
reflectᴱ H (val (addr a) $ N) (beta (function f var x T ⟩∈ U is B end) v refl p) (BlockMismatch q) | (nothing , r) | ok s = CONTRADICTION (s (cong orNone (sym r)))
reflectᴱ H (val (addr a) $ N) (beta (function f var x T ⟩∈ U is B end) v refl p) (BlockMismatch q) | (nothing , r) | warning W = expr (app₂ W)
reflectᴱ H (val (addr a) $ N) (beta (function f var x T ⟩∈ U is B end) v refl p) (block₁ W) with remember (typeOfⱽ H v)
reflectᴱ H (val (addr a) $ N) (beta (function f var x T ⟩∈ U is B end) v refl p) (block₁ W) | (just S , q) with S ≡ᵀ T
reflectᴱ H (val (addr a) $ N) (beta (function f var x T ⟩∈ U is B end) v refl p) (block₁ W) | (just T , q) | yes refl = heap (addr a p (function₁ (reflect-substitutionᴮ H B v x (sym q) W)))
reflectᴱ H (val (addr a) $ N) (beta (function f var x T ⟩∈ U is B end) v refl p) (block₁ W) | (just S , q) | no r = expr (FunctionCallMismatch (λ s r (trans (cong orNone (sym q)) (trans (sym s) (cong src (cong orNone (cong typeOfᴹᴼ p)))))))
reflectᴱ H (val (addr a) $ N) (beta (function f var x T ⟩∈ U is B end) v refl p) (block₁ W) | (nothing , q) with typeOf-val-not-none v
reflectᴱ H (val (addr a) $ N) (beta (function f var x T ⟩∈ U is B end) v refl p) (block₁ W) | (nothing , q) | ok r = CONTRADICTION (r (cong orNone (sym q)))
reflectᴱ H (val (addr a) $ N) (beta (function f var x T ⟩∈ U is B end) v refl p) (block₁ W) | (nothing , q) | warning W = expr (app₂ W)
reflectᴱ H (block var b T is B end) (block s) (BlockMismatch p) with preservationᴮ H B s
reflectᴱ H (block var b T is B end) (block s) (BlockMismatch p) | ok q = expr (BlockMismatch (λ r p (trans r q)))
reflectᴱ H (block var b T is B end) (block s) (BlockMismatch p) | warning (heap W) = heap W
reflectᴱ H (block var b T is B end) (block s) (BlockMismatch p) | warning (block W) = expr (block₁ W)
reflectᴱ H (block var b T is B end) (block s) (block₁ W) with reflectᴮ H B s W
reflectᴱ H (block var b T is B end) (block s) (block₁ W) | heap W = heap W
reflectᴱ H (block var b T is B end) (block s) (block₁ W) | block W = expr (block₁ W)
reflectᴱ H (block var b T is B end) (return v) W = expr (block₁ (return W))
reflectᴱ H (function f var x T ⟩∈ U is B end) (function a defn) (UnallocatedAddress ())
reflectᴱ H (binexp M op N) (binOp₀ ()) (UnallocatedAddress p)
reflectᴱ H (binexp M op N) (binOp₁ s) (BinOpMismatch₁ p) with preservationᴱ H M s
reflectᴱ H (binexp M op N) (binOp₁ s) (BinOpMismatch₁ p) | ok q = expr (BinOpMismatch₁ (subst₁ (BinOpWarning op) (sym q) p))
reflectᴱ H (binexp M op N) (binOp₁ s) (BinOpMismatch₁ p) | warning (heap W) = heap W
reflectᴱ H (binexp M op N) (binOp₁ s) (BinOpMismatch₁ p) | warning (expr W) = expr (bin₁ W)
reflectᴱ H (binexp M op N) (binOp₁ s) (BinOpMismatch₂ p) with heap-weakeningᴱ H N (rednᴱ⊑ s)
reflectᴱ H (binexp M op N) (binOp₁ s) (BinOpMismatch₂ p) | ok q = expr (BinOpMismatch₂ ((subst₁ (BinOpWarning op) (sym q) p)))
reflectᴱ H (binexp M op N) (binOp₁ s) (BinOpMismatch₂ p) | warning W = expr (bin₂ W)
reflectᴱ H (binexp M op N) (binOp₁ s) (bin₁ W) with reflectᴱ H M s W
reflectᴱ H (binexp M op N) (binOp₁ s) (bin₁ W) | heap W = heap W
reflectᴱ H (binexp M op N) (binOp₁ s) (bin₁ W) | expr W = expr (bin₁ W)
reflectᴱ H (binexp M op N) (binOp₁ s) (bin₂ W) = expr (bin₂ (reflect-weakeningᴱ H N (rednᴱ⊑ s) W))
reflectᴱ H (binexp M op N) (binOp₂ s) (BinOpMismatch₁ p) with heap-weakeningᴱ H M (rednᴱ⊑ s)
reflectᴱ H (binexp M op N) (binOp₂ s) (BinOpMismatch₁ p) | ok q = expr (BinOpMismatch₁ (subst₁ (BinOpWarning op) (sym q) p))
reflectᴱ H (binexp M op N) (binOp₂ s) (BinOpMismatch₁ p) | warning W = expr (bin₁ W)
reflectᴱ H (binexp M op N) (binOp₂ s) (BinOpMismatch₂ p) with preservationᴱ H N s
reflectᴱ H (binexp M op N) (binOp₂ s) (BinOpMismatch₂ p) | ok q = expr (BinOpMismatch₂ (subst₁ (BinOpWarning op) (sym q) p))
reflectᴱ H (binexp M op N) (binOp₂ s) (BinOpMismatch₂ p) | warning (heap W) = heap W
reflectᴱ H (binexp M op N) (binOp₂ s) (BinOpMismatch₂ p) | warning (expr W) = expr (bin₂ W)
reflectᴱ H (binexp M op N) (binOp₂ s) (bin₁ W) = expr (bin₁ (reflect-weakeningᴱ H M (rednᴱ⊑ s) W))
reflectᴱ H (binexp M op N) (binOp₂ s) (bin₂ W) with reflectᴱ H N s W
reflectᴱ H (binexp M op N) (binOp₂ s) (bin₂ W) | heap W = heap W
reflectᴱ H (binexp M op N) (binOp₂ s) (bin₂ W) | expr W = expr (bin₂ W)
reflectᴮ H (local var x T M B) (local s) (LocalVarMismatch p) with preservationᴱ H M s
reflectᴮ H (local var x T M B) (local s) (LocalVarMismatch p) | ok q = block (LocalVarMismatch (λ r p (trans r q)))
reflectᴮ H (local var x T M B) (local s) (LocalVarMismatch p) | warning (expr W) = block (local₁ W)
reflectᴮ H (local var x T M B) (local s) (LocalVarMismatch p) | warning (heap W) = heap W
reflectᴮ H (local var x T M B) (local s) (local₁ W) with reflectᴱ H M s W
reflectᴮ H (local var x T M B) (local s) (local₁ W) | heap W = heap W
reflectᴮ H (local var x T M B) (local s) (local₁ W) | expr W = block (local₁ W)
reflectᴮ H (local var x T M B) (local s) (local₂ W) = block (local₂ (reflect-weakeningᴮ H B (rednᴱ⊑ s) W))
reflectᴮ H (local var x T M B) (subst v) W with remember (typeOfⱽ H v)
reflectᴮ H (local var x T M B) (subst v) W | (just S , p) with S ≡ᵀ T
reflectᴮ H (local var x T M B) (subst v) W | (just T , p) | yes refl = block (local₂ (reflect-substitutionᴮ H B v x (sym p) W))
reflectᴮ H (local var x T M B) (subst v) W | (just S , p) | no q = block (LocalVarMismatch (λ r q (trans (cong orNone (sym p)) (sym r))))
reflectᴮ H (local var x T M B) (subst v) W | (nothing , p) with typeOf-val-not-none v
reflectᴮ H (local var x T M B) (subst v) W | (nothing , p) | ok r = CONTRADICTION (r (cong orNone (sym p)))
reflectᴮ H (local var x T M B) (subst v) W | (nothing , p) | warning W = block (local₁ W)
reflectᴮ H (function f var y T ⟩∈ U is C end B) (function a defn) W = block (function₂ (reflect-weakeningᴮ H B (snoc defn) (reflect-substitutionᴮ _ B (addr a) f refl W)))
reflectᴮ H (return M B) (return s) (return W) with reflectᴱ H M s W
reflectᴮ H (return M B) (return s) (return W) | heap W = heap W
reflectᴮ H (return M B) (return s) (return W) | expr W = block (return W)
reflectᴴᴱ : H M {H M} (H M ⟶ᴱ M H) Warningᴴᴱ H (typeCheckᴴᴱ H M) Warningᴴᴱ H (typeCheckᴴᴱ H M)
reflectᴴᴮ : H B {H B} (H B ⟶ᴮ B H) Warningᴴᴮ H (typeCheckᴴᴮ H B) Warningᴴᴮ H (typeCheckᴴᴮ H B)
reflectᴴᴱ H M s (expr W) = reflectᴱ H M s W
reflectᴴᴱ H (function f var x T ⟩∈ U is B end) (function a p) (heap (addr b refl W)) with b ≡ᴬ a
reflectᴴᴱ H (function f var x T ⟩∈ U is B end) (function a defn) (heap (addr a refl (FunctionDefnMismatch p))) | yes refl with heap-weakeningᴮ H B (snoc defn)
reflectᴴᴱ H (function f var x T ⟩∈ U is B end) (function a defn) (heap (addr a refl (FunctionDefnMismatch p))) | yes refl | ok r = expr (FunctionDefnMismatch λ q p (trans q r))
reflectᴴᴱ H (function f var x T ⟩∈ U is B end) (function a defn) (heap (addr a refl (FunctionDefnMismatch p))) | yes refl | warning W = expr (function₁ W)
reflectᴴᴱ H (function f var x T ⟩∈ U is B end) (function a defn) (heap (addr a refl (function₁ W))) | yes refl = expr (function₁ (reflect-weakeningᴮ H B (snoc defn) W))
reflectᴴᴱ H (function f var x T ⟩∈ U is B end) (function a p) (heap (addr b refl W)) | no r = heap (addr b (lookup-not-allocated p r) (reflect-weakeningᴼ H _ (snoc p) W))
reflectᴴᴱ H (M $ N) (app₁ s) (heap W) with reflectᴴᴱ H M s (heap W)
reflectᴴᴱ H (M $ N) (app₁ s) (heap W) | heap W = heap W
reflectᴴᴱ H (M $ N) (app₁ s) (heap W) | expr W = expr (app₁ W)
reflectᴴᴱ H (M $ N) (app₂ p s) (heap W) with reflectᴴᴱ H N s (heap W)
reflectᴴᴱ H (M $ N) (app₂ p s) (heap W) | heap W = heap W
reflectᴴᴱ H (M $ N) (app₂ p s) (heap W) | expr W = expr (app₂ W)
reflectᴴᴱ H (M $ N) (beta O v p q) (heap W) = heap W
reflectᴴᴱ H (block var b T is B end) (block s) (heap W) with reflectᴴᴮ H B s (heap W)
reflectᴴᴱ H (block var b T is B end) (block s) (heap W) | heap W = heap W
reflectᴴᴱ H (block var b T is B end) (block s) (heap W) | block W = expr (block₁ W)
reflectᴴᴱ H (block var b T is return N B end) (return v) (heap W) = heap W
reflectᴴᴱ H (block var b T is done end) done (heap W) = heap W
reflectᴴᴱ H (binexp M op N) (binOp₀ s) (heap W) = heap W
reflectᴴᴱ H (binexp M op N) (binOp₁ s) (heap W) with reflectᴴᴱ H M s (heap W)
reflectᴴᴱ H (binexp M op N) (binOp₁ s) (heap W) | heap W = heap W
reflectᴴᴱ H (binexp M op N) (binOp₁ s) (heap W) | expr W = expr (bin₁ W)
reflectᴴᴱ H (binexp M op N) (binOp₂ s) (heap W) with reflectᴴᴱ H N s (heap W)
reflectᴴᴱ H (binexp M op N) (binOp₂ s) (heap W) | heap W = heap W
reflectᴴᴱ H (binexp M op N) (binOp₂ s) (heap W) | expr W = expr (bin₂ W)
reflectᴴᴮ H B s (block W) = reflectᴮ H B s W
reflectᴴᴮ H (local var x T M B) (local s) (heap W) with reflectᴴᴱ H M s (heap W)
reflectᴴᴮ H (local var x T M B) (local s) (heap W) | heap W = heap W
reflectᴴᴮ H (local var x T M B) (local s) (heap W) | expr W = block (local₁ W)
reflectᴴᴮ H (local var x T M B) (subst v) (heap W) = heap W
reflectᴴᴮ H (function f var y T ⟩∈ U is C end B) (function a p) (heap (addr b refl W)) with b ≡ᴬ a
reflectᴴᴮ H (function f var y T ⟩∈ U is C end B) (function a defn) (heap (addr a refl (FunctionDefnMismatch p))) | yes refl with heap-weakeningᴮ H C (snoc defn)
reflectᴴᴮ H (function f var y T ⟩∈ U is C end B) (function a defn) (heap (addr a refl (FunctionDefnMismatch p))) | yes refl | ok r = block (FunctionDefnMismatch (λ q p (trans q r)))
reflectᴴᴮ H (function f var y T ⟩∈ U is C end B) (function a defn) (heap (addr a refl (FunctionDefnMismatch p))) | yes refl | warning W = block (function₁ W)
reflectᴴᴮ H (function f var y T ⟩∈ U is C end B) (function a defn) (heap (addr a refl (function₁ W))) | yes refl = block (function₁ (reflect-weakeningᴮ H C (snoc defn) W))
reflectᴴᴮ H (function f var y T ⟩∈ U is C end B) (function a p) (heap (addr b refl W)) | no r = heap (addr b (lookup-not-allocated p r) (reflect-weakeningᴼ H _ (snoc p) W))
reflectᴴᴮ H (return M B) (return s) (heap W) with reflectᴴᴱ H M s (heap W)
reflectᴴᴮ H (return M B) (return s) (heap W) | heap W = heap W
reflectᴴᴮ H (return M B) (return s) (heap W) | expr W = block (return W)
reflect* : H B {H B} (H B ⟶* B H) Warningᴴᴮ H (typeCheckᴴᴮ H B) Warningᴴᴮ H (typeCheckᴴᴮ H B)
reflect* H B refl W = W
reflect* H B (step s t) W = reflectᴴᴮ H B s (reflect* _ _ t W)
runtimeBinOpWarning : H {op} v BinOpError op (valueType v) BinOpWarning op (orNone (typeOfⱽ H v))
runtimeBinOpWarning H v (+ p) = + (λ q p (mustBeNumber H v q))
runtimeBinOpWarning H v (- p) = - (λ q p (mustBeNumber H v q))
runtimeBinOpWarning H v (* p) = * (λ q p (mustBeNumber H v q))
runtimeBinOpWarning H v (/ p) = / (λ q p (mustBeNumber H v q))
runtimeBinOpWarning H v (< p) = < (λ q p (mustBeNumber H v q))
runtimeBinOpWarning H v (> p) = > (λ q p (mustBeNumber H v q))
runtimeBinOpWarning H v (<= p) = <= (λ q p (mustBeNumber H v q))
runtimeBinOpWarning H v (>= p) = >= (λ q p (mustBeNumber H v q))
runtimeBinOpWarning H v (·· p) = ·· (λ q p (mustBeString H v q))
runtimeWarningᴱ : H M RuntimeErrorᴱ H M Warningᴱ H (typeCheckᴱ H M)
runtimeWarningᴮ : H B RuntimeErrorᴮ H B Warningᴮ H (typeCheckᴮ H B)
runtimeWarningᴱ H (var x) UnboundVariable = UnboundVariable refl
runtimeWarningᴱ H (val (addr a)) (SEGV p) = UnallocatedAddress p
runtimeWarningᴱ H (M $ N) (FunctionMismatch v w p) with typeOf-val-not-none w
runtimeWarningᴱ H (M $ N) (FunctionMismatch v w p) | ok q = FunctionCallMismatch (λ r p (mustBeFunction H v (λ r q (trans r r))))
runtimeWarningᴱ H (M $ N) (FunctionMismatch v w p) | warning W = app₂ W
runtimeWarningᴱ H (M $ N) (app₁ err) = app₁ (runtimeWarningᴱ H M err)
runtimeWarningᴱ H (M $ N) (app₂ err) = app₂ (runtimeWarningᴱ H N err)
runtimeWarningᴱ H (block var b T is B end) (block err) = block₁ (runtimeWarningᴮ H B err)
runtimeWarningᴱ H (binexp M op N) (BinOpMismatch₁ v w p) = BinOpMismatch₁ (runtimeBinOpWarning H v p)
runtimeWarningᴱ H (binexp M op N) (BinOpMismatch₂ v w p) = BinOpMismatch₂ (runtimeBinOpWarning H w p)
runtimeWarningᴱ H (binexp M op N) (bin₁ err) = bin₁ (runtimeWarningᴱ H M err)
runtimeWarningᴱ H (binexp M op N) (bin₂ err) = bin₂ (runtimeWarningᴱ H N err)
runtimeWarningᴮ H (local var x T M B) (local err) = local₁ (runtimeWarningᴱ H M err)
runtimeWarningᴮ H (return M B) (return err) = return (runtimeWarningᴱ H M err)
wellTypedProgramsDontGoWrong : H B B (∅ᴴ B ⟶* B H) (RuntimeErrorᴮ H B) Warningᴮ ∅ᴴ (typeCheckᴮ ∅ᴴ B)
wellTypedProgramsDontGoWrong H B B t err with reflect* ∅ᴴ B t (block (runtimeWarningᴮ H B err))
wellTypedProgramsDontGoWrong H B B t err | heap (addr a refl ())
wellTypedProgramsDontGoWrong H B B t err | block W = W

View File

@ -0,0 +1,112 @@
{-# OPTIONS --rewriting #-}
open import Luau.Type using (Mode)
module Properties.TypeCheck (m : Mode) where
open import Agda.Builtin.Equality using (_≡_; refl)
open import Agda.Builtin.Bool using (Bool; true; false)
open import FFI.Data.Maybe using (Maybe; just; nothing)
open import FFI.Data.Either using (Either)
open import Luau.TypeCheck(m) using (_⊢ᴱ_∈_; _⊢ᴮ_∈_; ⊢ᴼ_; ⊢ᴴ_; _⊢ᴴᴱ_▷_∈_; _⊢ᴴᴮ_▷_∈_; nil; var; addr; number; bool; string; app; function; block; binexp; done; return; local; nothing; orNone; tgtBinOp)
open import Luau.Syntax using (Block; Expr; Value; BinaryOperator; yes; nil; addr; number; bool; string; val; var; binexp; _$_; function_is_end; block_is_end; _∙_; return; done; local_←_; _⟨_⟩; _⟨_⟩∈_; var_∈_; name; fun; arg; +; -; *; /; <; >; ==; ~=; <=; >=)
open import Luau.Type using (Type; nil; any; none; number; boolean; string; _⇒_; tgt)
open import Luau.RuntimeType using (RuntimeType; nil; number; function; string; valueType)
open import Luau.VarCtxt using (VarCtxt; ∅; _↦_; _⊕_↦_; _⋒_; _⊝_) renaming (_[_] to _[_]ⱽ)
open import Luau.Addr using (Addr)
open import Luau.Var using (Var; _≡ⱽ_)
open import Luau.Heap using (Heap; Object; function_is_end) renaming (_[_] to _[_]ᴴ)
open import Properties.Contradiction using (CONTRADICTION)
open import Properties.Dec using (yes; no)
open import Properties.Equality using (_≢_; sym; trans; cong)
open import Properties.Product using (_×_; _,_)
open import Properties.Remember using (Remember; remember; _,_)
src : Type Type
src = Luau.Type.src m
typeOfᴼ : Object yes Type
typeOfᴼ (function f var x S ⟩∈ T is B end) = (S T)
typeOfᴹᴼ : Maybe(Object yes) Maybe Type
typeOfᴹᴼ nothing = nothing
typeOfᴹᴼ (just O) = just (typeOfᴼ O)
typeOfⱽ : Heap yes Value Maybe Type
typeOfⱽ H nil = just nil
typeOfⱽ H (bool b) = just boolean
typeOfⱽ H (addr a) = typeOfᴹᴼ (H [ a ]ᴴ)
typeOfⱽ H (number n) = just number
typeOfⱽ H (string x) = just string
typeOfᴱ : Heap yes VarCtxt (Expr yes) Type
typeOfᴮ : Heap yes VarCtxt (Block yes) Type
typeOfᴱ H Γ (var x) = orNone(Γ [ x ]ⱽ)
typeOfᴱ H Γ (val v) = orNone(typeOfⱽ H v)
typeOfᴱ H Γ (M $ N) = tgt(typeOfᴱ H Γ M)
typeOfᴱ H Γ (function f var x S ⟩∈ T is B end) = S T
typeOfᴱ H Γ (block var b T is B end) = T
typeOfᴱ H Γ (binexp M op N) = tgtBinOp op
typeOfᴮ H Γ (function f var x S ⟩∈ T is C end B) = typeOfᴮ H (Γ f (S T)) B
typeOfᴮ H Γ (local var x T M B) = typeOfᴮ H (Γ x T) B
typeOfᴮ H Γ (return M B) = typeOfᴱ H Γ M
typeOfᴮ H Γ done = nil
mustBeFunction : H Γ v (none src (typeOfᴱ H Γ (val v))) (function valueType(v))
mustBeFunction H Γ nil p = CONTRADICTION (p refl)
mustBeFunction H Γ (addr a) p = refl
mustBeFunction H Γ (number n) p = CONTRADICTION (p refl)
mustBeFunction H Γ (bool true) p = CONTRADICTION (p refl)
mustBeFunction H Γ (bool false) p = CONTRADICTION (p refl)
mustBeFunction H Γ (string x) p = CONTRADICTION (p refl)
mustBeNumber : H Γ v (typeOfᴱ H Γ (val v) number) (valueType(v) number)
mustBeNumber H Γ (addr a) p with remember (H [ a ]ᴴ)
mustBeNumber H Γ (addr a) p | (just O , q) with trans (cong orNone (cong typeOfᴹᴼ (sym q))) p
mustBeNumber H Γ (addr a) p | (just function f var x T ⟩∈ U is B end , q) | ()
mustBeNumber H Γ (addr a) p | (nothing , q) with trans (cong orNone (cong typeOfᴹᴼ (sym q))) p
mustBeNumber H Γ (addr a) p | nothing , q | ()
mustBeNumber H Γ (number n) p = refl
mustBeString : H Γ v (typeOfᴱ H Γ (val v) string) (valueType(v) string)
mustBeString H Γ (addr a) p with remember (H [ a ]ᴴ)
mustBeString H Γ (addr a) p | (just O , q) with trans (cong orNone (cong typeOfᴹᴼ (sym q))) p
mustBeString H Γ (addr a) p | (just function f var x T ⟩∈ U is B end , q) | ()
mustBeString H Γ (addr a) p | (nothing , q) with trans (cong orNone (cong typeOfᴹᴼ (sym q))) p
mustBeString H Γ (addr a) p | (nothing , q) | ()
mustBeString H Γ (string x) p = refl
typeCheckᴱ : H Γ M (Γ ⊢ᴱ M (typeOfᴱ H Γ M))
typeCheckᴮ : H Γ B (Γ ⊢ᴮ B (typeOfᴮ H Γ B))
typeCheckᴱ H Γ (var x) = var refl
typeCheckᴱ H Γ (val nil) = nil
typeCheckᴱ H Γ (val (addr a)) = addr (orNone (typeOfᴹᴼ (H [ a ]ᴴ)))
typeCheckᴱ H Γ (val (number n)) = number
typeCheckᴱ H Γ (val (bool b)) = bool
typeCheckᴱ H Γ (val (string x)) = string
typeCheckᴱ H Γ (M $ N) = app (typeCheckᴱ H Γ M) (typeCheckᴱ H Γ N)
typeCheckᴱ H Γ (function f var x T ⟩∈ U is B end) = function (typeCheckᴮ H (Γ x T) B)
typeCheckᴱ H Γ (block var b T is B end) = block (typeCheckᴮ H Γ B)
typeCheckᴱ H Γ (binexp M op N) = binexp (typeCheckᴱ H Γ M) (typeCheckᴱ H Γ N)
typeCheckᴮ H Γ (function f var x T ⟩∈ U is C end B) = function (typeCheckᴮ H (Γ x T) C) (typeCheckᴮ H (Γ f (T U)) B)
typeCheckᴮ H Γ (local var x T M B) = local (typeCheckᴱ H Γ M) (typeCheckᴮ H (Γ x T) B)
typeCheckᴮ H Γ (return M B) = return (typeCheckᴱ H Γ M) (typeCheckᴮ H Γ B)
typeCheckᴮ H Γ done = done
typeCheckᴼ : H O (⊢ᴼ O)
typeCheckᴼ H nothing = nothing
typeCheckᴼ H (just function f var x T ⟩∈ U is B end) = function (typeCheckᴮ H (x T) B)
typeCheckᴴ : H (⊢ᴴ H)
typeCheckᴴ H a {O} p = typeCheckᴼ H (O)
typeCheckᴴᴱ : H Γ M (Γ ⊢ᴴᴱ H M typeOfᴱ H Γ M)
typeCheckᴴᴱ H Γ M = (typeCheckᴴ H , typeCheckᴱ H Γ M)
typeCheckᴴᴮ : H Γ M (Γ ⊢ᴴᴮ H M typeOfᴮ H Γ M)
typeCheckᴴᴮ H Γ M = (typeCheckᴴ H , typeCheckᴮ H Γ M)

View File

@ -1 +1,4 @@
false
ANNOTATED PROGRAM:
return true == false
RAN WITH RESULT: false

View File

@ -1 +1,4 @@
true
ANNOTATED PROGRAM:
return 1.0 == 1.0
RAN WITH RESULT: true

View File

@ -1 +1,4 @@
1.0
ANNOTATED PROGRAM:
return 1.0 + 2.0 - 2.0 * 2.0 / 2.0
RAN WITH RESULT: 1.0

View File

@ -0,0 +1,3 @@
local x: string = "hello"
local y: string = 37
return x .. y

View File

@ -0,0 +1,11 @@
ANNOTATED PROGRAM:
local x : string = "hello"
local y : string = 37.0
return x .. y
RUNTIME ERROR:
value 37.0 is not a string
in return statement
TYPE ERROR:
Local variable y has type string but expression has type number

View File

@ -0,0 +1,3 @@
local x: string = "hello"
local y: string = "world"
return x .. y

View File

@ -0,0 +1,6 @@
ANNOTATED PROGRAM:
local x : string = "hello"
local y : string = "world"
return x .. y
RAN WITH RESULT: "helloworld"

View File

@ -1 +1,7 @@
nil
UNANNOTATED PROGRAM:
local function foo(x)
return nil
end
return foo(nil)
RAN WITH RESULT: nil

View File

@ -0,0 +1 @@
return "foo bar"

View File

@ -0,0 +1,4 @@
ANNOTATED PROGRAM:
return "foo bar"
RAN WITH RESULT: "foo bar"

View File

@ -56,3 +56,9 @@ This document tracks unimplemented RFCs.
[RFC: Generalized iteration](https://github.com/Roblox/luau/blob/master/rfcs/generalized-iteration.md)
**Status**: Needs implementation
## table.clone
[RFC: table.clone](https://github.com/Roblox/luau/blob/master/rfcs/function-table-clone.md)
**Status**: Needs implementation

View File

@ -0,0 +1,64 @@
# table.clone
## Summary
Add `table.clone` function that, given a table, produces a copy of that table with the same keys/values/metatable.
## Motivation
There are multiple cases today when cloning tables is a useful operation.
- When working with tables as data containers, some algorithms may require modifying the table that can't be done in place for some reason.
- When working with tables as objects, it can be useful to obtain an identical copy of the object for further modification, preserving the metatable.
- When working with immutable data structures, any modification needs to clone some parts of the data structure to produce a new version of the object.
While it's possible to implement this function in user code today, it's impossible to implement it with maximum efficiency; furthermore, cloning is a reasonably fundamental
operation so from the ergonomics perspective it can be expected to be provided by the standard library.
## Design
`table.clone(t)` takes a table, `t`, and returns a new table that:
- has the same metatable
- has the same keys and values
- is not frozen, even if `t` was
The copy is shallow: implementing a deep recursive copy automatically is challenging (for similar reasons why we decided to avoid this in `table.freeze`), and often only certain keys need to be cloned recursively which can be done after the initial clone.
The table can be modified after cloning; as such, functions that compute a slightly modified copy of the table can be easily built on top of `table.clone`.
`table.clone(t)` is functionally equivalent to the following code, but it's more ergonomic (on the account of being built-in) and significantly faster:
```lua
assert(type(t) == "table")
local nt = {}
for k,v in pairs(t) do
nt[k] = v
end
if type(getmetatable(t)) == "table" then
setmetatable(nt, getmetatable(t))
end
```
The reason why `table.clone` can be dramatically more efficient is that it can directly copy the internal structure, preserving capacity and exact key order, and is thus
limited purely by memory bandwidth. In comparison, the code above can't predict the table size ahead of time, has to recreate the internal table structure one key at a time,
and bears the interpreter overhead (which can be avoided for numeric keys with `table.move` but that doesn't work for the general case of dictionaries).
Out of the abundance of caution, `table.clone` will fail to clone the table if it has a protected metatable. This is motivated by the fact that you can't do this today, so
there are no new potential vectors to escape various sandboxes. Superficially it seems like it's probably reasonable to allow cloning tables with protected metatables, but
there may be cases where code manufactures tables with unique protected metatables expecting 1-1 relationship and cloning would break that, so for now this RFC proposes a more
conservative route. We are likely to relax this restriction in the future.
## Drawbacks
Adding a new function to `table` library theoretically increases complexity. In practice though, we already effectively implement `table.clone` internally for some VM optimizations, so exposing this to the users bears no cost.
Assigning a type to this function is a little difficult if we want to enforce the "argument must be a table" constraint. It's likely that we'll need to type this as `table.clone(T): T` for the time being, which is less precise.
## Alternatives
We can implement something similar to `Object.assign` from JavaScript instead, that simultaneously assigns extra keys. However, this won't be fundamentally more efficient than
assigning the keys afterwards, and can be implemented in user space. Additionally, we can later extend `clone` with an extra argument if we so choose, so this proposal is the
minimal viable one.
We can immediately remove the rule wrt protected metatables, as it's not clear that it's actually problematic to be able to clone tables with protected metatables.