Merge branch 'master' into merge

This commit is contained in:
Arseny Kapoulkine 2022-02-24 15:16:33 -08:00
commit 2a549cfbad
47 changed files with 684 additions and 97 deletions

View file

@ -34,6 +34,11 @@ jobs:
with: with:
path: ~/.cabal/store path: ~/.cabal/store
key: prototyping-${{ runner.os }}-${{ matrix.agda }} key: prototyping-${{ runner.os }}-${{ matrix.agda }}
- uses: actions/cache@v2
id: luau-ast-cache
with:
path: ./build
key: prototyping-${{ runner.os }}-${{ hashFiles('Ast/**', 'Analysis/**', 'CLI/Ast.cpp', 'CLI/FileUtils.*')}}
- name: install cabal - name: install cabal
run: sudo apt-get install -y cabal-install run: sudo apt-get install -y cabal-install
- name: cabal update - name: cabal update
@ -43,26 +48,35 @@ jobs:
working-directory: prototyping working-directory: prototyping
run: | run: |
cabal install Agda-${{ matrix.agda }} cabal install Agda-${{ matrix.agda }}
cabal install --lib scientific --package-env . cabal install --lib scientific vector aeson --package-env .
cabal install --lib vector --package-env . - name: check targets
cabal install --lib aeson --package-env .
- name: check examples
working-directory: prototyping working-directory: prototyping
run: ~/.cabal/bin/agda Examples.agda run: |
~/.cabal/bin/agda Examples.agda
~/.cabal/bin/agda Properties.agda
- name: build executables - name: build executables
working-directory: prototyping working-directory: prototyping
run: | run: |
~/.cabal/bin/agda --compile PrettyPrinter.agda ~/.cabal/bin/agda --compile PrettyPrinter.agda
~/.cabal/bin/agda --compile Interpreter.agda ~/.cabal/bin/agda --compile Interpreter.agda
- name: cmake configure - name: cmake configure
run: cmake . if: steps.luau-ast-cache.outputs.cache-hit != 'true'
run: |
mkdir -p build
cd build
cmake build ../
- name: cmake build luau-ast - name: cmake build luau-ast
run: cmake --build . --target Luau.Ast.CLI if: steps.luau-ast-cache.outputs.cache-hit != 'true'
- name: run smoketest run: |
cmake --build ./build --target Luau.Ast.CLI
- name: run tests
working-directory: prototyping working-directory: prototyping
run: | run: |
../luau-ast Examples/SmokeTest.lua | ./PrettyPrinter > Examples/SmokeTestOutput.lua mkdir test-failures
../luau-ast Examples/SmokeTest.lua | ./Interpreter python tests.py -l ../build/luau-ast --write-diff-failures --diff-failure-location test-failures/
- name: diff smoketest - uses: actions/upload-artifact@v2
working-directory: prototyping if: failure()
run: diff Examples/SmokeTest.lua Examples/SmokeTestOutput.lua with:
name: test failures
path: prototyping/test-failures
retention-days: 5

View file

@ -178,11 +178,11 @@ LUA_API int lua_pushthread(lua_State* L);
/* /*
** get functions (Lua -> stack) ** get functions (Lua -> stack)
*/ */
LUA_API void lua_gettable(lua_State* L, int idx); LUA_API int lua_gettable(lua_State* L, int idx);
LUA_API void lua_getfield(lua_State* L, int idx, const char* k); LUA_API int lua_getfield(lua_State* L, int idx, const char* k);
LUA_API void lua_rawgetfield(lua_State* L, int idx, const char* k); LUA_API int lua_rawgetfield(lua_State* L, int idx, const char* k);
LUA_API void lua_rawget(lua_State* L, int idx); LUA_API int lua_rawget(lua_State* L, int idx);
LUA_API void lua_rawgeti(lua_State* L, int idx, int n); LUA_API int lua_rawgeti(lua_State* L, int idx, int n);
LUA_API void lua_createtable(lua_State* L, int narr, int nrec); LUA_API void lua_createtable(lua_State* L, int narr, int nrec);
LUA_API void lua_setreadonly(lua_State* L, int idx, int enabled); LUA_API void lua_setreadonly(lua_State* L, int idx, int enabled);

View file

@ -659,16 +659,16 @@ int lua_pushthread(lua_State* L)
** get functions (Lua -> stack) ** get functions (Lua -> stack)
*/ */
void lua_gettable(lua_State* L, int idx) int lua_gettable(lua_State* L, int idx)
{ {
luaC_checkthreadsleep(L); luaC_checkthreadsleep(L);
StkId t = index2addr(L, idx); StkId t = index2addr(L, idx);
api_checkvalidindex(L, t); api_checkvalidindex(L, t);
luaV_gettable(L, t, L->top - 1, L->top - 1); luaV_gettable(L, t, L->top - 1, L->top - 1);
return; return ttype(L->top - 1);
} }
void lua_getfield(lua_State* L, int idx, const char* k) int lua_getfield(lua_State* L, int idx, const char* k)
{ {
luaC_checkthreadsleep(L); luaC_checkthreadsleep(L);
StkId t = index2addr(L, idx); StkId t = index2addr(L, idx);
@ -677,10 +677,10 @@ void lua_getfield(lua_State* L, int idx, const char* k)
setsvalue(L, &key, luaS_new(L, k)); setsvalue(L, &key, luaS_new(L, k));
luaV_gettable(L, t, &key, L->top); luaV_gettable(L, t, &key, L->top);
api_incr_top(L); api_incr_top(L);
return; return ttype(L->top - 1);
} }
void lua_rawgetfield(lua_State* L, int idx, const char* k) int lua_rawgetfield(lua_State* L, int idx, const char* k)
{ {
luaC_checkthreadsleep(L); luaC_checkthreadsleep(L);
StkId t = index2addr(L, idx); StkId t = index2addr(L, idx);
@ -689,26 +689,26 @@ void lua_rawgetfield(lua_State* L, int idx, const char* k)
setsvalue(L, &key, luaS_new(L, k)); setsvalue(L, &key, luaS_new(L, k));
setobj2s(L, L->top, luaH_getstr(hvalue(t), tsvalue(&key))); setobj2s(L, L->top, luaH_getstr(hvalue(t), tsvalue(&key)));
api_incr_top(L); api_incr_top(L);
return; return ttype(L->top - 1);
} }
void lua_rawget(lua_State* L, int idx) int lua_rawget(lua_State* L, int idx)
{ {
luaC_checkthreadsleep(L); luaC_checkthreadsleep(L);
StkId t = index2addr(L, idx); StkId t = index2addr(L, idx);
api_check(L, ttistable(t)); api_check(L, ttistable(t));
setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1)); setobj2s(L, L->top - 1, luaH_get(hvalue(t), L->top - 1));
return; return ttype(L->top - 1);
} }
void lua_rawgeti(lua_State* L, int idx, int n) int lua_rawgeti(lua_State* L, int idx, int n)
{ {
luaC_checkthreadsleep(L); luaC_checkthreadsleep(L);
StkId t = index2addr(L, idx); StkId t = index2addr(L, idx);
api_check(L, ttistable(t)); api_check(L, ttistable(t));
setobj2s(L, L->top, luaH_getnum(hvalue(t), n)); setobj2s(L, L->top, luaH_getnum(hvalue(t), n));
api_incr_top(L); api_incr_top(L);
return; return ttype(L->top - 1);
} }
void lua_createtable(lua_State* L, int narray, int nrec) void lua_createtable(lua_State* L, int narray, int nrec)

View file

@ -68,8 +68,8 @@ SingletonType = STRING | 'true' | 'false'
Type = Type =
SimpleType ['?'] | SimpleType ['?'] |
SimpleType ['|' Type] | Type ['|' Type] |
SimpleType ['&' Type] Type ['&' Type]
GenericTypePackParameter = NAME '...' ['=' (TypePack | VariadicTypePack | GenericTypePack)] GenericTypePackParameter = NAME '...' ['=' (TypePack | VariadicTypePack | GenericTypePack)]
GenericTypeParameterList = NAME ['=' Type] [',' GenericTypeParameterList] | GenericTypePackParameter {',' GenericTypePackParameter} GenericTypeParameterList = NAME ['=' Type] [',' GenericTypeParameterList] | GenericTypePackParameter {',' GenericTypePackParameter}

View file

@ -317,3 +317,13 @@ The code above can be rewritten as follows to avoid the warning and the associat
```lua ```lua
local x = if flag then false else true local x = if flag then false else true
``` ```
## CommentDirective (26)
Luau uses comments that start from `!` to control certain aspects of analysis, for example setting type checking mode via `--!strict` or disabling individual lints with `--!nolint`. Unknown directives are ignored, for example `--!nostrict` doesn't have any effect on the type checking process as the correct spelling is `--!nonstrict`. This warning flags comment directives that are ignored during processing:
```lua
--!nostrict
-- Unknown comment directive 'nostrict'; did you mean 'nonstrict'?"
```
```

View file

@ -2,5 +2,11 @@
*.agdai *.agdai
Main Main
MAlonzo MAlonzo
Examples
PrettyPrinter PrettyPrinter
Interpreter
Properties
!Tests/Interpreter
!Tests/PrettyPrinter
.ghc.* .ghc.*
test-failures/

View file

@ -6,4 +6,3 @@ open import Luau.Heap using (∅)
ex1 : (local (var "x") nil return (var "x") done) ⟶ᴮ (return nil done) ex1 : (local (var "x") nil return (var "x") done) ⟶ᴮ (return nil done)
ex1 = subst ex1 = subst

View file

@ -3,8 +3,9 @@
module Examples.Run where module Examples.Run where
open import Agda.Builtin.Equality using (_≡_; refl) open import Agda.Builtin.Equality using (_≡_; refl)
open import Luau.Syntax using (nil; var; _$_; function_is_end; return; _∙_; done; _⟨_⟩) open import Agda.Builtin.Bool using (true; false)
open import Luau.Value using (nil) 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.Run using (run; return) open import Luau.Run using (run; return)
open import Luau.Heap using (lookup-next; next-emp; lookup-next-emp) open import Luau.Heap using (lookup-next; next-emp; lookup-next-emp)
@ -13,3 +14,12 @@ import Agda.Builtin.Equality.Rewrite
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" $ nil) done) return nil _)
ex1 = refl 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 = 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 = 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 = refl

View file

@ -1,8 +0,0 @@
module FFI.Data.Bool where
{-# FOREIGN GHC import qualified Data.Bool #-}
data Bool : Set where
false : Bool
true : Bool
{-# COMPILE GHC Bool = data Data.Bool.Bool (Data.Bool.False|Data.Bool.True) #-}

View file

@ -1,6 +1,21 @@
module FFI.Data.Scientific where module FFI.Data.Scientific where
open import Agda.Builtin.Float using (Float)
open import FFI.Data.String using (String)
open import FFI.Data.HaskellString using (HaskellString; pack; unpack)
{-# FOREIGN GHC import qualified Data.Scientific #-} {-# FOREIGN GHC import qualified Data.Scientific #-}
{-# FOREIGN GHC import qualified Text.Show #-}
postulate Scientific : Set postulate Scientific : Set
{-# COMPILE GHC Scientific = type Data.Scientific.Scientific #-} {-# COMPILE GHC Scientific = type Data.Scientific.Scientific #-}
postulate
showHaskell : Scientific HaskellString
toFloat : Scientific Float
{-# COMPILE GHC showHaskell = \x -> Text.Show.show x #-}
{-# COMPILE GHC toFloat = \x -> Data.Scientific.toRealFloat x #-}
show : Scientific String
show x = pack (showHaskell x)

View file

@ -3,7 +3,7 @@ module FFI.Data.Vector where
open import Agda.Builtin.Equality using (_≡_) open import Agda.Builtin.Equality using (_≡_)
open import Agda.Builtin.Int using (Int; pos; negsuc) open import Agda.Builtin.Int using (Int; pos; negsuc)
open import Agda.Builtin.Nat using (Nat) open import Agda.Builtin.Nat using (Nat)
open import FFI.Data.Bool using (Bool; false; true) open import Agda.Builtin.Bool using (Bool; false; true)
open import FFI.Data.HaskellInt using (HaskellInt; haskellIntToInt; intToHaskellInt) open import FFI.Data.HaskellInt using (HaskellInt; haskellIntToInt; intToHaskellInt)
open import FFI.Data.Maybe using (Maybe; just; nothing) open import FFI.Data.Maybe using (Maybe; just; nothing)

View file

@ -36,4 +36,3 @@ runString txt | (Right value) = runJSON value
main : IO main : IO
main = getContents >>= runString main = getContents >>= runString

View file

@ -1,11 +1,50 @@
module Luau.OpSem where module Luau.OpSem where
open import Agda.Builtin.Equality using (_≡_) 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 Utility.Bool using (not; _or_; _and_)
open import Agda.Builtin.Nat using (_==_)
open import FFI.Data.Maybe using (just) open import FFI.Data.Maybe using (just)
open import Luau.Heap using (Heap; _≡_⊕_↦_; _[_]; function_is_end) open import Luau.Heap using (Heap; _≡_⊕_↦_; _[_]; function_is_end)
open import Luau.Substitution using (_[_/_]ᴮ) 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) 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) open import Luau.Value using (addr; val; number; Value; bool)
open import Luau.RuntimeType using (RuntimeType; valueType)
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 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 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 _⊢_⟶ᴮ_⊣_ {a} : Heap a Block a Block a Heap a Set data _⊢_⟶ᴮ_⊣_ {a} : Heap a Block a Block a Heap a Set
data _⊢_⟶ᴱ_⊣_ {a} : Heap a Expr a Expr a Heap a Set data _⊢_⟶ᴱ_⊣_ {a} : Heap a Expr a Expr a Heap a Set
@ -23,17 +62,23 @@ data _⊢_⟶ᴱ_⊣_ where
------------------------------------------- -------------------------------------------
H (function F is B end) ⟶ᴱ (addr a) H H (function F is B end) ⟶ᴱ (addr a) H
app : {H H M M N} app : {H H M M N}
H M ⟶ᴱ M H H M ⟶ᴱ M H
----------------------------- -----------------------------
H (M $ N) ⟶ᴱ (M $ N) H H (M $ N) ⟶ᴱ (M $ N) H
beta : {H M a F B} app₂ : {H H V N N}
H N ⟶ᴱ N H
-----------------------------
H (val V $ N) ⟶ᴱ (val V $ N) H
beta : {H a F B V}
H [ a ] just(function F is B end) H [ a ] just(function F is B end)
----------------------------------------------------- -----------------------------------------------------------------------------
H (addr a $ M) ⟶ᴱ (block (fun F) is local (arg F) M B end) H H (addr a $ val V) ⟶ᴱ (block (fun F) is (B [ V / name(arg F) ]ᴮ) end) H
block : {H H B B b} block : {H H B B b}
@ -51,6 +96,34 @@ data _⊢_⟶ᴱ_⊣_ where
--------------------------------- ---------------------------------
H (block b is done end) ⟶ᴱ nil H H (block b is done end) ⟶ᴱ nil H
binOpEquality :
{H x y}
---------------------------------------------------------------------------
H (binexp (val x) BinaryOperator.≡ (val y)) ⟶ᴱ (val (evalEqOp x y)) H
binOpInequality :
{H x y}
----------------------------------------------------------------------------
H (binexp (val x) BinaryOperator.≅ (val y)) ⟶ᴱ (val (evalNeqOp x y)) 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}
H x ⟶ᴱ x H
---------------------------------------------
H (binexp x op y) ⟶ᴱ (binexp x op y) H
binOp₂ :
{H H x op y y}
H y ⟶ᴱ y H
---------------------------------------------
H (binexp x op y) ⟶ᴱ (binexp x op y) H
data _⊢_⟶ᴮ_⊣_ where data _⊢_⟶ᴮ_⊣_ where
local : {H H x M M B} local : {H H x M M B}
@ -88,5 +161,3 @@ data _⊢_⟶*_⊣_ {a} : Heap a → Block a → Block a → Heap a → Set wher
H B ⟶* B″ H″ H B ⟶* B″ H″
------------------ ------------------
H B ⟶* B″ H″ H B ⟶* B″ H″

View file

@ -3,19 +3,25 @@ module Luau.RuntimeError where
open import Agda.Builtin.Equality using (_≡_) open import Agda.Builtin.Equality using (_≡_)
open import Luau.Heap using (Heap; _[_]) open import Luau.Heap using (Heap; _[_])
open import FFI.Data.Maybe using (just; nothing) open import FFI.Data.Maybe using (just; nothing)
open import Luau.Syntax using (Block; Expr; nil; var; addr; block_is_end; _$_; local_←_; return; done; _∙_) 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 Properties.Equality using (_≢_)
data RuntimeErrorᴮ {a} (H : Heap a) : Block a Set data RuntimeErrorᴮ {a} (H : Heap a) : Block a Set
data RuntimeErrorᴱ {a} (H : Heap a) : Expr a Set data RuntimeErrorᴱ {a} (H : Heap a) : Expr a Set
data RuntimeErrorᴱ H where data RuntimeErrorᴱ H where
NilIsNotAFunction : {M} RuntimeErrorᴱ H (nil $ M) TypeMismatch : t v (t valueType v) RuntimeErrorᴱ H (val v)
UnboundVariable : x RuntimeErrorᴱ H (var x) UnboundVariable : x RuntimeErrorᴱ H (var x)
SEGV : a (H [ a ] nothing) RuntimeErrorᴱ H (addr a) SEGV : a (H [ a ] nothing) RuntimeErrorᴱ H (addr a)
app : {M N} RuntimeErrorᴱ H M RuntimeErrorᴱ H (M $ N) 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 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) return : {M B} RuntimeErrorᴱ H M RuntimeErrorᴮ H (return M B)

View file

@ -1,19 +1,27 @@
module Luau.RuntimeError.ToString where module Luau.RuntimeError.ToString where
open import Agda.Builtin.Float using (primShowFloat)
open import FFI.Data.String using (String; _++_) open import FFI.Data.String using (String; _++_)
open import Luau.RuntimeError using (RuntimeErrorᴮ; RuntimeErrorᴱ; local; return; NilIsNotAFunction; UnboundVariable; SEGV; app; block) open import Luau.RuntimeError using (RuntimeErrorᴮ; RuntimeErrorᴱ; local; return; TypeMismatch; UnboundVariable; SEGV; app₁; app₂; block; bin₁; bin₂)
open import Luau.RuntimeType.ToString using (runtimeTypeToString)
open import Luau.Addr.ToString using (addrToString) open import Luau.Addr.ToString using (addrToString)
open import Luau.Syntax.ToString using (exprToString)
open import Luau.Var.ToString using (varToString) open import Luau.Var.ToString using (varToString)
open import Luau.Syntax using (name) open import Luau.Value.ToString using (valueToString)
open import Luau.Syntax using (name; _$_)
errToStringᴱ : {a H B} RuntimeErrorᴱ {a} H B String errToStringᴱ : {a H B} RuntimeErrorᴱ {a} H B String
errToStringᴮ : {a H B} RuntimeErrorᴮ {a} H B String errToStringᴮ : {a H B} RuntimeErrorᴮ {a} H B String
errToStringᴱ NilIsNotAFunction = "nil is not a function"
errToStringᴱ (UnboundVariable x) = "variable " ++ varToString x ++ " is unbound" errToStringᴱ (UnboundVariable x) = "variable " ++ varToString x ++ " is unbound"
errToStringᴱ (SEGV a x) = "address " ++ addrToString a ++ " is unallocated" errToStringᴱ (SEGV a x) = "address " ++ addrToString a ++ " is unallocated"
errToStringᴱ (app E) = errToStringᴱ E 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ᴱ (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ᴮ (local x E) = errToStringᴱ E ++ "\n in definition of " ++ varToString (name x)
errToStringᴮ (return E) = errToStringᴱ E ++ "\n in return statement" errToStringᴮ (return E) = errToStringᴱ E ++ "\n in return statement"

View file

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

View file

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

View file

@ -1,6 +1,6 @@
module Luau.Substitution where module Luau.Substitution where
open import Luau.Syntax using (Expr; Stat; Block; nil; addr; var; function_is_end; _$_; block_is_end; local_←_; _∙_; done; return; _⟨_⟩ ; name; fun; arg) 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.Value using (Value; val)
open import Luau.Var using (Var; _≡ⱽ_) open import Luau.Var using (Var; _≡ⱽ_)
open import Properties.Dec using (Dec; yes; no) open import Properties.Dec using (Dec; yes; no)
@ -11,11 +11,15 @@ var_[_/_]ᴱwhenever_ : ∀ {a P} → Var → Value → Var → (Dec P) → Expr
_[_/_]ᴮunless_ : {a P} Block a Value Var (Dec P) Block a _[_/_]ᴮunless_ : {a P} Block a Value Var (Dec P) Block a
nil [ v / x ]ᴱ = nil nil [ v / x ]ᴱ = nil
true [ v / x ]ᴱ = true
false [ v / x ]ᴱ = false
var y [ v / x ]ᴱ = var y [ v / x ]ᴱwhenever (x ≡ⱽ y) var y [ v / x ]ᴱ = var y [ v / x ]ᴱwhenever (x ≡ⱽ y)
addr a [ v / x ]ᴱ = addr a addr a [ v / x ]ᴱ = addr a
(number y) [ v / x ]ᴱ = number y
(M $ N) [ v / x ]ᴱ = (M [ v / x ]ᴱ) $ (N [ v / x ]ᴱ) (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 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 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 ≡ⱽ fun F))
(local y M B) [ v / x ]ᴮ = local y (M [ v / x ]ᴱ) (B [ v / x ]ᴮunless (x ≡ⱽ name y)) (local y M B) [ v / x ]ᴮ = local y (M [ v / x ]ᴱ) (B [ v / x ]ᴮunless (x ≡ⱽ name y))
@ -27,4 +31,3 @@ var y [ v / x ]ᴱwhenever no p = var y
B [ v / x ]ᴮunless yes p = B B [ v / x ]ᴮunless yes p = B
B [ v / x ]ᴮunless no p = B [ v / x ]ᴮ B [ v / x ]ᴮunless no p = B [ v / x ]ᴮ

View file

@ -1,6 +1,7 @@
module Luau.Syntax where module Luau.Syntax where
open import Agda.Builtin.Equality using (_≡_) open import Agda.Builtin.Equality using (_≡_)
open import Agda.Builtin.Float using (Float)
open import Properties.Dec using () open import Properties.Dec using ()
open import Luau.Var using (Var) open import Luau.Var using (Var)
open import Luau.Addr using (Addr) open import Luau.Addr using (Addr)
@ -32,6 +33,18 @@ arg : ∀ {a} → FunDec a → VarDec a
arg (f x ⟩∈ T) = x arg (f x ⟩∈ T) = x
arg (f x ) = x arg (f x ) = x
data BinaryOperator : Set where
+ : BinaryOperator
- : BinaryOperator
* : BinaryOperator
/ : BinaryOperator
< : BinaryOperator
> : BinaryOperator
: BinaryOperator
: BinaryOperator
: BinaryOperator
: BinaryOperator
data Block (a : Annotated) : Set data Block (a : Annotated) : Set
data Stat (a : Annotated) : Set data Stat (a : Annotated) : Set
data Expr (a : Annotated) : Set data Expr (a : Annotated) : Set
@ -47,9 +60,12 @@ data Stat a where
data Expr a where data Expr a where
nil : Expr a nil : Expr a
true : Expr a
false : Expr a
var : Var Expr a var : Var Expr a
addr : Addr Expr a addr : Addr Expr a
_$_ : Expr a Expr a Expr a _$_ : Expr a Expr a Expr a
function_is_end : FunDec a Block a Expr a function_is_end : FunDec a Block a Expr a
block_is_end : Var Block a Expr a block_is_end : Var Block a Expr a
number : Float Expr a
binexp : Expr a BinaryOperator Expr a Expr a

View file

@ -1,14 +1,15 @@
module Luau.Syntax.FromJSON where module Luau.Syntax.FromJSON where
open import Luau.Syntax using (Block; Stat ; Expr; nil; _$_; var; var_∈_; function_is_end; _⟨_⟩; local_←_; return; done; _∙_; maybe; VarDec) 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.Type.FromJSON using (typeFromJSON) open import Luau.Type.FromJSON using (typeFromJSON)
open import Agda.Builtin.List using (List; _∷_; []) open import Agda.Builtin.List using (List; _∷_; [])
open import Agda.Builtin.Bool using (true; false)
open import FFI.Data.Aeson using (Value; Array; Object; object; array; string; fromString; lookup) open import FFI.Data.Aeson using (Value; Array; Object; object; array; string; fromString; lookup)
open import FFI.Data.Bool using (true; false)
open import FFI.Data.Either using (Either; Left; Right) open import FFI.Data.Either using (Either; Left; Right)
open import FFI.Data.Maybe using (Maybe; nothing; just) open import FFI.Data.Maybe using (Maybe; nothing; just)
open import FFI.Data.Scientific using (toFloat)
open import FFI.Data.String using (String; _++_) open import FFI.Data.String using (String; _++_)
open import FFI.Data.Vector using (head; tail; null; empty) open import FFI.Data.Vector using (head; tail; null; empty)
@ -19,8 +20,12 @@ lokal = fromString "local"
list = fromString "list" list = fromString "list"
name = fromString "name" name = fromString "name"
type = fromString "type" type = fromString "type"
value = fromString "value"
values = fromString "values" values = fromString "values"
vars = fromString "vars" vars = fromString "vars"
op = fromString "op"
left = fromString "left"
right = fromString "right"
data Lookup : Set where data Lookup : Set where
_,_ : String Value Lookup _,_ : String Value Lookup
@ -32,6 +37,8 @@ lookupIn (key ∷ keys) obj with lookup (fromString key) obj
lookupIn (key keys) obj | nothing = lookupIn keys obj lookupIn (key keys) obj | nothing = lookupIn keys obj
lookupIn (key keys) obj | just value = (key , value) lookupIn (key keys) obj | just value = (key , value)
binOpFromJSON : Value Either String BinaryOperator
binOpFromString : String Either String BinaryOperator
varDecFromJSON : Value Either String (VarDec maybe) varDecFromJSON : Value Either String (VarDec maybe)
varDecFromObject : Object Either String (VarDec maybe) varDecFromObject : Object Either String (VarDec maybe)
exprFromJSON : Value Either String (Expr maybe) exprFromJSON : Value Either String (Expr maybe)
@ -41,6 +48,21 @@ statFromObject : Object → Either String (Stat maybe)
blockFromJSON : Value Either String (Block maybe) blockFromJSON : Value Either String (Block maybe)
blockFromArray : Array Either String (Block maybe) blockFromArray : Array Either String (Block maybe)
binOpFromJSON (string s) = binOpFromString s
binOpFromJSON val = 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 "CompareLt" = Right <
binOpFromString "CompareLe" = Right
binOpFromString "CompareGt" = Right >
binOpFromString "CompareGe" = Right
binOpFromString s = Left ("'" ++ s ++ "' is not a valid operator")
varDecFromJSON (object arg) = varDecFromObject arg varDecFromJSON (object arg) = varDecFromObject arg
varDecFromJSON val = Left "VarDec not an object" varDecFromJSON val = Left "VarDec not an object"
@ -83,6 +105,24 @@ 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 | Right x = Right (var (Luau.Syntax.name x))
exprFromObject obj | just (string "AstExprLocal") | just x | Left err = Left err 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 "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 _ = Left "AstExprConstantNumber value is not a number"
exprFromObject obj | just (string "AstExprConstantNumber") | nothing = Left "AstExprConstantNumber 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 _ = 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
exprFromObject obj | just (string "AstExprBinary") | just o | just l | just r with binOpFromJSON o | exprFromJSON l | exprFromJSON r
exprFromObject obj | just (string "AstExprBinary") | just o | just l | just r | Right o | Right l | Right r = Right (binexp l o r)
exprFromObject obj | just (string "AstExprBinary") | just o | just l | just r | Left err | _ | _ = Left err
exprFromObject obj | just (string "AstExprBinary") | just o | just l | just r | _ | Left err | _ = Left err
exprFromObject obj | just (string "AstExprBinary") | just o | just l | just r | _ | _ | Left err = Left err
exprFromObject obj | just (string "AstExprBinary") | nothing | _ | _ = Left "Missing 'op' in AstExprBinary"
exprFromObject obj | just (string "AstExprBinary") | _ | nothing | _ = Left "Missing 'left' in AstExprBinary"
exprFromObject obj | just (string "AstExprBinary") | _ | _ | nothing = Left "Missing 'right' in AstExprBinary"
exprFromObject obj | just (string ty) = Left ("TODO: Unsupported AstExpr " ++ ty) exprFromObject obj | just (string ty) = Left ("TODO: Unsupported AstExpr " ++ ty)
exprFromObject obj | just _ = Left "AstExpr type not a string" exprFromObject obj | just _ = Left "AstExpr type not a string"
exprFromObject obj | nothing = Left "AstExpr missing type" exprFromObject obj | nothing = Left "AstExpr missing type"
@ -140,3 +180,4 @@ blockFromArray arr | just value | Left err = Left err
blockFromArray arr | just value | Right S with blockFromArray(tail arr) blockFromArray arr | just value | Right S with blockFromArray(tail arr)
blockFromArray arr | just value | Right S | Left err = Left (err) blockFromArray arr | just value | Right S | Left err = Left (err)
blockFromArray arr | just value | Right S | Right B = Right (S B) blockFromArray arr | just value | Right S | Right B = Right (S B)

View file

@ -1,6 +1,7 @@
module Luau.Syntax.ToString where module Luau.Syntax.ToString where
open import Luau.Syntax using (Block; Stat; Expr; VarDec; FunDec; nil; var; var_∈_; addr; _$_; function_is_end; return; local_←_; _∙_; done; block_is_end; _⟨_⟩; _⟨_⟩∈_) 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 FFI.Data.String using (String; _++_) open import FFI.Data.String using (String; _++_)
open import Luau.Addr.ToString using (addrToString) open import Luau.Addr.ToString using (addrToString)
open import Luau.Type.ToString using (typeToString) open import Luau.Type.ToString using (typeToString)
@ -16,6 +17,18 @@ funDecToString ("" ⟨ x ⟩) = "function(" ++ varDecToString x ++ ")"
funDecToString (f x ⟩∈ T) = "function " ++ varToString f ++ "(" ++ varDecToString x ++ "): " ++ typeToString T funDecToString (f x ⟩∈ T) = "function " ++ varToString f ++ "(" ++ varDecToString x ++ "): " ++ typeToString T
funDecToString (f x ) = "function " ++ varToString f ++ "(" ++ varDecToString x ++ ")" funDecToString (f x ) = "function " ++ varToString f ++ "(" ++ varDecToString x ++ ")"
binOpToString : BinaryOperator String
binOpToString + = "+"
binOpToString - = "-"
binOpToString * = "*"
binOpToString / = "/"
binOpToString < = "<"
binOpToString > = ">"
binOpToString = "=="
binOpToString = "~="
binOpToString = "<="
binOpToString = ">="
exprToString : {a} String Expr a String exprToString : {a} String Expr a String
statToString : {a} String Stat a String statToString : {a} String Stat a String
blockToString : {a} String Block a String blockToString : {a} String Block a String
@ -36,6 +49,10 @@ exprToString lb (block b is B end) =
"(" ++ b ++ "()" ++ lb ++ "(" ++ b ++ "()" ++ lb ++
" " ++ (blockToString (lb ++ " ") B) ++ lb ++ " " ++ (blockToString (lb ++ " ") B) ++ lb ++
"end)()" "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) = statToString lb (function F is B end) =
"local " ++ funDecToString F ++ lb ++ "local " ++ funDecToString F ++ lb ++

View file

@ -7,6 +7,7 @@ data Type : Set where
_⇒_ : Type Type Type _⇒_ : Type Type Type
none : Type none : Type
any : Type any : Type
number : Type
__ : Type Type Type __ : Type Type Type
_∩_ : Type Type Type _∩_ : Type Type Type
@ -15,6 +16,7 @@ src nil = none
src (S T) = S src (S T) = S
src none = none src none = none
src any = any src any = any
src number = none
src (S T) = (src S) (src T) src (S T) = (src S) (src T)
src (S T) = (src S) (src T) src (S T) = (src S) (src T)
@ -23,6 +25,7 @@ tgt nil = none
tgt (S T) = T tgt (S T) = T
tgt none = none tgt none = none
tgt any = any tgt any = any
tgt number = none
tgt (S T) = (tgt S) (tgt T) tgt (S T) = (tgt S) (tgt T)
tgt (S T) = (tgt S) (tgt T) tgt (S T) = (tgt S) (tgt T)
@ -40,4 +43,3 @@ normalizeOptional (S T) | S | nil = optional S
normalizeOptional (S T) | nil | T = optional T normalizeOptional (S T) | nil | T = optional T
normalizeOptional (S T) | S | T = S T normalizeOptional (S T) | S | T = S T
normalizeOptional T = T normalizeOptional T = T

View file

@ -1,11 +1,11 @@
module Luau.Type.FromJSON where module Luau.Type.FromJSON where
open import Luau.Type using (Type; nil; _⇒_; __; _∩_; any) open import Luau.Type using (Type; nil; _⇒_; __; _∩_; any; number)
open import Agda.Builtin.List using (List; _∷_; []) open import Agda.Builtin.List using (List; _∷_; [])
open import Agda.Builtin.Bool using (true; false)
open import FFI.Data.Aeson using (Value; Array; Object; object; array; string; fromString; lookup) open import FFI.Data.Aeson using (Value; Array; Object; object; array; string; fromString; lookup)
open import FFI.Data.Bool using (true; false)
open import FFI.Data.Either using (Either; Left; Right) open import FFI.Data.Either using (Either; Left; Right)
open import FFI.Data.Maybe using (Maybe; nothing; just) open import FFI.Data.Maybe using (Maybe; nothing; just)
open import FFI.Data.String using (String; _++_) open import FFI.Data.String using (String; _++_)
@ -41,6 +41,7 @@ typeFromJSON (object o) | just (string "AstTypeFunction") | nothing | nothing =
typeFromJSON (object o) | just (string "AstTypeReference") with lookup name o 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 "nil") = Right nil
typeFromJSON (object o) | just (string "AstTypeReference") | just (string "any") = Right any 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") | _ = Left "Unknown referenced type" typeFromJSON (object o) | just (string "AstTypeReference") | _ = Left "Unknown referenced type"
typeFromJSON (object o) | just (string "AstTypeUnion") with lookup types o typeFromJSON (object o) | just (string "AstTypeUnion") with lookup types o

View file

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

View file

@ -1,15 +1,20 @@
module Luau.Value where 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.Addr using (Addr)
open import Luau.Syntax using (Block; Expr; nil; addr) open import Luau.Syntax using (Block; Expr; nil; addr; number; true; false)
open import Luau.Var using (Var) open import Luau.Var using (Var)
data Value : Set where data Value : Set where
nil : Value nil : Value
addr : Addr Value addr : Addr Value
number : Float Value
bool : Bool Value
val : {a} Value Expr a val : {a} Value Expr a
val nil = nil val nil = nil
val (addr a) = addr a val (addr a) = addr a
val (number x) = number x
val (bool false) = false
val (bool true) = true

View file

@ -1,10 +1,14 @@
module Luau.Value.ToString where module Luau.Value.ToString where
open import Agda.Builtin.String using (String) open import Agda.Builtin.String using (String)
open import Luau.Value using (Value; nil; addr) 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) open import Luau.Addr.ToString using (addrToString)
valueToString : Value String valueToString : Value String
valueToString nil = "nil" valueToString nil = "nil"
valueToString (addr a) = addrToString a valueToString (addr a) = addrToString a
valueToString (number x) = primShowFloat x
valueToString (bool false) = "false"
valueToString (bool true) = "true"

View file

@ -30,4 +30,3 @@ runString txt | (Right value) = runJSON value
main : IO main : IO
main = getContents >>= runString main = getContents >>= runString

View file

@ -1,5 +1,7 @@
module Properties where module Properties where
import Properties.Contradiction
import Properties.Dec import Properties.Dec
import Properties.Equality
import Properties.Step import Properties.Step
import Properties.Remember import Properties.Remember

View file

@ -0,0 +1,9 @@
module Properties.Contradiction where
data : Set where
¬ : Set Set
¬ A = A
CONTRADICTION : {A : Set} A
CONTRADICTION ()

View file

@ -0,0 +1,23 @@
module Properties.Equality where
open import Agda.Builtin.Equality using (_≡_; refl)
open import Properties.Contradiction using (¬)
sym : {A : Set} {a b : A} (a b) (b a)
sym refl = refl
trans : {A : Set} {a b c : A} (a b) (b c) (a c)
trans refl refl = refl
cong : {A B : Set} {a b : A} (f : A B) (a b) (f a f b)
cong f refl = refl
subst₁ : {A : Set} {a b : A} (F : A Set) (a b) (F a) (F b)
subst₁ F refl x = x
subst₂ : {A B : Set} {a b : A} {c d : B} (F : A B Set) (a b) (c d) (F a c) (F b d)
subst₂ F refl refl x = x
_≢_ : {A : Set} A A Set
(a b) = ¬(a b)

View file

@ -1,13 +1,16 @@
module Properties.Step where module Properties.Step where
open import Agda.Builtin.Equality using (_≡_; refl) open import Agda.Builtin.Equality using (_≡_; refl)
open import Agda.Builtin.Float using (primFloatPlus; primFloatMinus; primFloatTimes; primFloatDiv)
open import Agda.Builtin.Bool using (true; false)
open import FFI.Data.Maybe using (just; nothing) open import FFI.Data.Maybe using (just; nothing)
open import Luau.Heap using (Heap; _[_]; alloc; ok; function_is_end) open import Luau.Heap using (Heap; _[_]; alloc; ok; function_is_end)
open import Luau.Syntax using (Block; Expr; nil; var; addr; function_is_end; block_is_end; _$_; local_←_; return; done; _∙_; name; fun; arg) 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 ; beta; function; block; return; done; local; subst) 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ᴮ; NilIsNotAFunction; UnboundVariable; SEGV; app; block; local; return) 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.Substitution using (_[_/_]ᴮ) open import Luau.Substitution using (_[_/_]ᴮ)
open import Luau.Value using (nil; addr; val) open import Luau.Value using (nil; addr; val; number; bool)
open import Properties.Remember using (remember; _,_) open import Properties.Remember using (remember; _,_)
data StepResultᴮ {a} (H : Heap a) (B : Block a) : Set data StepResultᴮ {a} (H : Heap a) (B : Block a) : Set
@ -30,13 +33,21 @@ stepᴮ : ∀ {a} H B → StepResultᴮ {a} H B
stepᴱ H nil = value nil refl stepᴱ H nil = value nil refl
stepᴱ H (var x) = error (UnboundVariable x) stepᴱ H (var x) = error (UnboundVariable x)
stepᴱ H (addr a) = value (addr a) refl 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 (M $ N) with stepᴱ H M stepᴱ H (M $ N) with stepᴱ H M
stepᴱ H (M $ N) | step H M D = step H (M $ N) (app D) stepᴱ H (M $ N) | step H M D = step H (M $ N) (app₁ D)
stepᴱ H (nil $ N) | value nil refl = error NilIsNotAFunction stepᴱ H (_ $ N) | value V refl with stepᴱ H N
stepᴱ H (addr a $ N) | value (addr a) refl with remember (H [ a ]) stepᴱ H (_ $ N) | value V refl | step H N s = step H (val V $ N) (app₂ s)
stepᴱ H (addr a $ N) | value (addr a) refl | (nothing , p) = error (app (SEGV a p)) stepᴱ H (_ $ _) | value nil refl | value W refl = error (app₁ (TypeMismatch function nil λ()))
stepᴱ H (addr a $ N) | value (addr a) refl | (just(function F is B end) , p) = step H (block fun F is (local arg F N) B end) (beta p) stepᴱ H (_ $ _) | value (number n) refl | value W refl = error (app₁ (TypeMismatch function (number n) λ()))
stepᴱ H (M $ N) | error E = error (app E) 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 (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) 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 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 (return _ B) end) | return V refl = step H (val V) return
@ -44,6 +55,22 @@ 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 B end) | error E = error (block b E)
stepᴱ H (function F is C end) with alloc H (function F is C end) 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 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 B) with alloc H (function F is C end) 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 / fun F ]ᴮ) (function p)

View file

@ -25,3 +25,21 @@ and run!
``` ```
luau-ast Examples/SmokeTest.lua | ./PrettyPrinter luau-ast Examples/SmokeTest.lua | ./PrettyPrinter
``` ```
## Testing
We have a series of snapshot tests in the `Tests/` directory. You interact with the tests using the `tests` Python script in the `prototyping` directory. To simply run the tests, run:
```sh
tests --luau-cli ../build/luau-ast --build
```
This will build the test targets and run them. Run `tests --help` for information about all the command-line options.
### Adding a new test
To add a new test, add it to `Tests/{SUITE_NAME}/{CASE_NAME}`. You'll need an `in.lua` file and an `out.txt` file. The `in.lua` file is the input Luau source code, while the `out.txt` file is the expected output after running `luau-ast in.lua | test_executable`.
### Updating a test
If you make a change to the prototype that results in an expected change in behavior, you might want to update the test cases automatically. To do this, run `tests` with the `--accept-new-output` (`-a` for short) flag. Rather than diffing the output, this will overwrite the `out.txt` files for each test case with the actual result. Commit the resulting changes with your PR.

View file

@ -0,0 +1 @@
return true == false

View file

@ -0,0 +1 @@
false

View file

@ -0,0 +1 @@
return 1 == 1

View file

@ -0,0 +1 @@
true

View file

@ -0,0 +1 @@
return 1 + 2 - 2 * 2 / 2

View file

@ -0,0 +1 @@
1.0

View file

@ -0,0 +1,5 @@
local function foo(x)
return nil
end
return foo(nil)

View file

@ -0,0 +1 @@
nil

View file

@ -15,4 +15,5 @@ local b : nil = nil
local c : (nil) -> nil = nil local c : (nil) -> nil = nil
local d : (any & nil) = nil local d : (any & nil) = nil
local e : any? = nil local e : any? = nil
local f : number = 123
return id2(nil2) return id2(nil2)

View file

@ -15,4 +15,5 @@ local b : nil = nil
local c : (nil) -> nil = nil local c : (nil) -> nil = nil
local d : (any & nil) = nil local d : (any & nil) = nil
local e : any? = nil local e : any? = nil
local f : number = 123.0
return id2(nil2) return id2(nil2)

View file

@ -0,0 +1,16 @@
module Utility.Bool where
open import Agda.Builtin.Bool using (Bool; true; false)
not : Bool Bool
not false = true
not true = false
_or_ : Bool Bool Bool
true or _ = true
_ or true = true
_ or _ = false
_and_ : Bool Bool Bool
true and true = true
_ and _ = false

197
prototyping/tests.py Executable file
View file

@ -0,0 +1,197 @@
#!/usr/bin/python
import argparse
import difflib
import enum
import os
import os.path
import subprocess
import sys
SUITES = ["interpreter", "prettyprinter"]
IN_FILE_NAME = "in.lua"
OUT_FILE_NAME = "out.txt"
SUITE_EXE_NAMES = {
"interpreter": "Interpreter",
"prettyprinter": "PrettyPrinter",
}
SUITE_ENTRY_POINTS = {
"interpreter": "Interpreter.agda",
"prettyprinter": "PrettyPrinter.agda",
}
SUITE_ROOTS = {
"interpreter": "Tests/Interpreter",
"prettyprinter": "Tests/PrettyPrinter",
}
class TestResultStatus(enum.Enum):
CLI_ERROR = 0
EXE_ERROR = 1
DIFF_ERROR = 2
SUCCESS = 3
WROTE_NEW = 4
class DiffFailure:
def __init__(self, expected, actual):
self.expected = expected
self.actual = actual
def diff_text(self):
diff_generator = difflib.context_diff(self.expected.splitlines(), self.actual.splitlines(), fromfile="expected", tofile="actual", n=3)
return "".join(diff_generator)
def diff_html(self):
differ = difflib.HtmlDiff(tabsize=4)
return differ.make_file(self.expected.splitlines(), self.actual.splitlines(), fromdesc="Expected", todesc="Actual", context=True, numlines=5)
class TestCaseResult:
def __init__(self, suite, case, status, details):
self.suite = suite
self.case = case
self.status = status
self.details = details
def did_pass(self):
return self.status == TestResultStatus.SUCCESS or self.status == TestResultStatus.WROTE_NEW
def to_string(self):
prefix = f"[{self.suite}/{self.case}]: "
if self.status == TestResultStatus.CLI_ERROR:
return f"{prefix}CLI ERROR: {self.details}"
elif self.status == TestResultStatus.EXE_ERROR:
return f"{prefix}EXE ERROR: {self.details}"
elif self.status == TestResultStatus.DIFF_ERROR:
text_diff = self.details.diff_text()
return f"{prefix}FAILED:\n{text_diff}"
elif self.status == TestResultStatus.SUCCESS:
return f"{prefix}SUCCEEDED"
elif self.status == TestResultStatus.WROTE_NEW:
return f"{prefix}WROTE NEW RESULT"
def write_artifact(self, artifact_root):
if self.status != TestResultStatus.DIFF_ERROR:
return
filename = f"{self.suite}-{self.case}.out.html"
path = os.path.join(artifact_root, filename)
html = self.details.diff_html()
with open(path, "w") as file:
file.write(html)
parser = argparse.ArgumentParser(description="Runs prototype test cases")
parser.add_argument("--luau-cli", "-l", dest="cli_location", required=True, help="The location of luau-cli")
parser.add_argument("--root", "-r", dest="prototype_root", required=False, default=os.getcwd(), help="The root of the prototype")
parser.add_argument("--build", "-b", dest="build", action="store_true", default=True, help="Whether to automatically build required test binaries")
parser.add_argument("--suite", "-s", dest="suites", action="append", default=[], choices=SUITES, help="Which test suites to run")
parser.add_argument("--case", "-c", dest="cases", action="append", default=[], help="Which test cases to run")
parser.add_argument("--accept-new-output", "-a", dest="snapshot", action="store_true", default=False, help="Whether to write the new output to files, instead of diffing against it")
parser.add_argument("--write-diff-failures", dest="write_diffs", action="store_true", default=False, help="Whether to write test failure diffs to files")
parser.add_argument("--diff-failure-location", dest="diff_location", default=None, help="Where to write diff failure files to")
def build_suite(root, suite):
entry_point = SUITE_ENTRY_POINTS.get(suite)
if entry_point is None:
return (False, "Invalid suite")
result = subprocess.run(["~/.cabal/bin/agda", "--compile", entry_point], shell=True, cwd=root, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if result.returncode == 0:
return (True, None)
else:
return (False, result.stdout)
def run_test(in_path, out_path, cli_path, exe_path, snapshot):
cli_result = subprocess.run([cli_path, in_path], capture_output=True)
if cli_result.returncode != 0:
return (TestResultStatus.CLI_ERROR, f"CLI error: {cli_result.stderr}")
exe_result = subprocess.run(exe_path, input=cli_result.stdout, capture_output=True)
if exe_result.returncode != 0:
return (TestResultStatus.EXE_ERROR, f"Executable error; stdout:{exe_result.stdout}\n\nstderr: {exe_result.stderr}")
actual_result = exe_result.stdout.decode("utf-8")
if snapshot:
with open(out_path, "w") as out_file:
out_file.write(actual_result)
return (TestResultStatus.WROTE_NEW, None)
else:
with open(out_path, "r") as out_file:
expected_result = out_file.read()
if expected_result != actual_result:
return (TestResultStatus.DIFF_ERROR, DiffFailure(expected_result, actual_result))
return (TestResultStatus.SUCCESS, None)
def should_run_case(case_name, filters):
if len(filters) == 0:
return True
return any([f in case_name for f in filters])
def run_test_suite(args, suite, suite_root, suite_exe):
results = []
for entry in os.listdir(suite_root):
if not should_run_case(entry, args.cases):
continue
case_path = os.path.join(suite_root, entry)
if os.path.isdir(case_path):
in_path = os.path.join(case_path, IN_FILE_NAME)
out_path = os.path.join(case_path, OUT_FILE_NAME)
if not os.path.exists(in_path) or not os.path.exists(out_path):
continue
status, details = run_test(in_path, out_path, args.cli_location, suite_exe, args.snapshot)
result = TestCaseResult(suite, entry, status, details)
results.append(result)
return results
def main():
args = parser.parse_args()
suites = args.suites if len(args.suites) > 0 else SUITES
root = os.path.abspath(args.prototype_root)
if args.build:
for suite in suites:
success, reason = build_suite(root, suite)
if not success:
print(f"Error building executable for test suite {suite}:\n{reason}")
sys.exit(1)
else:
print(f"Built executable for test suite {suite} successfully.")
failed = False
for suite in suites:
suite_root = os.path.join(root, SUITE_ROOTS.get(suite))
suite_exe = os.path.join(root, SUITE_EXE_NAMES.get(suite))
print(f"Running test suite {suite}...")
results = run_test_suite(args, suite, suite_root, suite_exe)
passed = 0
total = len(results)
for result in results:
if result.did_pass():
passed += 1
else:
failed = True
print(f"Suite {suite} [{passed} / {total} passed]:")
for result in results:
print(result.to_string())
if args.write_diffs:
result.write_artifact(args.diff_location)
if failed:
sys.exit(1)
if __name__ == "__main__":
main()

View file

@ -23,12 +23,6 @@ This document tracks unimplemented RFCs.
**Status**: Implemented but depends on new transaction log implementation that is not fully live yet. **Status**: Implemented but depends on new transaction log implementation that is not fully live yet.
## Default type parameters
[RFC: Default type alias type parameters](https://github.com/Roblox/luau/blob/master/rfcs/syntax-default-type-alias-type-parameters.md)
**Status**: Implemented but not fully rolled out yet.
## Singleton types ## Singleton types
[RFC: Singleton types](https://github.com/Roblox/luau/blob/master/rfcs/syntax-singleton-types.md) [RFC: Singleton types](https://github.com/Roblox/luau/blob/master/rfcs/syntax-singleton-types.md)

View file

@ -1,5 +1,7 @@
# Default type alias type parameters # Default type alias type parameters
**Status**: Implemented
## Summary ## Summary
Introduce syntax to provide default type values inside the type alias type parameter list. Introduce syntax to provide default type values inside the type alias type parameter list.

View file

@ -712,6 +712,47 @@ TEST_CASE("Reference")
CHECK(dtorhits == 2); CHECK(dtorhits == 2);
} }
TEST_CASE("ApiTables")
{
StateRef globalState(luaL_newstate(), lua_close);
lua_State* L = globalState.get();
lua_newtable(L);
lua_pushnumber(L, 123.0);
lua_setfield(L, -2, "key");
lua_pushstring(L, "test");
lua_rawseti(L, -2, 5);
// lua_gettable
lua_pushstring(L, "key");
CHECK(lua_gettable(L, -2) == LUA_TNUMBER);
CHECK(lua_tonumber(L, -1) == 123.0);
lua_pop(L, 1);
// lua_getfield
CHECK(lua_getfield(L, -1, "key") == LUA_TNUMBER);
CHECK(lua_tonumber(L, -1) == 123.0);
lua_pop(L, 1);
// lua_rawgetfield
CHECK(lua_rawgetfield(L, -1, "key") == LUA_TNUMBER);
CHECK(lua_tonumber(L, -1) == 123.0);
lua_pop(L, 1);
// lua_rawget
lua_pushstring(L, "key");
CHECK(lua_rawget(L, -2) == LUA_TNUMBER);
CHECK(lua_tonumber(L, -1) == 123.0);
lua_pop(L, 1);
// lua_rawgeti
CHECK(lua_rawgeti(L, -1, 5) == LUA_TSTRING);
CHECK(strcmp(lua_tostring(L, -1), "test") == 0);
lua_pop(L, 1);
lua_pop(L, 1);
}
TEST_CASE("ApiFunctionCalls") TEST_CASE("ApiFunctionCalls")
{ {
StateRef globalState = runConformance("apicalls.lua"); StateRef globalState = runConformance("apicalls.lua");