diff --git a/.building/README.md b/.building/README.md new file mode 100644 index 000000000..1ce016bcc --- /dev/null +++ b/.building/README.md @@ -0,0 +1,100 @@ +# Install luarocks on Windows with Lua 5.1 and LuaJIT-2.0.4 + +## Install MSVC 2022 +1. Download and install [MSVC 2022](https://visualstudio.microsoft.com/de/downloads/#build-tools-for-visual-studio-2022). +2. Search for vcvarsall.bat and copy the path to the clipboard. +3. Put the path to Windows environment variable `PATH` (e.g. `C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build`). +4. After that you can run `vcvarsall` from any directory. + +[More about vcvarsall!](https://learn.microsoft.com/en-us/cpp/build/building-on-the-command-line?view=msvc-170#developer_command_file_locations) + +## Install and init luarocks + +1. Open `cmd.exe` as *administrator* +2. Change directory to `NoitaMP\mods\noita-mp`, like `cd fullPathTo\NoitaMP\mods\noita-mp`. +3. Run the following command as *administrator* in `cmd.exe`: + ```cmd + REM // cd fullPathTo\NoitaMP\mods\noita-mp + set INIT_PATH=%CD% + + REM // resolve absolute path + set REL_PATH=..\..\.building\luarocks-3.9.1-windows-32 + set ABS_PATH= + rem // Save current directory and change to target directory + pushd %REL_PATH% + rem // Save value of CD variable (current directory) + set ABS_PATH=%CD% + rem // Restore original directory + popd + echo Relative path: %REL_PATH% + echo Maps to path: %ABS_PATH% + + REM // make use of LuaJIT-2.0.4 + %ABS_PATH%\luarocks config --local variables.LUA_BINDIR %INIT_PATH%\..\..\LuaJIT-2.0.4\bin + %ABS_PATH%\luarocks config --local variables.LUA_DIR %INIT_PATH%\..\..\LuaJIT-2.0.4 + %ABS_PATH%\luarocks config --local variables.LUA_INCDIR %INIT_PATH%\..\..\LuaJIT-2.0.4\include + + REM // init luarocks + %ABS_PATH%\luarocks --lua-version="5.1" init noita-mp --output="%INIT_PATH%" --homepage="https://github.com/Ismoh/NoitaMP" --lua-versions="5.1" --license="GNU GPL v3" + ``` + [source for above](https://stackoverflow.com/questions/1645843/resolve-absolute-path-from-relative-path-and-or-file-name) +4. Result should look like this: + ```cmd + Initializing project 'noita-mp' for Lua 5.1 ... + ----------------------------------------------- + + Checking your Lua installation ... + + Wrote template at D:\______BACKUP\NoitaMP_repo\NoitaMP\mods\noita-mp -- you should now edit and finish it. + + Adding entries to .gitignore ... + Preparing ./.luarocks/ ... + Wrote .luarocks/config-5.1.lua + Preparing ./lua_modules/ ... + Preparing ./luarocks.bat ... + Preparing ./lua.bat for version 5.1... + ``` +5. If you run `luarocks` in `NoitaMP\mods\noita-mp` directory, it should work now. + +## Make use of LuaJIT-2.0.4 +1. Check LuaJITs doc for compiling it on [Windows](https://luajit.org/install.html#windows). +2. After compiling LuaJIT, copy the following files into destination directory: ([Double check here on 3.](https://gist.github.com/Egor-Skriptunoff/cb952f7eaf39b7b1bf739b818ece87cd)) + - `luajit.exe` and `lua51.dll` into `NoitaMP\LuaJIT-2.0.4\bin` + - `lua51.lib` into `NoitaMP\LuaJIT-2.0.4\lib` + - Install jit.* modules by copying `NoitaMP\.building\LuaJIT-2.0.4\src\jit` into `NoitaMP\LuaJIT-2.0.4\jit` + - Add includes by copying `lauxlib.h`, `lua.h`, `lua.hpp`, `luaconf.h`, `lualib.h` from `NoitaMP\.building\LuaJIT-2.0.4\src` into `NoitaMP\LuaJIT-2.0.4\include` +3. Change `config-5.1.lua` like so, but use your local absolute path to `NoitaMP\LuaJIT-2.0.4\`: + ```lua + lua_interpreter = "luajit.exe" + variables = { + LUA_DIR = "yourAbsolutePathTo\\NoitaMP\\LuaJIT-2.0.4", -- LUA_DIR = "C:\\msys64\\mingw32", + LUA_BINDIR = "yourAbsolutePathTo\\NoitaMP\\LuaJIT-2.0.4\\bin", -- LUA_BINDIR = "C:\\msys64\\mingw32\\bin", + LUA_INCDIR = "yourAbsolutePathTo\\NoitaMP\\LuaJIT-2.0.4\\include", -- LUA_INCDIR = "C:\\msys64\\mingw32/include/lua5.1", + LUA_LIBDIR = "yourAbsolutePathTo\\NoitaMP\\LuaJIT-2.0.4\\lib" + } + ``` +4. Run `luarocks` in `\NoitaMP\mods\noita-mp` directory again. Done! + +## Create a rockspec +`luarocks write_rockspec --license="GNU GPL v3" --lua-versions="5.1" --rockspec-format="3.0"` + +## Run unit test +Change dir to `NoitaMP\mods\noita-mp` and run `luarocks test`. +If you want to store logs, run `luarocks test > result.log`. + +## Check for updates on dependencies +Run `luarocks list` in `NoitaMP\mods\noita-mp` directory. + +## Install dependencies +Run +``` +call "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" x86 10.0.22000.0 -vcvars_ver=14 +luarocks install {name} +``` +in `NoitaMP\mods\noita-mp` directory. + + + +## Install all dependencies defined in noita-mp-*.rockspec +Run `luarocks install --only-deps noita-mp-*.rockspec`. Replace `*` with the version number of the rockspec. +Simply type in `luarocks install --only-deps noita` and hit tab to autocomplete the rockspec name. \ No newline at end of file diff --git a/.debug/UI.png b/.debug/UI.png deleted file mode 100644 index 123169352..000000000 Binary files a/.debug/UI.png and /dev/null differ diff --git a/.debug/client-ui.png b/.debug/client-ui.png deleted file mode 100644 index eb319d3c5..000000000 Binary files a/.debug/client-ui.png and /dev/null differ diff --git a/.debug/custom-mp-map.png b/.debug/custom-mp-map.png deleted file mode 100644 index 36b8fcdd7..000000000 Binary files a/.debug/custom-mp-map.png and /dev/null differ diff --git a/.debug/host-ui.png b/.debug/host-ui.png deleted file mode 100644 index dc91f03f8..000000000 Binary files a/.debug/host-ui.png and /dev/null differ diff --git a/.debug/luacheck-v-0-23-0.exe b/.debug/luacheck-v-0-23-0.exe deleted file mode 100644 index bb6f7f504..000000000 Binary files a/.debug/luacheck-v-0-23-0.exe and /dev/null differ diff --git a/.debug/network ids chat history.PNG b/.debug/network ids chat history.PNG deleted file mode 100644 index 18120ead9..000000000 Binary files a/.debug/network ids chat history.PNG and /dev/null differ diff --git a/.debug/run-github-actions-locally.ps1 b/.debug/run-github-actions-locally.ps1 deleted file mode 100644 index 5851c0da1..000000000 --- a/.debug/run-github-actions-locally.ps1 +++ /dev/null @@ -1,13 +0,0 @@ -bash -c "curl https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash && \ -cd NoitaMP && \ -sudo service docker start && \ -act -l && \ - -sudo ./bin/act -v -s WORKFLOW_PAT=$(pass tokens/github) pull_request_target -" - -## pass insert tokens/github - - -https://stackoverflow.com/a/67360592/3493998 - diff --git a/.debug/run-noita.bat b/.debug/run-noita.bat deleted file mode 100644 index 020ebe8d9..000000000 --- a/.debug/run-noita.bat +++ /dev/null @@ -1,18 +0,0 @@ -@REM setlocal enabledelayedexpansion - -@REM FOR /f "tokens=2 delims==" %%d IN ('wmic logicaldisk where "drivetype=3" get name /format:value') DO ( - -@REM echo %%d -@REM cd /d %%d - -@REM for /f "tokens=* delims=" %%a in ('dir /s /b noita.exe') do set "noita_exe=%%a" -@REM echo %%noita_exe%%=%noita_exe% - -@REM for /f "tokens=*" %%a in ('dir /s /b noita_dev.exe') do set "noita_dev_exe=%%a" -@REM echo %%noita_dev_exe%%=%noita_dev_exe% -@REM ) - -@REM endlocal - -start "" "C:\Program Files (x86)\Steam\steamapps\common\Noita\noita.exe" -start "" "C:\Program Files (x86)\Steam\steamapps\common\Noita\noita_dev.exe" -lua_debug \ No newline at end of file diff --git a/.debug/saving network ids chat history.png b/.debug/saving network ids chat history.png deleted file mode 100644 index 85ed99c52..000000000 Binary files a/.debug/saving network ids chat history.png and /dev/null differ diff --git a/.debug/sh.exe.lnk b/.debug/sh.exe.lnk deleted file mode 100644 index 61119d2a2..000000000 Binary files a/.debug/sh.exe.lnk and /dev/null differ diff --git a/.debug/syek.png b/.debug/syek.png deleted file mode 100644 index 7c1ef7135..000000000 Binary files a/.debug/syek.png and /dev/null differ diff --git a/.debug/unit-testing-locally.ps1 b/.debug/unit-testing-locally.ps1 deleted file mode 100644 index 32333e9fc..000000000 --- a/.debug/unit-testing-locally.ps1 +++ /dev/null @@ -1,113 +0,0 @@ -cd "D:\______BACKUP\NoitaMP_repo\NoitaMP\.debug\" - -$message1 = "Do you want to test if LuaJIT-2.0.4 is installed? [y/n]" -$no1 = New-Object System.Management.Automation.Host.ChoiceDescription "&n" -$yes1 = New-Object System.Management.Automation.Host.ChoiceDescription "&y" -$options1 = [System.Management.Automation.Host.ChoiceDescription[]]($no1, $yes1) -Write-Output $message1 -$result1 = $host.ui.PromptForChoice($title1, $message1, $options1, 0) -switch ($result1) -{ - 0 { - "LuaJIT-2.0.4 might be installed?! User chose: $result1" - } - 1 { - "Yes please install LuaJIT-2.0.4. User chose: $result1" - } -} - -if ($result1 -eq 1) -{ - Start-Process -FilePath "C:\Program Files (x86)\LuaJIT-2.0.4\bin\luajit.exe" -Wait - if ($LASTEXITCODE -eq 0) - { - Write-Output "luajit is installed. Nothing to do." - } - else - { - Write-Output "luajit is not installed. Read further steps." - - $message = "Do you want to install LuaJIT-2.0.4? [y/n]" - $no = New-Object System.Management.Automation.Host.ChoiceDescription "&n" - $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&y" - $options = [System.Management.Automation.Host.ChoiceDescription[]]($no, $yes) - Write-Output $message - $result = $host.ui.PromptForChoice($title, $message, $options, 0) - switch ($result) - { - 0 { - "You selected No." - } - 1 { - "You selected Yes." - } - } - - if ($result -eq 1) - { - ### Build - robocopy "..\.building\LuaJIT-2.0.4\" "..\temp\LuaJIT-2.0.4" /s /e - cd "..\temp\LuaJIT-2.0.4" - mingw32-make PLAT = mingw - - ### Install - ### binaries - robocopy "src\" "C:\Program Files (x86)\LuaJIT-2.0.4\bin" luajit.exe - robocopy "src\" "C:\Program Files (x86)\LuaJIT-2.0.4\bin" lua51.dll - - ### modules written in lua - robocopy "src\jit\" "C:\Program Files (x86)\LuaJIT-2.0.4\jit" /s /e - - ### includes - robocopy "src\" "C:\Program Files (x86)\LuaJIT-2.0.4\include" luaconf.h - robocopy "src\" "C:\Program Files (x86)\LuaJIT-2.0.4\include" lua.h - robocopy "src\" "C:\Program Files (x86)\LuaJIT-2.0.4\include" lualib.h - robocopy "src\" "C:\Program Files (x86)\LuaJIT-2.0.4\include" lauxlib.h - robocopy "src\" "C:\Program Files (x86)\LuaJIT-2.0.4\include" lua.hpp - - Write-Output "LuaJIT-2.0.4 is installed." - Write-Output "Executing luajit.exe -v" - Start-Process -FilePath "C:\Program Files (x86)\LuaJIT-2.0.4\bin\luajit.exe" -ArgumentList " -v" -Wait -NoNewWindow - Write-Output "Executing luajit.exe -e `"print(_VERSION)`"" - Start-Process -FilePath "C:\Program Files (x86)\LuaJIT-2.0.4\bin\luajit.exe" -ArgumentList " -e `"print(_VERSION)`"" -Wait -NoNewWindow - } - } -} - -$message3 = "Do you want to adjust/extend LUA_PATH and LUA_CPATH? [y/n]" -$no3 = New-Object System.Management.Automation.Host.ChoiceDescription "&n" -$yes3 = New-Object System.Management.Automation.Host.ChoiceDescription "&y" -$options3 = [System.Management.Automation.Host.ChoiceDescription[]]($no3, $yes3) -Write-Output $message3 -$result3 = $host.ui.PromptForChoice($title3, $message3, $options3, 0) -switch ($result3) -{ - 0 { - "Never touch my LUA_PATH and LUA_CPATH! User chose: $result1" - } - 1 { - "Yes please adjust my LUA_PATH and LUA_CPATH. User chose: $result1" - } -} - -if ($result3 -eq 1) -{ - Write-Output "Executing D:\______BACKUP\NoitaMP_repo\NoitaMP\mods\noita-mp\files\scripts\init\init_.lua, D:\______BACKUP\NoitaMP_repo\NoitaMP, D:\______BACKUP\NoitaMP_repo\NoitaMP -Wait -NoNewWindow" - Start-Process -FilePath "C:\Program Files (x86)\LuaJIT-2.0.4\bin\luajit.exe" -ArgumentList "D:\______BACKUP\NoitaMP_repo\NoitaMP\mods\noita-mp\files\scripts\init\init_.lua", "D:\______BACKUP\NoitaMP_repo\NoitaMP", "D:\______BACKUP\NoitaMP_repo\NoitaMP" -Wait -NoNewWindow - - $luaPath = Get-Content D:\______BACKUP\NoitaMP_repo\NoitaMP\lua_path.txt -Raw - [Environment]::SetEnvironmentVariable("LUA_PATH", $env:LUA_PATH + ";" + $luaPath, "Machine") - - $luacPath = Get-Content D:\______BACKUP\NoitaMP_repo\NoitaMP\lua_cpath.txt -Raw - [Environment]::SetEnvironmentVariable("LUA_CPATH", $env:LUA_CPATH + ";" + $luacPath, "Machine") -} - -$files = Get-ChildItem -Path "D:\______BACKUP\NoitaMP_repo\NoitaMP\.testing\tests" -Filter *.lua -Recurse -foreach ($file in $files) # https://stackoverflow.com/a/11568420/3493998 -{ - Write-Host "Running lua file $file" - Start-Process -FilePath "C:\Program Files (x86)\LuaJIT-2.0.4\bin\luajit.exe" -ArgumentList $file.FullName,"-o","text","--verbose","D:\______BACKUP\NoitaMP_repo\NoitaMP" -Wait -NoNewWindow - # https://stackoverflow.com/a/45330000/3493998 - # & 'C:\Program Files (x86)\LuaJIT-2.0.4\bin\luajit.exe' $file.FullName -o text --verbose >> "D:\______BACKUP\NoitaMP_repo\NoitaMP\.testing\testresult.log" - type ..\\.testing\testresult.log -} diff --git a/.debug/where-is-the-lag-comming-from.png b/.debug/where-is-the-lag-comming-from.png deleted file mode 100644 index 6678121ce..000000000 Binary files a/.debug/where-is-the-lag-comming-from.png and /dev/null differ diff --git a/.github/NoitaMP-logo.png b/.github/NoitaMP-logo.png deleted file mode 100644 index 7d3a7633a..000000000 Binary files a/.github/NoitaMP-logo.png and /dev/null differ diff --git a/.github/workflows/update-git-submodules.yml b/.github/workflows/update-git-submodules.yml deleted file mode 100644 index 3a0117c88..000000000 --- a/.github/workflows/update-git-submodules.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: Git submodule updater - -on: - push: - - schedule: - - cron: '0 6 * * 0' - workflow_dispatch: - -jobs: - update-submodules: - name: Update submodules - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v3 - with: - submodules: true - persist-credentials: false - -# - name: Import GPG key -# id: import-gpg -# uses: crazy-max/ghaction-import-gpg@v5.1.0 -# with: -# gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} -# passphrase: ${{ secrets.GPG_PASS }} -# git_config_global: true -# git_user_signingkey: true -# git_commit_gpgsign: true - - - name: Update submodules - run: | - git submodule foreach 'git fetch -t --unshallow - git checkout "$(git describe --tags --abbrev=0 origin/HEAD)"' - - - name: Try to commit - run: | - if git commit -am"$( - echo 'Update submodules (automated)' - echo - git submodule status | grep '^+' | cut '-d ' -f2- - )"; then - ./configure - make - git push - fi -# env: -# GITHUB_TOKEN: ${{ secrets.GH_PASS }} -# GIT_AUTHOR_NAME: ${{ steps.import-gpg.outputs.name }} -# GIT_AUTHOR_EMAIL: ${{ steps.import-gpg.outputs.email }} -# GIT_COMMITTER_NAME: ${{ steps.import-gpg.outputs.name }} -# GIT_COMMITTER_EMAIL: ${{ steps.import-gpg.outputs.email }} \ No newline at end of file diff --git a/.github/workflows/version-and-changelog-update.yml b/.github/workflows/version-and-changelog-update.yml index 7ed757bb4..141a05692 100644 --- a/.github/workflows/version-and-changelog-update.yml +++ b/.github/workflows/version-and-changelog-update.yml @@ -1,5 +1,7 @@ name: Version and changelog update on: + pull_request: + types: [ opened, edited, synchronize, closed ] pull_request_target: types: [ opened, edited, synchronize, closed ] jobs: @@ -7,25 +9,32 @@ jobs: name: Copy labels from issue to pull request runs-on: ubuntu-latest outputs: - labelNames: ${{ steps.add_labels.outputs.labelNames }} + labelNames: ${{ steps.find-linked-issues.outputs.pull-request-labels }} steps: + - uses: actions/checkout@v3.3.0 + - name: Print GitHub context run: echo "$GITHUB_CONTEXT" env: GITHUB_CONTEXT: ${{ toJson(github) }} - - - uses: actions/checkout@v3.1.0 - - - name: Is there a issue linked in "development"? - id: validator - uses: HarshCasper/validate-issues-over-pull-requests@v0.1.2 + + - name: Find linked issues + id: find-linked-issues + uses: Ismoh-Games/find-linked-issues@v0.0.5 with: - prbody: ${{ github.event.pull_request.body }} - prurl: ${{ github.event.pull_request.url }} + token: ${{ secrets.WORKFLOW_PAT }} + repository: ${{ github.repository }} + pull-request-number: ${{ github.event.pull_request.number }} + pull-request-body: ${{ github.event.pull_request.body }} + copy-issues-labels: true + + - name: Echo output + run: | + echo "is-pull-request-linked-to-issues: ${{ steps.find-linked-issues.outputs.is-pull-request-linked-to-issues }}" + echo "linked-issues: ${{ steps.find-linked-issues.outputs.linked-issues }}" + echo "pull-request-labels: ${{ steps.find-linked-issues.outputs.pull-request-labels }}" - - name: "'Development' set?" - env: - PRNUM: ${{ github.event.pull_request.number }} + - name: Linked issue found? run: | commentListResponse=`curl -u Ismoh:${{ secrets.WORKFLOW_PAT }} -H 'Accept: application/vnd.github+json' https://api.github.com/repos/Ismoh/NoitaMP/issues/${{github.event.number}}/comments` echo "commentListResponse="$commentListResponse @@ -44,7 +53,7 @@ jobs: fi done - if [ ${{ steps.validator.outputs.valid }} == 0 ] + if [ ${{ steps.find-linked-issues.outputs.is-pull-request-linked-to-issues }} == 'False' ] then body=":robot: _meep moop beep boop_

Hi @${{ github.event.pull_request.user.login }},
your pull request is not linked to any issue, please make the corresponding changes in the **very first comment** by adding
\`Fixes #issue-number\` or \`Resolves #issue-number\`.
If your pull request isn't linked to any issue, **ignore** this comment!" echo "body="$body @@ -61,50 +70,6 @@ jobs: exit 1 fi fi - - - name: Find linked issues - if: ${{ steps.validator.outputs.valid == 1 }} - id: links - uses: hossainemruz/linked-issues@main - with: - pr_url: ${{github.event.pull_request.html_url}} - format: IssueNumber - - - name: Add labels of associated/linked issue to the pull request - if: ${{ steps.validator.outputs.valid == 1 }} - id: add_labels - run: | - for issueNumber in ${{ steps.links.outputs.issues }} - do - issueUrl=$( echo ${{ github.event.pull_request.base.repo.issues_url }} | sed "s/{\/number}/\/$issueNumber/g" ) - labels=$( curl $issueUrl | jq '.labels') - echo "labels="$labels - - for label in $( echo $labels | jq -r '.[] | .name' ) - do - labelNames="${labelNames:+$labelNames,}\"$label\"" - done - - done - echo "labelNames="$labelNames - data="{\"labels\":[${labelNames}]}" - - curlResponse=`curl --write-out '%{http_code}' --output /dev/null --request POST \ - --header 'Accept: application/vnd.github.v3+json' \ - --header 'Authorization: token ${{ github.token }}' \ - --header 'Content-Type: application/json' \ - --url 'https://api.github.com/repos/${{github.repository}}/issues/${{github.event.number}}/labels' \ - --data-raw $data` - - if [[ $curlResponse == *"200"* ]] - then - echo "SUCCESS" - else - echo "FAILURE" - exit 1 - fi - - echo "::set-output name=labelNames::$labelNames" update-version: needs: find-linked-issues-and-copy-labels-to-pull-request @@ -126,7 +91,7 @@ jobs: with: version-source: file version-file: ${{ env.VERSION_FILE_NAME }} - version-file-extraction-pattern: '^v(.*)' + version-file-extraction-pattern: '{"version":"v([^"]+)"}' next-version-increment-major: ${{ contains(env.LABEL_NAMES, 'rework') }} next-version-increment-minor: ${{ contains(env.LABEL_NAMES, 'enhancement') }} next-version-increment-patch: ${{ contains(env.LABEL_NAMES, 'bug') }} @@ -183,7 +148,7 @@ jobs: git fetch git checkout ${{ github.base_ref }} git pull origin ${{ github.base_ref }} - echo "{\"version\":\"$NEXT_VERSION\"}" > $VERSION_FILE_NAME + echo "{\"version\":\"v$NEXT_VERSION\"}" > $VERSION_FILE_NAME git config --local user.email "action@github.com" git config --local user.name "github-actions" git add $VERSION_FILE_NAME diff --git a/.github/workflows/windows-latest-lua-unit-testing.yml b/.github/workflows/windows-latest-lua-unit-testing.yml index d3998fa71..cfd30bfe4 100644 --- a/.github/workflows/windows-latest-lua-unit-testing.yml +++ b/.github/workflows/windows-latest-lua-unit-testing.yml @@ -1,167 +1,241 @@ name: Windows Lua Unit Testing -on: [push, pull_request] +on: [ push, pull_request ] jobs: lua-unit-testing-on-windows-latest: - name: "LuaUnit on Windows-latest (mingw32)" + name: "LuaUnit on Windows-latest (MSVC)" runs-on: windows-latest - - env: - temp_dir: ${{ github.workspace }}\temp - lua_temp_dir: ${{ github.workspace }}\temp\lua-5.1.5 - luajit_temp_dir: ${{ github.workspace }}\temp\luaJIT-2.0.4 - lua_install_dir: ${{ github.workspace }}\Lua - lua_install_bin_dir: ${{ github.workspace }}\Lua\bin - lua_install_lib_dir: ${{ github.workspace }}\Lua\lib - lua_install_share_dir: ${{ github.workspace }}\Lua\share - lua_install_include_dir: ${{ github.workspace }}\Lua\include - + steps: - uses: actions/checkout@v3.1.0 - - uses: msys2/setup-msys2@v2 - with: - msystem: MINGW32 - update: true - - - name: Make directories and files for Lua installation + + - name: Build LuaJIT-2.0.4 + shell: cmd run: | - ### https://gist.github.com/Egor-Skriptunoff/cb952f7eaf39b7b1bf739b818ece87cd - ### http://lua-users.org/wiki/BuildingLuaInWindowsForNewbies - New-Item -Path "${{ github.workspace }}" -Name "Lua" -ItemType "directory" - New-Item -Path "${{ env.lua_install_dir }}" -Name "bin" -ItemType "directory" - New-Item -Path "${{ env.lua_install_dir }}" -Name "lib" -ItemType "directory" - New-Item -Path "${{ env.lua_install_dir }}" -Name "share" -ItemType "directory" - New-Item -Path "${{ env.lua_install_dir }}" -Name "include" -ItemType "directory" - New-Item -Path "${{ github.workspace }}" -Name "temp" -ItemType "directory" - New-Item -Path "${{ env.temp_dir }}" -Name "lua_path.txt" - New-Item -Path "${{ env.temp_dir }}" -Name "lua_cpath.txt" - - - name: Build and install LuaJIT 2.0.4 + :: Build LuaJIT 2.0.4 + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x86 10.0.22000.0 -vcvars_ver=14 + cd ${{ github.workspace }}\.building\LuaJIT-2.0.4\src + msvcbuild + + if exist luajit.exe ( + echo "LuaJIT-2.0.4 built successfully" + ) else ( + echo "::error::LuaJIT-2.0.4 build failed" + exit 1 + ) + + - name: Install LuaJIT-2.0.4 + shell: pwsh run: | - ### https://gist.github.com/Egor-Skriptunoff/cb952f7eaf39b7b1bf739b818ece87cd - ### http://lua-users.org/wiki/BuildingLuaInWindowsForNewbies - - ### Build - Copy-Item -Path "${{ github.workspace }}\.building\LuaJIT-2.0.4\" -Destination "${{ env.luajit_temp_dir }}\" -Recurse - cd ${{ env.luajit_temp_dir }}\ - mingw32-make PLAT=mingw - - ### Install - ### binaries - Copy-Item "${{ env.luajit_temp_dir }}\src\luajit.exe" -Destination "${{ env.lua_install_bin_dir }}\" - Copy-Item "${{ env.luajit_temp_dir }}\src\lua51.dll" -Destination "${{ env.lua_install_bin_dir }}\" - - ### modules written in lua - Copy-Item "${{ env.luajit_temp_dir }}\src\jit\" -Destination "${{ env.lua_install_lib_dir }}\jit\" - - ### includes - Copy-Item "${{ env.luajit_temp_dir }}\src\luaconf.h" -Destination "${{ env.lua_install_include_dir }}\" - Copy-Item "${{ env.luajit_temp_dir }}\src\lua.h" -Destination "${{ env.lua_install_include_dir }}\" - Copy-Item "${{ env.luajit_temp_dir }}\src\lualib.h" -Destination "${{ env.lua_install_include_dir }}\" - Copy-Item "${{ env.luajit_temp_dir }}\src\lauxlib.h" -Destination "${{ env.lua_install_include_dir }}\" - Copy-Item "${{ env.luajit_temp_dir }}\src\lua.hpp" -Destination "${{ env.lua_install_include_dir }}\" - - Start-Process -FilePath "${{ env.lua_install_bin_dir }}\luajit.exe" -ArgumentList " -v" -Wait -NoNewWindow - Start-Process -FilePath "${{ env.lua_install_bin_dir }}\luajit.exe" -ArgumentList " -e `"print(_VERSION)`"" -Wait -NoNewWindow - - - name: Run lua script to adjust lua package paths + # Install binaries + Copy-Item "${{ github.workspace }}\.building\LuaJIT-2.0.4\src\luajit.exe" -Destination "${{ github.workspace }}\LuaJIT-2.0.4\bin" + Copy-Item "${{ github.workspace }}\.building\LuaJIT-2.0.4\src\lua51.dll" -Destination "${{ github.workspace }}\LuaJIT-2.0.4\bin" + Copy-Item "${{ github.workspace }}\.building\LuaJIT-2.0.4\src\lua51.lib" -Destination "${{ github.workspace }}\LuaJIT-2.0.4\bin" + + # 'Install' JIT modules + Copy-Item "${{ github.workspace }}\.building\LuaJIT-2.0.4\src\jit\*" -Destination "${{ github.workspace }}\LuaJIT-2.0.4\lua\jit\" -Recurse + + # 'Install' JIT includes + Copy-Item "${{ github.workspace }}\.building\LuaJIT-2.0.4\src\luaconf.h" -Destination "${{ github.workspace }}\LuaJIT-2.0.4\include" + Copy-Item "${{ github.workspace }}\.building\LuaJIT-2.0.4\src\lua.h" -Destination "${{ github.workspace }}\LuaJIT-2.0.4\include" + Copy-Item "${{ github.workspace }}\.building\LuaJIT-2.0.4\src\lualib.h" -Destination "${{ github.workspace }}\LuaJIT-2.0.4\include" + Copy-Item "${{ github.workspace }}\.building\LuaJIT-2.0.4\src\lauxlib.h" -Destination "${{ github.workspace }}\LuaJIT-2.0.4\include" + Copy-Item "${{ github.workspace }}\.building\LuaJIT-2.0.4\src\lua.hpp" -Destination "${{ github.workspace }}\LuaJIT-2.0.4\include" + + # 'Install' JIT library + Copy-Item "${{ github.workspace }}\.building\LuaJIT-2.0.4\src\lua51.lib" -Destination "${{ github.workspace }}\LuaJIT-2.0.4\lib" + + # Test luajit.exe + Start-Process -FilePath "${{ github.workspace }}\LuaJIT-2.0.4\bin\luajit.exe" -ArgumentList "-v" -Wait -NoNewWindow + Start-Process -FilePath "${{ github.workspace }}\LuaJIT-2.0.4\bin\luajit.exe" -ArgumentList "-e `"print(_VERSION)`"" -Wait -NoNewWindow + + - name: Install and init luarocks + shell: cmd run: | - Start-Process -FilePath "${{ env.lua_install_bin_dir }}\luajit.exe" -ArgumentList " ${{ github.workspace }}\mods\noita-mp\files\scripts\init\init_.lua ${{ env.temp_dir }}" -Wait -NoNewWindow - - - name: Set GitHub env variables - shell: bash + cd ${{ github.workspace}}\mods\noita-mp\ + set INIT_PATH=%CD% + REM // resolve absolute path + set REL_PATH=..\..\.building\luarocks-3.9.1-windows-32 + set ABS_PATH= + rem // Save current directory and change to target directory + pushd %REL_PATH% + rem // Save value of CD variable (current directory) + set ABS_PATH=%CD% + rem // Restore original directory + popd + echo Relative path: %REL_PATH% + echo Maps to path: %ABS_PATH% + + REM // init luarocks + %ABS_PATH%\luarocks --lua-dir="${{ github.workspace}}\LuaJIT-2.0.4" --lua-version="5.1" init noita-mp --output="${{ github.workspace}}\mods\noita-mp" --homepage="https://github.com/Ismoh/NoitaMP" --lua-versions="5.1" --license="GNU GPL v3" + + REM // change luarocks projects config + %ABS_PATH%\luarocks config --scope="project" lua_interpreter luajit.exe + %ABS_PATH%\luarocks config --scope="project" lua_dir ${{ github.workspace}}\LuaJIT-2.0.4 + %ABS_PATH%\luarocks config --scope="project" variables.LUA_BINDIR ${{ github.workspace}}\LuaJIT-2.0.4\bin + %ABS_PATH%\luarocks config --scope="project" variables.LUA_DIR ${{ github.workspace}}\LuaJIT-2.0.4 + %ABS_PATH%\luarocks config --scope="project" variables.LUA_INCDIR ${{ github.workspace}}\LuaJIT-2.0.4\include + %ABS_PATH%\luarocks config --scope="project" variables.CFLAGS "GODDAMNIT" + %ABS_PATH%\luarocks config + + if exist lua.bat ( + echo "LuaRocks project init successfully" + ) else ( + echo "::error::LuaRocks project init failed. Unable to find lua.bat" + exit 1 + ) + if exist luarocks.bat ( + echo "LuaRocks project init successfully" + ) else ( + echo "::error::LuaRocks project init failed. Unable to find luarocks.bat" + exit 1 + ) + + - name: Fix LuaRocks bug run: | - fixedpath=$(echo "${{ env.temp_dir }}/lua_path.txt" | sed -e 's_\\_/_g') ### replace \ with / - cat $fixedpath - echo "LUA_PATH=;;${{ env.lua_install_lib_dir }}\\?.lua;${{ env.lua_install_lib_dir }}\\?\\init.lua;${{ env.lua_install_lib_dir }}\\jit\\?.lua;${{ env.lua_install_lib_dir }}\\jit\\?\\init.lua;${{ env.lua_install_share_dir }}\\lua\\5.1\\?.lua;$(cat $fixedpath)" >> $GITHUB_ENV - - fixedpath=$(echo "${{ env.temp_dir }}/lua_cpath.txt" | sed -e 's_\\_/_g') ### replace \ with / - cat $fixedpath - echo "LUA_CPATH=$(cat $fixedpath)" >> $GITHUB_ENV - + cd ${{ github.workspace}}\mods\noita-mp\.luarocks + sed -i 's/GODDAMNIT/\-v \-O2/g' config-5.1.lua + cat config-5.1.lua + +# - name: Build and install cache.dll +# shell: cmd +# run: | +# call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x86 10.0.22000.0 -vcvars_ver=14 +# cd ${{ github.workspace }}\ +# msbuild noitamp_cache.vcxproj + - name: Run LuaUnit 3.4 + shell: cmd id: lua_unit_tests run: | - $files = Get-ChildItem -Path ${{ github.workspace }}\.testing\tests -Filter *.lua -Recurse - foreach ($file in $files) # https://stackoverflow.com/a/11568420/3493998 - { - Write-Host "Running lua file $file" - # https://stackoverflow.com/a/45330000/3493998 - & '${{ env.lua_install_bin_dir }}\luajit.exe' $file.FullName -o text --verbose > ${{ github.workspace }}\.testing\testresult.log - type ${{ github.workspace }}\.testing\testresult.log - } - - # https://timheuer.com/blog/manually-force-a-failure-in-github-action-step/ - $testFail = Select-String -Path ${{ github.workspace }}\.testing\testresult.log -Pattern 'FAIL' -CaseSensitive - echo "{fail}={$testFail}" >> $GITHUB_OUTPUT - - $testError = Select-String -Path ${{ github.workspace }}\.testing\testresult.log -Pattern 'ERROR' -CaseSensitive - echo "{error}={$testError}" >> $GITHUB_OUTPUT - - $notFound = Get-Content -Path ${{ github.workspace }}\.testing\testresult.log - echo "{not_found}={$notFound}" >> $GITHUB_OUTPUT - - - name: Unit test failed? - if: ${{ steps.lua_unit_tests.outputs.fail != '' || steps.lua_unit_tests.outputs.error != '' || steps.lua_unit_tests.outputs.not_found == '' }} - run: | - echo "steps.lua_unit_tests.outputs.fail = ${{ steps.lua_unit_tests.outputs.fail }}" - echo "steps.lua_unit_tests.outputs.error = ${{ steps.lua_unit_tests.outputs.error }}" - echo "steps.lua_unit_tests.outputs.not_found = ${{ steps.lua_unit_tests.outputs.not_found }}" - echo "Unit tests failed!" - # exit 1 - - - name: Install luarocks 3.8.0 + cd ${{ github.workspace}}\mods\noita-mp\ + call luarocks.bat test > result.log + + if exist result.log ( + echo "LuaUnit tests successfully" + ) else ( + echo "::error::LuaUnit tests failed. Unable to find result.log" + exit 1 + ) + + type result.log + + - name: Failed unit tests? + shell: cmd run: | - Invoke-WebRequest -Uri "http://luarocks.github.io/luarocks/releases/luarocks-3.8.0-windows-32.zip" -OutFile "${{ github.workspace }}\luarocks-3.8.0-win32.zip" - Expand-Archive -Path ${{ github.workspace }}\luarocks-3.8.0-win32.zip -DestinationPath "${{ env.temp_dir }}" - - Start-Process -FilePath "${{ env.temp_dir }}\luarocks-3.8.0-windows-32\luarocks.exe" -ArgumentList " --version " -Wait -NoNewWindow - + cd ${{ github.workspace}}/mods/noita-mp + + for /F "tokens=9 delims= " %%a in ('findstr /I "Ran*" result.log') do set "failOrErrorCount=%%a" + echo "failOrErrorCount:%failOrErrorCount%" + if NOT %failOrErrorCount% == 0 ( + echo "::error title=LuaUnit tests failed::%failOrErrorCount% failures or errors occurred!" + exit 1 + ) + + + + - name: Install dependencies + shell: cmd run: | - #echo "C:\msys64\mingw32\bin" >> $GITHUB_PATH - #cp C:\ProgramData\chocolatey\lib\mingw\tools\install\mingw64\bin\x86_64-w64-mingw32-gcc.exe C:\ProgramData\chocolatey\lib\mingw\tools\install\mingw64\bin\mingw32-gcc.exe - - Start-Process -FilePath "${{ env.temp_dir }}\luarocks-3.8.0-windows-32\luarocks.exe" -ArgumentList "--lua-dir=${{ env.lua_install_dir }} --lua-version=5.1 --tree=${{ env.lua_install_dir }} install luacov" -Wait -NoNewWindow - Start-Process -FilePath "${{ env.temp_dir }}\luarocks-3.8.0-windows-32\luarocks.exe" -ArgumentList "--lua-dir=${{ env.lua_install_dir }} --lua-version=5.1 --tree=${{ env.lua_install_dir }} install lua-path" -Wait -NoNewWindow - Start-Process -FilePath "${{ env.temp_dir }}\luarocks-3.8.0-windows-32\luarocks.exe" -ArgumentList "--lua-dir=${{ env.lua_install_dir }} --lua-version=5.1 --tree=${{ env.lua_install_dir }} install dkjson" -Wait -NoNewWindow - Start-Process -FilePath "${{ env.temp_dir }}\luarocks-3.8.0-windows-32\luarocks.exe" -ArgumentList "--lua-dir=${{ env.lua_install_dir }} --lua-version=5.1 --tree=${{ env.lua_install_dir }} install luafilesystem" -Wait -NoNewWindow - Start-Process -FilePath "${{ env.temp_dir }}\luarocks-3.8.0-windows-32\luarocks.exe" -ArgumentList "--lua-dir=${{ env.lua_install_dir }} --lua-version=5.1 --tree=${{ env.lua_install_dir }} install luacov-coveralls" -Wait -NoNewWindow - - ls -R ${{ env.lua_install_dir }} - - - name: Generate coverage report with luacov + call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x86 10.0.22000.0 -vcvars_ver=14 + cd ${{ github.workspace}}\mods\noita-mp\ + + call luarocks.bat install luacov + call luarocks.bat install luacov-coveralls + + if exist ${{ github.workspace }}\mods\noita-mp\lua_modules\bin\luacov.bat ( + echo "LuaCov install successfully" + ) else ( + echo "::error::LuaCov install failed" + exit 1 + ) + if exist ${{ github.workspace }}\mods\noita-mp\lua_modules\bin\luacov-coveralls.bat ( + echo "LuaCov Coveralls install successfully" + ) else ( + echo "::error::LuaCov Coveralls install failed" + exit 1 + ) + + - name: Write LuaRocks path into files + shell: cmd run: | - dir -Path ${{ github.workspace }}\.testing\tests -Filter *.lua -Recurse | %{& '${{ env.lua_install_bin_dir }}\luajit.exe' -lluacov $_.FullName -o text --verbose } - - Start-Process -FilePath "${{ env.lua_install_bin_dir }}\luacov.bat" -Wait -NoNewWindow - - # - name: Generate coverage report with luacov-coveralls - # shell: cmd - # env: - # COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # COVERALLS_DEBUG: true - # run: | - # ${{ env.lua_install_bin_dir }}\luacov-coveralls.bat -v - - - name: Fix codecov path issue - # shell: pwsh + cd ${{ github.workspace }}\mods\noita-mp\ + call luarocks path --lr-path >> lpath.txt + call luarocks path --lr-cpath >> cpath.txt + call luarocks path --lr-bin >> path.txt + + - name: Set LuaRocks path into GitHub action path run: | - # ls -R - # $content = Get-Content -Path ${{ github.workspace }}/luacov.report.out - # $content = $content.Replace("\", "/") - # $content > ${{ github.workspace }}/luacov.report.out - # Write-Host $content - - $(cat ${{ github.workspace }}/luacov.report.out | sed -e 's_\\_/_g') > ${{ github.workspace }}/luacov.report.out - cat ${{ github.workspace }}/luacov.report.out + cd ${{ github.workspace }}\mods\noita-mp\ + + $lpath = Get-Content lpath.txt -Raw + echo "LUA_PATH=$lpath" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + + echo "$lpath" | Out-File -Append -FilePath $env:GITHUB_PATH -Encoding utf8 + + $cpath = Get-Content cpath.txt -Raw + echo "LUA_CPATH=$cpath" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + echo "$cpath" | Out-File -Append -FilePath $env:GITHUB_PATH -Encoding utf8 + + $path = Get-Content path.txt -Raw + echo "$path" | Out-File -Append -FilePath $env:GITHUB_PATH -Encoding utf8 + + - name: Generate coverage report with luacov + shell: cmd + run: | + cd ${{ github.workspace }}\mods\noita-mp\ + call lua.bat -lluacov ${{ github.workspace }}\mods\noita-mp\tests\startUnitTests.lua -o text --verbose + call ${{ github.workspace }}\mods\noita-mp\lua_modules\bin\luacov.bat -c=${{ github.workspace }}\mods\noita-mp\.luacov + ls -R + + if exist ${{ github.workspace }}\mods\noita-mp\luacov.stats.out ( + echo "LuaCov report successfully" + ) else ( + echo "::error::LuaCov report failed. Unable to find luacov.stats.out" + exit 1 + ) + + if exist ${{ github.workspace }}\mods\noita-mp\luacov.report.out ( + echo "LuaCov report successfully" + ) else ( + echo "::error::LuaCov report failed. Unable to find luacov.report.out" + exit 1 + ) + + - name: Fix wrong paths in luacov.report.out + run : | + cd ${{ github.workspace }}\mods\noita-mp\ + cat luacov.report.out + sed -i 's/\.\.\noita\-mp/mods\\noita\-mp/g' luacov.report.out + cat luacov.report.out + sed -i 's/D\:\\a\\NoitaMP\\NoitaMP\\mods\\noita\-mp\\\.\.\\\.\.\\mods\\noita\-mp/mods\\noita\-mp/g' luacov.report.out + cat luacov.report.out + sed -i 's/D\:\\a\\NoitaMP\\NoitaMP\\mods\\noita\-mp/mods\\noita\-mp/g' luacov.report.out + cat luacov.report.out - name: Upload coverage to Codecov uses: codecov/codecov-action@v3 with: - directory: ${{ github.workspace }} + file: mods/noita-mp/luacov.report.out flags: unittesting functionalities: network name: Windows Lua Unit Testing verbose: true + + - name: Generate coverage report with luacov-coveralls + shell: cmd + env: + COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} + COVERALLS_DEBUG: true + run: | + cd ${{ github.workspace}}\mods\noita-mp\ + call ${{ github.workspace }}\mods\noita-mp\lua_modules\bin\luacov-coveralls.bat --verbose --root=${{ github.workspace}}\mods\noita-mp\ + + if exist ${{ github.workspace }}\mods\noita-mp\luacov.report.out ( + echo "LuaCov Coveralls report successfully" + ) else ( + echo "::error::LuaCov Coveralls report failed. Unable to find luacov.report.out" + exit 1 + ) diff --git a/.gitignore b/.gitignore index 1bef56cac..593a52b94 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,18 @@ +# Generated files +mods/noita-mp/luacov.stats.out +mods/noita-mp/result.log + # Compiled Lua sources # luac.out # luarocks build files -# *.src.rock -# *.zip -# *.tar.gz +*.src.rock +*.zip +*.tar.gz +mods/noita-mp/.luarocks +mods/noita-mp/luarocks.bat +mods/noita-mp/lua.bat +mods/noita-mp/lua_modules/lib/luarocks # Visual studio folder .vs/ @@ -48,4 +56,4 @@ noitamp_cache.exp # *.app # *.i*86 # *.x86_64 -# *.hex \ No newline at end of file +# *.hex diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 1ca78f020..000000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "luaunit"] - path = mods/noita-mp/files/lib/external - url = https://github.com/bluebird75/luaunit.git diff --git a/.luacov b/.luacov deleted file mode 100644 index 20a0bf04d..000000000 --- a/.luacov +++ /dev/null @@ -1,22 +0,0 @@ --- Configuration file for LuaCov -return { - exclude = { - ".building", - ".debug", - ".github", - ".testing", - ".vscode", - "docs", - ".gitattritbutes", - ".gitignore", - ".luacov", - "CODE_OF_CONDUCT.md", - "codecov.yml", - "CONTRIBUTING.md", - "coveralls.yml", - "LICENSE", - "README.md", - "SUPPORT.md", - "luarocks-3.8.0/.codecov.yml", - } -} diff --git a/.testing/tests/mods/noita-mp/config_test.lua b/.testing/tests/mods/noita-mp/config_test.lua deleted file mode 100644 index c332208e8..000000000 --- a/.testing/tests/mods/noita-mp/config_test.lua +++ /dev/null @@ -1,42 +0,0 @@ -function table.pack(...) - return { n = select("#", ...), ... } -end -function vararg(...) - local args = table.pack(...) - for i = 1, args.n do - -- do something with args[i], careful, it might be nil! - print(("vararg %s = %s"):format(i, args[i])) - end - return args -end - -local vArgs = vararg(...) -if vArgs[6] then - print(("Found 6th arg to fix paths: "):format(vArgs[6])) - local dofileDefault = _G.dofile - local dofile = function(path) - local fixedPath = vArgs[4] .. "/" .. path - print(("dofile: %s -> %s"):format(path, fixedPath)) - return dofileDefault(fixedPath) - end - _G.dofile = dofile -end - -local init_ = loadfile(vArgs[4] .. "/mods/noita-mp/files/scripts/init/init_.lua") -init_(vArgs[4] .. "/") -local init_package_loading = dofile("mods/noita-mp/files/scripts/init/init_package_loading.lua") -init_package_loading(vArgs[4] .. "/") - -local lu = require("luaunit") - -TestConfig = {} - -function TestConfig:setUp() - print("\n setUp") -end - -function TestConfig:tearDown() - print("tearDown\n") -end - -os.exit(lu.LuaUnit.run()) diff --git a/.testing/tests/mods/noita-mp/files/scripts/init/init__test.lua b/.testing/tests/mods/noita-mp/files/scripts/init/init__test.lua deleted file mode 100644 index 3a331ee7e..000000000 --- a/.testing/tests/mods/noita-mp/files/scripts/init/init__test.lua +++ /dev/null @@ -1,15 +0,0 @@ -dofile("mods/noita-mp/files/scripts/init/init_.lua") - -local lu = require("luaunit") - -TestInit_ = {} - -function TestInit_:setUp() - print("\nsetUp") -end - -function TestInit_:tearDown() - print("tearDown\n") -end - -os.exit(lu.LuaUnit.run()) diff --git a/.testing/tests/mods/noita-mp/files/scripts/net/Server_test.lua b/.testing/tests/mods/noita-mp/files/scripts/net/Server_test.lua deleted file mode 100644 index 10920da97..000000000 --- a/.testing/tests/mods/noita-mp/files/scripts/net/Server_test.lua +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env lua -dofile("mods/noita-mp/files/scripts/init/init_.lua") - -local lu = require("luaunit") - -TestServer = {} - -function TestServer:setUp() - print("\nsetUp") -end - -function TestServer:tearDown() - print("tearDown\n") -end - -function TestServer:test() - -- -end - -os.exit(lu.LuaUnit.run()) \ No newline at end of file diff --git a/.testing/tests/mods/noita-mp/files/scripts/util/EntityUtils_test.lua b/.testing/tests/mods/noita-mp/files/scripts/util/EntityUtils_test.lua deleted file mode 100644 index c3f5ce0ca..000000000 --- a/.testing/tests/mods/noita-mp/files/scripts/util/EntityUtils_test.lua +++ /dev/null @@ -1,15 +0,0 @@ -dofile("mods/noita-mp/files/scripts/init/init_.lua") - -local lu = require("luaunit") - -TestEntityUtils = {} - -function TestEntityUtils:setUp() - print("\nsetUp") -end - -function TestEntityUtils:tearDown() - print("tearDown\n") -end - -os.exit(lu.LuaUnit.run()) diff --git a/.testing/tests/mods/noita-mp/files/scripts/util/GlobalsUtils_test.lua b/.testing/tests/mods/noita-mp/files/scripts/util/GlobalsUtils_test.lua deleted file mode 100644 index 72391003c..000000000 --- a/.testing/tests/mods/noita-mp/files/scripts/util/GlobalsUtils_test.lua +++ /dev/null @@ -1,15 +0,0 @@ -dofile("mods/noita-mp/files/scripts/init/init_.lua") - -local lu = require("luaunit") - -TestGlobalsUtils = {} - -function TestGlobalsUtils:setUp() - print("\nsetUp") -end - -function TestGlobalsUtils:tearDown() - print("tearDown\n") -end - -os.exit(lu.LuaUnit.run()) diff --git a/.testing/tests/mods/noita-mp/files/scripts/util/NetworkUtils_test.lua b/.testing/tests/mods/noita-mp/files/scripts/util/NetworkUtils_test.lua deleted file mode 100644 index 5b5e0c88b..000000000 --- a/.testing/tests/mods/noita-mp/files/scripts/util/NetworkUtils_test.lua +++ /dev/null @@ -1,49 +0,0 @@ ----@diagnostic disable: undefined-global -#!/usr/bin/env lua -dofile("mods/noita-mp/files/scripts/init/init_.lua") - -local lu = require("luaunit") -local NetworkUtils = require("NetworkUtils") -local sock = require("sock") - -TestNetworkUtils = {} - -function TestNetworkUtils:setUp() - print("\nsetUp") -end - -function TestNetworkUtils:tearDown() - print("tearDown\n") -end - -function TestNetworkUtils:testAlreadySent() - local event = NetworkUtils.events.newNuid.name - local data = { - networkMessageId = 367, - owner = { "ownerName", "ownerGuid" }, - localEntityId = 4673, - newNuid = 4, - x = 0.25, - y = 3.55, - rotation = 49, - velocity = { x = 0, y = 3 }, - filename = "/mods/", - health = { current = 123, max = 125 }, - isPolymorphed = false - } - - local server = sock.newServer("*", 22122) - local client = sock.newClient("*", 22122) - - client.connect("*", 22122) - - local result = NetworkUtils.alreadySent(client, event, data) - lu.assertIsFalse(result) - - server.send(client, event, data) - - local result = NetworkUtils.alreadySent(client, event, data) - lu.assertIsTrue(result) -end - -os.exit(lu.LuaUnit.run()) \ No newline at end of file diff --git a/.testing/tests/mods/noita-mp/files/scripts/util/NetworkVscUtils_test.lua b/.testing/tests/mods/noita-mp/files/scripts/util/NetworkVscUtils_test.lua deleted file mode 100644 index c4b6215b2..000000000 --- a/.testing/tests/mods/noita-mp/files/scripts/util/NetworkVscUtils_test.lua +++ /dev/null @@ -1,15 +0,0 @@ -dofile("mods/noita-mp/files/scripts/init/init_.lua") - -local lu = require("luaunit") - -TestNetworkVscUtils = {} - -function TestNetworkVscUtils:setUp() - print("\nsetUp") -end - -function TestNetworkVscUtils:tearDown() - print("tearDown\n") -end - -os.exit(lu.LuaUnit.run()) diff --git a/.testing/tests/mods/noita-mp/files/scripts/util/NuidUtils_test.lua b/.testing/tests/mods/noita-mp/files/scripts/util/NuidUtils_test.lua deleted file mode 100644 index 0e71d63d8..000000000 --- a/.testing/tests/mods/noita-mp/files/scripts/util/NuidUtils_test.lua +++ /dev/null @@ -1,15 +0,0 @@ -dofile("mods/noita-mp/files/scripts/init/init_.lua") - -local lu = require("luaunit") - -TestNuidUtils = {} - -function TestNuidUtils:setUp() - print("\nsetUp") -end - -function TestNuidUtils:tearDown() - print("tearDown\n") -end - -os.exit(lu.LuaUnit.run()) diff --git a/.testing/tests/mods/noita-mp/init_test.lua b/.testing/tests/mods/noita-mp/init_test.lua deleted file mode 100644 index f2314e72c..000000000 --- a/.testing/tests/mods/noita-mp/init_test.lua +++ /dev/null @@ -1,15 +0,0 @@ -dofile("mods/noita-mp/files/scripts/init/init_.lua") - -local lu = require("luaunit") - -TestInit = {} - -function TestInit:setUp() - print("\nsetUp") -end - -function TestInit:tearDown() - print("tearDown\n") -end - -os.exit(lu.LuaUnit.run()) diff --git a/LuaJIT-2.0.4/bin/lua51.dll b/LuaJIT-2.0.4/bin/lua51.dll new file mode 100644 index 000000000..e636c4fd9 Binary files /dev/null and b/LuaJIT-2.0.4/bin/lua51.dll differ diff --git a/LuaJIT-2.0.4/bin/luajit.exe b/LuaJIT-2.0.4/bin/luajit.exe new file mode 100644 index 000000000..77f8d4416 Binary files /dev/null and b/LuaJIT-2.0.4/bin/luajit.exe differ diff --git a/LuaJIT-2.0.4/include/lauxlib.h b/LuaJIT-2.0.4/include/lauxlib.h new file mode 100644 index 000000000..fed1491b8 --- /dev/null +++ b/LuaJIT-2.0.4/include/lauxlib.h @@ -0,0 +1,167 @@ +/* +** $Id: lauxlib.h,v 1.88.1.1 2007/12/27 13:02:25 roberto Exp $ +** Auxiliary functions for building Lua libraries +** See Copyright Notice in lua.h +*/ + + +#ifndef lauxlib_h +#define lauxlib_h + + +#include +#include + +#include "lua.h" + + +#define luaL_getn(L,i) ((int)lua_objlen(L, i)) +#define luaL_setn(L,i,j) ((void)0) /* no op! */ + +/* extra error code for `luaL_load' */ +#define LUA_ERRFILE (LUA_ERRERR+1) + +typedef struct luaL_Reg { + const char *name; + lua_CFunction func; +} luaL_Reg; + +LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname, + const luaL_Reg *l, int nup); +LUALIB_API void (luaL_register) (lua_State *L, const char *libname, + const luaL_Reg *l); +LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e); +LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e); +LUALIB_API int (luaL_typerror) (lua_State *L, int narg, const char *tname); +LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg); +LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg, + size_t *l); +LUALIB_API const char *(luaL_optlstring) (lua_State *L, int numArg, + const char *def, size_t *l); +LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int numArg); +LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int nArg, lua_Number def); + +LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int numArg); +LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int nArg, + lua_Integer def); + +LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg); +LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t); +LUALIB_API void (luaL_checkany) (lua_State *L, int narg); + +LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname); +LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname); + +LUALIB_API void (luaL_where) (lua_State *L, int lvl); +LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...); + +LUALIB_API int (luaL_checkoption) (lua_State *L, int narg, const char *def, + const char *const lst[]); + +LUALIB_API int (luaL_ref) (lua_State *L, int t); +LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref); + +LUALIB_API int (luaL_loadfile) (lua_State *L, const char *filename); +LUALIB_API int (luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz, + const char *name); +LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s); + +LUALIB_API lua_State *(luaL_newstate) (void); + + +LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p, + const char *r); + +LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx, + const char *fname, int szhint); + +/* From Lua 5.2. */ +LUALIB_API int luaL_fileresult(lua_State *L, int stat, const char *fname); +LUALIB_API int luaL_execresult(lua_State *L, int stat); +LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename, + const char *mode); +LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz, + const char *name, const char *mode); +LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg, + int level); + + +/* +** =============================================================== +** some useful macros +** =============================================================== +*/ + +#define luaL_argcheck(L, cond,numarg,extramsg) \ + ((void)((cond) || luaL_argerror(L, (numarg), (extramsg)))) +#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL)) +#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL)) +#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n))) +#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d))) +#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n))) +#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d))) + +#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i))) + +#define luaL_dofile(L, fn) \ + (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0)) + +#define luaL_dostring(L, s) \ + (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0)) + +#define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n))) + +#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n))) + +/* +** {====================================================== +** Generic Buffer manipulation +** ======================================================= +*/ + + + +typedef struct luaL_Buffer { + char *p; /* current position in buffer */ + int lvl; /* number of strings in the stack (level) */ + lua_State *L; + char buffer[LUAL_BUFFERSIZE]; +} luaL_Buffer; + +#define luaL_addchar(B,c) \ + ((void)((B)->p < ((B)->buffer+LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), \ + (*(B)->p++ = (char)(c))) + +/* compatibility only */ +#define luaL_putchar(B,c) luaL_addchar(B,c) + +#define luaL_addsize(B,n) ((B)->p += (n)) + +LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B); +LUALIB_API char *(luaL_prepbuffer) (luaL_Buffer *B); +LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l); +LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s); +LUALIB_API void (luaL_addvalue) (luaL_Buffer *B); +LUALIB_API void (luaL_pushresult) (luaL_Buffer *B); + + +/* }====================================================== */ + + +/* compatibility with ref system */ + +/* pre-defined references */ +#define LUA_NOREF (-2) +#define LUA_REFNIL (-1) + +#define lua_ref(L,lock) ((lock) ? luaL_ref(L, LUA_REGISTRYINDEX) : \ + (lua_pushstring(L, "unlocked references are obsolete"), lua_error(L), 0)) + +#define lua_unref(L,ref) luaL_unref(L, LUA_REGISTRYINDEX, (ref)) + +#define lua_getref(L,ref) lua_rawgeti(L, LUA_REGISTRYINDEX, (ref)) + + +#define luaL_reg luaL_Reg + +#endif diff --git a/LuaJIT-2.0.4/include/lua.h b/LuaJIT-2.0.4/include/lua.h new file mode 100644 index 000000000..c83fd3bbe --- /dev/null +++ b/LuaJIT-2.0.4/include/lua.h @@ -0,0 +1,393 @@ +/* +** $Id: lua.h,v 1.218.1.5 2008/08/06 13:30:12 roberto Exp $ +** Lua - An Extensible Extension Language +** Lua.org, PUC-Rio, Brazil (http://www.lua.org) +** See Copyright Notice at the end of this file +*/ + + +#ifndef lua_h +#define lua_h + +#include +#include + + +#include "luaconf.h" + + +#define LUA_VERSION "Lua 5.1" +#define LUA_RELEASE "Lua 5.1.4" +#define LUA_VERSION_NUM 501 +#define LUA_COPYRIGHT "Copyright (C) 1994-2008 Lua.org, PUC-Rio" +#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes" + + +/* mark for precompiled code (`Lua') */ +#define LUA_SIGNATURE "\033Lua" + +/* option for multiple returns in `lua_pcall' and `lua_call' */ +#define LUA_MULTRET (-1) + + +/* +** pseudo-indices +*/ +#define LUA_REGISTRYINDEX (-10000) +#define LUA_ENVIRONINDEX (-10001) +#define LUA_GLOBALSINDEX (-10002) +#define lua_upvalueindex(i) (LUA_GLOBALSINDEX-(i)) + + +/* thread status; 0 is OK */ +#define LUA_YIELD 1 +#define LUA_ERRRUN 2 +#define LUA_ERRSYNTAX 3 +#define LUA_ERRMEM 4 +#define LUA_ERRERR 5 + + +typedef struct lua_State lua_State; + +typedef int (*lua_CFunction) (lua_State *L); + + +/* +** functions that read/write blocks when loading/dumping Lua chunks +*/ +typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz); + +typedef int (*lua_Writer) (lua_State *L, const void* p, size_t sz, void* ud); + + +/* +** prototype for memory-allocation functions +*/ +typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize); + + +/* +** basic types +*/ +#define LUA_TNONE (-1) + +#define LUA_TNIL 0 +#define LUA_TBOOLEAN 1 +#define LUA_TLIGHTUSERDATA 2 +#define LUA_TNUMBER 3 +#define LUA_TSTRING 4 +#define LUA_TTABLE 5 +#define LUA_TFUNCTION 6 +#define LUA_TUSERDATA 7 +#define LUA_TTHREAD 8 + + + +/* minimum Lua stack available to a C function */ +#define LUA_MINSTACK 20 + + +/* +** generic extra include file +*/ +#if defined(LUA_USER_H) +#include LUA_USER_H +#endif + + +/* type of numbers in Lua */ +typedef LUA_NUMBER lua_Number; + + +/* type for integer functions */ +typedef LUA_INTEGER lua_Integer; + + + +/* +** state manipulation +*/ +LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud); +LUA_API void (lua_close) (lua_State *L); +LUA_API lua_State *(lua_newthread) (lua_State *L); + +LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); + + +/* +** basic stack manipulation +*/ +LUA_API int (lua_gettop) (lua_State *L); +LUA_API void (lua_settop) (lua_State *L, int idx); +LUA_API void (lua_pushvalue) (lua_State *L, int idx); +LUA_API void (lua_remove) (lua_State *L, int idx); +LUA_API void (lua_insert) (lua_State *L, int idx); +LUA_API void (lua_replace) (lua_State *L, int idx); +LUA_API int (lua_checkstack) (lua_State *L, int sz); + +LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n); + + +/* +** access functions (stack -> C) +*/ + +LUA_API int (lua_isnumber) (lua_State *L, int idx); +LUA_API int (lua_isstring) (lua_State *L, int idx); +LUA_API int (lua_iscfunction) (lua_State *L, int idx); +LUA_API int (lua_isuserdata) (lua_State *L, int idx); +LUA_API int (lua_type) (lua_State *L, int idx); +LUA_API const char *(lua_typename) (lua_State *L, int tp); + +LUA_API int (lua_equal) (lua_State *L, int idx1, int idx2); +LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2); +LUA_API int (lua_lessthan) (lua_State *L, int idx1, int idx2); + +LUA_API lua_Number (lua_tonumber) (lua_State *L, int idx); +LUA_API lua_Integer (lua_tointeger) (lua_State *L, int idx); +LUA_API int (lua_toboolean) (lua_State *L, int idx); +LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len); +LUA_API size_t (lua_objlen) (lua_State *L, int idx); +LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx); +LUA_API void *(lua_touserdata) (lua_State *L, int idx); +LUA_API lua_State *(lua_tothread) (lua_State *L, int idx); +LUA_API const void *(lua_topointer) (lua_State *L, int idx); + + +/* +** push functions (C -> stack) +*/ +LUA_API void (lua_pushnil) (lua_State *L); +LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n); +LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n); +LUA_API void (lua_pushlstring) (lua_State *L, const char *s, size_t l); +LUA_API void (lua_pushstring) (lua_State *L, const char *s); +LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt, + va_list argp); +LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...); +LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n); +LUA_API void (lua_pushboolean) (lua_State *L, int b); +LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p); +LUA_API int (lua_pushthread) (lua_State *L); + + +/* +** get functions (Lua -> stack) +*/ +LUA_API void (lua_gettable) (lua_State *L, int idx); +LUA_API void (lua_getfield) (lua_State *L, int idx, const char *k); +LUA_API void (lua_rawget) (lua_State *L, int idx); +LUA_API void (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_newuserdata) (lua_State *L, size_t sz); +LUA_API int (lua_getmetatable) (lua_State *L, int objindex); +LUA_API void (lua_getfenv) (lua_State *L, int idx); + + +/* +** set functions (stack -> Lua) +*/ +LUA_API void (lua_settable) (lua_State *L, int idx); +LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k); +LUA_API void (lua_rawset) (lua_State *L, int idx); +LUA_API void (lua_rawseti) (lua_State *L, int idx, int n); +LUA_API int (lua_setmetatable) (lua_State *L, int objindex); +LUA_API int (lua_setfenv) (lua_State *L, int idx); + + +/* +** `load' and `call' functions (load and run Lua code) +*/ +LUA_API void (lua_call) (lua_State *L, int nargs, int nresults); +LUA_API int (lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc); +LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud); +LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt, + const char *chunkname); + +LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data); + + +/* +** coroutine functions +*/ +LUA_API int (lua_yield) (lua_State *L, int nresults); +LUA_API int (lua_resume) (lua_State *L, int narg); +LUA_API int (lua_status) (lua_State *L); + +/* +** garbage-collection function and options +*/ + +#define LUA_GCSTOP 0 +#define LUA_GCRESTART 1 +#define LUA_GCCOLLECT 2 +#define LUA_GCCOUNT 3 +#define LUA_GCCOUNTB 4 +#define LUA_GCSTEP 5 +#define LUA_GCSETPAUSE 6 +#define LUA_GCSETSTEPMUL 7 + +LUA_API int (lua_gc) (lua_State *L, int what, int data); + + +/* +** miscellaneous functions +*/ + +LUA_API int (lua_error) (lua_State *L); + +LUA_API int (lua_next) (lua_State *L, int idx); + +LUA_API void (lua_concat) (lua_State *L, int n); + +LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud); +LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud); + + + +/* +** =============================================================== +** some useful macros +** =============================================================== +*/ + +#define lua_pop(L,n) lua_settop(L, -(n)-1) + +#define lua_newtable(L) lua_createtable(L, 0, 0) + +#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n))) + +#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0) + +#define lua_strlen(L,i) lua_objlen(L, (i)) + +#define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION) +#define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE) +#define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA) +#define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL) +#define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN) +#define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD) +#define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE) +#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0) + +#define lua_pushliteral(L, s) \ + lua_pushlstring(L, "" s, (sizeof(s)/sizeof(char))-1) + +#define lua_setglobal(L,s) lua_setfield(L, LUA_GLOBALSINDEX, (s)) +#define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, (s)) + +#define lua_tostring(L,i) lua_tolstring(L, (i), NULL) + + + +/* +** compatibility macros and functions +*/ + +#define lua_open() luaL_newstate() + +#define lua_getregistry(L) lua_pushvalue(L, LUA_REGISTRYINDEX) + +#define lua_getgccount(L) lua_gc(L, LUA_GCCOUNT, 0) + +#define lua_Chunkreader lua_Reader +#define lua_Chunkwriter lua_Writer + + +/* hack */ +LUA_API void lua_setlevel (lua_State *from, lua_State *to); + + +/* +** {====================================================================== +** Debug API +** ======================================================================= +*/ + + +/* +** Event codes +*/ +#define LUA_HOOKCALL 0 +#define LUA_HOOKRET 1 +#define LUA_HOOKLINE 2 +#define LUA_HOOKCOUNT 3 +#define LUA_HOOKTAILRET 4 + + +/* +** Event masks +*/ +#define LUA_MASKCALL (1 << LUA_HOOKCALL) +#define LUA_MASKRET (1 << LUA_HOOKRET) +#define LUA_MASKLINE (1 << LUA_HOOKLINE) +#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT) + +typedef struct lua_Debug lua_Debug; /* activation record */ + + +/* Functions to be called by the debuger in specific events */ +typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar); + + +LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar); +LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar); +LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n); +LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n); +LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n); +LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n); +LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count); +LUA_API lua_Hook lua_gethook (lua_State *L); +LUA_API int lua_gethookmask (lua_State *L); +LUA_API int lua_gethookcount (lua_State *L); + +/* From Lua 5.2. */ +LUA_API void *lua_upvalueid (lua_State *L, int idx, int n); +LUA_API void lua_upvaluejoin (lua_State *L, int idx1, int n1, int idx2, int n2); +LUA_API int lua_loadx (lua_State *L, lua_Reader reader, void *dt, + const char *chunkname, const char *mode); + + +struct lua_Debug { + int event; + const char *name; /* (n) */ + const char *namewhat; /* (n) `global', `local', `field', `method' */ + const char *what; /* (S) `Lua', `C', `main', `tail' */ + const char *source; /* (S) */ + int currentline; /* (l) */ + int nups; /* (u) number of upvalues */ + int linedefined; /* (S) */ + int lastlinedefined; /* (S) */ + char short_src[LUA_IDSIZE]; /* (S) */ + /* private part */ + int i_ci; /* active function */ +}; + +/* }====================================================================== */ + + +/****************************************************************************** +* Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining +* a copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to +* permit persons to whom the Software is furnished to do so, subject to +* the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +******************************************************************************/ + + +#endif diff --git a/LuaJIT-2.0.4/include/lua.hpp b/LuaJIT-2.0.4/include/lua.hpp new file mode 100644 index 000000000..07e9002dc --- /dev/null +++ b/LuaJIT-2.0.4/include/lua.hpp @@ -0,0 +1,9 @@ +// C++ wrapper for LuaJIT header files. + +extern "C" { +#include "lua.h" +#include "lauxlib.h" +#include "lualib.h" +#include "luajit.h" +} + diff --git a/LuaJIT-2.0.4/include/luaconf.h b/LuaJIT-2.0.4/include/luaconf.h new file mode 100644 index 000000000..84fa64187 --- /dev/null +++ b/LuaJIT-2.0.4/include/luaconf.h @@ -0,0 +1,156 @@ +/* +** Configuration header. +** Copyright (C) 2005-2015 Mike Pall. See Copyright Notice in luajit.h +*/ + +#ifndef luaconf_h +#define luaconf_h + +#ifndef WINVER +#define WINVER 0x0501 +#endif +#include +#include + +/* Default path for loading Lua and C modules with require(). */ +#if defined(_WIN32) +/* +** In Windows, any exclamation mark ('!') in the path is replaced by the +** path of the directory of the executable file of the current process. +*/ +#define LUA_LDIR "!\\lua\\" +#define LUA_CDIR "!\\" +#define LUA_PATH_DEFAULT \ + ".\\?.lua;" LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" +#define LUA_CPATH_DEFAULT \ + ".\\?.dll;" LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll" +#else +/* +** Note to distribution maintainers: do NOT patch the following lines! +** Please read ../doc/install.html#distro and pass PREFIX=/usr instead. +*/ +#ifndef LUA_MULTILIB +#define LUA_MULTILIB "lib" +#endif +#ifndef LUA_LMULTILIB +#define LUA_LMULTILIB "lib" +#endif +#define LUA_LROOT "/usr/local" +#define LUA_LUADIR "/lua/5.1/" +#define LUA_LJDIR "/luajit-2.0.4/" + +#ifdef LUA_ROOT +#define LUA_JROOT LUA_ROOT +#define LUA_RLDIR LUA_ROOT "/share" LUA_LUADIR +#define LUA_RCDIR LUA_ROOT "/" LUA_MULTILIB LUA_LUADIR +#define LUA_RLPATH ";" LUA_RLDIR "?.lua;" LUA_RLDIR "?/init.lua" +#define LUA_RCPATH ";" LUA_RCDIR "?.so" +#else +#define LUA_JROOT LUA_LROOT +#define LUA_RLPATH +#define LUA_RCPATH +#endif + +#define LUA_JPATH ";" LUA_JROOT "/share" LUA_LJDIR "?.lua" +#define LUA_LLDIR LUA_LROOT "/share" LUA_LUADIR +#define LUA_LCDIR LUA_LROOT "/" LUA_LMULTILIB LUA_LUADIR +#define LUA_LLPATH ";" LUA_LLDIR "?.lua;" LUA_LLDIR "?/init.lua" +#define LUA_LCPATH1 ";" LUA_LCDIR "?.so" +#define LUA_LCPATH2 ";" LUA_LCDIR "loadall.so" + +#define LUA_PATH_DEFAULT "./?.lua" LUA_JPATH LUA_LLPATH LUA_RLPATH +#define LUA_CPATH_DEFAULT "./?.so" LUA_LCPATH1 LUA_RCPATH LUA_LCPATH2 +#endif + +/* Environment variable names for path overrides and initialization code. */ +#define LUA_PATH "LUA_PATH" +#define LUA_CPATH "LUA_CPATH" +#define LUA_INIT "LUA_INIT" + +/* Special file system characters. */ +#if defined(_WIN32) +#define LUA_DIRSEP "\\" +#else +#define LUA_DIRSEP "/" +#endif +#define LUA_PATHSEP ";" +#define LUA_PATH_MARK "?" +#define LUA_EXECDIR "!" +#define LUA_IGMARK "-" +#define LUA_PATH_CONFIG \ + LUA_DIRSEP "\n" LUA_PATHSEP "\n" LUA_PATH_MARK "\n" \ + LUA_EXECDIR "\n" LUA_IGMARK + +/* Quoting in error messages. */ +#define LUA_QL(x) "'" x "'" +#define LUA_QS LUA_QL("%s") + +/* Various tunables. */ +#define LUAI_MAXSTACK 65500 /* Max. # of stack slots for a thread (<64K). */ +#define LUAI_MAXCSTACK 8000 /* Max. # of stack slots for a C func (<10K). */ +#define LUAI_GCPAUSE 200 /* Pause GC until memory is at 200%. */ +#define LUAI_GCMUL 200 /* Run GC at 200% of allocation speed. */ +#define LUA_MAXCAPTURES 32 /* Max. pattern captures. */ + +/* Compatibility with older library function names. */ +#define LUA_COMPAT_MOD /* OLD: math.mod, NEW: math.fmod */ +#define LUA_COMPAT_GFIND /* OLD: string.gfind, NEW: string.gmatch */ + +/* Configuration for the frontend (the luajit executable). */ +#if defined(luajit_c) +#define LUA_PROGNAME "luajit" /* Fallback frontend name. */ +#define LUA_PROMPT "> " /* Interactive prompt. */ +#define LUA_PROMPT2 ">> " /* Continuation prompt. */ +#define LUA_MAXINPUT 512 /* Max. input line length. */ +#endif + +/* Note: changing the following defines breaks the Lua 5.1 ABI. */ +#define LUA_INTEGER ptrdiff_t +#define LUA_IDSIZE 60 /* Size of lua_Debug.short_src. */ +/* +** Size of lauxlib and io.* on-stack buffers. Weird workaround to avoid using +** unreasonable amounts of stack space, but still retain ABI compatibility. +** Blame Lua for depending on BUFSIZ in the ABI, blame **** for wrecking it. +*/ +#define LUAL_BUFFERSIZE (BUFSIZ > 16384 ? 8192 : BUFSIZ) + +/* The following defines are here only for compatibility with luaconf.h +** from the standard Lua distribution. They must not be changed for LuaJIT. +*/ +#define LUA_NUMBER_DOUBLE +#define LUA_NUMBER double +#define LUAI_UACNUMBER double +#define LUA_NUMBER_SCAN "%lf" +#define LUA_NUMBER_FMT "%.14g" +#define lua_number2str(s, n) sprintf((s), LUA_NUMBER_FMT, (n)) +#define LUAI_MAXNUMBER2STR 32 +#define LUA_INTFRMLEN "l" +#define LUA_INTFRM_T long + +/* Linkage of public API functions. */ +#if defined(LUA_BUILD_AS_DLL) +#if defined(LUA_CORE) || defined(LUA_LIB) +#define LUA_API __declspec(dllexport) +#else +#define LUA_API __declspec(dllimport) +#endif +#else +#define LUA_API extern +#endif + +#define LUALIB_API LUA_API + +/* Support for internal assertions. */ +#if defined(LUA_USE_ASSERT) || defined(LUA_USE_APICHECK) +#include +#endif +#ifdef LUA_USE_ASSERT +#define lua_assert(x) assert(x) +#endif +#ifdef LUA_USE_APICHECK +#define luai_apicheck(L, o) { (void)L; assert(o); } +#else +#define luai_apicheck(L, o) { (void)L; } +#endif + +#endif diff --git a/LuaJIT-2.0.4/include/lualib.h b/LuaJIT-2.0.4/include/lualib.h new file mode 100644 index 000000000..96530e79a --- /dev/null +++ b/LuaJIT-2.0.4/include/lualib.h @@ -0,0 +1,43 @@ +/* +** Standard library header. +** Copyright (C) 2005-2015 Mike Pall. See Copyright Notice in luajit.h +*/ + +#ifndef _LUALIB_H +#define _LUALIB_H + +#include "lua.h" + +#define LUA_FILEHANDLE "FILE*" + +#define LUA_COLIBNAME "coroutine" +#define LUA_MATHLIBNAME "math" +#define LUA_STRLIBNAME "string" +#define LUA_TABLIBNAME "table" +#define LUA_IOLIBNAME "io" +#define LUA_OSLIBNAME "os" +#define LUA_LOADLIBNAME "package" +#define LUA_DBLIBNAME "debug" +#define LUA_BITLIBNAME "bit" +#define LUA_JITLIBNAME "jit" +#define LUA_FFILIBNAME "ffi" + +LUALIB_API int luaopen_base(lua_State *L); +LUALIB_API int luaopen_math(lua_State *L); +LUALIB_API int luaopen_string(lua_State *L); +LUALIB_API int luaopen_table(lua_State *L); +LUALIB_API int luaopen_io(lua_State *L); +LUALIB_API int luaopen_os(lua_State *L); +LUALIB_API int luaopen_package(lua_State *L); +LUALIB_API int luaopen_debug(lua_State *L); +LUALIB_API int luaopen_bit(lua_State *L); +LUALIB_API int luaopen_jit(lua_State *L); +LUALIB_API int luaopen_ffi(lua_State *L); + +LUALIB_API void luaL_openlibs(lua_State *L); + +#ifndef lua_assert +#define lua_assert(x) ((void)0) +#endif + +#endif diff --git a/LuaJIT-2.0.4/lib/lua51.lib b/LuaJIT-2.0.4/lib/lua51.lib new file mode 100644 index 000000000..4558be0b0 Binary files /dev/null and b/LuaJIT-2.0.4/lib/lua51.lib differ diff --git a/LuaJIT-2.0.4/lua/jit/bc.lua b/LuaJIT-2.0.4/lua/jit/bc.lua new file mode 100644 index 000000000..46a40892e --- /dev/null +++ b/LuaJIT-2.0.4/lua/jit/bc.lua @@ -0,0 +1,191 @@ +---------------------------------------------------------------------------- +-- LuaJIT bytecode listing module. +-- +-- Copyright (C) 2005-2015 Mike Pall. All rights reserved. +-- Released under the MIT license. See Copyright Notice in luajit.h +---------------------------------------------------------------------------- +-- +-- This module lists the bytecode of a Lua function. If it's loaded by -jbc +-- it hooks into the parser and lists all functions of a chunk as they +-- are parsed. +-- +-- Example usage: +-- +-- luajit -jbc -e 'local x=0; for i=1,1e6 do x=x+i end; print(x)' +-- luajit -jbc=- foo.lua +-- luajit -jbc=foo.list foo.lua +-- +-- Default output is to stderr. To redirect the output to a file, pass a +-- filename as an argument (use '-' for stdout) or set the environment +-- variable LUAJIT_LISTFILE. The file is overwritten every time the module +-- is started. +-- +-- This module can also be used programmatically: +-- +-- local bc = require("jit.bc") +-- +-- local function foo() print("hello") end +-- +-- bc.dump(foo) --> -- BYTECODE -- [...] +-- print(bc.line(foo, 2)) --> 0002 KSTR 1 1 ; "hello" +-- +-- local out = { +-- -- Do something with each line: +-- write = function(t, ...) io.write(...) end, +-- close = function(t) end, +-- flush = function(t) end, +-- } +-- bc.dump(foo, out) +-- +------------------------------------------------------------------------------ + +-- Cache some library functions and objects. +local jit = require("jit") +assert(jit.version_num == 20004, "LuaJIT core/library version mismatch") +local jutil = require("jit.util") +local vmdef = require("jit.vmdef") +local bit = require("bit") +local sub, gsub, format = string.sub, string.gsub, string.format +local byte, band, shr = string.byte, bit.band, bit.rshift +local funcinfo, funcbc, funck = jutil.funcinfo, jutil.funcbc, jutil.funck +local funcuvname = jutil.funcuvname +local bcnames = vmdef.bcnames +local stdout, stderr = io.stdout, io.stderr + +------------------------------------------------------------------------------ + +local function ctlsub(c) + if c == "\n" then return "\\n" + elseif c == "\r" then return "\\r" + elseif c == "\t" then return "\\t" + else return format("\\%03d", byte(c)) + end +end + +-- Return one bytecode line. +local function bcline(func, pc, prefix) + local ins, m = funcbc(func, pc) + if not ins then return end + local ma, mb, mc = band(m, 7), band(m, 15*8), band(m, 15*128) + local a = band(shr(ins, 8), 0xff) + local oidx = 6*band(ins, 0xff) + local op = sub(bcnames, oidx+1, oidx+6) + local s = format("%04d %s %-6s %3s ", + pc, prefix or " ", op, ma == 0 and "" or a) + local d = shr(ins, 16) + if mc == 13*128 then -- BCMjump + return format("%s=> %04d\n", s, pc+d-0x7fff) + end + if mb ~= 0 then + d = band(d, 0xff) + elseif mc == 0 then + return s.."\n" + end + local kc + if mc == 10*128 then -- BCMstr + kc = funck(func, -d-1) + kc = format(#kc > 40 and '"%.40s"~' or '"%s"', gsub(kc, "%c", ctlsub)) + elseif mc == 9*128 then -- BCMnum + kc = funck(func, d) + if op == "TSETM " then kc = kc - 2^52 end + elseif mc == 12*128 then -- BCMfunc + local fi = funcinfo(funck(func, -d-1)) + if fi.ffid then + kc = vmdef.ffnames[fi.ffid] + else + kc = fi.loc + end + elseif mc == 5*128 then -- BCMuv + kc = funcuvname(func, d) + end + if ma == 5 then -- BCMuv + local ka = funcuvname(func, a) + if kc then kc = ka.." ; "..kc else kc = ka end + end + if mb ~= 0 then + local b = shr(ins, 24) + if kc then return format("%s%3d %3d ; %s\n", s, b, d, kc) end + return format("%s%3d %3d\n", s, b, d) + end + if kc then return format("%s%3d ; %s\n", s, d, kc) end + if mc == 7*128 and d > 32767 then d = d - 65536 end -- BCMlits + return format("%s%3d\n", s, d) +end + +-- Collect branch targets of a function. +local function bctargets(func) + local target = {} + for pc=1,1000000000 do + local ins, m = funcbc(func, pc) + if not ins then break end + if band(m, 15*128) == 13*128 then target[pc+shr(ins, 16)-0x7fff] = true end + end + return target +end + +-- Dump bytecode instructions of a function. +local function bcdump(func, out, all) + if not out then out = stdout end + local fi = funcinfo(func) + if all and fi.children then + for n=-1,-1000000000,-1 do + local k = funck(func, n) + if not k then break end + if type(k) == "proto" then bcdump(k, out, true) end + end + end + out:write(format("-- BYTECODE -- %s-%d\n", fi.loc, fi.lastlinedefined)) + local target = bctargets(func) + for pc=1,1000000000 do + local s = bcline(func, pc, target[pc] and "=>") + if not s then break end + out:write(s) + end + out:write("\n") + out:flush() +end + +------------------------------------------------------------------------------ + +-- Active flag and output file handle. +local active, out + +-- List handler. +local function h_list(func) + return bcdump(func, out) +end + +-- Detach list handler. +local function bclistoff() + if active then + active = false + jit.attach(h_list) + if out and out ~= stdout and out ~= stderr then out:close() end + out = nil + end +end + +-- Open the output file and attach list handler. +local function bcliston(outfile) + if active then bclistoff() end + if not outfile then outfile = os.getenv("LUAJIT_LISTFILE") end + if outfile then + out = outfile == "-" and stdout or assert(io.open(outfile, "w")) + else + out = stderr + end + jit.attach(h_list, "bc") + active = true +end + +-- Public module functions. +module(...) + +line = bcline +dump = bcdump +targets = bctargets + +on = bcliston +off = bclistoff +start = bcliston -- For -j command line option. + diff --git a/LuaJIT-2.0.4/lua/jit/bcsave.lua b/LuaJIT-2.0.4/lua/jit/bcsave.lua new file mode 100644 index 000000000..0319b3d25 --- /dev/null +++ b/LuaJIT-2.0.4/lua/jit/bcsave.lua @@ -0,0 +1,659 @@ +---------------------------------------------------------------------------- +-- LuaJIT module to save/list bytecode. +-- +-- Copyright (C) 2005-2015 Mike Pall. All rights reserved. +-- Released under the MIT license. See Copyright Notice in luajit.h +---------------------------------------------------------------------------- +-- +-- This module saves or lists the bytecode for an input file. +-- It's run by the -b command line option. +-- +------------------------------------------------------------------------------ + +local jit = require("jit") +assert(jit.version_num == 20004, "LuaJIT core/library version mismatch") +local bit = require("bit") + +-- Symbol name prefix for LuaJIT bytecode. +local LJBC_PREFIX = "luaJIT_BC_" + +------------------------------------------------------------------------------ + +local function usage() + io.stderr:write[[ +Save LuaJIT bytecode: luajit -b[options] input output + -l Only list bytecode. + -s Strip debug info (default). + -g Keep debug info. + -n name Set module name (default: auto-detect from input name). + -t type Set output file type (default: auto-detect from output name). + -a arch Override architecture for object files (default: native). + -o os Override OS for object files (default: native). + -e chunk Use chunk string as input. + -- Stop handling options. + - Use stdin as input and/or stdout as output. + +File types: c h obj o raw (default) +]] + os.exit(1) +end + +local function check(ok, ...) + if ok then return ok, ... end + io.stderr:write("luajit: ", ...) + io.stderr:write("\n") + os.exit(1) +end + +local function readfile(input) + if type(input) == "function" then return input end + if input == "-" then input = nil end + return check(loadfile(input)) +end + +local function savefile(name, mode) + if name == "-" then return io.stdout end + return check(io.open(name, mode)) +end + +------------------------------------------------------------------------------ + +local map_type = { + raw = "raw", c = "c", h = "h", o = "obj", obj = "obj", +} + +local map_arch = { + x86 = true, x64 = true, arm = true, ppc = true, ppcspe = true, + mips = true, mipsel = true, +} + +local map_os = { + linux = true, windows = true, osx = true, freebsd = true, netbsd = true, + openbsd = true, dragonfly = true, solaris = true, +} + +local function checkarg(str, map, err) + str = string.lower(str) + local s = check(map[str], "unknown ", err) + return s == true and str or s +end + +local function detecttype(str) + local ext = string.match(string.lower(str), "%.(%a+)$") + return map_type[ext] or "raw" +end + +local function checkmodname(str) + check(string.match(str, "^[%w_.%-]+$"), "bad module name") + return string.gsub(str, "[%.%-]", "_") +end + +local function detectmodname(str) + if type(str) == "string" then + local tail = string.match(str, "[^/\\]+$") + if tail then str = tail end + local head = string.match(str, "^(.*)%.[^.]*$") + if head then str = head end + str = string.match(str, "^[%w_.%-]+") + else + str = nil + end + check(str, "cannot derive module name, use -n name") + return string.gsub(str, "[%.%-]", "_") +end + +------------------------------------------------------------------------------ + +local function bcsave_tail(fp, output, s) + local ok, err = fp:write(s) + if ok and output ~= "-" then ok, err = fp:close() end + check(ok, "cannot write ", output, ": ", err) +end + +local function bcsave_raw(output, s) + local fp = savefile(output, "wb") + bcsave_tail(fp, output, s) +end + +local function bcsave_c(ctx, output, s) + local fp = savefile(output, "w") + if ctx.type == "c" then + fp:write(string.format([[ +#ifdef _cplusplus +extern "C" +#endif +#ifdef _WIN32 +__declspec(dllexport) +#endif +const char %s%s[] = { +]], LJBC_PREFIX, ctx.modname)) + else + fp:write(string.format([[ +#define %s%s_SIZE %d +static const char %s%s[] = { +]], LJBC_PREFIX, ctx.modname, #s, LJBC_PREFIX, ctx.modname)) + end + local t, n, m = {}, 0, 0 + for i=1,#s do + local b = tostring(string.byte(s, i)) + m = m + #b + 1 + if m > 78 then + fp:write(table.concat(t, ",", 1, n), ",\n") + n, m = 0, #b + 1 + end + n = n + 1 + t[n] = b + end + bcsave_tail(fp, output, table.concat(t, ",", 1, n).."\n};\n") +end + +local function bcsave_elfobj(ctx, output, s, ffi) + ffi.cdef[[ +typedef struct { + uint8_t emagic[4], eclass, eendian, eversion, eosabi, eabiversion, epad[7]; + uint16_t type, machine; + uint32_t version; + uint32_t entry, phofs, shofs; + uint32_t flags; + uint16_t ehsize, phentsize, phnum, shentsize, shnum, shstridx; +} ELF32header; +typedef struct { + uint8_t emagic[4], eclass, eendian, eversion, eosabi, eabiversion, epad[7]; + uint16_t type, machine; + uint32_t version; + uint64_t entry, phofs, shofs; + uint32_t flags; + uint16_t ehsize, phentsize, phnum, shentsize, shnum, shstridx; +} ELF64header; +typedef struct { + uint32_t name, type, flags, addr, ofs, size, link, info, align, entsize; +} ELF32sectheader; +typedef struct { + uint32_t name, type; + uint64_t flags, addr, ofs, size; + uint32_t link, info; + uint64_t align, entsize; +} ELF64sectheader; +typedef struct { + uint32_t name, value, size; + uint8_t info, other; + uint16_t sectidx; +} ELF32symbol; +typedef struct { + uint32_t name; + uint8_t info, other; + uint16_t sectidx; + uint64_t value, size; +} ELF64symbol; +typedef struct { + ELF32header hdr; + ELF32sectheader sect[6]; + ELF32symbol sym[2]; + uint8_t space[4096]; +} ELF32obj; +typedef struct { + ELF64header hdr; + ELF64sectheader sect[6]; + ELF64symbol sym[2]; + uint8_t space[4096]; +} ELF64obj; +]] + local symname = LJBC_PREFIX..ctx.modname + local is64, isbe = false, false + if ctx.arch == "x64" then + is64 = true + elseif ctx.arch == "ppc" or ctx.arch == "ppcspe" or ctx.arch == "mips" then + isbe = true + end + + -- Handle different host/target endianess. + local function f32(x) return x end + local f16, fofs = f32, f32 + if ffi.abi("be") ~= isbe then + f32 = bit.bswap + function f16(x) return bit.rshift(bit.bswap(x), 16) end + if is64 then + local two32 = ffi.cast("int64_t", 2^32) + function fofs(x) return bit.bswap(x)*two32 end + else + fofs = f32 + end + end + + -- Create ELF object and fill in header. + local o = ffi.new(is64 and "ELF64obj" or "ELF32obj") + local hdr = o.hdr + if ctx.os == "bsd" or ctx.os == "other" then -- Determine native hdr.eosabi. + local bf = assert(io.open("/bin/ls", "rb")) + local bs = bf:read(9) + bf:close() + ffi.copy(o, bs, 9) + check(hdr.emagic[0] == 127, "no support for writing native object files") + else + hdr.emagic = "\127ELF" + hdr.eosabi = ({ freebsd=9, netbsd=2, openbsd=12, solaris=6 })[ctx.os] or 0 + end + hdr.eclass = is64 and 2 or 1 + hdr.eendian = isbe and 2 or 1 + hdr.eversion = 1 + hdr.type = f16(1) + hdr.machine = f16(({ x86=3, x64=62, arm=40, ppc=20, ppcspe=20, mips=8, mipsel=8 })[ctx.arch]) + if ctx.arch == "mips" or ctx.arch == "mipsel" then + hdr.flags = 0x50001006 + end + hdr.version = f32(1) + hdr.shofs = fofs(ffi.offsetof(o, "sect")) + hdr.ehsize = f16(ffi.sizeof(hdr)) + hdr.shentsize = f16(ffi.sizeof(o.sect[0])) + hdr.shnum = f16(6) + hdr.shstridx = f16(2) + + -- Fill in sections and symbols. + local sofs, ofs = ffi.offsetof(o, "space"), 1 + for i,name in ipairs{ + ".symtab", ".shstrtab", ".strtab", ".rodata", ".note.GNU-stack", + } do + local sect = o.sect[i] + sect.align = fofs(1) + sect.name = f32(ofs) + ffi.copy(o.space+ofs, name) + ofs = ofs + #name+1 + end + o.sect[1].type = f32(2) -- .symtab + o.sect[1].link = f32(3) + o.sect[1].info = f32(1) + o.sect[1].align = fofs(8) + o.sect[1].ofs = fofs(ffi.offsetof(o, "sym")) + o.sect[1].entsize = fofs(ffi.sizeof(o.sym[0])) + o.sect[1].size = fofs(ffi.sizeof(o.sym)) + o.sym[1].name = f32(1) + o.sym[1].sectidx = f16(4) + o.sym[1].size = fofs(#s) + o.sym[1].info = 17 + o.sect[2].type = f32(3) -- .shstrtab + o.sect[2].ofs = fofs(sofs) + o.sect[2].size = fofs(ofs) + o.sect[3].type = f32(3) -- .strtab + o.sect[3].ofs = fofs(sofs + ofs) + o.sect[3].size = fofs(#symname+1) + ffi.copy(o.space+ofs+1, symname) + ofs = ofs + #symname + 2 + o.sect[4].type = f32(1) -- .rodata + o.sect[4].flags = fofs(2) + o.sect[4].ofs = fofs(sofs + ofs) + o.sect[4].size = fofs(#s) + o.sect[5].type = f32(1) -- .note.GNU-stack + o.sect[5].ofs = fofs(sofs + ofs + #s) + + -- Write ELF object file. + local fp = savefile(output, "wb") + fp:write(ffi.string(o, ffi.sizeof(o)-4096+ofs)) + bcsave_tail(fp, output, s) +end + +local function bcsave_peobj(ctx, output, s, ffi) + ffi.cdef[[ +typedef struct { + uint16_t arch, nsects; + uint32_t time, symtabofs, nsyms; + uint16_t opthdrsz, flags; +} PEheader; +typedef struct { + char name[8]; + uint32_t vsize, vaddr, size, ofs, relocofs, lineofs; + uint16_t nreloc, nline; + uint32_t flags; +} PEsection; +typedef struct __attribute((packed)) { + union { + char name[8]; + uint32_t nameref[2]; + }; + uint32_t value; + int16_t sect; + uint16_t type; + uint8_t scl, naux; +} PEsym; +typedef struct __attribute((packed)) { + uint32_t size; + uint16_t nreloc, nline; + uint32_t cksum; + uint16_t assoc; + uint8_t comdatsel, unused[3]; +} PEsymaux; +typedef struct { + PEheader hdr; + PEsection sect[2]; + // Must be an even number of symbol structs. + PEsym sym0; + PEsymaux sym0aux; + PEsym sym1; + PEsymaux sym1aux; + PEsym sym2; + PEsym sym3; + uint32_t strtabsize; + uint8_t space[4096]; +} PEobj; +]] + local symname = LJBC_PREFIX..ctx.modname + local is64 = false + if ctx.arch == "x86" then + symname = "_"..symname + elseif ctx.arch == "x64" then + is64 = true + end + local symexport = " /EXPORT:"..symname..",DATA " + + -- The file format is always little-endian. Swap if the host is big-endian. + local function f32(x) return x end + local f16 = f32 + if ffi.abi("be") then + f32 = bit.bswap + function f16(x) return bit.rshift(bit.bswap(x), 16) end + end + + -- Create PE object and fill in header. + local o = ffi.new("PEobj") + local hdr = o.hdr + hdr.arch = f16(({ x86=0x14c, x64=0x8664, arm=0x1c0, ppc=0x1f2, mips=0x366, mipsel=0x366 })[ctx.arch]) + hdr.nsects = f16(2) + hdr.symtabofs = f32(ffi.offsetof(o, "sym0")) + hdr.nsyms = f32(6) + + -- Fill in sections and symbols. + o.sect[0].name = ".drectve" + o.sect[0].size = f32(#symexport) + o.sect[0].flags = f32(0x00100a00) + o.sym0.sect = f16(1) + o.sym0.scl = 3 + o.sym0.name = ".drectve" + o.sym0.naux = 1 + o.sym0aux.size = f32(#symexport) + o.sect[1].name = ".rdata" + o.sect[1].size = f32(#s) + o.sect[1].flags = f32(0x40300040) + o.sym1.sect = f16(2) + o.sym1.scl = 3 + o.sym1.name = ".rdata" + o.sym1.naux = 1 + o.sym1aux.size = f32(#s) + o.sym2.sect = f16(2) + o.sym2.scl = 2 + o.sym2.nameref[1] = f32(4) + o.sym3.sect = f16(-1) + o.sym3.scl = 2 + o.sym3.value = f32(1) + o.sym3.name = "@feat.00" -- Mark as SafeSEH compliant. + ffi.copy(o.space, symname) + local ofs = #symname + 1 + o.strtabsize = f32(ofs + 4) + o.sect[0].ofs = f32(ffi.offsetof(o, "space") + ofs) + ffi.copy(o.space + ofs, symexport) + ofs = ofs + #symexport + o.sect[1].ofs = f32(ffi.offsetof(o, "space") + ofs) + + -- Write PE object file. + local fp = savefile(output, "wb") + fp:write(ffi.string(o, ffi.sizeof(o)-4096+ofs)) + bcsave_tail(fp, output, s) +end + +local function bcsave_machobj(ctx, output, s, ffi) + ffi.cdef[[ +typedef struct +{ + uint32_t magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags; +} mach_header; +typedef struct +{ + mach_header; uint32_t reserved; +} mach_header_64; +typedef struct { + uint32_t cmd, cmdsize; + char segname[16]; + uint32_t vmaddr, vmsize, fileoff, filesize; + uint32_t maxprot, initprot, nsects, flags; +} mach_segment_command; +typedef struct { + uint32_t cmd, cmdsize; + char segname[16]; + uint64_t vmaddr, vmsize, fileoff, filesize; + uint32_t maxprot, initprot, nsects, flags; +} mach_segment_command_64; +typedef struct { + char sectname[16], segname[16]; + uint32_t addr, size; + uint32_t offset, align, reloff, nreloc, flags; + uint32_t reserved1, reserved2; +} mach_section; +typedef struct { + char sectname[16], segname[16]; + uint64_t addr, size; + uint32_t offset, align, reloff, nreloc, flags; + uint32_t reserved1, reserved2, reserved3; +} mach_section_64; +typedef struct { + uint32_t cmd, cmdsize, symoff, nsyms, stroff, strsize; +} mach_symtab_command; +typedef struct { + int32_t strx; + uint8_t type, sect; + int16_t desc; + uint32_t value; +} mach_nlist; +typedef struct { + uint32_t strx; + uint8_t type, sect; + uint16_t desc; + uint64_t value; +} mach_nlist_64; +typedef struct +{ + uint32_t magic, nfat_arch; +} mach_fat_header; +typedef struct +{ + uint32_t cputype, cpusubtype, offset, size, align; +} mach_fat_arch; +typedef struct { + struct { + mach_header hdr; + mach_segment_command seg; + mach_section sec; + mach_symtab_command sym; + } arch[1]; + mach_nlist sym_entry; + uint8_t space[4096]; +} mach_obj; +typedef struct { + struct { + mach_header_64 hdr; + mach_segment_command_64 seg; + mach_section_64 sec; + mach_symtab_command sym; + } arch[1]; + mach_nlist_64 sym_entry; + uint8_t space[4096]; +} mach_obj_64; +typedef struct { + mach_fat_header fat; + mach_fat_arch fat_arch[4]; + struct { + mach_header hdr; + mach_segment_command seg; + mach_section sec; + mach_symtab_command sym; + } arch[4]; + mach_nlist sym_entry; + uint8_t space[4096]; +} mach_fat_obj; +]] + local symname = '_'..LJBC_PREFIX..ctx.modname + local isfat, is64, align, mobj = false, false, 4, "mach_obj" + if ctx.arch == "x64" then + is64, align, mobj = true, 8, "mach_obj_64" + elseif ctx.arch == "arm" then + isfat, mobj = true, "mach_fat_obj" + else + check(ctx.arch == "x86", "unsupported architecture for OSX") + end + local function aligned(v, a) return bit.band(v+a-1, -a) end + local be32 = bit.bswap -- Mach-O FAT is BE, supported archs are LE. + + -- Create Mach-O object and fill in header. + local o = ffi.new(mobj) + local mach_size = aligned(ffi.offsetof(o, "space")+#symname+2, align) + local cputype = ({ x86={7}, x64={0x01000007}, arm={7,12,12,12} })[ctx.arch] + local cpusubtype = ({ x86={3}, x64={3}, arm={3,6,9,11} })[ctx.arch] + if isfat then + o.fat.magic = be32(0xcafebabe) + o.fat.nfat_arch = be32(#cpusubtype) + end + + -- Fill in sections and symbols. + for i=0,#cpusubtype-1 do + local ofs = 0 + if isfat then + local a = o.fat_arch[i] + a.cputype = be32(cputype[i+1]) + a.cpusubtype = be32(cpusubtype[i+1]) + -- Subsequent slices overlap each other to share data. + ofs = ffi.offsetof(o, "arch") + i*ffi.sizeof(o.arch[0]) + a.offset = be32(ofs) + a.size = be32(mach_size-ofs+#s) + end + local a = o.arch[i] + a.hdr.magic = is64 and 0xfeedfacf or 0xfeedface + a.hdr.cputype = cputype[i+1] + a.hdr.cpusubtype = cpusubtype[i+1] + a.hdr.filetype = 1 + a.hdr.ncmds = 2 + a.hdr.sizeofcmds = ffi.sizeof(a.seg)+ffi.sizeof(a.sec)+ffi.sizeof(a.sym) + a.seg.cmd = is64 and 0x19 or 0x1 + a.seg.cmdsize = ffi.sizeof(a.seg)+ffi.sizeof(a.sec) + a.seg.vmsize = #s + a.seg.fileoff = mach_size-ofs + a.seg.filesize = #s + a.seg.maxprot = 1 + a.seg.initprot = 1 + a.seg.nsects = 1 + ffi.copy(a.sec.sectname, "__data") + ffi.copy(a.sec.segname, "__DATA") + a.sec.size = #s + a.sec.offset = mach_size-ofs + a.sym.cmd = 2 + a.sym.cmdsize = ffi.sizeof(a.sym) + a.sym.symoff = ffi.offsetof(o, "sym_entry")-ofs + a.sym.nsyms = 1 + a.sym.stroff = ffi.offsetof(o, "sym_entry")+ffi.sizeof(o.sym_entry)-ofs + a.sym.strsize = aligned(#symname+2, align) + end + o.sym_entry.type = 0xf + o.sym_entry.sect = 1 + o.sym_entry.strx = 1 + ffi.copy(o.space+1, symname) + + -- Write Macho-O object file. + local fp = savefile(output, "wb") + fp:write(ffi.string(o, mach_size)) + bcsave_tail(fp, output, s) +end + +local function bcsave_obj(ctx, output, s) + local ok, ffi = pcall(require, "ffi") + check(ok, "FFI library required to write this file type") + if ctx.os == "windows" then + return bcsave_peobj(ctx, output, s, ffi) + elseif ctx.os == "osx" then + return bcsave_machobj(ctx, output, s, ffi) + else + return bcsave_elfobj(ctx, output, s, ffi) + end +end + +------------------------------------------------------------------------------ + +local function bclist(input, output) + local f = readfile(input) + require("jit.bc").dump(f, savefile(output, "w"), true) +end + +local function bcsave(ctx, input, output) + local f = readfile(input) + local s = string.dump(f, ctx.strip) + local t = ctx.type + if not t then + t = detecttype(output) + ctx.type = t + end + if t == "raw" then + bcsave_raw(output, s) + else + if not ctx.modname then ctx.modname = detectmodname(input) end + if t == "obj" then + bcsave_obj(ctx, output, s) + else + bcsave_c(ctx, output, s) + end + end +end + +local function docmd(...) + local arg = {...} + local n = 1 + local list = false + local ctx = { + strip = true, arch = jit.arch, os = string.lower(jit.os), + type = false, modname = false, + } + while n <= #arg do + local a = arg[n] + if type(a) == "string" and string.sub(a, 1, 1) == "-" and a ~= "-" then + table.remove(arg, n) + if a == "--" then break end + for m=2,#a do + local opt = string.sub(a, m, m) + if opt == "l" then + list = true + elseif opt == "s" then + ctx.strip = true + elseif opt == "g" then + ctx.strip = false + else + if arg[n] == nil or m ~= #a then usage() end + if opt == "e" then + if n ~= 1 then usage() end + arg[1] = check(loadstring(arg[1])) + elseif opt == "n" then + ctx.modname = checkmodname(table.remove(arg, n)) + elseif opt == "t" then + ctx.type = checkarg(table.remove(arg, n), map_type, "file type") + elseif opt == "a" then + ctx.arch = checkarg(table.remove(arg, n), map_arch, "architecture") + elseif opt == "o" then + ctx.os = checkarg(table.remove(arg, n), map_os, "OS name") + else + usage() + end + end + end + else + n = n + 1 + end + end + if list then + if #arg == 0 or #arg > 2 then usage() end + bclist(arg[1], arg[2] or "-") + else + if #arg ~= 2 then usage() end + bcsave(ctx, arg[1], arg[2]) + end +end + +------------------------------------------------------------------------------ + +-- Public module functions. +module(...) + +start = docmd -- Process -b command line option. + diff --git a/LuaJIT-2.0.4/lua/jit/dis_arm.lua b/LuaJIT-2.0.4/lua/jit/dis_arm.lua new file mode 100644 index 000000000..59be715a9 --- /dev/null +++ b/LuaJIT-2.0.4/lua/jit/dis_arm.lua @@ -0,0 +1,689 @@ +---------------------------------------------------------------------------- +-- LuaJIT ARM disassembler module. +-- +-- Copyright (C) 2005-2015 Mike Pall. All rights reserved. +-- Released under the MIT license. See Copyright Notice in luajit.h +---------------------------------------------------------------------------- +-- This is a helper module used by the LuaJIT machine code dumper module. +-- +-- It disassembles most user-mode ARMv7 instructions +-- NYI: Advanced SIMD and VFP instructions. +------------------------------------------------------------------------------ + +local type = type +local sub, byte, format = string.sub, string.byte, string.format +local match, gmatch, gsub = string.match, string.gmatch, string.gsub +local concat = table.concat +local bit = require("bit") +local band, bor, ror, tohex = bit.band, bit.bor, bit.ror, bit.tohex +local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift + +------------------------------------------------------------------------------ +-- Opcode maps +------------------------------------------------------------------------------ + +local map_loadc = { + shift = 8, mask = 15, + [10] = { + shift = 20, mask = 1, + [0] = { + shift = 23, mask = 3, + [0] = "vmovFmDN", "vstmFNdr", + _ = { + shift = 21, mask = 1, + [0] = "vstrFdl", + { shift = 16, mask = 15, [13] = "vpushFdr", _ = "vstmdbFNdr", } + }, + }, + { + shift = 23, mask = 3, + [0] = "vmovFDNm", + { shift = 16, mask = 15, [13] = "vpopFdr", _ = "vldmFNdr", }, + _ = { + shift = 21, mask = 1, + [0] = "vldrFdl", "vldmdbFNdr", + }, + }, + }, + [11] = { + shift = 20, mask = 1, + [0] = { + shift = 23, mask = 3, + [0] = "vmovGmDN", "vstmGNdr", + _ = { + shift = 21, mask = 1, + [0] = "vstrGdl", + { shift = 16, mask = 15, [13] = "vpushGdr", _ = "vstmdbGNdr", } + }, + }, + { + shift = 23, mask = 3, + [0] = "vmovGDNm", + { shift = 16, mask = 15, [13] = "vpopGdr", _ = "vldmGNdr", }, + _ = { + shift = 21, mask = 1, + [0] = "vldrGdl", "vldmdbGNdr", + }, + }, + }, + _ = { + shift = 0, mask = 0 -- NYI ldc, mcrr, mrrc. + }, +} + +local map_vfps = { + shift = 6, mask = 0x2c001, + [0] = "vmlaF.dnm", "vmlsF.dnm", + [0x04000] = "vnmlsF.dnm", [0x04001] = "vnmlaF.dnm", + [0x08000] = "vmulF.dnm", [0x08001] = "vnmulF.dnm", + [0x0c000] = "vaddF.dnm", [0x0c001] = "vsubF.dnm", + [0x20000] = "vdivF.dnm", + [0x24000] = "vfnmsF.dnm", [0x24001] = "vfnmaF.dnm", + [0x28000] = "vfmaF.dnm", [0x28001] = "vfmsF.dnm", + [0x2c000] = "vmovF.dY", + [0x2c001] = { + shift = 7, mask = 0x1e01, + [0] = "vmovF.dm", "vabsF.dm", + [0x0200] = "vnegF.dm", [0x0201] = "vsqrtF.dm", + [0x0800] = "vcmpF.dm", [0x0801] = "vcmpeF.dm", + [0x0a00] = "vcmpzF.d", [0x0a01] = "vcmpzeF.d", + [0x0e01] = "vcvtG.dF.m", + [0x1000] = "vcvt.f32.u32Fdm", [0x1001] = "vcvt.f32.s32Fdm", + [0x1800] = "vcvtr.u32F.dm", [0x1801] = "vcvt.u32F.dm", + [0x1a00] = "vcvtr.s32F.dm", [0x1a01] = "vcvt.s32F.dm", + }, +} + +local map_vfpd = { + shift = 6, mask = 0x2c001, + [0] = "vmlaG.dnm", "vmlsG.dnm", + [0x04000] = "vnmlsG.dnm", [0x04001] = "vnmlaG.dnm", + [0x08000] = "vmulG.dnm", [0x08001] = "vnmulG.dnm", + [0x0c000] = "vaddG.dnm", [0x0c001] = "vsubG.dnm", + [0x20000] = "vdivG.dnm", + [0x24000] = "vfnmsG.dnm", [0x24001] = "vfnmaG.dnm", + [0x28000] = "vfmaG.dnm", [0x28001] = "vfmsG.dnm", + [0x2c000] = "vmovG.dY", + [0x2c001] = { + shift = 7, mask = 0x1e01, + [0] = "vmovG.dm", "vabsG.dm", + [0x0200] = "vnegG.dm", [0x0201] = "vsqrtG.dm", + [0x0800] = "vcmpG.dm", [0x0801] = "vcmpeG.dm", + [0x0a00] = "vcmpzG.d", [0x0a01] = "vcmpzeG.d", + [0x0e01] = "vcvtF.dG.m", + [0x1000] = "vcvt.f64.u32GdFm", [0x1001] = "vcvt.f64.s32GdFm", + [0x1800] = "vcvtr.u32FdG.m", [0x1801] = "vcvt.u32FdG.m", + [0x1a00] = "vcvtr.s32FdG.m", [0x1a01] = "vcvt.s32FdG.m", + }, +} + +local map_datac = { + shift = 24, mask = 1, + [0] = { + shift = 4, mask = 1, + [0] = { + shift = 8, mask = 15, + [10] = map_vfps, + [11] = map_vfpd, + -- NYI cdp, mcr, mrc. + }, + { + shift = 8, mask = 15, + [10] = { + shift = 20, mask = 15, + [0] = "vmovFnD", "vmovFDn", + [14] = "vmsrD", + [15] = { shift = 12, mask = 15, [15] = "vmrs", _ = "vmrsD", }, + }, + }, + }, + "svcT", +} + +local map_loadcu = { + shift = 0, mask = 0, -- NYI unconditional CP load/store. +} + +local map_datacu = { + shift = 0, mask = 0, -- NYI unconditional CP data. +} + +local map_simddata = { + shift = 0, mask = 0, -- NYI SIMD data. +} + +local map_simdload = { + shift = 0, mask = 0, -- NYI SIMD load/store, preload. +} + +local map_preload = { + shift = 0, mask = 0, -- NYI preload. +} + +local map_media = { + shift = 20, mask = 31, + [0] = false, + { --01 + shift = 5, mask = 7, + [0] = "sadd16DNM", "sasxDNM", "ssaxDNM", "ssub16DNM", + "sadd8DNM", false, false, "ssub8DNM", + }, + { --02 + shift = 5, mask = 7, + [0] = "qadd16DNM", "qasxDNM", "qsaxDNM", "qsub16DNM", + "qadd8DNM", false, false, "qsub8DNM", + }, + { --03 + shift = 5, mask = 7, + [0] = "shadd16DNM", "shasxDNM", "shsaxDNM", "shsub16DNM", + "shadd8DNM", false, false, "shsub8DNM", + }, + false, + { --05 + shift = 5, mask = 7, + [0] = "uadd16DNM", "uasxDNM", "usaxDNM", "usub16DNM", + "uadd8DNM", false, false, "usub8DNM", + }, + { --06 + shift = 5, mask = 7, + [0] = "uqadd16DNM", "uqasxDNM", "uqsaxDNM", "uqsub16DNM", + "uqadd8DNM", false, false, "uqsub8DNM", + }, + { --07 + shift = 5, mask = 7, + [0] = "uhadd16DNM", "uhasxDNM", "uhsaxDNM", "uhsub16DNM", + "uhadd8DNM", false, false, "uhsub8DNM", + }, + { --08 + shift = 5, mask = 7, + [0] = "pkhbtDNMU", false, "pkhtbDNMU", + { shift = 16, mask = 15, [15] = "sxtb16DMU", _ = "sxtab16DNMU", }, + "pkhbtDNMU", "selDNM", "pkhtbDNMU", + }, + false, + { --0a + shift = 5, mask = 7, + [0] = "ssatDxMu", "ssat16DxM", "ssatDxMu", + { shift = 16, mask = 15, [15] = "sxtbDMU", _ = "sxtabDNMU", }, + "ssatDxMu", false, "ssatDxMu", + }, + { --0b + shift = 5, mask = 7, + [0] = "ssatDxMu", "revDM", "ssatDxMu", + { shift = 16, mask = 15, [15] = "sxthDMU", _ = "sxtahDNMU", }, + "ssatDxMu", "rev16DM", "ssatDxMu", + }, + { --0c + shift = 5, mask = 7, + [3] = { shift = 16, mask = 15, [15] = "uxtb16DMU", _ = "uxtab16DNMU", }, + }, + false, + { --0e + shift = 5, mask = 7, + [0] = "usatDwMu", "usat16DwM", "usatDwMu", + { shift = 16, mask = 15, [15] = "uxtbDMU", _ = "uxtabDNMU", }, + "usatDwMu", false, "usatDwMu", + }, + { --0f + shift = 5, mask = 7, + [0] = "usatDwMu", "rbitDM", "usatDwMu", + { shift = 16, mask = 15, [15] = "uxthDMU", _ = "uxtahDNMU", }, + "usatDwMu", "revshDM", "usatDwMu", + }, + { --10 + shift = 12, mask = 15, + [15] = { + shift = 5, mask = 7, + "smuadNMS", "smuadxNMS", "smusdNMS", "smusdxNMS", + }, + _ = { + shift = 5, mask = 7, + [0] = "smladNMSD", "smladxNMSD", "smlsdNMSD", "smlsdxNMSD", + }, + }, + false, false, false, + { --14 + shift = 5, mask = 7, + [0] = "smlaldDNMS", "smlaldxDNMS", "smlsldDNMS", "smlsldxDNMS", + }, + { --15 + shift = 5, mask = 7, + [0] = { shift = 12, mask = 15, [15] = "smmulNMS", _ = "smmlaNMSD", }, + { shift = 12, mask = 15, [15] = "smmulrNMS", _ = "smmlarNMSD", }, + false, false, false, false, + "smmlsNMSD", "smmlsrNMSD", + }, + false, false, + { --18 + shift = 5, mask = 7, + [0] = { shift = 12, mask = 15, [15] = "usad8NMS", _ = "usada8NMSD", }, + }, + false, + { --1a + shift = 5, mask = 3, [2] = "sbfxDMvw", + }, + { --1b + shift = 5, mask = 3, [2] = "sbfxDMvw", + }, + { --1c + shift = 5, mask = 3, + [0] = { shift = 0, mask = 15, [15] = "bfcDvX", _ = "bfiDMvX", }, + }, + { --1d + shift = 5, mask = 3, + [0] = { shift = 0, mask = 15, [15] = "bfcDvX", _ = "bfiDMvX", }, + }, + { --1e + shift = 5, mask = 3, [2] = "ubfxDMvw", + }, + { --1f + shift = 5, mask = 3, [2] = "ubfxDMvw", + }, +} + +local map_load = { + shift = 21, mask = 9, + { + shift = 20, mask = 5, + [0] = "strtDL", "ldrtDL", [4] = "strbtDL", [5] = "ldrbtDL", + }, + _ = { + shift = 20, mask = 5, + [0] = "strDL", "ldrDL", [4] = "strbDL", [5] = "ldrbDL", + } +} + +local map_load1 = { + shift = 4, mask = 1, + [0] = map_load, map_media, +} + +local map_loadm = { + shift = 20, mask = 1, + [0] = { + shift = 23, mask = 3, + [0] = "stmdaNR", "stmNR", + { shift = 16, mask = 63, [45] = "pushR", _ = "stmdbNR", }, "stmibNR", + }, + { + shift = 23, mask = 3, + [0] = "ldmdaNR", { shift = 16, mask = 63, [61] = "popR", _ = "ldmNR", }, + "ldmdbNR", "ldmibNR", + }, +} + +local map_data = { + shift = 21, mask = 15, + [0] = "andDNPs", "eorDNPs", "subDNPs", "rsbDNPs", + "addDNPs", "adcDNPs", "sbcDNPs", "rscDNPs", + "tstNP", "teqNP", "cmpNP", "cmnNP", + "orrDNPs", "movDPs", "bicDNPs", "mvnDPs", +} + +local map_mul = { + shift = 21, mask = 7, + [0] = "mulNMSs", "mlaNMSDs", "umaalDNMS", "mlsDNMS", + "umullDNMSs", "umlalDNMSs", "smullDNMSs", "smlalDNMSs", +} + +local map_sync = { + shift = 20, mask = 15, -- NYI: brackets around N. R(D+1) for ldrexd/strexd. + [0] = "swpDMN", false, false, false, + "swpbDMN", false, false, false, + "strexDMN", "ldrexDN", "strexdDN", "ldrexdDN", + "strexbDMN", "ldrexbDN", "strexhDN", "ldrexhDN", +} + +local map_mulh = { + shift = 21, mask = 3, + [0] = { shift = 5, mask = 3, + [0] = "smlabbNMSD", "smlatbNMSD", "smlabtNMSD", "smlattNMSD", }, + { shift = 5, mask = 3, + [0] = "smlawbNMSD", "smulwbNMS", "smlawtNMSD", "smulwtNMS", }, + { shift = 5, mask = 3, + [0] = "smlalbbDNMS", "smlaltbDNMS", "smlalbtDNMS", "smlalttDNMS", }, + { shift = 5, mask = 3, + [0] = "smulbbNMS", "smultbNMS", "smulbtNMS", "smulttNMS", }, +} + +local map_misc = { + shift = 4, mask = 7, + -- NYI: decode PSR bits of msr. + [0] = { shift = 21, mask = 1, [0] = "mrsD", "msrM", }, + { shift = 21, mask = 3, "bxM", false, "clzDM", }, + { shift = 21, mask = 3, "bxjM", }, + { shift = 21, mask = 3, "blxM", }, + false, + { shift = 21, mask = 3, [0] = "qaddDMN", "qsubDMN", "qdaddDMN", "qdsubDMN", }, + false, + { shift = 21, mask = 3, "bkptK", }, +} + +local map_datar = { + shift = 4, mask = 9, + [9] = { + shift = 5, mask = 3, + [0] = { shift = 24, mask = 1, [0] = map_mul, map_sync, }, + { shift = 20, mask = 1, [0] = "strhDL", "ldrhDL", }, + { shift = 20, mask = 1, [0] = "ldrdDL", "ldrsbDL", }, + { shift = 20, mask = 1, [0] = "strdDL", "ldrshDL", }, + }, + _ = { + shift = 20, mask = 25, + [16] = { shift = 7, mask = 1, [0] = map_misc, map_mulh, }, + _ = { + shift = 0, mask = 0xffffffff, + [bor(0xe1a00000)] = "nop", + _ = map_data, + } + }, +} + +local map_datai = { + shift = 20, mask = 31, -- NYI: decode PSR bits of msr. Decode imm12. + [16] = "movwDW", [20] = "movtDW", + [18] = { shift = 0, mask = 0xf00ff, [0] = "nopv6", _ = "msrNW", }, + [22] = "msrNW", + _ = map_data, +} + +local map_branch = { + shift = 24, mask = 1, + [0] = "bB", "blB" +} + +local map_condins = { + [0] = map_datar, map_datai, map_load, map_load1, + map_loadm, map_branch, map_loadc, map_datac +} + +-- NYI: setend. +local map_uncondins = { + [0] = false, map_simddata, map_simdload, map_preload, + false, "blxB", map_loadcu, map_datacu, +} + +------------------------------------------------------------------------------ + +local map_gpr = { + [0] = "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc", +} + +local map_cond = { + [0] = "eq", "ne", "hs", "lo", "mi", "pl", "vs", "vc", + "hi", "ls", "ge", "lt", "gt", "le", "al", +} + +local map_shift = { [0] = "lsl", "lsr", "asr", "ror", } + +------------------------------------------------------------------------------ + +-- Output a nicely formatted line with an opcode and operands. +local function putop(ctx, text, operands) + local pos = ctx.pos + local extra = "" + if ctx.rel then + local sym = ctx.symtab[ctx.rel] + if sym then + extra = "\t->"..sym + elseif band(ctx.op, 0x0e000000) ~= 0x0a000000 then + extra = "\t; 0x"..tohex(ctx.rel) + end + end + if ctx.hexdump > 0 then + ctx.out(format("%08x %s %-5s %s%s\n", + ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra)) + else + ctx.out(format("%08x %-5s %s%s\n", + ctx.addr+pos, text, concat(operands, ", "), extra)) + end + ctx.pos = pos + 4 +end + +-- Fallback for unknown opcodes. +local function unknown(ctx) + return putop(ctx, ".long", { "0x"..tohex(ctx.op) }) +end + +-- Format operand 2 of load/store opcodes. +local function fmtload(ctx, op, pos) + local base = map_gpr[band(rshift(op, 16), 15)] + local x, ofs + local ext = (band(op, 0x04000000) == 0) + if not ext and band(op, 0x02000000) == 0 then + ofs = band(op, 4095) + if band(op, 0x00800000) == 0 then ofs = -ofs end + if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end + ofs = "#"..ofs + elseif ext and band(op, 0x00400000) ~= 0 then + ofs = band(op, 15) + band(rshift(op, 4), 0xf0) + if band(op, 0x00800000) == 0 then ofs = -ofs end + if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end + ofs = "#"..ofs + else + ofs = map_gpr[band(op, 15)] + if ext or band(op, 0xfe0) == 0 then + elseif band(op, 0xfe0) == 0x60 then + ofs = format("%s, rrx", ofs) + else + local sh = band(rshift(op, 7), 31) + if sh == 0 then sh = 32 end + ofs = format("%s, %s #%d", ofs, map_shift[band(rshift(op, 5), 3)], sh) + end + if band(op, 0x00800000) == 0 then ofs = "-"..ofs end + end + if ofs == "#0" then + x = format("[%s]", base) + elseif band(op, 0x01000000) == 0 then + x = format("[%s], %s", base, ofs) + else + x = format("[%s, %s]", base, ofs) + end + if band(op, 0x01200000) == 0x01200000 then x = x.."!" end + return x +end + +-- Format operand 2 of vector load/store opcodes. +local function fmtvload(ctx, op, pos) + local base = map_gpr[band(rshift(op, 16), 15)] + local ofs = band(op, 255)*4 + if band(op, 0x00800000) == 0 then ofs = -ofs end + if base == "pc" then ctx.rel = ctx.addr + pos + 8 + ofs end + if ofs == 0 then + return format("[%s]", base) + else + return format("[%s, #%d]", base, ofs) + end +end + +local function fmtvr(op, vr, sh0, sh1) + if vr == "s" then + return format("s%d", 2*band(rshift(op, sh0), 15)+band(rshift(op, sh1), 1)) + else + return format("d%d", band(rshift(op, sh0), 15)+band(rshift(op, sh1-4), 16)) + end +end + +-- Disassemble a single instruction. +local function disass_ins(ctx) + local pos = ctx.pos + local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4) + local op = bor(lshift(b3, 24), lshift(b2, 16), lshift(b1, 8), b0) + local operands = {} + local suffix = "" + local last, name, pat + local vr + ctx.op = op + ctx.rel = nil + + local cond = rshift(op, 28) + local opat + if cond == 15 then + opat = map_uncondins[band(rshift(op, 25), 7)] + else + if cond ~= 14 then suffix = map_cond[cond] end + opat = map_condins[band(rshift(op, 25), 7)] + end + while type(opat) ~= "string" do + if not opat then return unknown(ctx) end + opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._ + end + name, pat = match(opat, "^([a-z0-9]*)(.*)") + if sub(pat, 1, 1) == "." then + local s2, p2 = match(pat, "^([a-z0-9.]*)(.*)") + suffix = suffix..s2 + pat = p2 + end + + for p in gmatch(pat, ".") do + local x = nil + if p == "D" then + x = map_gpr[band(rshift(op, 12), 15)] + elseif p == "N" then + x = map_gpr[band(rshift(op, 16), 15)] + elseif p == "S" then + x = map_gpr[band(rshift(op, 8), 15)] + elseif p == "M" then + x = map_gpr[band(op, 15)] + elseif p == "d" then + x = fmtvr(op, vr, 12, 22) + elseif p == "n" then + x = fmtvr(op, vr, 16, 7) + elseif p == "m" then + x = fmtvr(op, vr, 0, 5) + elseif p == "P" then + if band(op, 0x02000000) ~= 0 then + x = ror(band(op, 255), 2*band(rshift(op, 8), 15)) + else + x = map_gpr[band(op, 15)] + if band(op, 0xff0) ~= 0 then + operands[#operands+1] = x + local s = map_shift[band(rshift(op, 5), 3)] + local r = nil + if band(op, 0xf90) == 0 then + if s == "ror" then s = "rrx" else r = "#32" end + elseif band(op, 0x10) == 0 then + r = "#"..band(rshift(op, 7), 31) + else + r = map_gpr[band(rshift(op, 8), 15)] + end + if name == "mov" then name = s; x = r + elseif r then x = format("%s %s", s, r) + else x = s end + end + end + elseif p == "L" then + x = fmtload(ctx, op, pos) + elseif p == "l" then + x = fmtvload(ctx, op, pos) + elseif p == "B" then + local addr = ctx.addr + pos + 8 + arshift(lshift(op, 8), 6) + if cond == 15 then addr = addr + band(rshift(op, 23), 2) end + ctx.rel = addr + x = "0x"..tohex(addr) + elseif p == "F" then + vr = "s" + elseif p == "G" then + vr = "d" + elseif p == "." then + suffix = suffix..(vr == "s" and ".f32" or ".f64") + elseif p == "R" then + if band(op, 0x00200000) ~= 0 and #operands == 1 then + operands[1] = operands[1].."!" + end + local t = {} + for i=0,15 do + if band(rshift(op, i), 1) == 1 then t[#t+1] = map_gpr[i] end + end + x = "{"..concat(t, ", ").."}" + elseif p == "r" then + if band(op, 0x00200000) ~= 0 and #operands == 2 then + operands[1] = operands[1].."!" + end + local s = tonumber(sub(last, 2)) + local n = band(op, 255) + if vr == "d" then n = rshift(n, 1) end + operands[#operands] = format("{%s-%s%d}", last, vr, s+n-1) + elseif p == "W" then + x = band(op, 0x0fff) + band(rshift(op, 4), 0xf000) + elseif p == "T" then + x = "#0x"..tohex(band(op, 0x00ffffff), 6) + elseif p == "U" then + x = band(rshift(op, 7), 31) + if x == 0 then x = nil end + elseif p == "u" then + x = band(rshift(op, 7), 31) + if band(op, 0x40) == 0 then + if x == 0 then x = nil else x = "lsl #"..x end + else + if x == 0 then x = "asr #32" else x = "asr #"..x end + end + elseif p == "v" then + x = band(rshift(op, 7), 31) + elseif p == "w" then + x = band(rshift(op, 16), 31) + elseif p == "x" then + x = band(rshift(op, 16), 31) + 1 + elseif p == "X" then + x = band(rshift(op, 16), 31) - last + 1 + elseif p == "Y" then + x = band(rshift(op, 12), 0xf0) + band(op, 0x0f) + elseif p == "K" then + x = "#0x"..tohex(band(rshift(op, 4), 0x0000fff0) + band(op, 15), 4) + elseif p == "s" then + if band(op, 0x00100000) ~= 0 then suffix = "s"..suffix end + else + assert(false) + end + if x then + last = x + if type(x) == "number" then x = "#"..x end + operands[#operands+1] = x + end + end + + return putop(ctx, name..suffix, operands) +end + +------------------------------------------------------------------------------ + +-- Disassemble a block of code. +local function disass_block(ctx, ofs, len) + if not ofs then ofs = 0 end + local stop = len and ofs+len or #ctx.code + ctx.pos = ofs + ctx.rel = nil + while ctx.pos < stop do disass_ins(ctx) end +end + +-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len). +local function create_(code, addr, out) + local ctx = {} + ctx.code = code + ctx.addr = addr or 0 + ctx.out = out or io.write + ctx.symtab = {} + ctx.disass = disass_block + ctx.hexdump = 8 + return ctx +end + +-- Simple API: disassemble code (a string) at address and output via out. +local function disass_(code, addr, out) + create_(code, addr, out):disass() +end + +-- Return register name for RID. +local function regname_(r) + if r < 16 then return map_gpr[r] end + return "d"..(r-16) +end + +-- Public module functions. +module(...) + +create = create_ +disass = disass_ +regname = regname_ + diff --git a/LuaJIT-2.0.4/lua/jit/dis_mips.lua b/LuaJIT-2.0.4/lua/jit/dis_mips.lua new file mode 100644 index 000000000..acdd2be16 --- /dev/null +++ b/LuaJIT-2.0.4/lua/jit/dis_mips.lua @@ -0,0 +1,428 @@ +---------------------------------------------------------------------------- +-- LuaJIT MIPS disassembler module. +-- +-- Copyright (C) 2005-2015 Mike Pall. All rights reserved. +-- Released under the MIT/X license. See Copyright Notice in luajit.h +---------------------------------------------------------------------------- +-- This is a helper module used by the LuaJIT machine code dumper module. +-- +-- It disassembles all standard MIPS32R1/R2 instructions. +-- Default mode is big-endian, but see: dis_mipsel.lua +------------------------------------------------------------------------------ + +local type = type +local sub, byte, format = string.sub, string.byte, string.format +local match, gmatch, gsub = string.match, string.gmatch, string.gsub +local concat = table.concat +local bit = require("bit") +local band, bor, tohex = bit.band, bit.bor, bit.tohex +local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift + +------------------------------------------------------------------------------ +-- Primary and extended opcode maps +------------------------------------------------------------------------------ + +local map_movci = { shift = 16, mask = 1, [0] = "movfDSC", "movtDSC", } +local map_srl = { shift = 21, mask = 1, [0] = "srlDTA", "rotrDTA", } +local map_srlv = { shift = 6, mask = 1, [0] = "srlvDTS", "rotrvDTS", } + +local map_special = { + shift = 0, mask = 63, + [0] = { shift = 0, mask = -1, [0] = "nop", _ = "sllDTA" }, + map_movci, map_srl, "sraDTA", + "sllvDTS", false, map_srlv, "sravDTS", + "jrS", "jalrD1S", "movzDST", "movnDST", + "syscallY", "breakY", false, "sync", + "mfhiD", "mthiS", "mfloD", "mtloS", + false, false, false, false, + "multST", "multuST", "divST", "divuST", + false, false, false, false, + "addDST", "addu|moveDST0", "subDST", "subu|neguDS0T", + "andDST", "orDST", "xorDST", "nor|notDST0", + false, false, "sltDST", "sltuDST", + false, false, false, false, + "tgeSTZ", "tgeuSTZ", "tltSTZ", "tltuSTZ", + "teqSTZ", false, "tneSTZ", +} + +local map_special2 = { + shift = 0, mask = 63, + [0] = "maddST", "madduST", "mulDST", false, + "msubST", "msubuST", + [32] = "clzDS", [33] = "cloDS", + [63] = "sdbbpY", +} + +local map_bshfl = { + shift = 6, mask = 31, + [2] = "wsbhDT", + [16] = "sebDT", + [24] = "sehDT", +} + +local map_special3 = { + shift = 0, mask = 63, + [0] = "extTSAK", [4] = "insTSAL", + [32] = map_bshfl, + [59] = "rdhwrTD", +} + +local map_regimm = { + shift = 16, mask = 31, + [0] = "bltzSB", "bgezSB", "bltzlSB", "bgezlSB", + false, false, false, false, + "tgeiSI", "tgeiuSI", "tltiSI", "tltiuSI", + "teqiSI", false, "tneiSI", false, + "bltzalSB", "bgezalSB", "bltzallSB", "bgezallSB", + false, false, false, false, + false, false, false, false, + false, false, false, "synciSO", +} + +local map_cop0 = { + shift = 25, mask = 1, + [0] = { + shift = 21, mask = 15, + [0] = "mfc0TDW", [4] = "mtc0TDW", + [10] = "rdpgprDT", + [11] = { shift = 5, mask = 1, [0] = "diT0", "eiT0", }, + [14] = "wrpgprDT", + }, { + shift = 0, mask = 63, + [1] = "tlbr", [2] = "tlbwi", [6] = "tlbwr", [8] = "tlbp", + [24] = "eret", [31] = "deret", + [32] = "wait", + }, +} + +local map_cop1s = { + shift = 0, mask = 63, + [0] = "add.sFGH", "sub.sFGH", "mul.sFGH", "div.sFGH", + "sqrt.sFG", "abs.sFG", "mov.sFG", "neg.sFG", + "round.l.sFG", "trunc.l.sFG", "ceil.l.sFG", "floor.l.sFG", + "round.w.sFG", "trunc.w.sFG", "ceil.w.sFG", "floor.w.sFG", + false, + { shift = 16, mask = 1, [0] = "movf.sFGC", "movt.sFGC" }, + "movz.sFGT", "movn.sFGT", + false, "recip.sFG", "rsqrt.sFG", false, + false, false, false, false, + false, false, false, false, + false, "cvt.d.sFG", false, false, + "cvt.w.sFG", "cvt.l.sFG", "cvt.ps.sFGH", false, + false, false, false, false, + false, false, false, false, + "c.f.sVGH", "c.un.sVGH", "c.eq.sVGH", "c.ueq.sVGH", + "c.olt.sVGH", "c.ult.sVGH", "c.ole.sVGH", "c.ule.sVGH", + "c.sf.sVGH", "c.ngle.sVGH", "c.seq.sVGH", "c.ngl.sVGH", + "c.lt.sVGH", "c.nge.sVGH", "c.le.sVGH", "c.ngt.sVGH", +} + +local map_cop1d = { + shift = 0, mask = 63, + [0] = "add.dFGH", "sub.dFGH", "mul.dFGH", "div.dFGH", + "sqrt.dFG", "abs.dFG", "mov.dFG", "neg.dFG", + "round.l.dFG", "trunc.l.dFG", "ceil.l.dFG", "floor.l.dFG", + "round.w.dFG", "trunc.w.dFG", "ceil.w.dFG", "floor.w.dFG", + false, + { shift = 16, mask = 1, [0] = "movf.dFGC", "movt.dFGC" }, + "movz.dFGT", "movn.dFGT", + false, "recip.dFG", "rsqrt.dFG", false, + false, false, false, false, + false, false, false, false, + "cvt.s.dFG", false, false, false, + "cvt.w.dFG", "cvt.l.dFG", false, false, + false, false, false, false, + false, false, false, false, + "c.f.dVGH", "c.un.dVGH", "c.eq.dVGH", "c.ueq.dVGH", + "c.olt.dVGH", "c.ult.dVGH", "c.ole.dVGH", "c.ule.dVGH", + "c.df.dVGH", "c.ngle.dVGH", "c.deq.dVGH", "c.ngl.dVGH", + "c.lt.dVGH", "c.nge.dVGH", "c.le.dVGH", "c.ngt.dVGH", +} + +local map_cop1ps = { + shift = 0, mask = 63, + [0] = "add.psFGH", "sub.psFGH", "mul.psFGH", false, + false, "abs.psFG", "mov.psFG", "neg.psFG", + false, false, false, false, + false, false, false, false, + false, + { shift = 16, mask = 1, [0] = "movf.psFGC", "movt.psFGC" }, + "movz.psFGT", "movn.psFGT", + false, false, false, false, + false, false, false, false, + false, false, false, false, + "cvt.s.puFG", false, false, false, + false, false, false, false, + "cvt.s.plFG", false, false, false, + "pll.psFGH", "plu.psFGH", "pul.psFGH", "puu.psFGH", + "c.f.psVGH", "c.un.psVGH", "c.eq.psVGH", "c.ueq.psVGH", + "c.olt.psVGH", "c.ult.psVGH", "c.ole.psVGH", "c.ule.psVGH", + "c.psf.psVGH", "c.ngle.psVGH", "c.pseq.psVGH", "c.ngl.psVGH", + "c.lt.psVGH", "c.nge.psVGH", "c.le.psVGH", "c.ngt.psVGH", +} + +local map_cop1w = { + shift = 0, mask = 63, + [32] = "cvt.s.wFG", [33] = "cvt.d.wFG", +} + +local map_cop1l = { + shift = 0, mask = 63, + [32] = "cvt.s.lFG", [33] = "cvt.d.lFG", +} + +local map_cop1bc = { + shift = 16, mask = 3, + [0] = "bc1fCB", "bc1tCB", "bc1flCB", "bc1tlCB", +} + +local map_cop1 = { + shift = 21, mask = 31, + [0] = "mfc1TG", false, "cfc1TG", "mfhc1TG", + "mtc1TG", false, "ctc1TG", "mthc1TG", + map_cop1bc, false, false, false, + false, false, false, false, + map_cop1s, map_cop1d, false, false, + map_cop1w, map_cop1l, map_cop1ps, +} + +local map_cop1x = { + shift = 0, mask = 63, + [0] = "lwxc1FSX", "ldxc1FSX", false, false, + false, "luxc1FSX", false, false, + "swxc1FSX", "sdxc1FSX", false, false, + false, "suxc1FSX", false, "prefxMSX", + false, false, false, false, + false, false, false, false, + false, false, false, false, + false, false, "alnv.psFGHS", false, + "madd.sFRGH", "madd.dFRGH", false, false, + false, false, "madd.psFRGH", false, + "msub.sFRGH", "msub.dFRGH", false, false, + false, false, "msub.psFRGH", false, + "nmadd.sFRGH", "nmadd.dFRGH", false, false, + false, false, "nmadd.psFRGH", false, + "nmsub.sFRGH", "nmsub.dFRGH", false, false, + false, false, "nmsub.psFRGH", false, +} + +local map_pri = { + [0] = map_special, map_regimm, "jJ", "jalJ", + "beq|beqz|bST00B", "bne|bnezST0B", "blezSB", "bgtzSB", + "addiTSI", "addiu|liTS0I", "sltiTSI", "sltiuTSI", + "andiTSU", "ori|liTS0U", "xoriTSU", "luiTU", + map_cop0, map_cop1, false, map_cop1x, + "beql|beqzlST0B", "bnel|bnezlST0B", "blezlSB", "bgtzlSB", + false, false, false, false, + map_special2, false, false, map_special3, + "lbTSO", "lhTSO", "lwlTSO", "lwTSO", + "lbuTSO", "lhuTSO", "lwrTSO", false, + "sbTSO", "shTSO", "swlTSO", "swTSO", + false, false, "swrTSO", "cacheNSO", + "llTSO", "lwc1HSO", "lwc2TSO", "prefNSO", + false, "ldc1HSO", "ldc2TSO", false, + "scTSO", "swc1HSO", "swc2TSO", false, + false, "sdc1HSO", "sdc2TSO", false, +} + +------------------------------------------------------------------------------ + +local map_gpr = { + [0] = "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "sp", "r30", "ra", +} + +------------------------------------------------------------------------------ + +-- Output a nicely formatted line with an opcode and operands. +local function putop(ctx, text, operands) + local pos = ctx.pos + local extra = "" + if ctx.rel then + local sym = ctx.symtab[ctx.rel] + if sym then extra = "\t->"..sym end + end + if ctx.hexdump > 0 then + ctx.out(format("%08x %s %-7s %s%s\n", + ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra)) + else + ctx.out(format("%08x %-7s %s%s\n", + ctx.addr+pos, text, concat(operands, ", "), extra)) + end + ctx.pos = pos + 4 +end + +-- Fallback for unknown opcodes. +local function unknown(ctx) + return putop(ctx, ".long", { "0x"..tohex(ctx.op) }) +end + +local function get_be(ctx) + local pos = ctx.pos + local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4) + return bor(lshift(b0, 24), lshift(b1, 16), lshift(b2, 8), b3) +end + +local function get_le(ctx) + local pos = ctx.pos + local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4) + return bor(lshift(b3, 24), lshift(b2, 16), lshift(b1, 8), b0) +end + +-- Disassemble a single instruction. +local function disass_ins(ctx) + local op = ctx:get() + local operands = {} + local last = nil + ctx.op = op + ctx.rel = nil + + local opat = map_pri[rshift(op, 26)] + while type(opat) ~= "string" do + if not opat then return unknown(ctx) end + opat = opat[band(rshift(op, opat.shift), opat.mask)] or opat._ + end + local name, pat = match(opat, "^([a-z0-9_.]*)(.*)") + local altname, pat2 = match(pat, "|([a-z0-9_.|]*)(.*)") + if altname then pat = pat2 end + + for p in gmatch(pat, ".") do + local x = nil + if p == "S" then + x = map_gpr[band(rshift(op, 21), 31)] + elseif p == "T" then + x = map_gpr[band(rshift(op, 16), 31)] + elseif p == "D" then + x = map_gpr[band(rshift(op, 11), 31)] + elseif p == "F" then + x = "f"..band(rshift(op, 6), 31) + elseif p == "G" then + x = "f"..band(rshift(op, 11), 31) + elseif p == "H" then + x = "f"..band(rshift(op, 16), 31) + elseif p == "R" then + x = "f"..band(rshift(op, 21), 31) + elseif p == "A" then + x = band(rshift(op, 6), 31) + elseif p == "M" then + x = band(rshift(op, 11), 31) + elseif p == "N" then + x = band(rshift(op, 16), 31) + elseif p == "C" then + x = band(rshift(op, 18), 7) + if x == 0 then x = nil end + elseif p == "K" then + x = band(rshift(op, 11), 31) + 1 + elseif p == "L" then + x = band(rshift(op, 11), 31) - last + 1 + elseif p == "I" then + x = arshift(lshift(op, 16), 16) + elseif p == "U" then + x = band(op, 0xffff) + elseif p == "O" then + local disp = arshift(lshift(op, 16), 16) + operands[#operands] = format("%d(%s)", disp, last) + elseif p == "X" then + local index = map_gpr[band(rshift(op, 16), 31)] + operands[#operands] = format("%s(%s)", index, last) + elseif p == "B" then + x = ctx.addr + ctx.pos + arshift(lshift(op, 16), 16)*4 + 4 + ctx.rel = x + x = "0x"..tohex(x) + elseif p == "J" then + x = band(ctx.addr + ctx.pos, 0xf0000000) + band(op, 0x03ffffff)*4 + ctx.rel = x + x = "0x"..tohex(x) + elseif p == "V" then + x = band(rshift(op, 8), 7) + if x == 0 then x = nil end + elseif p == "W" then + x = band(op, 7) + if x == 0 then x = nil end + elseif p == "Y" then + x = band(rshift(op, 6), 0x000fffff) + if x == 0 then x = nil end + elseif p == "Z" then + x = band(rshift(op, 6), 1023) + if x == 0 then x = nil end + elseif p == "0" then + if last == "r0" or last == 0 then + local n = #operands + operands[n] = nil + last = operands[n-1] + if altname then + local a1, a2 = match(altname, "([^|]*)|(.*)") + if a1 then name, altname = a1, a2 + else name = altname end + end + end + elseif p == "1" then + if last == "ra" then + operands[#operands] = nil + end + else + assert(false) + end + if x then operands[#operands+1] = x; last = x end + end + + return putop(ctx, name, operands) +end + +------------------------------------------------------------------------------ + +-- Disassemble a block of code. +local function disass_block(ctx, ofs, len) + if not ofs then ofs = 0 end + local stop = len and ofs+len or #ctx.code + stop = stop - stop % 4 + ctx.pos = ofs - ofs % 4 + ctx.rel = nil + while ctx.pos < stop do disass_ins(ctx) end +end + +-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len). +local function create_(code, addr, out) + local ctx = {} + ctx.code = code + ctx.addr = addr or 0 + ctx.out = out or io.write + ctx.symtab = {} + ctx.disass = disass_block + ctx.hexdump = 8 + ctx.get = get_be + return ctx +end + +local function create_el_(code, addr, out) + local ctx = create_(code, addr, out) + ctx.get = get_le + return ctx +end + +-- Simple API: disassemble code (a string) at address and output via out. +local function disass_(code, addr, out) + create_(code, addr, out):disass() +end + +local function disass_el_(code, addr, out) + create_el_(code, addr, out):disass() +end + +-- Return register name for RID. +local function regname_(r) + if r < 32 then return map_gpr[r] end + return "f"..(r-32) +end + +-- Public module functions. +module(...) + +create = create_ +create_el = create_el_ +disass = disass_ +disass_el = disass_el_ +regname = regname_ + diff --git a/LuaJIT-2.0.4/lua/jit/dis_mipsel.lua b/LuaJIT-2.0.4/lua/jit/dis_mipsel.lua new file mode 100644 index 000000000..dd9d26ae6 --- /dev/null +++ b/LuaJIT-2.0.4/lua/jit/dis_mipsel.lua @@ -0,0 +1,20 @@ +---------------------------------------------------------------------------- +-- LuaJIT MIPSEL disassembler wrapper module. +-- +-- Copyright (C) 2005-2015 Mike Pall. All rights reserved. +-- Released under the MIT license. See Copyright Notice in luajit.h +---------------------------------------------------------------------------- +-- This module just exports the little-endian functions from the +-- MIPS disassembler module. All the interesting stuff is there. +------------------------------------------------------------------------------ + +local require = require + +module(...) + +local dis_mips = require(_PACKAGE.."dis_mips") + +create = dis_mips.create_el +disass = dis_mips.disass_el +regname = dis_mips.regname + diff --git a/LuaJIT-2.0.4/lua/jit/dis_ppc.lua b/LuaJIT-2.0.4/lua/jit/dis_ppc.lua new file mode 100644 index 000000000..d05c43111 --- /dev/null +++ b/LuaJIT-2.0.4/lua/jit/dis_ppc.lua @@ -0,0 +1,591 @@ +---------------------------------------------------------------------------- +-- LuaJIT PPC disassembler module. +-- +-- Copyright (C) 2005-2015 Mike Pall. All rights reserved. +-- Released under the MIT/X license. See Copyright Notice in luajit.h +---------------------------------------------------------------------------- +-- This is a helper module used by the LuaJIT machine code dumper module. +-- +-- It disassembles all common, non-privileged 32/64 bit PowerPC instructions +-- plus the e500 SPE instructions and some Cell/Xenon extensions. +-- +-- NYI: VMX, VMX128 +------------------------------------------------------------------------------ + +local type = type +local sub, byte, format = string.sub, string.byte, string.format +local match, gmatch, gsub = string.match, string.gmatch, string.gsub +local concat = table.concat +local bit = require("bit") +local band, bor, tohex = bit.band, bit.bor, bit.tohex +local lshift, rshift, arshift = bit.lshift, bit.rshift, bit.arshift + +------------------------------------------------------------------------------ +-- Primary and extended opcode maps +------------------------------------------------------------------------------ + +local map_crops = { + shift = 1, mask = 1023, + [0] = "mcrfXX", + [33] = "crnor|crnotCCC=", [129] = "crandcCCC", + [193] = "crxor|crclrCCC%", [225] = "crnandCCC", + [257] = "crandCCC", [289] = "creqv|crsetCCC%", + [417] = "crorcCCC", [449] = "cror|crmoveCCC=", + [16] = "b_lrKB", [528] = "b_ctrKB", + [150] = "isync", +} + +local map_rlwinm = setmetatable({ + shift = 0, mask = -1, +}, +{ __index = function(t, x) + local rot = band(rshift(x, 11), 31) + local mb = band(rshift(x, 6), 31) + local me = band(rshift(x, 1), 31) + if mb == 0 and me == 31-rot then + return "slwiRR~A." + elseif me == 31 and mb == 32-rot then + return "srwiRR~-A." + else + return "rlwinmRR~AAA." + end + end +}) + +local map_rld = { + shift = 2, mask = 7, + [0] = "rldiclRR~HM.", "rldicrRR~HM.", "rldicRR~HM.", "rldimiRR~HM.", + { + shift = 1, mask = 1, + [0] = "rldclRR~RM.", "rldcrRR~RM.", + }, +} + +local map_ext = setmetatable({ + shift = 1, mask = 1023, + + [0] = "cmp_YLRR", [32] = "cmpl_YLRR", + [4] = "twARR", [68] = "tdARR", + + [8] = "subfcRRR.", [40] = "subfRRR.", + [104] = "negRR.", [136] = "subfeRRR.", + [200] = "subfzeRR.", [232] = "subfmeRR.", + [520] = "subfcoRRR.", [552] = "subfoRRR.", + [616] = "negoRR.", [648] = "subfeoRRR.", + [712] = "subfzeoRR.", [744] = "subfmeoRR.", + + [9] = "mulhduRRR.", [73] = "mulhdRRR.", [233] = "mulldRRR.", + [457] = "divduRRR.", [489] = "divdRRR.", + [745] = "mulldoRRR.", + [969] = "divduoRRR.", [1001] = "divdoRRR.", + + [10] = "addcRRR.", [138] = "addeRRR.", + [202] = "addzeRR.", [234] = "addmeRR.", [266] = "addRRR.", + [522] = "addcoRRR.", [650] = "addeoRRR.", + [714] = "addzeoRR.", [746] = "addmeoRR.", [778] = "addoRRR.", + + [11] = "mulhwuRRR.", [75] = "mulhwRRR.", [235] = "mullwRRR.", + [459] = "divwuRRR.", [491] = "divwRRR.", + [747] = "mullwoRRR.", + [971] = "divwouRRR.", [1003] = "divwoRRR.", + + [15] = "iselltRRR", [47] = "iselgtRRR", [79] = "iseleqRRR", + + [144] = { shift = 20, mask = 1, [0] = "mtcrfRZ~", "mtocrfRZ~", }, + [19] = { shift = 20, mask = 1, [0] = "mfcrR", "mfocrfRZ", }, + [371] = { shift = 11, mask = 1023, [392] = "mftbR", [424] = "mftbuR", }, + [339] = { + shift = 11, mask = 1023, + [32] = "mferR", [256] = "mflrR", [288] = "mfctrR", [16] = "mfspefscrR", + }, + [467] = { + shift = 11, mask = 1023, + [32] = "mtxerR", [256] = "mtlrR", [288] = "mtctrR", [16] = "mtspefscrR", + }, + + [20] = "lwarxRR0R", [84] = "ldarxRR0R", + + [21] = "ldxRR0R", [53] = "lduxRRR", + [149] = "stdxRR0R", [181] = "stduxRRR", + [341] = "lwaxRR0R", [373] = "lwauxRRR", + + [23] = "lwzxRR0R", [55] = "lwzuxRRR", + [87] = "lbzxRR0R", [119] = "lbzuxRRR", + [151] = "stwxRR0R", [183] = "stwuxRRR", + [215] = "stbxRR0R", [247] = "stbuxRRR", + [279] = "lhzxRR0R", [311] = "lhzuxRRR", + [343] = "lhaxRR0R", [375] = "lhauxRRR", + [407] = "sthxRR0R", [439] = "sthuxRRR", + + [54] = "dcbst-R0R", [86] = "dcbf-R0R", + [150] = "stwcxRR0R.", [214] = "stdcxRR0R.", + [246] = "dcbtst-R0R", [278] = "dcbt-R0R", + [310] = "eciwxRR0R", [438] = "ecowxRR0R", + [470] = "dcbi-RR", + + [598] = { + shift = 21, mask = 3, + [0] = "sync", "lwsync", "ptesync", + }, + [758] = "dcba-RR", + [854] = "eieio", [982] = "icbi-R0R", [1014] = "dcbz-R0R", + + [26] = "cntlzwRR~", [58] = "cntlzdRR~", + [122] = "popcntbRR~", + [154] = "prtywRR~", [186] = "prtydRR~", + + [28] = "andRR~R.", [60] = "andcRR~R.", [124] = "nor|notRR~R=.", + [284] = "eqvRR~R.", [316] = "xorRR~R.", + [412] = "orcRR~R.", [444] = "or|mrRR~R=.", [476] = "nandRR~R.", + [508] = "cmpbRR~R", + + [512] = "mcrxrX", + + [532] = "ldbrxRR0R", [660] = "stdbrxRR0R", + + [533] = "lswxRR0R", [597] = "lswiRR0A", + [661] = "stswxRR0R", [725] = "stswiRR0A", + + [534] = "lwbrxRR0R", [662] = "stwbrxRR0R", + [790] = "lhbrxRR0R", [918] = "sthbrxRR0R", + + [535] = "lfsxFR0R", [567] = "lfsuxFRR", + [599] = "lfdxFR0R", [631] = "lfduxFRR", + [663] = "stfsxFR0R", [695] = "stfsuxFRR", + [727] = "stfdxFR0R", [759] = "stfduxFR0R", + [855] = "lfiwaxFR0R", + [983] = "stfiwxFR0R", + + [24] = "slwRR~R.", + + [27] = "sldRR~R.", [536] = "srwRR~R.", + [792] = "srawRR~R.", [824] = "srawiRR~A.", + + [794] = "sradRR~R.", [826] = "sradiRR~H.", [827] = "sradiRR~H.", + [922] = "extshRR~.", [954] = "extsbRR~.", [986] = "extswRR~.", + + [539] = "srdRR~R.", +}, +{ __index = function(t, x) + if band(x, 31) == 15 then return "iselRRRC" end + end +}) + +local map_ld = { + shift = 0, mask = 3, + [0] = "ldRRE", "lduRRE", "lwaRRE", +} + +local map_std = { + shift = 0, mask = 3, + [0] = "stdRRE", "stduRRE", +} + +local map_fps = { + shift = 5, mask = 1, + { + shift = 1, mask = 15, + [0] = false, false, "fdivsFFF.", false, + "fsubsFFF.", "faddsFFF.", "fsqrtsF-F.", false, + "fresF-F.", "fmulsFF-F.", "frsqrtesF-F.", false, + "fmsubsFFFF~.", "fmaddsFFFF~.", "fnmsubsFFFF~.", "fnmaddsFFFF~.", + } +} + +local map_fpd = { + shift = 5, mask = 1, + [0] = { + shift = 1, mask = 1023, + [0] = "fcmpuXFF", [32] = "fcmpoXFF", [64] = "mcrfsXX", + [38] = "mtfsb1A.", [70] = "mtfsb0A.", [134] = "mtfsfiA>>-A>", + [8] = "fcpsgnFFF.", [40] = "fnegF-F.", [72] = "fmrF-F.", + [136] = "fnabsF-F.", [264] = "fabsF-F.", + [12] = "frspF-F.", + [14] = "fctiwF-F.", [15] = "fctiwzF-F.", + [583] = "mffsF.", [711] = "mtfsfZF.", + [392] = "frinF-F.", [424] = "frizF-F.", + [456] = "fripF-F.", [488] = "frimF-F.", + [814] = "fctidF-F.", [815] = "fctidzF-F.", [846] = "fcfidF-F.", + }, + { + shift = 1, mask = 15, + [0] = false, false, "fdivFFF.", false, + "fsubFFF.", "faddFFF.", "fsqrtF-F.", "fselFFFF~.", + "freF-F.", "fmulFF-F.", "frsqrteF-F.", false, + "fmsubFFFF~.", "fmaddFFFF~.", "fnmsubFFFF~.", "fnmaddFFFF~.", + } +} + +local map_spe = { + shift = 0, mask = 2047, + + [512] = "evaddwRRR", [514] = "evaddiwRAR~", + [516] = "evsubwRRR~", [518] = "evsubiwRAR~", + [520] = "evabsRR", [521] = "evnegRR", + [522] = "evextsbRR", [523] = "evextshRR", [524] = "evrndwRR", + [525] = "evcntlzwRR", [526] = "evcntlswRR", + + [527] = "brincRRR", + + [529] = "evandRRR", [530] = "evandcRRR", [534] = "evxorRRR", + [535] = "evor|evmrRRR=", [536] = "evnor|evnotRRR=", + [537] = "eveqvRRR", [539] = "evorcRRR", [542] = "evnandRRR", + + [544] = "evsrwuRRR", [545] = "evsrwsRRR", + [546] = "evsrwiuRRA", [547] = "evsrwisRRA", + [548] = "evslwRRR", [550] = "evslwiRRA", + [552] = "evrlwRRR", [553] = "evsplatiRS", + [554] = "evrlwiRRA", [555] = "evsplatfiRS", + [556] = "evmergehiRRR", [557] = "evmergeloRRR", + [558] = "evmergehiloRRR", [559] = "evmergelohiRRR", + + [560] = "evcmpgtuYRR", [561] = "evcmpgtsYRR", + [562] = "evcmpltuYRR", [563] = "evcmpltsYRR", + [564] = "evcmpeqYRR", + + [632] = "evselRRR", [633] = "evselRRRW", + [634] = "evselRRRW", [635] = "evselRRRW", + [636] = "evselRRRW", [637] = "evselRRRW", + [638] = "evselRRRW", [639] = "evselRRRW", + + [640] = "evfsaddRRR", [641] = "evfssubRRR", + [644] = "evfsabsRR", [645] = "evfsnabsRR", [646] = "evfsnegRR", + [648] = "evfsmulRRR", [649] = "evfsdivRRR", + [652] = "evfscmpgtYRR", [653] = "evfscmpltYRR", [654] = "evfscmpeqYRR", + [656] = "evfscfuiR-R", [657] = "evfscfsiR-R", + [658] = "evfscfufR-R", [659] = "evfscfsfR-R", + [660] = "evfsctuiR-R", [661] = "evfsctsiR-R", + [662] = "evfsctufR-R", [663] = "evfsctsfR-R", + [664] = "evfsctuizR-R", [666] = "evfsctsizR-R", + [668] = "evfststgtYRR", [669] = "evfststltYRR", [670] = "evfststeqYRR", + + [704] = "efsaddRRR", [705] = "efssubRRR", + [708] = "efsabsRR", [709] = "efsnabsRR", [710] = "efsnegRR", + [712] = "efsmulRRR", [713] = "efsdivRRR", + [716] = "efscmpgtYRR", [717] = "efscmpltYRR", [718] = "efscmpeqYRR", + [719] = "efscfdR-R", + [720] = "efscfuiR-R", [721] = "efscfsiR-R", + [722] = "efscfufR-R", [723] = "efscfsfR-R", + [724] = "efsctuiR-R", [725] = "efsctsiR-R", + [726] = "efsctufR-R", [727] = "efsctsfR-R", + [728] = "efsctuizR-R", [730] = "efsctsizR-R", + [732] = "efststgtYRR", [733] = "efststltYRR", [734] = "efststeqYRR", + + [736] = "efdaddRRR", [737] = "efdsubRRR", + [738] = "efdcfuidR-R", [739] = "efdcfsidR-R", + [740] = "efdabsRR", [741] = "efdnabsRR", [742] = "efdnegRR", + [744] = "efdmulRRR", [745] = "efddivRRR", + [746] = "efdctuidzR-R", [747] = "efdctsidzR-R", + [748] = "efdcmpgtYRR", [749] = "efdcmpltYRR", [750] = "efdcmpeqYRR", + [751] = "efdcfsR-R", + [752] = "efdcfuiR-R", [753] = "efdcfsiR-R", + [754] = "efdcfufR-R", [755] = "efdcfsfR-R", + [756] = "efdctuiR-R", [757] = "efdctsiR-R", + [758] = "efdctufR-R", [759] = "efdctsfR-R", + [760] = "efdctuizR-R", [762] = "efdctsizR-R", + [764] = "efdtstgtYRR", [765] = "efdtstltYRR", [766] = "efdtsteqYRR", + + [768] = "evlddxRR0R", [769] = "evlddRR8", + [770] = "evldwxRR0R", [771] = "evldwRR8", + [772] = "evldhxRR0R", [773] = "evldhRR8", + [776] = "evlhhesplatxRR0R", [777] = "evlhhesplatRR2", + [780] = "evlhhousplatxRR0R", [781] = "evlhhousplatRR2", + [782] = "evlhhossplatxRR0R", [783] = "evlhhossplatRR2", + [784] = "evlwhexRR0R", [785] = "evlwheRR4", + [788] = "evlwhouxRR0R", [789] = "evlwhouRR4", + [790] = "evlwhosxRR0R", [791] = "evlwhosRR4", + [792] = "evlwwsplatxRR0R", [793] = "evlwwsplatRR4", + [796] = "evlwhsplatxRR0R", [797] = "evlwhsplatRR4", + + [800] = "evstddxRR0R", [801] = "evstddRR8", + [802] = "evstdwxRR0R", [803] = "evstdwRR8", + [804] = "evstdhxRR0R", [805] = "evstdhRR8", + [816] = "evstwhexRR0R", [817] = "evstwheRR4", + [820] = "evstwhoxRR0R", [821] = "evstwhoRR4", + [824] = "evstwwexRR0R", [825] = "evstwweRR4", + [828] = "evstwwoxRR0R", [829] = "evstwwoRR4", + + [1027] = "evmhessfRRR", [1031] = "evmhossfRRR", [1032] = "evmheumiRRR", + [1033] = "evmhesmiRRR", [1035] = "evmhesmfRRR", [1036] = "evmhoumiRRR", + [1037] = "evmhosmiRRR", [1039] = "evmhosmfRRR", [1059] = "evmhessfaRRR", + [1063] = "evmhossfaRRR", [1064] = "evmheumiaRRR", [1065] = "evmhesmiaRRR", + [1067] = "evmhesmfaRRR", [1068] = "evmhoumiaRRR", [1069] = "evmhosmiaRRR", + [1071] = "evmhosmfaRRR", [1095] = "evmwhssfRRR", [1096] = "evmwlumiRRR", + [1100] = "evmwhumiRRR", [1101] = "evmwhsmiRRR", [1103] = "evmwhsmfRRR", + [1107] = "evmwssfRRR", [1112] = "evmwumiRRR", [1113] = "evmwsmiRRR", + [1115] = "evmwsmfRRR", [1127] = "evmwhssfaRRR", [1128] = "evmwlumiaRRR", + [1132] = "evmwhumiaRRR", [1133] = "evmwhsmiaRRR", [1135] = "evmwhsmfaRRR", + [1139] = "evmwssfaRRR", [1144] = "evmwumiaRRR", [1145] = "evmwsmiaRRR", + [1147] = "evmwsmfaRRR", + + [1216] = "evaddusiaawRR", [1217] = "evaddssiaawRR", + [1218] = "evsubfusiaawRR", [1219] = "evsubfssiaawRR", + [1220] = "evmraRR", + [1222] = "evdivwsRRR", [1223] = "evdivwuRRR", + [1224] = "evaddumiaawRR", [1225] = "evaddsmiaawRR", + [1226] = "evsubfumiaawRR", [1227] = "evsubfsmiaawRR", + + [1280] = "evmheusiaawRRR", [1281] = "evmhessiaawRRR", + [1283] = "evmhessfaawRRR", [1284] = "evmhousiaawRRR", + [1285] = "evmhossiaawRRR", [1287] = "evmhossfaawRRR", + [1288] = "evmheumiaawRRR", [1289] = "evmhesmiaawRRR", + [1291] = "evmhesmfaawRRR", [1292] = "evmhoumiaawRRR", + [1293] = "evmhosmiaawRRR", [1295] = "evmhosmfaawRRR", + [1320] = "evmhegumiaaRRR", [1321] = "evmhegsmiaaRRR", + [1323] = "evmhegsmfaaRRR", [1324] = "evmhogumiaaRRR", + [1325] = "evmhogsmiaaRRR", [1327] = "evmhogsmfaaRRR", + [1344] = "evmwlusiaawRRR", [1345] = "evmwlssiaawRRR", + [1352] = "evmwlumiaawRRR", [1353] = "evmwlsmiaawRRR", + [1363] = "evmwssfaaRRR", [1368] = "evmwumiaaRRR", + [1369] = "evmwsmiaaRRR", [1371] = "evmwsmfaaRRR", + [1408] = "evmheusianwRRR", [1409] = "evmhessianwRRR", + [1411] = "evmhessfanwRRR", [1412] = "evmhousianwRRR", + [1413] = "evmhossianwRRR", [1415] = "evmhossfanwRRR", + [1416] = "evmheumianwRRR", [1417] = "evmhesmianwRRR", + [1419] = "evmhesmfanwRRR", [1420] = "evmhoumianwRRR", + [1421] = "evmhosmianwRRR", [1423] = "evmhosmfanwRRR", + [1448] = "evmhegumianRRR", [1449] = "evmhegsmianRRR", + [1451] = "evmhegsmfanRRR", [1452] = "evmhogumianRRR", + [1453] = "evmhogsmianRRR", [1455] = "evmhogsmfanRRR", + [1472] = "evmwlusianwRRR", [1473] = "evmwlssianwRRR", + [1480] = "evmwlumianwRRR", [1481] = "evmwlsmianwRRR", + [1491] = "evmwssfanRRR", [1496] = "evmwumianRRR", + [1497] = "evmwsmianRRR", [1499] = "evmwsmfanRRR", +} + +local map_pri = { + [0] = false, false, "tdiARI", "twiARI", + map_spe, false, false, "mulliRRI", + "subficRRI", false, "cmpl_iYLRU", "cmp_iYLRI", + "addicRRI", "addic.RRI", "addi|liRR0I", "addis|lisRR0I", + "b_KBJ", "sc", "bKJ", map_crops, + "rlwimiRR~AAA.", map_rlwinm, false, "rlwnmRR~RAA.", + "oriNRR~U", "orisRR~U", "xoriRR~U", "xorisRR~U", + "andi.RR~U", "andis.RR~U", map_rld, map_ext, + "lwzRRD", "lwzuRRD", "lbzRRD", "lbzuRRD", + "stwRRD", "stwuRRD", "stbRRD", "stbuRRD", + "lhzRRD", "lhzuRRD", "lhaRRD", "lhauRRD", + "sthRRD", "sthuRRD", "lmwRRD", "stmwRRD", + "lfsFRD", "lfsuFRD", "lfdFRD", "lfduFRD", + "stfsFRD", "stfsuFRD", "stfdFRD", "stfduFRD", + false, false, map_ld, map_fps, + false, false, map_std, map_fpd, +} + +------------------------------------------------------------------------------ + +local map_gpr = { + [0] = "r0", "sp", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", +} + +local map_cond = { [0] = "lt", "gt", "eq", "so", "ge", "le", "ne", "ns", } + +-- Format a condition bit. +local function condfmt(cond) + if cond <= 3 then + return map_cond[band(cond, 3)] + else + return format("4*cr%d+%s", rshift(cond, 2), map_cond[band(cond, 3)]) + end +end + +------------------------------------------------------------------------------ + +-- Output a nicely formatted line with an opcode and operands. +local function putop(ctx, text, operands) + local pos = ctx.pos + local extra = "" + if ctx.rel then + local sym = ctx.symtab[ctx.rel] + if sym then extra = "\t->"..sym end + end + if ctx.hexdump > 0 then + ctx.out(format("%08x %s %-7s %s%s\n", + ctx.addr+pos, tohex(ctx.op), text, concat(operands, ", "), extra)) + else + ctx.out(format("%08x %-7s %s%s\n", + ctx.addr+pos, text, concat(operands, ", "), extra)) + end + ctx.pos = pos + 4 +end + +-- Fallback for unknown opcodes. +local function unknown(ctx) + return putop(ctx, ".long", { "0x"..tohex(ctx.op) }) +end + +-- Disassemble a single instruction. +local function disass_ins(ctx) + local pos = ctx.pos + local b0, b1, b2, b3 = byte(ctx.code, pos+1, pos+4) + local op = bor(lshift(b0, 24), lshift(b1, 16), lshift(b2, 8), b3) + local operands = {} + local last = nil + local rs = 21 + ctx.op = op + ctx.rel = nil + + local opat = map_pri[rshift(b0, 2)] + while type(opat) ~= "string" do + if not opat then return unknown(ctx) end + opat = opat[band(rshift(op, opat.shift), opat.mask)] + end + local name, pat = match(opat, "^([a-z0-9_.]*)(.*)") + local altname, pat2 = match(pat, "|([a-z0-9_.]*)(.*)") + if altname then pat = pat2 end + + for p in gmatch(pat, ".") do + local x = nil + if p == "R" then + x = map_gpr[band(rshift(op, rs), 31)] + rs = rs - 5 + elseif p == "F" then + x = "f"..band(rshift(op, rs), 31) + rs = rs - 5 + elseif p == "A" then + x = band(rshift(op, rs), 31) + rs = rs - 5 + elseif p == "S" then + x = arshift(lshift(op, 27-rs), 27) + rs = rs - 5 + elseif p == "I" then + x = arshift(lshift(op, 16), 16) + elseif p == "U" then + x = band(op, 0xffff) + elseif p == "D" or p == "E" then + local disp = arshift(lshift(op, 16), 16) + if p == "E" then disp = band(disp, -4) end + if last == "r0" then last = "0" end + operands[#operands] = format("%d(%s)", disp, last) + elseif p >= "2" and p <= "8" then + local disp = band(rshift(op, rs), 31) * p + if last == "r0" then last = "0" end + operands[#operands] = format("%d(%s)", disp, last) + elseif p == "H" then + x = band(rshift(op, rs), 31) + lshift(band(op, 2), 4) + rs = rs - 5 + elseif p == "M" then + x = band(rshift(op, rs), 31) + band(op, 0x20) + elseif p == "C" then + x = condfmt(band(rshift(op, rs), 31)) + rs = rs - 5 + elseif p == "B" then + local bo = rshift(op, 21) + local cond = band(rshift(op, 16), 31) + local cn = "" + rs = rs - 10 + if band(bo, 4) == 0 then + cn = band(bo, 2) == 0 and "dnz" or "dz" + if band(bo, 0x10) == 0 then + cn = cn..(band(bo, 8) == 0 and "f" or "t") + end + if band(bo, 0x10) == 0 then x = condfmt(cond) end + name = name..(band(bo, 1) == band(rshift(op, 15), 1) and "-" or "+") + elseif band(bo, 0x10) == 0 then + cn = map_cond[band(cond, 3) + (band(bo, 8) == 0 and 4 or 0)] + if cond > 3 then x = "cr"..rshift(cond, 2) end + name = name..(band(bo, 1) == band(rshift(op, 15), 1) and "-" or "+") + end + name = gsub(name, "_", cn) + elseif p == "J" then + x = arshift(lshift(op, 27-rs), 29-rs)*4 + if band(op, 2) == 0 then x = ctx.addr + pos + x end + ctx.rel = x + x = "0x"..tohex(x) + elseif p == "K" then + if band(op, 1) ~= 0 then name = name.."l" end + if band(op, 2) ~= 0 then name = name.."a" end + elseif p == "X" or p == "Y" then + x = band(rshift(op, rs+2), 7) + if x == 0 and p == "Y" then x = nil else x = "cr"..x end + rs = rs - 5 + elseif p == "W" then + x = "cr"..band(op, 7) + elseif p == "Z" then + x = band(rshift(op, rs-4), 255) + rs = rs - 10 + elseif p == ">" then + operands[#operands] = rshift(operands[#operands], 1) + elseif p == "0" then + if last == "r0" then + operands[#operands] = nil + if altname then name = altname end + end + elseif p == "L" then + name = gsub(name, "_", band(op, 0x00200000) ~= 0 and "d" or "w") + elseif p == "." then + if band(op, 1) == 1 then name = name.."." end + elseif p == "N" then + if op == 0x60000000 then name = "nop"; break end + elseif p == "~" then + local n = #operands + operands[n-1], operands[n] = operands[n], operands[n-1] + elseif p == "=" then + local n = #operands + if last == operands[n-1] then + operands[n] = nil + name = altname + end + elseif p == "%" then + local n = #operands + if last == operands[n-1] and last == operands[n-2] then + operands[n] = nil + operands[n-1] = nil + name = altname + end + elseif p == "-" then + rs = rs - 5 + else + assert(false) + end + if x then operands[#operands+1] = x; last = x end + end + + return putop(ctx, name, operands) +end + +------------------------------------------------------------------------------ + +-- Disassemble a block of code. +local function disass_block(ctx, ofs, len) + if not ofs then ofs = 0 end + local stop = len and ofs+len or #ctx.code + stop = stop - stop % 4 + ctx.pos = ofs - ofs % 4 + ctx.rel = nil + while ctx.pos < stop do disass_ins(ctx) end +end + +-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len). +local function create_(code, addr, out) + local ctx = {} + ctx.code = code + ctx.addr = addr or 0 + ctx.out = out or io.write + ctx.symtab = {} + ctx.disass = disass_block + ctx.hexdump = 8 + return ctx +end + +-- Simple API: disassemble code (a string) at address and output via out. +local function disass_(code, addr, out) + create_(code, addr, out):disass() +end + +-- Return register name for RID. +local function regname_(r) + if r < 32 then return map_gpr[r] end + return "f"..(r-32) +end + +-- Public module functions. +module(...) + +create = create_ +disass = disass_ +regname = regname_ + diff --git a/LuaJIT-2.0.4/lua/jit/dis_x64.lua b/LuaJIT-2.0.4/lua/jit/dis_x64.lua new file mode 100644 index 000000000..a80981bd5 --- /dev/null +++ b/LuaJIT-2.0.4/lua/jit/dis_x64.lua @@ -0,0 +1,20 @@ +---------------------------------------------------------------------------- +-- LuaJIT x64 disassembler wrapper module. +-- +-- Copyright (C) 2005-2015 Mike Pall. All rights reserved. +-- Released under the MIT license. See Copyright Notice in luajit.h +---------------------------------------------------------------------------- +-- This module just exports the 64 bit functions from the combined +-- x86/x64 disassembler module. All the interesting stuff is there. +------------------------------------------------------------------------------ + +local require = require + +module(...) + +local dis_x86 = require(_PACKAGE.."dis_x86") + +create = dis_x86.create64 +disass = dis_x86.disass64 +regname = dis_x86.regname64 + diff --git a/LuaJIT-2.0.4/lua/jit/dis_x86.lua b/LuaJIT-2.0.4/lua/jit/dis_x86.lua new file mode 100644 index 000000000..078d6094d --- /dev/null +++ b/LuaJIT-2.0.4/lua/jit/dis_x86.lua @@ -0,0 +1,836 @@ +---------------------------------------------------------------------------- +-- LuaJIT x86/x64 disassembler module. +-- +-- Copyright (C) 2005-2015 Mike Pall. All rights reserved. +-- Released under the MIT license. See Copyright Notice in luajit.h +---------------------------------------------------------------------------- +-- This is a helper module used by the LuaJIT machine code dumper module. +-- +-- Sending small code snippets to an external disassembler and mixing the +-- output with our own stuff was too fragile. So I had to bite the bullet +-- and write yet another x86 disassembler. Oh well ... +-- +-- The output format is very similar to what ndisasm generates. But it has +-- been developed independently by looking at the opcode tables from the +-- Intel and AMD manuals. The supported instruction set is quite extensive +-- and reflects what a current generation Intel or AMD CPU implements in +-- 32 bit and 64 bit mode. Yes, this includes MMX, SSE, SSE2, SSE3, SSSE3, +-- SSE4.1, SSE4.2, SSE4a and even privileged and hypervisor (VMX/SVM) +-- instructions. +-- +-- Notes: +-- * The (useless) a16 prefix, 3DNow and pre-586 opcodes are unsupported. +-- * No attempt at optimization has been made -- it's fast enough for my needs. +-- * The public API may change when more architectures are added. +------------------------------------------------------------------------------ + +local type = type +local sub, byte, format = string.sub, string.byte, string.format +local match, gmatch, gsub = string.match, string.gmatch, string.gsub +local lower, rep = string.lower, string.rep + +-- Map for 1st opcode byte in 32 bit mode. Ugly? Well ... read on. +local map_opc1_32 = { +--0x +[0]="addBmr","addVmr","addBrm","addVrm","addBai","addVai","push es","pop es", +"orBmr","orVmr","orBrm","orVrm","orBai","orVai","push cs","opc2*", +--1x +"adcBmr","adcVmr","adcBrm","adcVrm","adcBai","adcVai","push ss","pop ss", +"sbbBmr","sbbVmr","sbbBrm","sbbVrm","sbbBai","sbbVai","push ds","pop ds", +--2x +"andBmr","andVmr","andBrm","andVrm","andBai","andVai","es:seg","daa", +"subBmr","subVmr","subBrm","subVrm","subBai","subVai","cs:seg","das", +--3x +"xorBmr","xorVmr","xorBrm","xorVrm","xorBai","xorVai","ss:seg","aaa", +"cmpBmr","cmpVmr","cmpBrm","cmpVrm","cmpBai","cmpVai","ds:seg","aas", +--4x +"incVR","incVR","incVR","incVR","incVR","incVR","incVR","incVR", +"decVR","decVR","decVR","decVR","decVR","decVR","decVR","decVR", +--5x +"pushUR","pushUR","pushUR","pushUR","pushUR","pushUR","pushUR","pushUR", +"popUR","popUR","popUR","popUR","popUR","popUR","popUR","popUR", +--6x +"sz*pushaw,pusha","sz*popaw,popa","boundVrm","arplWmr", +"fs:seg","gs:seg","o16:","a16", +"pushUi","imulVrmi","pushBs","imulVrms", +"insb","insVS","outsb","outsVS", +--7x +"joBj","jnoBj","jbBj","jnbBj","jzBj","jnzBj","jbeBj","jaBj", +"jsBj","jnsBj","jpeBj","jpoBj","jlBj","jgeBj","jleBj","jgBj", +--8x +"arith!Bmi","arith!Vmi","arith!Bmi","arith!Vms", +"testBmr","testVmr","xchgBrm","xchgVrm", +"movBmr","movVmr","movBrm","movVrm", +"movVmg","leaVrm","movWgm","popUm", +--9x +"nop*xchgVaR|pause|xchgWaR|repne nop","xchgVaR","xchgVaR","xchgVaR", +"xchgVaR","xchgVaR","xchgVaR","xchgVaR", +"sz*cbw,cwde,cdqe","sz*cwd,cdq,cqo","call farViw","wait", +"sz*pushfw,pushf","sz*popfw,popf","sahf","lahf", +--Ax +"movBao","movVao","movBoa","movVoa", +"movsb","movsVS","cmpsb","cmpsVS", +"testBai","testVai","stosb","stosVS", +"lodsb","lodsVS","scasb","scasVS", +--Bx +"movBRi","movBRi","movBRi","movBRi","movBRi","movBRi","movBRi","movBRi", +"movVRI","movVRI","movVRI","movVRI","movVRI","movVRI","movVRI","movVRI", +--Cx +"shift!Bmu","shift!Vmu","retBw","ret","$lesVrm","$ldsVrm","movBmi","movVmi", +"enterBwu","leave","retfBw","retf","int3","intBu","into","iretVS", +--Dx +"shift!Bm1","shift!Vm1","shift!Bmc","shift!Vmc","aamBu","aadBu","salc","xlatb", +"fp*0","fp*1","fp*2","fp*3","fp*4","fp*5","fp*6","fp*7", +--Ex +"loopneBj","loopeBj","loopBj","sz*jcxzBj,jecxzBj,jrcxzBj", +"inBau","inVau","outBua","outVua", +"callVj","jmpVj","jmp farViw","jmpBj","inBad","inVad","outBda","outVda", +--Fx +"lock:","int1","repne:rep","rep:","hlt","cmc","testb!Bm","testv!Vm", +"clc","stc","cli","sti","cld","std","incb!Bm","incd!Vm", +} +assert(#map_opc1_32 == 255) + +-- Map for 1st opcode byte in 64 bit mode (overrides only). +local map_opc1_64 = setmetatable({ + [0x06]=false, [0x07]=false, [0x0e]=false, + [0x16]=false, [0x17]=false, [0x1e]=false, [0x1f]=false, + [0x27]=false, [0x2f]=false, [0x37]=false, [0x3f]=false, + [0x60]=false, [0x61]=false, [0x62]=false, [0x63]="movsxdVrDmt", [0x67]="a32:", + [0x40]="rex*", [0x41]="rex*b", [0x42]="rex*x", [0x43]="rex*xb", + [0x44]="rex*r", [0x45]="rex*rb", [0x46]="rex*rx", [0x47]="rex*rxb", + [0x48]="rex*w", [0x49]="rex*wb", [0x4a]="rex*wx", [0x4b]="rex*wxb", + [0x4c]="rex*wr", [0x4d]="rex*wrb", [0x4e]="rex*wrx", [0x4f]="rex*wrxb", + [0x82]=false, [0x9a]=false, [0xc4]=false, [0xc5]=false, [0xce]=false, + [0xd4]=false, [0xd5]=false, [0xd6]=false, [0xea]=false, +}, { __index = map_opc1_32 }) + +-- Map for 2nd opcode byte (0F xx). True CISC hell. Hey, I told you. +-- Prefix dependent MMX/SSE opcodes: (none)|rep|o16|repne, -|F3|66|F2 +local map_opc2 = { +--0x +[0]="sldt!Dmp","sgdt!Ump","larVrm","lslVrm",nil,"syscall","clts","sysret", +"invd","wbinvd",nil,"ud1",nil,"$prefetch!Bm","femms","3dnowMrmu", +--1x +"movupsXrm|movssXrm|movupdXrm|movsdXrm", +"movupsXmr|movssXmr|movupdXmr|movsdXmr", +"movhlpsXrm$movlpsXrm|movsldupXrm|movlpdXrm|movddupXrm", +"movlpsXmr||movlpdXmr", +"unpcklpsXrm||unpcklpdXrm", +"unpckhpsXrm||unpckhpdXrm", +"movlhpsXrm$movhpsXrm|movshdupXrm|movhpdXrm", +"movhpsXmr||movhpdXmr", +"$prefetcht!Bm","hintnopVm","hintnopVm","hintnopVm", +"hintnopVm","hintnopVm","hintnopVm","hintnopVm", +--2x +"movUmx$","movUmy$","movUxm$","movUym$","movUmz$",nil,"movUzm$",nil, +"movapsXrm||movapdXrm", +"movapsXmr||movapdXmr", +"cvtpi2psXrMm|cvtsi2ssXrVmt|cvtpi2pdXrMm|cvtsi2sdXrVmt", +"movntpsXmr|movntssXmr|movntpdXmr|movntsdXmr", +"cvttps2piMrXm|cvttss2siVrXm|cvttpd2piMrXm|cvttsd2siVrXm", +"cvtps2piMrXm|cvtss2siVrXm|cvtpd2piMrXm|cvtsd2siVrXm", +"ucomissXrm||ucomisdXrm", +"comissXrm||comisdXrm", +--3x +"wrmsr","rdtsc","rdmsr","rdpmc","sysenter","sysexit",nil,"getsec", +"opc3*38",nil,"opc3*3a",nil,nil,nil,nil,nil, +--4x +"cmovoVrm","cmovnoVrm","cmovbVrm","cmovnbVrm", +"cmovzVrm","cmovnzVrm","cmovbeVrm","cmovaVrm", +"cmovsVrm","cmovnsVrm","cmovpeVrm","cmovpoVrm", +"cmovlVrm","cmovgeVrm","cmovleVrm","cmovgVrm", +--5x +"movmskpsVrXm$||movmskpdVrXm$","sqrtpsXrm|sqrtssXrm|sqrtpdXrm|sqrtsdXrm", +"rsqrtpsXrm|rsqrtssXrm","rcppsXrm|rcpssXrm", +"andpsXrm||andpdXrm","andnpsXrm||andnpdXrm", +"orpsXrm||orpdXrm","xorpsXrm||xorpdXrm", +"addpsXrm|addssXrm|addpdXrm|addsdXrm","mulpsXrm|mulssXrm|mulpdXrm|mulsdXrm", +"cvtps2pdXrm|cvtss2sdXrm|cvtpd2psXrm|cvtsd2ssXrm", +"cvtdq2psXrm|cvttps2dqXrm|cvtps2dqXrm", +"subpsXrm|subssXrm|subpdXrm|subsdXrm","minpsXrm|minssXrm|minpdXrm|minsdXrm", +"divpsXrm|divssXrm|divpdXrm|divsdXrm","maxpsXrm|maxssXrm|maxpdXrm|maxsdXrm", +--6x +"punpcklbwPrm","punpcklwdPrm","punpckldqPrm","packsswbPrm", +"pcmpgtbPrm","pcmpgtwPrm","pcmpgtdPrm","packuswbPrm", +"punpckhbwPrm","punpckhwdPrm","punpckhdqPrm","packssdwPrm", +"||punpcklqdqXrm","||punpckhqdqXrm", +"movPrVSm","movqMrm|movdquXrm|movdqaXrm", +--7x +"pshufwMrmu|pshufhwXrmu|pshufdXrmu|pshuflwXrmu","pshiftw!Pmu", +"pshiftd!Pmu","pshiftq!Mmu||pshiftdq!Xmu", +"pcmpeqbPrm","pcmpeqwPrm","pcmpeqdPrm","emms|", +"vmreadUmr||extrqXmuu$|insertqXrmuu$","vmwriteUrm||extrqXrm$|insertqXrm$", +nil,nil, +"||haddpdXrm|haddpsXrm","||hsubpdXrm|hsubpsXrm", +"movVSmMr|movqXrm|movVSmXr","movqMmr|movdquXmr|movdqaXmr", +--8x +"joVj","jnoVj","jbVj","jnbVj","jzVj","jnzVj","jbeVj","jaVj", +"jsVj","jnsVj","jpeVj","jpoVj","jlVj","jgeVj","jleVj","jgVj", +--9x +"setoBm","setnoBm","setbBm","setnbBm","setzBm","setnzBm","setbeBm","setaBm", +"setsBm","setnsBm","setpeBm","setpoBm","setlBm","setgeBm","setleBm","setgBm", +--Ax +"push fs","pop fs","cpuid","btVmr","shldVmru","shldVmrc",nil,nil, +"push gs","pop gs","rsm","btsVmr","shrdVmru","shrdVmrc","fxsave!Dmp","imulVrm", +--Bx +"cmpxchgBmr","cmpxchgVmr","$lssVrm","btrVmr", +"$lfsVrm","$lgsVrm","movzxVrBmt","movzxVrWmt", +"|popcntVrm","ud2Dp","bt!Vmu","btcVmr", +"bsfVrm","bsrVrm|lzcntVrm|bsrWrm","movsxVrBmt","movsxVrWmt", +--Cx +"xaddBmr","xaddVmr", +"cmppsXrmu|cmpssXrmu|cmppdXrmu|cmpsdXrmu","$movntiVmr|", +"pinsrwPrWmu","pextrwDrPmu", +"shufpsXrmu||shufpdXrmu","$cmpxchg!Qmp", +"bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR","bswapVR", +--Dx +"||addsubpdXrm|addsubpsXrm","psrlwPrm","psrldPrm","psrlqPrm", +"paddqPrm","pmullwPrm", +"|movq2dqXrMm|movqXmr|movdq2qMrXm$","pmovmskbVrMm||pmovmskbVrXm", +"psubusbPrm","psubuswPrm","pminubPrm","pandPrm", +"paddusbPrm","padduswPrm","pmaxubPrm","pandnPrm", +--Ex +"pavgbPrm","psrawPrm","psradPrm","pavgwPrm", +"pmulhuwPrm","pmulhwPrm", +"|cvtdq2pdXrm|cvttpd2dqXrm|cvtpd2dqXrm","$movntqMmr||$movntdqXmr", +"psubsbPrm","psubswPrm","pminswPrm","porPrm", +"paddsbPrm","paddswPrm","pmaxswPrm","pxorPrm", +--Fx +"|||lddquXrm","psllwPrm","pslldPrm","psllqPrm", +"pmuludqPrm","pmaddwdPrm","psadbwPrm","maskmovqMrm||maskmovdquXrm$", +"psubbPrm","psubwPrm","psubdPrm","psubqPrm", +"paddbPrm","paddwPrm","padddPrm","ud", +} +assert(map_opc2[255] == "ud") + +-- Map for three-byte opcodes. Can't wait for their next invention. +local map_opc3 = { +["38"] = { -- [66] 0f 38 xx +--0x +[0]="pshufbPrm","phaddwPrm","phadddPrm","phaddswPrm", +"pmaddubswPrm","phsubwPrm","phsubdPrm","phsubswPrm", +"psignbPrm","psignwPrm","psigndPrm","pmulhrswPrm", +nil,nil,nil,nil, +--1x +"||pblendvbXrma",nil,nil,nil, +"||blendvpsXrma","||blendvpdXrma",nil,"||ptestXrm", +nil,nil,nil,nil, +"pabsbPrm","pabswPrm","pabsdPrm",nil, +--2x +"||pmovsxbwXrm","||pmovsxbdXrm","||pmovsxbqXrm","||pmovsxwdXrm", +"||pmovsxwqXrm","||pmovsxdqXrm",nil,nil, +"||pmuldqXrm","||pcmpeqqXrm","||$movntdqaXrm","||packusdwXrm", +nil,nil,nil,nil, +--3x +"||pmovzxbwXrm","||pmovzxbdXrm","||pmovzxbqXrm","||pmovzxwdXrm", +"||pmovzxwqXrm","||pmovzxdqXrm",nil,"||pcmpgtqXrm", +"||pminsbXrm","||pminsdXrm","||pminuwXrm","||pminudXrm", +"||pmaxsbXrm","||pmaxsdXrm","||pmaxuwXrm","||pmaxudXrm", +--4x +"||pmulddXrm","||phminposuwXrm", +--Fx +[0xf0] = "|||crc32TrBmt",[0xf1] = "|||crc32TrVmt", +}, + +["3a"] = { -- [66] 0f 3a xx +--0x +[0x00]=nil,nil,nil,nil,nil,nil,nil,nil, +"||roundpsXrmu","||roundpdXrmu","||roundssXrmu","||roundsdXrmu", +"||blendpsXrmu","||blendpdXrmu","||pblendwXrmu","palignrPrmu", +--1x +nil,nil,nil,nil, +"||pextrbVmXru","||pextrwVmXru","||pextrVmSXru","||extractpsVmXru", +nil,nil,nil,nil,nil,nil,nil,nil, +--2x +"||pinsrbXrVmu","||insertpsXrmu","||pinsrXrVmuS",nil, +--4x +[0x40] = "||dppsXrmu", +[0x41] = "||dppdXrmu", +[0x42] = "||mpsadbwXrmu", +--6x +[0x60] = "||pcmpestrmXrmu",[0x61] = "||pcmpestriXrmu", +[0x62] = "||pcmpistrmXrmu",[0x63] = "||pcmpistriXrmu", +}, +} + +-- Map for VMX/SVM opcodes 0F 01 C0-FF (sgdt group with register operands). +local map_opcvm = { +[0xc1]="vmcall",[0xc2]="vmlaunch",[0xc3]="vmresume",[0xc4]="vmxoff", +[0xc8]="monitor",[0xc9]="mwait", +[0xd8]="vmrun",[0xd9]="vmmcall",[0xda]="vmload",[0xdb]="vmsave", +[0xdc]="stgi",[0xdd]="clgi",[0xde]="skinit",[0xdf]="invlpga", +[0xf8]="swapgs",[0xf9]="rdtscp", +} + +-- Map for FP opcodes. And you thought stack machines are simple? +local map_opcfp = { +-- D8-DF 00-BF: opcodes with a memory operand. +-- D8 +[0]="faddFm","fmulFm","fcomFm","fcompFm","fsubFm","fsubrFm","fdivFm","fdivrFm", +"fldFm",nil,"fstFm","fstpFm","fldenvVm","fldcwWm","fnstenvVm","fnstcwWm", +-- DA +"fiaddDm","fimulDm","ficomDm","ficompDm", +"fisubDm","fisubrDm","fidivDm","fidivrDm", +-- DB +"fildDm","fisttpDm","fistDm","fistpDm",nil,"fld twordFmp",nil,"fstp twordFmp", +-- DC +"faddGm","fmulGm","fcomGm","fcompGm","fsubGm","fsubrGm","fdivGm","fdivrGm", +-- DD +"fldGm","fisttpQm","fstGm","fstpGm","frstorDmp",nil,"fnsaveDmp","fnstswWm", +-- DE +"fiaddWm","fimulWm","ficomWm","ficompWm", +"fisubWm","fisubrWm","fidivWm","fidivrWm", +-- DF +"fildWm","fisttpWm","fistWm","fistpWm", +"fbld twordFmp","fildQm","fbstp twordFmp","fistpQm", +-- xx C0-FF: opcodes with a pseudo-register operand. +-- D8 +"faddFf","fmulFf","fcomFf","fcompFf","fsubFf","fsubrFf","fdivFf","fdivrFf", +-- D9 +"fldFf","fxchFf",{"fnop"},nil, +{"fchs","fabs",nil,nil,"ftst","fxam"}, +{"fld1","fldl2t","fldl2e","fldpi","fldlg2","fldln2","fldz"}, +{"f2xm1","fyl2x","fptan","fpatan","fxtract","fprem1","fdecstp","fincstp"}, +{"fprem","fyl2xp1","fsqrt","fsincos","frndint","fscale","fsin","fcos"}, +-- DA +"fcmovbFf","fcmoveFf","fcmovbeFf","fcmovuFf",nil,{nil,"fucompp"},nil,nil, +-- DB +"fcmovnbFf","fcmovneFf","fcmovnbeFf","fcmovnuFf", +{nil,nil,"fnclex","fninit"},"fucomiFf","fcomiFf",nil, +-- DC +"fadd toFf","fmul toFf",nil,nil, +"fsub toFf","fsubr toFf","fdivr toFf","fdiv toFf", +-- DD +"ffreeFf",nil,"fstFf","fstpFf","fucomFf","fucompFf",nil,nil, +-- DE +"faddpFf","fmulpFf",nil,{nil,"fcompp"}, +"fsubrpFf","fsubpFf","fdivrpFf","fdivpFf", +-- DF +nil,nil,nil,nil,{"fnstsw ax"},"fucomipFf","fcomipFf",nil, +} +assert(map_opcfp[126] == "fcomipFf") + +-- Map for opcode groups. The subkey is sp from the ModRM byte. +local map_opcgroup = { + arith = { "add", "or", "adc", "sbb", "and", "sub", "xor", "cmp" }, + shift = { "rol", "ror", "rcl", "rcr", "shl", "shr", "sal", "sar" }, + testb = { "testBmi", "testBmi", "not", "neg", "mul", "imul", "div", "idiv" }, + testv = { "testVmi", "testVmi", "not", "neg", "mul", "imul", "div", "idiv" }, + incb = { "inc", "dec" }, + incd = { "inc", "dec", "callUmp", "$call farDmp", + "jmpUmp", "$jmp farDmp", "pushUm" }, + sldt = { "sldt", "str", "lldt", "ltr", "verr", "verw" }, + sgdt = { "vm*$sgdt", "vm*$sidt", "$lgdt", "vm*$lidt", + "smsw", nil, "lmsw", "vm*$invlpg" }, + bt = { nil, nil, nil, nil, "bt", "bts", "btr", "btc" }, + cmpxchg = { nil, "sz*,cmpxchg8bQmp,cmpxchg16bXmp", nil, nil, + nil, nil, "vmptrld|vmxon|vmclear", "vmptrst" }, + pshiftw = { nil, nil, "psrlw", nil, "psraw", nil, "psllw" }, + pshiftd = { nil, nil, "psrld", nil, "psrad", nil, "pslld" }, + pshiftq = { nil, nil, "psrlq", nil, nil, nil, "psllq" }, + pshiftdq = { nil, nil, "psrlq", "psrldq", nil, nil, "psllq", "pslldq" }, + fxsave = { "$fxsave", "$fxrstor", "$ldmxcsr", "$stmxcsr", + nil, "lfenceDp$", "mfenceDp$", "sfenceDp$clflush" }, + prefetch = { "prefetch", "prefetchw" }, + prefetcht = { "prefetchnta", "prefetcht0", "prefetcht1", "prefetcht2" }, +} + +------------------------------------------------------------------------------ + +-- Maps for register names. +local map_regs = { + B = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh", + "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" }, + B64 = { "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil", + "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b" }, + W = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di", + "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w" }, + D = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", + "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" }, + Q = { "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" }, + M = { "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7", + "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7" }, -- No x64 ext! + X = { "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", + "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15" }, +} +local map_segregs = { "es", "cs", "ss", "ds", "fs", "gs", "segr6", "segr7" } + +-- Maps for size names. +local map_sz2n = { + B = 1, W = 2, D = 4, Q = 8, M = 8, X = 16, +} +local map_sz2prefix = { + B = "byte", W = "word", D = "dword", + Q = "qword", + M = "qword", X = "xword", + F = "dword", G = "qword", -- No need for sizes/register names for these two. +} + +------------------------------------------------------------------------------ + +-- Output a nicely formatted line with an opcode and operands. +local function putop(ctx, text, operands) + local code, pos, hex = ctx.code, ctx.pos, "" + local hmax = ctx.hexdump + if hmax > 0 then + for i=ctx.start,pos-1 do + hex = hex..format("%02X", byte(code, i, i)) + end + if #hex > hmax then hex = sub(hex, 1, hmax)..". " + else hex = hex..rep(" ", hmax-#hex+2) end + end + if operands then text = text.." "..operands end + if ctx.o16 then text = "o16 "..text; ctx.o16 = false end + if ctx.a32 then text = "a32 "..text; ctx.a32 = false end + if ctx.rep then text = ctx.rep.." "..text; ctx.rep = false end + if ctx.rex then + local t = (ctx.rexw and "w" or "")..(ctx.rexr and "r" or "").. + (ctx.rexx and "x" or "")..(ctx.rexb and "b" or "") + if t ~= "" then text = "rex."..t.." "..text end + ctx.rexw = false; ctx.rexr = false; ctx.rexx = false; ctx.rexb = false + ctx.rex = false + end + if ctx.seg then + local text2, n = gsub(text, "%[", "["..ctx.seg..":") + if n == 0 then text = ctx.seg.." "..text else text = text2 end + ctx.seg = false + end + if ctx.lock then text = "lock "..text; ctx.lock = false end + local imm = ctx.imm + if imm then + local sym = ctx.symtab[imm] + if sym then text = text.."\t->"..sym end + end + ctx.out(format("%08x %s%s\n", ctx.addr+ctx.start, hex, text)) + ctx.mrm = false + ctx.start = pos + ctx.imm = nil +end + +-- Clear all prefix flags. +local function clearprefixes(ctx) + ctx.o16 = false; ctx.seg = false; ctx.lock = false; ctx.rep = false + ctx.rexw = false; ctx.rexr = false; ctx.rexx = false; ctx.rexb = false + ctx.rex = false; ctx.a32 = false +end + +-- Fallback for incomplete opcodes at the end. +local function incomplete(ctx) + ctx.pos = ctx.stop+1 + clearprefixes(ctx) + return putop(ctx, "(incomplete)") +end + +-- Fallback for unknown opcodes. +local function unknown(ctx) + clearprefixes(ctx) + return putop(ctx, "(unknown)") +end + +-- Return an immediate of the specified size. +local function getimm(ctx, pos, n) + if pos+n-1 > ctx.stop then return incomplete(ctx) end + local code = ctx.code + if n == 1 then + local b1 = byte(code, pos, pos) + return b1 + elseif n == 2 then + local b1, b2 = byte(code, pos, pos+1) + return b1+b2*256 + else + local b1, b2, b3, b4 = byte(code, pos, pos+3) + local imm = b1+b2*256+b3*65536+b4*16777216 + ctx.imm = imm + return imm + end +end + +-- Process pattern string and generate the operands. +local function putpat(ctx, name, pat) + local operands, regs, sz, mode, sp, rm, sc, rx, sdisp + local code, pos, stop = ctx.code, ctx.pos, ctx.stop + + -- Chars used: 1DFGIMPQRSTUVWXacdfgijmoprstuwxyz + for p in gmatch(pat, ".") do + local x = nil + if p == "V" or p == "U" then + if ctx.rexw then sz = "Q"; ctx.rexw = false + elseif ctx.o16 then sz = "W"; ctx.o16 = false + elseif p == "U" and ctx.x64 then sz = "Q" + else sz = "D" end + regs = map_regs[sz] + elseif p == "T" then + if ctx.rexw then sz = "Q"; ctx.rexw = false else sz = "D" end + regs = map_regs[sz] + elseif p == "B" then + sz = "B" + regs = ctx.rex and map_regs.B64 or map_regs.B + elseif match(p, "[WDQMXFG]") then + sz = p + regs = map_regs[sz] + elseif p == "P" then + sz = ctx.o16 and "X" or "M"; ctx.o16 = false + regs = map_regs[sz] + elseif p == "S" then + name = name..lower(sz) + elseif p == "s" then + local imm = getimm(ctx, pos, 1); if not imm then return end + x = imm <= 127 and format("+0x%02x", imm) + or format("-0x%02x", 256-imm) + pos = pos+1 + elseif p == "u" then + local imm = getimm(ctx, pos, 1); if not imm then return end + x = format("0x%02x", imm) + pos = pos+1 + elseif p == "w" then + local imm = getimm(ctx, pos, 2); if not imm then return end + x = format("0x%x", imm) + pos = pos+2 + elseif p == "o" then -- [offset] + if ctx.x64 then + local imm1 = getimm(ctx, pos, 4); if not imm1 then return end + local imm2 = getimm(ctx, pos+4, 4); if not imm2 then return end + x = format("[0x%08x%08x]", imm2, imm1) + pos = pos+8 + else + local imm = getimm(ctx, pos, 4); if not imm then return end + x = format("[0x%08x]", imm) + pos = pos+4 + end + elseif p == "i" or p == "I" then + local n = map_sz2n[sz] + if n == 8 and ctx.x64 and p == "I" then + local imm1 = getimm(ctx, pos, 4); if not imm1 then return end + local imm2 = getimm(ctx, pos+4, 4); if not imm2 then return end + x = format("0x%08x%08x", imm2, imm1) + else + if n == 8 then n = 4 end + local imm = getimm(ctx, pos, n); if not imm then return end + if sz == "Q" and (imm < 0 or imm > 0x7fffffff) then + imm = (0xffffffff+1)-imm + x = format(imm > 65535 and "-0x%08x" or "-0x%x", imm) + else + x = format(imm > 65535 and "0x%08x" or "0x%x", imm) + end + end + pos = pos+n + elseif p == "j" then + local n = map_sz2n[sz] + if n == 8 then n = 4 end + local imm = getimm(ctx, pos, n); if not imm then return end + if sz == "B" and imm > 127 then imm = imm-256 + elseif imm > 2147483647 then imm = imm-4294967296 end + pos = pos+n + imm = imm + pos + ctx.addr + if imm > 4294967295 and not ctx.x64 then imm = imm-4294967296 end + ctx.imm = imm + if sz == "W" then + x = format("word 0x%04x", imm%65536) + elseif ctx.x64 then + local lo = imm % 0x1000000 + x = format("0x%02x%06x", (imm-lo) / 0x1000000, lo) + else + x = format("0x%08x", imm) + end + elseif p == "R" then + local r = byte(code, pos-1, pos-1)%8 + if ctx.rexb then r = r + 8; ctx.rexb = false end + x = regs[r+1] + elseif p == "a" then x = regs[1] + elseif p == "c" then x = "cl" + elseif p == "d" then x = "dx" + elseif p == "1" then x = "1" + else + if not mode then + mode = ctx.mrm + if not mode then + if pos > stop then return incomplete(ctx) end + mode = byte(code, pos, pos) + pos = pos+1 + end + rm = mode%8; mode = (mode-rm)/8 + sp = mode%8; mode = (mode-sp)/8 + sdisp = "" + if mode < 3 then + if rm == 4 then + if pos > stop then return incomplete(ctx) end + sc = byte(code, pos, pos) + pos = pos+1 + rm = sc%8; sc = (sc-rm)/8 + rx = sc%8; sc = (sc-rx)/8 + if ctx.rexx then rx = rx + 8; ctx.rexx = false end + if rx == 4 then rx = nil end + end + if mode > 0 or rm == 5 then + local dsz = mode + if dsz ~= 1 then dsz = 4 end + local disp = getimm(ctx, pos, dsz); if not disp then return end + if mode == 0 then rm = nil end + if rm or rx or (not sc and ctx.x64 and not ctx.a32) then + if dsz == 1 and disp > 127 then + sdisp = format("-0x%x", 256-disp) + elseif disp >= 0 and disp <= 0x7fffffff then + sdisp = format("+0x%x", disp) + else + sdisp = format("-0x%x", (0xffffffff+1)-disp) + end + else + sdisp = format(ctx.x64 and not ctx.a32 and + not (disp >= 0 and disp <= 0x7fffffff) + and "0xffffffff%08x" or "0x%08x", disp) + end + pos = pos+dsz + end + end + if rm and ctx.rexb then rm = rm + 8; ctx.rexb = false end + if ctx.rexr then sp = sp + 8; ctx.rexr = false end + end + if p == "m" then + if mode == 3 then x = regs[rm+1] + else + local aregs = ctx.a32 and map_regs.D or ctx.aregs + local srm, srx = "", "" + if rm then srm = aregs[rm+1] + elseif not sc and ctx.x64 and not ctx.a32 then srm = "rip" end + ctx.a32 = false + if rx then + if rm then srm = srm.."+" end + srx = aregs[rx+1] + if sc > 0 then srx = srx.."*"..(2^sc) end + end + x = format("[%s%s%s]", srm, srx, sdisp) + end + if mode < 3 and + (not match(pat, "[aRrgp]") or match(pat, "t")) then -- Yuck. + x = map_sz2prefix[sz].." "..x + end + elseif p == "r" then x = regs[sp+1] + elseif p == "g" then x = map_segregs[sp+1] + elseif p == "p" then -- Suppress prefix. + elseif p == "f" then x = "st"..rm + elseif p == "x" then + if sp == 0 and ctx.lock and not ctx.x64 then + x = "CR8"; ctx.lock = false + else + x = "CR"..sp + end + elseif p == "y" then x = "DR"..sp + elseif p == "z" then x = "TR"..sp + elseif p == "t" then + else + error("bad pattern `"..pat.."'") + end + end + if x then operands = operands and operands..", "..x or x end + end + ctx.pos = pos + return putop(ctx, name, operands) +end + +-- Forward declaration. +local map_act + +-- Fetch and cache MRM byte. +local function getmrm(ctx) + local mrm = ctx.mrm + if not mrm then + local pos = ctx.pos + if pos > ctx.stop then return nil end + mrm = byte(ctx.code, pos, pos) + ctx.pos = pos+1 + ctx.mrm = mrm + end + return mrm +end + +-- Dispatch to handler depending on pattern. +local function dispatch(ctx, opat, patgrp) + if not opat then return unknown(ctx) end + if match(opat, "%|") then -- MMX/SSE variants depending on prefix. + local p + if ctx.rep then + p = ctx.rep=="rep" and "%|([^%|]*)" or "%|[^%|]*%|[^%|]*%|([^%|]*)" + ctx.rep = false + elseif ctx.o16 then p = "%|[^%|]*%|([^%|]*)"; ctx.o16 = false + else p = "^[^%|]*" end + opat = match(opat, p) + if not opat then return unknown(ctx) end +-- ctx.rep = false; ctx.o16 = false + --XXX fails for 66 f2 0f 38 f1 06 crc32 eax,WORD PTR [esi] + --XXX remove in branches? + end + if match(opat, "%$") then -- reg$mem variants. + local mrm = getmrm(ctx); if not mrm then return incomplete(ctx) end + opat = match(opat, mrm >= 192 and "^[^%$]*" or "%$(.*)") + if opat == "" then return unknown(ctx) end + end + if opat == "" then return unknown(ctx) end + local name, pat = match(opat, "^([a-z0-9 ]*)(.*)") + if pat == "" and patgrp then pat = patgrp end + return map_act[sub(pat, 1, 1)](ctx, name, pat) +end + +-- Get a pattern from an opcode map and dispatch to handler. +local function dispatchmap(ctx, opcmap) + local pos = ctx.pos + local opat = opcmap[byte(ctx.code, pos, pos)] + pos = pos + 1 + ctx.pos = pos + return dispatch(ctx, opat) +end + +-- Map for action codes. The key is the first char after the name. +map_act = { + -- Simple opcodes without operands. + [""] = function(ctx, name, pat) + return putop(ctx, name) + end, + + -- Operand size chars fall right through. + B = putpat, W = putpat, D = putpat, Q = putpat, + V = putpat, U = putpat, T = putpat, + M = putpat, X = putpat, P = putpat, + F = putpat, G = putpat, + + -- Collect prefixes. + [":"] = function(ctx, name, pat) + ctx[pat == ":" and name or sub(pat, 2)] = name + if ctx.pos - ctx.start > 5 then return unknown(ctx) end -- Limit #prefixes. + end, + + -- Chain to special handler specified by name. + ["*"] = function(ctx, name, pat) + return map_act[name](ctx, name, sub(pat, 2)) + end, + + -- Use named subtable for opcode group. + ["!"] = function(ctx, name, pat) + local mrm = getmrm(ctx); if not mrm then return incomplete(ctx) end + return dispatch(ctx, map_opcgroup[name][((mrm-(mrm%8))/8)%8+1], sub(pat, 2)) + end, + + -- o16,o32[,o64] variants. + sz = function(ctx, name, pat) + if ctx.o16 then ctx.o16 = false + else + pat = match(pat, ",(.*)") + if ctx.rexw then + local p = match(pat, ",(.*)") + if p then pat = p; ctx.rexw = false end + end + end + pat = match(pat, "^[^,]*") + return dispatch(ctx, pat) + end, + + -- Two-byte opcode dispatch. + opc2 = function(ctx, name, pat) + return dispatchmap(ctx, map_opc2) + end, + + -- Three-byte opcode dispatch. + opc3 = function(ctx, name, pat) + return dispatchmap(ctx, map_opc3[pat]) + end, + + -- VMX/SVM dispatch. + vm = function(ctx, name, pat) + return dispatch(ctx, map_opcvm[ctx.mrm]) + end, + + -- Floating point opcode dispatch. + fp = function(ctx, name, pat) + local mrm = getmrm(ctx); if not mrm then return incomplete(ctx) end + local rm = mrm%8 + local idx = pat*8 + ((mrm-rm)/8)%8 + if mrm >= 192 then idx = idx + 64 end + local opat = map_opcfp[idx] + if type(opat) == "table" then opat = opat[rm+1] end + return dispatch(ctx, opat) + end, + + -- REX prefix. + rex = function(ctx, name, pat) + if ctx.rex then return unknown(ctx) end -- Only 1 REX prefix allowed. + for p in gmatch(pat, ".") do ctx["rex"..p] = true end + ctx.rex = true + end, + + -- Special case for nop with REX prefix. + nop = function(ctx, name, pat) + return dispatch(ctx, ctx.rex and pat or "nop") + end, +} + +------------------------------------------------------------------------------ + +-- Disassemble a block of code. +local function disass_block(ctx, ofs, len) + if not ofs then ofs = 0 end + local stop = len and ofs+len or #ctx.code + ofs = ofs + 1 + ctx.start = ofs + ctx.pos = ofs + ctx.stop = stop + ctx.imm = nil + ctx.mrm = false + clearprefixes(ctx) + while ctx.pos <= stop do dispatchmap(ctx, ctx.map1) end + if ctx.pos ~= ctx.start then incomplete(ctx) end +end + +-- Extended API: create a disassembler context. Then call ctx:disass(ofs, len). +local function create_(code, addr, out) + local ctx = {} + ctx.code = code + ctx.addr = (addr or 0) - 1 + ctx.out = out or io.write + ctx.symtab = {} + ctx.disass = disass_block + ctx.hexdump = 16 + ctx.x64 = false + ctx.map1 = map_opc1_32 + ctx.aregs = map_regs.D + return ctx +end + +local function create64_(code, addr, out) + local ctx = create_(code, addr, out) + ctx.x64 = true + ctx.map1 = map_opc1_64 + ctx.aregs = map_regs.Q + return ctx +end + +-- Simple API: disassemble code (a string) at address and output via out. +local function disass_(code, addr, out) + create_(code, addr, out):disass() +end + +local function disass64_(code, addr, out) + create64_(code, addr, out):disass() +end + +-- Return register name for RID. +local function regname_(r) + if r < 8 then return map_regs.D[r+1] end + return map_regs.X[r-7] +end + +local function regname64_(r) + if r < 16 then return map_regs.Q[r+1] end + return map_regs.X[r-15] +end + +-- Public module functions. +module(...) + +create = create_ +create64 = create64_ +disass = disass_ +disass64 = disass64_ +regname = regname_ +regname64 = regname64_ + diff --git a/LuaJIT-2.0.4/lua/jit/dump.lua b/LuaJIT-2.0.4/lua/jit/dump.lua new file mode 100644 index 000000000..d15c528ea --- /dev/null +++ b/LuaJIT-2.0.4/lua/jit/dump.lua @@ -0,0 +1,699 @@ +---------------------------------------------------------------------------- +-- LuaJIT compiler dump module. +-- +-- Copyright (C) 2005-2015 Mike Pall. All rights reserved. +-- Released under the MIT license. See Copyright Notice in luajit.h +---------------------------------------------------------------------------- +-- +-- This module can be used to debug the JIT compiler itself. It dumps the +-- code representations and structures used in various compiler stages. +-- +-- Example usage: +-- +-- luajit -jdump -e "local x=0; for i=1,1e6 do x=x+i end; print(x)" +-- luajit -jdump=im -e "for i=1,1000 do for j=1,1000 do end end" | less -R +-- luajit -jdump=is myapp.lua | less -R +-- luajit -jdump=-b myapp.lua +-- luajit -jdump=+aH,myapp.html myapp.lua +-- luajit -jdump=ixT,myapp.dump myapp.lua +-- +-- The first argument specifies the dump mode. The second argument gives +-- the output file name. Default output is to stdout, unless the environment +-- variable LUAJIT_DUMPFILE is set. The file is overwritten every time the +-- module is started. +-- +-- Different features can be turned on or off with the dump mode. If the +-- mode starts with a '+', the following features are added to the default +-- set of features; a '-' removes them. Otherwise the features are replaced. +-- +-- The following dump features are available (* marks the default): +-- +-- * t Print a line for each started, ended or aborted trace (see also -jv). +-- * b Dump the traced bytecode. +-- * i Dump the IR (intermediate representation). +-- r Augment the IR with register/stack slots. +-- s Dump the snapshot map. +-- * m Dump the generated machine code. +-- x Print each taken trace exit. +-- X Print each taken trace exit and the contents of all registers. +-- a Print the IR of aborted traces, too. +-- +-- The output format can be set with the following characters: +-- +-- T Plain text output. +-- A ANSI-colored text output +-- H Colorized HTML + CSS output. +-- +-- The default output format is plain text. It's set to ANSI-colored text +-- if the COLORTERM variable is set. Note: this is independent of any output +-- redirection, which is actually considered a feature. +-- +-- You probably want to use less -R to enjoy viewing ANSI-colored text from +-- a pipe or a file. Add this to your ~/.bashrc: export LESS="-R" +-- +------------------------------------------------------------------------------ + +-- Cache some library functions and objects. +local jit = require("jit") +assert(jit.version_num == 20004, "LuaJIT core/library version mismatch") +local jutil = require("jit.util") +local vmdef = require("jit.vmdef") +local funcinfo, funcbc = jutil.funcinfo, jutil.funcbc +local traceinfo, traceir, tracek = jutil.traceinfo, jutil.traceir, jutil.tracek +local tracemc, tracesnap = jutil.tracemc, jutil.tracesnap +local traceexitstub, ircalladdr = jutil.traceexitstub, jutil.ircalladdr +local bit = require("bit") +local band, shl, shr = bit.band, bit.lshift, bit.rshift +local sub, gsub, format = string.sub, string.gsub, string.format +local byte, char, rep = string.byte, string.char, string.rep +local type, tostring = type, tostring +local stdout, stderr = io.stdout, io.stderr + +-- Load other modules on-demand. +local bcline, disass + +-- Active flag, output file handle and dump mode. +local active, out, dumpmode + +------------------------------------------------------------------------------ + +local symtabmt = { __index = false } +local symtab = {} +local nexitsym = 0 + +-- Fill nested symbol table with per-trace exit stub addresses. +local function fillsymtab_tr(tr, nexit) + local t = {} + symtabmt.__index = t + if jit.arch == "mips" or jit.arch == "mipsel" then + t[traceexitstub(tr, 0)] = "exit" + return + end + for i=0,nexit-1 do + local addr = traceexitstub(tr, i) + t[addr] = tostring(i) + end + local addr = traceexitstub(tr, nexit) + if addr then t[addr] = "stack_check" end +end + +-- Fill symbol table with trace exit stub addresses. +local function fillsymtab(tr, nexit) + local t = symtab + if nexitsym == 0 then + local ircall = vmdef.ircall + for i=0,#ircall do + local addr = ircalladdr(i) + if addr ~= 0 then t[addr] = ircall[i] end + end + end + if nexitsym == 1000000 then -- Per-trace exit stubs. + fillsymtab_tr(tr, nexit) + elseif nexit > nexitsym then -- Shared exit stubs. + for i=nexitsym,nexit-1 do + local addr = traceexitstub(i) + if addr == nil then -- Fall back to per-trace exit stubs. + fillsymtab_tr(tr, nexit) + setmetatable(symtab, symtabmt) + nexit = 1000000 + break + end + t[addr] = tostring(i) + end + nexitsym = nexit + end + return t +end + +local function dumpwrite(s) + out:write(s) +end + +-- Disassemble machine code. +local function dump_mcode(tr) + local info = traceinfo(tr) + if not info then return end + local mcode, addr, loop = tracemc(tr) + if not mcode then return end + if not disass then disass = require("jit.dis_"..jit.arch) end + out:write("---- TRACE ", tr, " mcode ", #mcode, "\n") + local ctx = disass.create(mcode, addr, dumpwrite) + ctx.hexdump = 0 + ctx.symtab = fillsymtab(tr, info.nexit) + if loop ~= 0 then + symtab[addr+loop] = "LOOP" + ctx:disass(0, loop) + out:write("->LOOP:\n") + ctx:disass(loop, #mcode-loop) + symtab[addr+loop] = nil + else + ctx:disass(0, #mcode) + end +end + +------------------------------------------------------------------------------ + +local irtype_text = { + [0] = "nil", + "fal", + "tru", + "lud", + "str", + "p32", + "thr", + "pro", + "fun", + "p64", + "cdt", + "tab", + "udt", + "flt", + "num", + "i8 ", + "u8 ", + "i16", + "u16", + "int", + "u32", + "i64", + "u64", + "sfp", +} + +local colortype_ansi = { + [0] = "%s", + "%s", + "%s", + "\027[36m%s\027[m", + "\027[32m%s\027[m", + "%s", + "\027[1m%s\027[m", + "%s", + "\027[1m%s\027[m", + "%s", + "\027[33m%s\027[m", + "\027[31m%s\027[m", + "\027[36m%s\027[m", + "\027[34m%s\027[m", + "\027[34m%s\027[m", + "\027[35m%s\027[m", + "\027[35m%s\027[m", + "\027[35m%s\027[m", + "\027[35m%s\027[m", + "\027[35m%s\027[m", + "\027[35m%s\027[m", + "\027[35m%s\027[m", + "\027[35m%s\027[m", + "\027[35m%s\027[m", +} + +local function colorize_text(s, t) + return s +end + +local function colorize_ansi(s, t) + return format(colortype_ansi[t], s) +end + +local irtype_ansi = setmetatable({}, + { __index = function(tab, t) + local s = colorize_ansi(irtype_text[t], t); tab[t] = s; return s; end }) + +local html_escape = { ["<"] = "<", [">"] = ">", ["&"] = "&", } + +local function colorize_html(s, t) + s = gsub(s, "[<>&]", html_escape) + return format('%s', irtype_text[t], s) +end + +local irtype_html = setmetatable({}, + { __index = function(tab, t) + local s = colorize_html(irtype_text[t], t); tab[t] = s; return s; end }) + +local header_html = [[ + +]] + +local colorize, irtype + +-- Lookup tables to convert some literals into names. +local litname = { + ["SLOAD "] = setmetatable({}, { __index = function(t, mode) + local s = "" + if band(mode, 1) ~= 0 then s = s.."P" end + if band(mode, 2) ~= 0 then s = s.."F" end + if band(mode, 4) ~= 0 then s = s.."T" end + if band(mode, 8) ~= 0 then s = s.."C" end + if band(mode, 16) ~= 0 then s = s.."R" end + if band(mode, 32) ~= 0 then s = s.."I" end + t[mode] = s + return s + end}), + ["XLOAD "] = { [0] = "", "R", "V", "RV", "U", "RU", "VU", "RVU", }, + ["CONV "] = setmetatable({}, { __index = function(t, mode) + local s = irtype[band(mode, 31)] + s = irtype[band(shr(mode, 5), 31)].."."..s + if band(mode, 0x400) ~= 0 then s = s.." trunc" + elseif band(mode, 0x800) ~= 0 then s = s.." sext" end + local c = shr(mode, 14) + if c == 2 then s = s.." index" elseif c == 3 then s = s.." check" end + t[mode] = s + return s + end}), + ["FLOAD "] = vmdef.irfield, + ["FREF "] = vmdef.irfield, + ["FPMATH"] = vmdef.irfpm, +} + +local function ctlsub(c) + if c == "\n" then return "\\n" + elseif c == "\r" then return "\\r" + elseif c == "\t" then return "\\t" + else return format("\\%03d", byte(c)) + end +end + +local function fmtfunc(func, pc) + local fi = funcinfo(func, pc) + if fi.loc then + return fi.loc + elseif fi.ffid then + return vmdef.ffnames[fi.ffid] + elseif fi.addr then + return format("C:%x", fi.addr) + else + return "(?)" + end +end + +local function formatk(tr, idx) + local k, t, slot = tracek(tr, idx) + local tn = type(k) + local s + if tn == "number" then + if k == 2^52+2^51 then + s = "bias" + else + s = format("%+.14g", k) + end + elseif tn == "string" then + s = format(#k > 20 and '"%.20s"~' or '"%s"', gsub(k, "%c", ctlsub)) + elseif tn == "function" then + s = fmtfunc(k) + elseif tn == "table" then + s = format("{%p}", k) + elseif tn == "userdata" then + if t == 12 then + s = format("userdata:%p", k) + else + s = format("[%p]", k) + if s == "[0x00000000]" then s = "NULL" end + end + elseif t == 21 then -- int64_t + s = sub(tostring(k), 1, -3) + if sub(s, 1, 1) ~= "-" then s = "+"..s end + else + s = tostring(k) -- For primitives. + end + s = colorize(format("%-4s", s), t) + if slot then + s = format("%s @%d", s, slot) + end + return s +end + +local function printsnap(tr, snap) + local n = 2 + for s=0,snap[1]-1 do + local sn = snap[n] + if shr(sn, 24) == s then + n = n + 1 + local ref = band(sn, 0xffff) - 0x8000 -- REF_BIAS + if ref < 0 then + out:write(formatk(tr, ref)) + elseif band(sn, 0x80000) ~= 0 then -- SNAP_SOFTFPNUM + out:write(colorize(format("%04d/%04d", ref, ref+1), 14)) + else + local m, ot, op1, op2 = traceir(tr, ref) + out:write(colorize(format("%04d", ref), band(ot, 31))) + end + out:write(band(sn, 0x10000) == 0 and " " or "|") -- SNAP_FRAME + else + out:write("---- ") + end + end + out:write("]\n") +end + +-- Dump snapshots (not interleaved with IR). +local function dump_snap(tr) + out:write("---- TRACE ", tr, " snapshots\n") + for i=0,1000000000 do + local snap = tracesnap(tr, i) + if not snap then break end + out:write(format("#%-3d %04d [ ", i, snap[0])) + printsnap(tr, snap) + end +end + +-- Return a register name or stack slot for a rid/sp location. +local function ridsp_name(ridsp, ins) + if not disass then disass = require("jit.dis_"..jit.arch) end + local rid, slot = band(ridsp, 0xff), shr(ridsp, 8) + if rid == 253 or rid == 254 then + return (slot == 0 or slot == 255) and " {sink" or format(" {%04d", ins-slot) + end + if ridsp > 255 then return format("[%x]", slot*4) end + if rid < 128 then return disass.regname(rid) end + return "" +end + +-- Dump CALL* function ref and return optional ctype. +local function dumpcallfunc(tr, ins) + local ctype + if ins > 0 then + local m, ot, op1, op2 = traceir(tr, ins) + if band(ot, 31) == 0 then -- nil type means CARG(func, ctype). + ins = op1 + ctype = formatk(tr, op2) + end + end + if ins < 0 then + out:write(format("[0x%x](", tonumber((tracek(tr, ins))))) + else + out:write(format("%04d (", ins)) + end + return ctype +end + +-- Recursively gather CALL* args and dump them. +local function dumpcallargs(tr, ins) + if ins < 0 then + out:write(formatk(tr, ins)) + else + local m, ot, op1, op2 = traceir(tr, ins) + local oidx = 6*shr(ot, 8) + local op = sub(vmdef.irnames, oidx+1, oidx+6) + if op == "CARG " then + dumpcallargs(tr, op1) + if op2 < 0 then + out:write(" ", formatk(tr, op2)) + else + out:write(" ", format("%04d", op2)) + end + else + out:write(format("%04d", ins)) + end + end +end + +-- Dump IR and interleaved snapshots. +local function dump_ir(tr, dumpsnap, dumpreg) + local info = traceinfo(tr) + if not info then return end + local nins = info.nins + out:write("---- TRACE ", tr, " IR\n") + local irnames = vmdef.irnames + local snapref = 65536 + local snap, snapno + if dumpsnap then + snap = tracesnap(tr, 0) + snapref = snap[0] + snapno = 0 + end + for ins=1,nins do + if ins >= snapref then + if dumpreg then + out:write(format(".... SNAP #%-3d [ ", snapno)) + else + out:write(format(".... SNAP #%-3d [ ", snapno)) + end + printsnap(tr, snap) + snapno = snapno + 1 + snap = tracesnap(tr, snapno) + snapref = snap and snap[0] or 65536 + end + local m, ot, op1, op2, ridsp = traceir(tr, ins) + local oidx, t = 6*shr(ot, 8), band(ot, 31) + local op = sub(irnames, oidx+1, oidx+6) + if op == "LOOP " then + if dumpreg then + out:write(format("%04d ------------ LOOP ------------\n", ins)) + else + out:write(format("%04d ------ LOOP ------------\n", ins)) + end + elseif op ~= "NOP " and op ~= "CARG " and + (dumpreg or op ~= "RENAME") then + local rid = band(ridsp, 255) + if dumpreg then + out:write(format("%04d %-6s", ins, ridsp_name(ridsp, ins))) + else + out:write(format("%04d ", ins)) + end + out:write(format("%s%s %s %s ", + (rid == 254 or rid == 253) and "}" or + (band(ot, 128) == 0 and " " or ">"), + band(ot, 64) == 0 and " " or "+", + irtype[t], op)) + local m1, m2 = band(m, 3), band(m, 3*4) + if sub(op, 1, 4) == "CALL" then + local ctype + if m2 == 1*4 then -- op2 == IRMlit + out:write(format("%-10s (", vmdef.ircall[op2])) + else + ctype = dumpcallfunc(tr, op2) + end + if op1 ~= -1 then dumpcallargs(tr, op1) end + out:write(")") + if ctype then out:write(" ctype ", ctype) end + elseif op == "CNEW " and op2 == -1 then + out:write(formatk(tr, op1)) + elseif m1 ~= 3 then -- op1 != IRMnone + if op1 < 0 then + out:write(formatk(tr, op1)) + else + out:write(format(m1 == 0 and "%04d" or "#%-3d", op1)) + end + if m2 ~= 3*4 then -- op2 != IRMnone + if m2 == 1*4 then -- op2 == IRMlit + local litn = litname[op] + if litn and litn[op2] then + out:write(" ", litn[op2]) + elseif op == "UREFO " or op == "UREFC " then + out:write(format(" #%-3d", shr(op2, 8))) + else + out:write(format(" #%-3d", op2)) + end + elseif op2 < 0 then + out:write(" ", formatk(tr, op2)) + else + out:write(format(" %04d", op2)) + end + end + end + out:write("\n") + end + end + if snap then + if dumpreg then + out:write(format(".... SNAP #%-3d [ ", snapno)) + else + out:write(format(".... SNAP #%-3d [ ", snapno)) + end + printsnap(tr, snap) + end +end + +------------------------------------------------------------------------------ + +local recprefix = "" +local recdepth = 0 + +-- Format trace error message. +local function fmterr(err, info) + if type(err) == "number" then + if type(info) == "function" then info = fmtfunc(info) end + err = format(vmdef.traceerr[err], info) + end + return err +end + +-- Dump trace states. +local function dump_trace(what, tr, func, pc, otr, oex) + if what == "stop" or (what == "abort" and dumpmode.a) then + if dumpmode.i then dump_ir(tr, dumpmode.s, dumpmode.r and what == "stop") + elseif dumpmode.s then dump_snap(tr) end + if dumpmode.m then dump_mcode(tr) end + end + if what == "start" then + if dumpmode.H then out:write('
\n') end
+    out:write("---- TRACE ", tr, " ", what)
+    if otr then out:write(" ", otr, "/", oex) end
+    out:write(" ", fmtfunc(func, pc), "\n")
+  elseif what == "stop" or what == "abort" then
+    out:write("---- TRACE ", tr, " ", what)
+    if what == "abort" then
+      out:write(" ", fmtfunc(func, pc), " -- ", fmterr(otr, oex), "\n")
+    else
+      local info = traceinfo(tr)
+      local link, ltype = info.link, info.linktype
+      if link == tr or link == 0 then
+	out:write(" -> ", ltype, "\n")
+      elseif ltype == "root" then
+	out:write(" -> ", link, "\n")
+      else
+	out:write(" -> ", link, " ", ltype, "\n")
+      end
+    end
+    if dumpmode.H then out:write("
\n\n") else out:write("\n") end + else + out:write("---- TRACE ", what, "\n\n") + end + out:flush() +end + +-- Dump recorded bytecode. +local function dump_record(tr, func, pc, depth, callee) + if depth ~= recdepth then + recdepth = depth + recprefix = rep(" .", depth) + end + local line + if pc >= 0 then + line = bcline(func, pc, recprefix) + if dumpmode.H then line = gsub(line, "[<>&]", html_escape) end + else + line = "0000 "..recprefix.." FUNCC \n" + callee = func + end + if pc <= 0 then + out:write(sub(line, 1, -2), " ; ", fmtfunc(func), "\n") + else + out:write(line) + end + if pc >= 0 and band(funcbc(func, pc), 0xff) < 16 then -- ORDER BC + out:write(bcline(func, pc+1, recprefix)) -- Write JMP for cond. + end +end + +------------------------------------------------------------------------------ + +-- Dump taken trace exits. +local function dump_texit(tr, ex, ngpr, nfpr, ...) + out:write("---- TRACE ", tr, " exit ", ex, "\n") + if dumpmode.X then + local regs = {...} + if jit.arch == "x64" then + for i=1,ngpr do + out:write(format(" %016x", regs[i])) + if i % 4 == 0 then out:write("\n") end + end + else + for i=1,ngpr do + out:write(format(" %08x", regs[i])) + if i % 8 == 0 then out:write("\n") end + end + end + if jit.arch == "mips" or jit.arch == "mipsel" then + for i=1,nfpr,2 do + out:write(format(" %+17.14g", regs[ngpr+i])) + if i % 8 == 7 then out:write("\n") end + end + else + for i=1,nfpr do + out:write(format(" %+17.14g", regs[ngpr+i])) + if i % 4 == 0 then out:write("\n") end + end + end + end +end + +------------------------------------------------------------------------------ + +-- Detach dump handlers. +local function dumpoff() + if active then + active = false + jit.attach(dump_texit) + jit.attach(dump_record) + jit.attach(dump_trace) + if out and out ~= stdout and out ~= stderr then out:close() end + out = nil + end +end + +-- Open the output file and attach dump handlers. +local function dumpon(opt, outfile) + if active then dumpoff() end + + local colormode = os.getenv("COLORTERM") and "A" or "T" + if opt then + opt = gsub(opt, "[TAH]", function(mode) colormode = mode; return ""; end) + end + + local m = { t=true, b=true, i=true, m=true, } + if opt and opt ~= "" then + local o = sub(opt, 1, 1) + if o ~= "+" and o ~= "-" then m = {} end + for i=1,#opt do m[sub(opt, i, i)] = (o ~= "-") end + end + dumpmode = m + + if m.t or m.b or m.i or m.s or m.m then + jit.attach(dump_trace, "trace") + end + if m.b then + jit.attach(dump_record, "record") + if not bcline then bcline = require("jit.bc").line end + end + if m.x or m.X then + jit.attach(dump_texit, "texit") + end + + if not outfile then outfile = os.getenv("LUAJIT_DUMPFILE") end + if outfile then + out = outfile == "-" and stdout or assert(io.open(outfile, "w")) + else + out = stdout + end + + m[colormode] = true + if colormode == "A" then + colorize = colorize_ansi + irtype = irtype_ansi + elseif colormode == "H" then + colorize = colorize_html + irtype = irtype_html + out:write(header_html) + else + colorize = colorize_text + irtype = irtype_text + end + + active = true +end + +-- Public module functions. +module(...) + +on = dumpon +off = dumpoff +start = dumpon -- For -j command line option. + diff --git a/LuaJIT-2.0.4/lua/jit/v.lua b/LuaJIT-2.0.4/lua/jit/v.lua new file mode 100644 index 000000000..32666fd1a --- /dev/null +++ b/LuaJIT-2.0.4/lua/jit/v.lua @@ -0,0 +1,167 @@ +---------------------------------------------------------------------------- +-- Verbose mode of the LuaJIT compiler. +-- +-- Copyright (C) 2005-2015 Mike Pall. All rights reserved. +-- Released under the MIT license. See Copyright Notice in luajit.h +---------------------------------------------------------------------------- +-- +-- This module shows verbose information about the progress of the +-- JIT compiler. It prints one line for each generated trace. This module +-- is useful to see which code has been compiled or where the compiler +-- punts and falls back to the interpreter. +-- +-- Example usage: +-- +-- luajit -jv -e "for i=1,1000 do for j=1,1000 do end end" +-- luajit -jv=myapp.out myapp.lua +-- +-- Default output is to stderr. To redirect the output to a file, pass a +-- filename as an argument (use '-' for stdout) or set the environment +-- variable LUAJIT_VERBOSEFILE. The file is overwritten every time the +-- module is started. +-- +-- The output from the first example should look like this: +-- +-- [TRACE 1 (command line):1 loop] +-- [TRACE 2 (1/3) (command line):1 -> 1] +-- +-- The first number in each line is the internal trace number. Next are +-- the file name ('(command line)') and the line number (':1') where the +-- trace has started. Side traces also show the parent trace number and +-- the exit number where they are attached to in parentheses ('(1/3)'). +-- An arrow at the end shows where the trace links to ('-> 1'), unless +-- it loops to itself. +-- +-- In this case the inner loop gets hot and is traced first, generating +-- a root trace. Then the last exit from the 1st trace gets hot, too, +-- and triggers generation of the 2nd trace. The side trace follows the +-- path along the outer loop and *around* the inner loop, back to its +-- start, and then links to the 1st trace. Yes, this may seem unusual, +-- if you know how traditional compilers work. Trace compilers are full +-- of surprises like this -- have fun! :-) +-- +-- Aborted traces are shown like this: +-- +-- [TRACE --- foo.lua:44 -- leaving loop in root trace at foo:lua:50] +-- +-- Don't worry -- trace aborts are quite common, even in programs which +-- can be fully compiled. The compiler may retry several times until it +-- finds a suitable trace. +-- +-- Of course this doesn't work with features that are not-yet-implemented +-- (NYI error messages). The VM simply falls back to the interpreter. This +-- may not matter at all if the particular trace is not very high up in +-- the CPU usage profile. Oh, and the interpreter is quite fast, too. +-- +-- Also check out the -jdump module, which prints all the gory details. +-- +------------------------------------------------------------------------------ + +-- Cache some library functions and objects. +local jit = require("jit") +assert(jit.version_num == 20004, "LuaJIT core/library version mismatch") +local jutil = require("jit.util") +local vmdef = require("jit.vmdef") +local funcinfo, traceinfo = jutil.funcinfo, jutil.traceinfo +local type, format = type, string.format +local stdout, stderr = io.stdout, io.stderr + +-- Active flag and output file handle. +local active, out + +------------------------------------------------------------------------------ + +local startloc, startex + +local function fmtfunc(func, pc) + local fi = funcinfo(func, pc) + if fi.loc then + return fi.loc + elseif fi.ffid then + return vmdef.ffnames[fi.ffid] + elseif fi.addr then + return format("C:%x", fi.addr) + else + return "(?)" + end +end + +-- Format trace error message. +local function fmterr(err, info) + if type(err) == "number" then + if type(info) == "function" then info = fmtfunc(info) end + err = format(vmdef.traceerr[err], info) + end + return err +end + +-- Dump trace states. +local function dump_trace(what, tr, func, pc, otr, oex) + if what == "start" then + startloc = fmtfunc(func, pc) + startex = otr and "("..otr.."/"..oex..") " or "" + else + if what == "abort" then + local loc = fmtfunc(func, pc) + if loc ~= startloc then + out:write(format("[TRACE --- %s%s -- %s at %s]\n", + startex, startloc, fmterr(otr, oex), loc)) + else + out:write(format("[TRACE --- %s%s -- %s]\n", + startex, startloc, fmterr(otr, oex))) + end + elseif what == "stop" then + local info = traceinfo(tr) + local link, ltype = info.link, info.linktype + if ltype == "interpreter" then + out:write(format("[TRACE %3s %s%s -- fallback to interpreter]\n", + tr, startex, startloc)) + elseif link == tr or link == 0 then + out:write(format("[TRACE %3s %s%s %s]\n", + tr, startex, startloc, ltype)) + elseif ltype == "root" then + out:write(format("[TRACE %3s %s%s -> %d]\n", + tr, startex, startloc, link)) + else + out:write(format("[TRACE %3s %s%s -> %d %s]\n", + tr, startex, startloc, link, ltype)) + end + else + out:write(format("[TRACE %s]\n", what)) + end + out:flush() + end +end + +------------------------------------------------------------------------------ + +-- Detach dump handlers. +local function dumpoff() + if active then + active = false + jit.attach(dump_trace) + if out and out ~= stdout and out ~= stderr then out:close() end + out = nil + end +end + +-- Open the output file and attach dump handlers. +local function dumpon(outfile) + if active then dumpoff() end + if not outfile then outfile = os.getenv("LUAJIT_VERBOSEFILE") end + if outfile then + out = outfile == "-" and stdout or assert(io.open(outfile, "w")) + else + out = stderr + end + jit.attach(dump_trace, "trace") + active = true +end + +-- Public module functions. +module(...) + +on = dumpon +off = dumpoff +start = dumpon -- For -j command line option. + diff --git a/LuaJIT-2.0.4/lua/jit/vmdef.lua b/LuaJIT-2.0.4/lua/jit/vmdef.lua new file mode 100644 index 000000000..466066049 --- /dev/null +++ b/LuaJIT-2.0.4/lua/jit/vmdef.lua @@ -0,0 +1,331 @@ +-- This is a generated file. DO NOT EDIT! + +module(...) + +bcnames = "ISLT ISGE ISLE ISGT ISEQV ISNEV ISEQS ISNES ISEQN ISNEN ISEQP ISNEP ISTC ISFC IST ISF MOV NOT UNM LEN ADDVN SUBVN MULVN DIVVN MODVN ADDNV SUBNV MULNV DIVNV MODNV ADDVV SUBVV MULVV DIVVV MODVV POW CAT KSTR KCDATAKSHORTKNUM KPRI KNIL UGET USETV USETS USETN USETP UCLO FNEW TNEW TDUP GGET GSET TGETV TGETS TGETB TSETV TSETS TSETB TSETM CALLM CALL CALLMTCALLT ITERC ITERN VARG ISNEXTRETM RET RET0 RET1 FORI JFORI FORL IFORL JFORL ITERL IITERLJITERLLOOP ILOOP JLOOP JMP FUNCF IFUNCFJFUNCFFUNCV IFUNCVJFUNCVFUNCC FUNCCW" + +irnames = "LT GE LE GT ULT UGE ULE UGT EQ NE ABC RETF NOP BASE PVAL GCSTEPHIOP LOOP USE PHI RENAMEKPRI KINT KGC KPTR KKPTR KNULL KNUM KINT64KSLOT BNOT BSWAP BAND BOR BXOR BSHL BSHR BSAR BROL BROR ADD SUB MUL DIV MOD POW NEG ABS ATAN2 LDEXP MIN MAX FPMATHADDOV SUBOV MULOV AREF HREFK HREF NEWREFUREFO UREFC FREF STRREFALOAD HLOAD ULOAD FLOAD XLOAD SLOAD VLOAD ASTOREHSTOREUSTOREFSTOREXSTORESNEW XSNEW TNEW TDUP CNEW CNEWI TBAR OBAR XBAR CONV TOBIT TOSTR STRTO CALLN CALLL CALLS CALLXSCARG " + +irfpm = { [0]="floor", "ceil", "trunc", "sqrt", "exp", "exp2", "log", "log2", "log10", "sin", "cos", "tan", "other", } + +irfield = { [0]="str.len", "func.env", "func.pc", "tab.meta", "tab.array", "tab.node", "tab.asize", "tab.hmask", "tab.nomm", "udata.meta", "udata.udtype", "udata.file", "cdata.ctypeid", "cdata.ptr", "cdata.int", "cdata.int64", "cdata.int64_4", } + +ircall = { +[0]="lj_str_cmp", +"lj_str_new", +"lj_strscan_num", +"lj_str_fromint", +"lj_str_fromnum", +"lj_tab_new1", +"lj_tab_dup", +"lj_tab_newkey", +"lj_tab_len", +"lj_gc_step_jit", +"lj_gc_barrieruv", +"lj_mem_newgco", +"lj_math_random_step", +"lj_vm_modi", +"sinh", +"cosh", +"tanh", +"fputc", +"fwrite", +"fflush", +"lj_vm_floor", +"lj_vm_ceil", +"lj_vm_trunc", +"sqrt", +"exp", +"lj_vm_exp2", +"log", +"lj_vm_log2", +"log10", +"sin", +"cos", +"tan", +"lj_vm_powi", +"pow", +"atan2", +"ldexp", +"lj_vm_tobit", +"softfp_add", +"softfp_sub", +"softfp_mul", +"softfp_div", +"softfp_cmp", +"softfp_i2d", +"softfp_d2i", +"softfp_ui2d", +"softfp_f2d", +"softfp_d2ui", +"softfp_d2f", +"softfp_i2f", +"softfp_ui2f", +"softfp_f2i", +"softfp_f2ui", +"fp64_l2d", +"fp64_ul2d", +"fp64_l2f", +"fp64_ul2f", +"fp64_d2l", +"fp64_d2ul", +"fp64_f2l", +"fp64_f2ul", +"lj_carith_divi64", +"lj_carith_divu64", +"lj_carith_modi64", +"lj_carith_modu64", +"lj_carith_powi64", +"lj_carith_powu64", +"lj_cdata_setfin", +"strlen", +"memcpy", +"memset", +"lj_vm_errno", +"lj_carith_mul64", +} + +traceerr = { +[0]="error thrown or hook called during recording", +"trace too long", +"trace too deep", +"too many snapshots", +"blacklisted", +"NYI: bytecode %d", +"leaving loop in root trace", +"inner loop in root trace", +"loop unroll limit reached", +"bad argument type", +"JIT compilation disabled for function", +"call unroll limit reached", +"down-recursion, restarting", +"NYI: C function %p", +"NYI: FastFunc %s", +"NYI: unsupported variant of FastFunc %s", +"NYI: return to lower frame", +"store with nil or NaN key", +"missing metamethod", +"looping index lookup", +"NYI: mixed sparse/dense table", +"symbol not in cache", +"NYI: unsupported C type conversion", +"NYI: unsupported C function type", +"guard would always fail", +"too many PHIs", +"persistent type instability", +"failed to allocate mcode memory", +"machine code too long", +"hit mcode limit (retrying)", +"too many spill slots", +"inconsistent register allocation", +"NYI: cannot assemble IR instruction %d", +"NYI: PHI shuffling too complex", +"NYI: register coalescing too complex", +} + +ffnames = { +[0]="Lua", +"C", +"assert", +"type", +"next", +"pairs", +"ipairs_aux", +"ipairs", +"getmetatable", +"setmetatable", +"getfenv", +"setfenv", +"rawget", +"rawset", +"rawequal", +"unpack", +"select", +"tonumber", +"tostring", +"error", +"pcall", +"xpcall", +"loadfile", +"load", +"loadstring", +"dofile", +"gcinfo", +"collectgarbage", +"newproxy", +"print", +"coroutine.status", +"coroutine.running", +"coroutine.create", +"coroutine.yield", +"coroutine.resume", +"coroutine.wrap_aux", +"coroutine.wrap", +"math.abs", +"math.floor", +"math.ceil", +"math.sqrt", +"math.log10", +"math.exp", +"math.sin", +"math.cos", +"math.tan", +"math.asin", +"math.acos", +"math.atan", +"math.sinh", +"math.cosh", +"math.tanh", +"math.frexp", +"math.modf", +"math.deg", +"math.rad", +"math.log", +"math.atan2", +"math.pow", +"math.fmod", +"math.ldexp", +"math.min", +"math.max", +"math.random", +"math.randomseed", +"bit.tobit", +"bit.bnot", +"bit.bswap", +"bit.lshift", +"bit.rshift", +"bit.arshift", +"bit.rol", +"bit.ror", +"bit.band", +"bit.bor", +"bit.bxor", +"bit.tohex", +"string.len", +"string.byte", +"string.char", +"string.sub", +"string.rep", +"string.reverse", +"string.lower", +"string.upper", +"string.dump", +"string.find", +"string.match", +"string.gmatch_aux", +"string.gmatch", +"string.gsub", +"string.format", +"table.foreachi", +"table.foreach", +"table.getn", +"table.maxn", +"table.insert", +"table.remove", +"table.concat", +"table.sort", +"io.method.close", +"io.method.read", +"io.method.write", +"io.method.flush", +"io.method.seek", +"io.method.setvbuf", +"io.method.lines", +"io.method.__gc", +"io.method.__tostring", +"io.open", +"io.popen", +"io.tmpfile", +"io.close", +"io.read", +"io.write", +"io.flush", +"io.input", +"io.output", +"io.lines", +"io.type", +"os.execute", +"os.remove", +"os.rename", +"os.tmpname", +"os.getenv", +"os.exit", +"os.clock", +"os.date", +"os.time", +"os.difftime", +"os.setlocale", +"debug.getregistry", +"debug.getmetatable", +"debug.setmetatable", +"debug.getfenv", +"debug.setfenv", +"debug.getinfo", +"debug.getlocal", +"debug.setlocal", +"debug.getupvalue", +"debug.setupvalue", +"debug.upvalueid", +"debug.upvaluejoin", +"debug.sethook", +"debug.gethook", +"debug.debug", +"debug.traceback", +"jit.on", +"jit.off", +"jit.flush", +"jit.status", +"jit.attach", +"jit.util.funcinfo", +"jit.util.funcbc", +"jit.util.funck", +"jit.util.funcuvname", +"jit.util.traceinfo", +"jit.util.traceir", +"jit.util.tracek", +"jit.util.tracesnap", +"jit.util.tracemc", +"jit.util.traceexitstub", +"jit.util.ircalladdr", +"jit.opt.start", +"ffi.meta.__index", +"ffi.meta.__newindex", +"ffi.meta.__eq", +"ffi.meta.__len", +"ffi.meta.__lt", +"ffi.meta.__le", +"ffi.meta.__concat", +"ffi.meta.__call", +"ffi.meta.__add", +"ffi.meta.__sub", +"ffi.meta.__mul", +"ffi.meta.__div", +"ffi.meta.__mod", +"ffi.meta.__pow", +"ffi.meta.__unm", +"ffi.meta.__tostring", +"ffi.meta.__pairs", +"ffi.meta.__ipairs", +"ffi.clib.__index", +"ffi.clib.__newindex", +"ffi.clib.__gc", +"ffi.callback.free", +"ffi.callback.set", +"ffi.cdef", +"ffi.new", +"ffi.cast", +"ffi.typeof", +"ffi.istype", +"ffi.sizeof", +"ffi.alignof", +"ffi.offsetof", +"ffi.errno", +"ffi.string", +"ffi.copy", +"ffi.fill", +"ffi.abi", +"ffi.metatype", +"ffi.gc", +"ffi.load", +} + diff --git a/README.md b/README.md index 2225e1ff7..ba970e23d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,13 @@ # Noita Multiplayer +[![latest release](https://img.shields.io/github/v/release/ismoh/noitamp?include_prereleases&label=latest%20release&style=for-the-badge)](https://github.com/Ismoh/NoitaMP/releases) + +### Table of Contents +- [TL:DR](#tldr) +- [Documentation](#documentation) +- [Our awesome and valuable Contributors](#our-awesome-and-valuable-contributors) +- [Credits, Supporter and special thanks](#credits-supporter-and-special-thanks) +- [Used libraries, frameworks and other stuff](#used-libraries-frameworks-and-other-stuff) +- [Roadmap](#roadmap) ## TL;DR @@ -6,38 +15,31 @@ If you want to get notifications, [join](https://discord.gg/DhMurdcw4k) my discord server. There is a MEE6 role assigment for NoitaMP in #noita-modding! -## Badges - -
- -[![latest release](https://img.shields.io/github/v/release/ismoh/noitamp?include_prereleases&label=latest%20release&style=flat-square)](https://github.com/Ismoh/NoitaMP/releases) -![GitHub release (release name instead of tag name)](https://img.shields.io/github/v/release/ismoh/noitamp?display_name=release&include_prereleases&sort=date&style=flat-square) -![GitHub tag (latest SemVer pre-release)](https://img.shields.io/github/v/tag/ismoh/noitamp?include_prereleases&sort=semver&style=flat-square) -![.version](https://img.shields.io/badge/dynamic/json?label=.version&query=version&url=https%3A%2F%2Fraw.githubusercontent.com%2FIsmoh%2FNoitaMP%2Fdevelop%2Fmods%2Fnoita-mp%2F.version&style=flat-square) -[![amount of releases](https://flat.badgen.net/github/releases/ismoh/noitamp)](https://github.com/Ismoh/NoitaMP/releases) +--- -[![last-commit](https://img.shields.io/github/last-commit/ismoh/noitamp?style=flat-square)](https://github.com/Ismoh/NoitaMP/commit/develop) +[![latest release](https://img.shields.io/github/v/release/ismoh/noitamp?include_prereleases&label=latest%20release&style=for-the-badge)](https://github.com/Ismoh/NoitaMP/releases) +[![GitHub release](https://img.shields.io/github/v/release/ismoh/noitamp?display_name=release&include_prereleases&sort=date&style=for-the-badge)](https://github.com/Ismoh/NoitaMP/releases) +[![GitHub tag](https://img.shields.io/github/v/tag/ismoh/noitamp?include_prereleases&sort=semver&style=for-the-badge)](https://github.com/Ismoh/NoitaMP/tags) +[![.version](https://img.shields.io/badge/dynamic/json?label=.version&query=version&url=https%3A%2F%2Fraw.githubusercontent.com%2FIsmoh%2FNoitaMP%2Fdevelop%2Fmods%2Fnoita-mp%2F.version&style=for-the-badge)](https://github.com/Ismoh/NoitaMP/blob/develop/mods/noita-mp/.version) -[![platform](https://img.shields.io/badge/platform-ubuntu%20%7C%20windows-lightgrey?style=flat-square)](https://github.com/Ismoh/NoitaMP)[![ubuntu master](https://img.shields.io/github/workflow/status/ismoh/noitamp/Ubuntu%20Lua%20Unit%20Testing/master?label=&logo=ubuntu&style=flat-square)](https://github.com/Ismoh/NoitaMP/actions/workflows/ubuntu-latest-lua-unit-testing.yml?query=branch%3Amaster)[![windows master](https://img.shields.io/github/workflow/status/ismoh/noitamp/Windows%20Lua%20Unit%20Testing/master?label=&logo=windows&style=flat-square)](https://github.com/Ismoh/NoitaMP/actions/workflows/windows-latest-lua-unit-testing.yml?query=branch%3Amaster) +[![last-commit](https://img.shields.io/github/last-commit/ismoh/noitamp?style=for-the-badge)](https://github.com/Ismoh/NoitaMP/commit/develop) +[![luarocks-version](https://img.shields.io/badge/luarocks-v3.9.1-brightgreen?style=for-the-badge)](https://github.com/Ismoh/NoitaMP/blob/develop/.building/luarocks-3.9.1-windows-32) +[![GitHub issues by-label](https://img.shields.io/github/issues/ismoh/noitamp/help_wanted?style=for-the-badge)](https://github.com/Ismoh/NoitaMP/issues?q=is%3Aopen+is%3Aissue+label%3A%22help_wanted%22) +[![GitHub issues](https://img.shields.io/github/issues/ismoh/noitamp?style=for-the-badge)](https://github.com/Ismoh/NoitaMP/issues) -[![issues](https://flat.badgen.net/github/issues/ismoh/noitamp)](https://github.com/Ismoh/NoitaMP/issues?q=is%3Aissue) -[![open-issues](https://flat.badgen.net/github/open-issues/ismoh/noitamp)](https://github.com/Ismoh/NoitaMP/issues) -[![open-issues-help-wanted](https://flat.badgen.net/github/label-issues/ismoh/noitamp/help_wanted/open)](https://github.com/Ismoh/NoitaMP/issues?q=is%3Aopen+is%3Aissue+label%3A%22help_wanted%22) +![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/ismoh/noitamp/windows-latest-lua-unit-testing.yml?label=Tests%20&logo=windows&style=for-the-badge) +[![Coveralls](https://img.shields.io/coveralls/github/Ismoh/NoitaMP?logo=coveralls&style=for-the-badge)](https://coveralls.io/github/Ismoh/NoitaMP) +[![Codecov](https://img.shields.io/codecov/c/gh/Ismoh/NoitaMP?logo=codecov&style=for-the-badge)](https://codecov.io/gh/Ismoh/NoitaMP) -[![ubuntu - unit testing on develop](https://img.shields.io/github/workflow/status/ismoh/noitamp/Ubuntu%20Lua%20Unit%20Testing/develop?label=tests&logo=ubuntu&style=flat-square)](https://github.com/Ismoh/NoitaMP/actions/workflows/ubuntu-latest-lua-unit-testing.yml?query=branch%3Adevelop) -[![windows - unit testing on develop](https://img.shields.io/github/workflow/status/ismoh/noitamp/Windows%20Lua%20Unit%20Testing/develop?label=tests&logo=windows&style=flat-square)](https://github.com/Ismoh/NoitaMP/actions/workflows/windows-latest-lua-unit-testing.yml?query=branch%3Adevelop) +[![GitHub watchers](https://img.shields.io/github/watchers/ismoh/noitamp?style=for-the-badge)](https://github.com/Ismoh/NoitaMP/watchers) +[![GitHub forks](https://img.shields.io/github/forks/ismoh/noitamp?style=for-the-badge)](https://github.com/Ismoh/NoitaMP/network/members) +[![GitHub Repo stars](https://img.shields.io/github/stars/ismoh/noitamp?style=for-the-badge)](https://github.com/Ismoh/NoitaMP/stargazers) +![GitHub Sponsors](https://img.shields.io/github/sponsors/ismoh?style=for-the-badge) -[![Coveralls](https://img.shields.io/coveralls/github/Ismoh/NoitaMP?logo=coveralls&style=flat-square)](https://coveralls.io/github/Ismoh/NoitaMP) -[![Codecov](https://img.shields.io/codecov/c/gh/Ismoh/NoitaMP?logo=codecov&style=flat-square)](https://codecov.io/gh/Ismoh/NoitaMP) +[![GitHub](https://img.shields.io/github/license/ismoh/noitamp?style=for-the-badge)](https://github.com/Ismoh/NoitaMP/blob/master/LICENSE.md) -[![watchers](https://flat.badgen.net/github/watchers/ismoh/noitamp)](https://github.com/Ismoh/NoitaMP/watchers) -[![stars](https://flat.badgen.net/github/stars/ismoh/noitamp)](https://github.com/Ismoh/NoitaMP/stargazers) -[![forks](https://flat.badgen.net/github/forks/ismoh/noitamp)](https://github.com/Ismoh/NoitaMP/network/members) - -[![license](https://flat.badgen.net/github/license/ismoh/noitamp)](https://github.com/Ismoh/NoitaMP/blob/master/LICENSE.md) - -
+--- I love to play [Noita](https://noitagame.com/)! You should give it a try! Usually I like to play with my friends. Truly Noita is made for being a single-player game, @@ -48,8 +50,8 @@ Let's see, if I can do so?! I am new to Lua and modding, but someone said to me:
-[![gif](misc/2022-06-21_teaser.gif)](misc/2022-06-21_teaser.gif) - +[![gif](miscs/2022-06-21_teaser.gif)](miscs/2022-06-21_teaser.gif) +21.06.2022 teaser
## Documentation @@ -62,7 +64,7 @@ Installation, configuration and support can be found on the [docs](https://ismoh -## Credits | Supporter | Special Thanks +## Credits, Supporter and special thanks I wouldn't be able to create this mod without the help by diff --git a/bin/act b/bin/act deleted file mode 100644 index 3968e3239..000000000 Binary files a/bin/act and /dev/null differ diff --git a/codecov.yml b/codecov.yml index 48f94541f..344404408 100644 --- a/codecov.yml +++ b/codecov.yml @@ -1,18 +1,20 @@ -ignore: -- ".building" -- ".debug" -- ".github" -- ".testing" -- ".vscode" -- "docs" -- ".gitattritbutes" -- ".gitignore" -- ".luacov" -- "CODE_OF_CONDUCT.md" -- "codecov.yml" -- "CONTRIBUTING.md" -- "coveralls.yml" -- "LICENSE" -- "README.md" -- "SUPPORT.md" -- "luarocks-3.8.0/.codecov.yml" +codecov: + require_ci_to_pass: false +comment: + behavior: default + layout: reach,diff,flags,tree,reach + show_carryforward_flags: false +coverage: + precision: 2 + range: + - 70.0 + - 100.0 + round: down + status: + changes: false + default_rules: + flag_coverage_not_uploaded_behavior: include + patch: true + project: true +github_checks: + annotations: true diff --git a/contents/.gitmodules b/contents/.gitmodules deleted file mode 100644 index 1ca78f020..000000000 --- a/contents/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "luaunit"] - path = mods/noita-mp/files/lib/external - url = https://github.com/bluebird75/luaunit.git diff --git a/coveralls.yml b/coveralls.yml deleted file mode 100644 index 610c53e68..000000000 --- a/coveralls.yml +++ /dev/null @@ -1,5 +0,0 @@ -#https://linuxtut.com/en/f2296aa663230f71d883/ -#service_name: github-ci - -# https://github.com/coverallsapp/github-action -#base_path: "mods" \ No newline at end of file diff --git a/misc/2022-06-21_teaser.gif b/misc/2022-06-21_teaser.gif deleted file mode 100644 index 747ce20d8..000000000 --- a/misc/2022-06-21_teaser.gif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d6cd865af7e26b3b8bf2b4fc8428a6d625f01d96a10e5cc554154b69eee80a10 -size 79951153 diff --git a/miscs/2022-06-21_teaser.gif b/miscs/2022-06-21_teaser.gif new file mode 100644 index 000000000..93030e103 Binary files /dev/null and b/miscs/2022-06-21_teaser.gif differ diff --git a/miscs/Noita font template.pdn b/miscs/noita-font/Noita font template.pdn similarity index 100% rename from miscs/Noita font template.pdn rename to miscs/noita-font/Noita font template.pdn diff --git a/miscs/NoitaMP-font.png b/miscs/noita-font/NoitaMP-font.png similarity index 100% rename from miscs/NoitaMP-font.png rename to miscs/noita-font/NoitaMP-font.png diff --git a/miscs/backdrop shadow colour.png b/miscs/noita-font/backdrop shadow colour.png similarity index 100% rename from miscs/backdrop shadow colour.png rename to miscs/noita-font/backdrop shadow colour.png diff --git a/miscs/noita style font gardient.png b/miscs/noita-font/noita style font gardient.png similarity index 100% rename from miscs/noita style font gardient.png rename to miscs/noita-font/noita style font gardient.png diff --git a/mods/noita-mp/.luacov b/mods/noita-mp/.luacov new file mode 100644 index 000000000..163909b93 --- /dev/null +++ b/mods/noita-mp/.luacov @@ -0,0 +1,17 @@ +-- Configuration file for LuaCov +return { + statsfile = "luacov.stats.out", + reportfile = "luacov.report.out", + exclude = { + ".luarocks", + "data/", + "lua_modules/", + ".luacov", + ".version", + "lua.bat", + "luarocks.bat", + "mod.xml", + "modSettingsUpdater.lua", + "noita-mp-*" + } +} diff --git a/mods/noita-mp/data/biome_impl/testing-room-pixel-scene.png b/mods/noita-mp/data/biome_impl/testing-room-pixel-scene.png index 5dc76d61d..12ebb04ce 100644 Binary files a/mods/noita-mp/data/biome_impl/testing-room-pixel-scene.png and b/mods/noita-mp/data/biome_impl/testing-room-pixel-scene.png differ diff --git a/mods/noita-mp/files/scripts/init/init_.lua b/mods/noita-mp/files/scripts/init/init_.lua index 0bb5028a4..8a2fcc57e 100644 --- a/mods/noita-mp/files/scripts/init/init_.lua +++ b/mods/noita-mp/files/scripts/init/init_.lua @@ -12,19 +12,19 @@ if varargs and #varargs > 0 then print("'varargs' of init_.lua, see below:") print(unpack(varargs)) - destination_path = varargs[1] - print("destination_path = " .. tostring(destination_path)) - if varargs[2] then - print("WARNING: varargs[2] is set and should only be used locally to fix unit testing paths!") - local workDir = varargs[2] - print("Current working directory: " .. workDir) - local dofile = _G.dofile - _G.dofile = function(path) - print("Trying to load file: " .. path) - print("Trying to load file with DOFILE: " .. workDir .. "/" .. path) - return dofile(workDir .. "/" .. path) - end - end + --destination_path = varargs[1] + --print("destination_path = " .. tostring(destination_path)) + --if varargs[2] then + -- print("WARNING: varargs[2] is set and should only be used locally to fix unit testing paths!") + -- local workDir = varargs[2] + -- print("Current working directory: " .. workDir) + -- local dofile = _G.dofile + -- _G.dofile = function(path) + -- print("Trying to load file: " .. path) + -- print("Trying to load file with DOFILE: " .. workDir .. "/" .. path) + -- return dofile(workDir .. "/" .. path) + -- end + --end end else print("no 'varargs' set.") @@ -39,13 +39,13 @@ dofile("mods/noita-mp/files/scripts/extensions/ffi_extensions.lua") dofile("mods/noita-mp/files/scripts/extensions/globalExtensions.lua") local init_package_loading = dofile("mods/noita-mp/files/scripts/init/init_package_loading.lua") -if destination_path then - print("Running init_package_loading.lua with destination_path = " .. tostring(destination_path)) - init_package_loading(destination_path) -else - print("Running init_package_loading.lua without any destination_path") - init_package_loading() -end +--if destination_path then +-- print("Running init_package_loading.lua with destination_path = " .. tostring(destination_path)) +-- init_package_loading(destination_path) +--else +-- print("Running init_package_loading.lua without any destination_path") +-- init_package_loading() +--end dofile("mods/noita-mp/files/scripts/init/init_logger.lua") diff --git a/mods/noita-mp/files/scripts/init/init_package_loading.lua b/mods/noita-mp/files/scripts/init/init_package_loading.lua index cbf6b8c01..104f03b2c 100644 --- a/mods/noita-mp/files/scripts/init/init_package_loading.lua +++ b/mods/noita-mp/files/scripts/init/init_package_loading.lua @@ -1,181 +1,179 @@ -- https://subscription.packtpub.com/book/game-development/9781849515504/1/ch01lvl1sec10/preparing-a-basic-file-structure-for-the-game-engine ---[[ NoitaMP additions ]] -return function(destination_path) - if destination_path then - print("init_package_loading.lua: destination_path = " .. tostring(destination_path)) - end - - local default_package_path = package.path - package.path = package.path .. - ";./noita-mp/files/lib/external/?.lua;" .. - "./noita-mp/files/scripts/util/?.lua;" .. - "mods/noita-mp/files/lib/external/?.lua;" .. - "mods/noita-mp/files/scripts/util/?.lua;" - - if destination_path then - package.path = package.path .. ";" .. - destination_path .. "/noita-mp/files/lib/external/?.lua;" .. - destination_path .. "/noita-mp/files/scripts/util/?.lua;" .. - destination_path .. "/mods/noita-mp/files/lib/external/?.lua;" .. - destination_path .. "/mods/noita-mp/files/scripts/util/?.lua;" - end - - package.cpath = package.cpath .. - ";./noita-mp/files/lib/external/dlls/?.dll;" .. - ";mods/noita-mp/files/lib/external/dlls/?.dll;" - - if destination_path then - package.cpath = package.cpath .. ";" .. - destination_path .. "/noita-mp/files/lib/external/dlls/?.dll;" .. - destination_path .. "mods/noita-mp/files/lib/external/dlls/?.dll;" - end - - local fu = require("file_util") - --[[ NoitaMP additions ]] - -- A list of paths to lua script modules - local paths = { - "mods/noita-mp/files/{module}", - "mods/noita-mp/files/lib/{module}", - "mods/noita-mp/files/lib/external/{module}", - "mods/noita-mp/files/lib/external/dlls/{module}", - "mods/noita-mp/files/scripts/{module}", - "mods/noita-mp/files/scripts/components/{module}", - "mods/noita-mp/files/scripts/init/{module}", - "mods/noita-mp/files/scripts/net/{module}", - "mods/noita-mp/files/scripts/util/{module}" - } - - if destination_path then - paths = { - destination_path .. "/mods/noita-mp/files/{module}", - destination_path .. "/mods/noita-mp/files/lib/{module}", - destination_path .. "/mods/noita-mp/files/lib/external/{module}", - destination_path .. "/mods/noita-mp/files/lib/external/dlls/{module}", - destination_path .. "/mods/noita-mp/files/scripts/{module}", - destination_path .. "/mods/noita-mp/files/scripts/components/{module}", - destination_path .. "/mods/noita-mp/files/scripts/init/{module}", - destination_path .. "/mods/noita-mp/files/scripts/net/{module}", - destination_path .. "/mods/noita-mp/files/scripts/util/{module}" - } +function getNoitaMpRootDirectory() + -- Get the current directory of the script or the executable + local currentDirectory = io.popen("cd"):read("*a") + print("currentDirectory: " .. currentDirectory) + + -- Check if we are inside of noita-mp directory. Don't forget to escape the dash! + local startsAtI, endsAtI = string.find(currentDirectory, + "noita%-mp") -- https://stackoverflow.com/a/20223010/3493998 + local noitaMpRootDirectory = nil + if not startsAtI then + error("The current directory is not inside the noita-mp directory. Please run it again somewhere inside the noita-mp directory.") + else + noitaMpRootDirectory = string.sub(currentDirectory, 1, endsAtI) end + print("noitaMpRootDirectory: " .. noitaMpRootDirectory) + return noitaMpRootDirectory +end - -- A list of paths to binary Lua modules - local module_paths = { - "?.{extension}", - "?/init.{extension}", - "?/core.{extension}", - } - - -- List of supported OS paired with binary file extension name - local extensions = { - Windows = "dll", - Linux = "so", - Mac = "dylib" - } +local noitaMpRootDirectory = getNoitaMpRootDirectory() - -- os_name is a supplemental module for - -- OS and CPU architecture detection - local os_name = require("os_name") +--[[ NoitaMP additions ]] +local default_package_path = package.path +print("package.path = " .. package.path) +package.path = package.path .. ";" +package.path = package.path .. noitaMpRootDirectory .. "\\lua_modules\\share\\lua\\5.1\\?.lua;" +package.path = package.path .. noitaMpRootDirectory .. "\\files\\scripts\\util\\?.lua;" +package.path = package.path .. noitaMpRootDirectory .. "\\files\\lib\\external\\?.lua;" +package.path = package.path .. "mods\\noita-mp\\lua_modules\\share\\lua\\5.1\\?.lua;" +package.path = package.path .. "mods\\noita-mp\\files\\scripts\\util\\?.lua;" +package.path = package.path .. "mods\\noita-mp\\files\\lib\\external\\?.lua;" +print("package.path = " .. package.path) + +package.cpath = package.cpath .. ";" .. + --[[ Outside of Noita ]]-- + noitaMpRootDirectory .. "\\lua_modules\\lib\\lua\\5.1\\?.dll;" .. + noitaMpRootDirectory .. "\\files\\lib\\external\\dlls\\?.dll;" .. + --[[ Inside of Noita ]]-- + "mods\\noita-mp\\lua_modules\\lib\\lua\\5.1\\?.dll;" .. + "mods\\noita-mp\\files\\lib\\external\\dlls\\?.dll;" +print("package.cpath = " .. package.cpath) + +local fu = require("file_util") +--[[ NoitaMP additions ]] +-- A list of paths to lua script modules +local paths = { + noitaMpRootDirectory .. "/lua_modules/share/lua/5.1/{module}", + noitaMpRootDirectory .. "/lua_modules/lib/lua/5.1/{module}", + noitaMpRootDirectory .. "/files/scripts/util/{module}", + + "mods/noita-mp/lua_modules/share/lua/5.1/{module}", + "mods/noita-mp/lua_modules/lib/lua/5.1/{module}", + "mods/noita-mp/files/{module}", + "mods/noita-mp/files/scripts/{module}", + "mods/noita-mp/files/scripts/components/{module}", + "mods/noita-mp/files/scripts/init/{module}", + "mods/noita-mp/files/scripts/net/{module}", + "mods/noita-mp/files/scripts/util/{module}" +} + +-- A list of paths to binary Lua modules +local module_paths = { + "?.{extension}", + "?/init.{extension}", + "?/core.{extension}", +} + +-- List of supported OS paired with binary file extension name +local extensions = { + Windows = "dll", + Linux = "so", + Mac = "dylib" +} + +-- os_name is a supplemental module for +-- OS and CPU architecture detection +local os_name = require("os_name") - --[[ NoitaMP additions ]] - package.path = default_package_path - --[[ NoitaMP additions ]] - -- A dot character represent current working directory - local root_dir = "." - local current_platform, current_architecture = os_name.getOS() +--[[ NoitaMP additions ]] +package.path = default_package_path +--[[ NoitaMP additions ]] +-- A dot character represent current working directory +local root_dir = "." +local current_platform, current_architecture = os_name.getOS() - local cpaths, lpaths = {}, {} - local current_clib_extension = extensions[current_platform] +local cpaths, lpaths = {}, {} +local current_clib_extension = extensions[current_platform] - --[[ NoitaMP additions ]] - _G.os_name = current_platform - _G.os_arch = current_architecture +--[[ NoitaMP additions ]] +_G.os_name = current_platform +_G.os_arch = current_architecture - -- https://stackoverflow.com/a/14425862/3493998 - _G.path_separator = tostring(package.config:sub(1, 1)) +-- https://stackoverflow.com/a/14425862/3493998 +_G.path_separator = tostring(package.config:sub(1, 1)) - if _G.os_name == "Windows" then - _G.is_windows = true - end - if _G.os_name == "Linux" then - _G.is_linux = true - end +if _G.os_name == "Windows" then + _G.is_windows = true +end +if _G.os_name == "Linux" then + _G.is_linux = true +end - print("init_package_loading.lua | Detected OS " .. _G.os_name .. - "(" .. _G.os_arch .. ") with path separator '" .. _G.path_separator .. "'.") +print("init_package_loading.lua | Detected OS " .. _G.os_name .. + "(" .. _G.os_arch .. ") with path separator '" .. _G.path_separator .. "'.") - --[[ NoitaMP additions ]] - if current_clib_extension then - -- now you can process each defined path for module. - for _, path in ipairs(paths) do - local path = path:gsub("{(%w+)}", { root = root_dir, platform = current_platform }) - -- skip empty path entries - if #path > 0 then - -- make a substitution for each module file path. - for _, raw_module_path in ipairs(module_paths) do - local module_path = path:gsub( - "{(%w+)}", - { - module = raw_module_path - } - ) - -- add path for binary module - cpaths[#cpaths + 1] = module_path:gsub( - "{(%w+)}", - { - extension = current_clib_extension - } - ) - -- add paths for platform independent lua and luac modules - lpaths[#lpaths + 1] = module_path:gsub( - "{(%w+)}", - { - extension = "lua" - } - ) - lpaths[#lpaths + 1] = module_path:gsub( - "{(%w+)}", - { - extension = "luac" - } - ) - end +--[[ NoitaMP additions ]] +if current_clib_extension then + -- now you can process each defined path for module. + for _, path in ipairs(paths) do + local path = path:gsub("{(%w+)}", { root = root_dir, platform = current_platform }) + -- skip empty path entries + if #path > 0 then + -- make a substitution for each module file path. + for _, raw_module_path in ipairs(module_paths) do + local module_path = path:gsub( + "{(%w+)}", + { + module = raw_module_path + } + ) + -- add path for binary module + cpaths[#cpaths + 1] = module_path:gsub( + "{(%w+)}", + { + extension = current_clib_extension + } + ) + -- add paths for platform independent lua and luac modules + lpaths[#lpaths + 1] = module_path:gsub( + "{(%w+)}", + { + extension = "lua" + } + ) + lpaths[#lpaths + 1] = module_path:gsub( + "{(%w+)}", + { + extension = "luac" + } + ) end end - -- build module path list delimited with semicolon. - --package.path = table.concat(lpaths, ";") - --package.cpath = table.concat(cpaths, ";") - - --[[ NoitaMP additions ]] - package.path = fu.ReplacePathSeparator(table.concat(lpaths, ";")) - package.cpath = fu.ReplacePathSeparator(table.concat(cpaths, ";")) + end + -- build module path list delimited with semicolon. + --package.path = table.concat(lpaths, ";") + --package.cpath = table.concat(cpaths, ";") - if destination_path then - print("destination_path was set to export LPATH and CPATH!") + --[[ NoitaMP additions ]] + package.path = fu.ReplacePathSeparator(table.concat(lpaths, ";")) + package.cpath = fu.ReplacePathSeparator(table.concat(cpaths, ";")) - local lua_path_file = fu.RemoveTrailingPathSeparator(destination_path) .. _G.path_separator .. "lua_path.txt" - local lua_path_file_content = ";" .. package.path + if destination_path then + print("destination_path was set to export LPATH and CPATH!") - local lua_cpath_file = fu.RemoveTrailingPathSeparator(destination_path) .. _G.path_separator .. "lua_cpath.txt" - local lua_cpath_file_content = ";" .. package.cpath + local lua_path_file = fu.RemoveTrailingPathSeparator(destination_path) .. _G.path_separator .. "lua_path.txt" + local lua_path_file_content = ";" .. package.path - fu.WriteFile(lua_path_file, lua_path_file_content) + local lua_cpath_file = fu.RemoveTrailingPathSeparator(destination_path) .. _G.path_separator .. "lua_cpath.txt" + local lua_cpath_file_content = ";" .. package.cpath - print("init_package_loading.lua | File (" .. lua_path_file .. - ") created with content: " .. lua_path_file_content) + fu.WriteFile(lua_path_file, lua_path_file_content) - fu.WriteFile(lua_cpath_file, lua_cpath_file_content) - print("init_package_loading.lua | File (" .. lua_cpath_file .. - ") created with content: " .. lua_cpath_file_content) - else - print("destination_path was not set. Export LPATH and CPATH will be skipped!") - end + print("init_package_loading.lua | File (" .. lua_path_file .. + ") created with content: " .. lua_path_file_content) - print("init_package_loading.lua | package.path set to " .. package.path .. " .") - print("init_package_loading.lua | package.cpath set to " .. package.cpath .. " .") + fu.WriteFile(lua_cpath_file, lua_cpath_file_content) + print("init_package_loading.lua | File (" .. lua_cpath_file .. + ") created with content: " .. lua_cpath_file_content) else - --[[ NoitaMP additions ]] - error("Unable to detect OS!", 2) + print("destination_path was not set. Export LPATH and CPATH will be skipped!") end + + print("init_package_loading.lua | package.path set to " .. package.path .. " .") + print("init_package_loading.lua | package.cpath set to " .. package.cpath .. " .") +else + --[[ NoitaMP additions ]] + error("Unable to detect OS!", 2) end diff --git a/mods/noita-mp/files/scripts/net/Client.lua b/mods/noita-mp/files/scripts/net/Client.lua index 5096df6d5..0ba942507 100644 --- a/mods/noita-mp/files/scripts/net/Client.lua +++ b/mods/noita-mp/files/scripts/net/Client.lua @@ -922,6 +922,17 @@ function Client.new(sockClient) function self.sendNeedNuid(ownerName, ownerGuid, entityId) local cpc20 = CustomProfiler.start("Client.sendNeedNuid") + + if not ownerName then + error("ownerName is nil") + end + if not ownerGuid then + error("ownerGuid is nil") + end + if not entityId then + error("entityId is nil") + end + if not EntityUtils.isEntityAlive(entityId) then return end diff --git a/mods/noita-mp/files/scripts/util/EntityUtils.lua b/mods/noita-mp/files/scripts/util/EntityUtils.lua index f9a340927..757a1730b 100644 --- a/mods/noita-mp/files/scripts/util/EntityUtils.lua +++ b/mods/noita-mp/files/scripts/util/EntityUtils.lua @@ -366,7 +366,7 @@ function EntityUtils.processAndSyncEntityNetworking() NetworkVscUtils.addOrUpdateAllVscs(clientEntityId, localOwner.name, localOwner.guid) end if not NetworkVscUtils.hasNuidSet(clientEntityId) then - Client.sendNeedNuid(localOwner, clientEntityId) + Client.sendNeedNuid(localOwner.name, localOwner.guid, clientEntityId) end end end diff --git a/mods/noita-mp/files/scripts/util/guid.lua b/mods/noita-mp/files/scripts/util/guid.lua index 56c131c4f..6c91e0f43 100644 --- a/mods/noita-mp/files/scripts/util/guid.lua +++ b/mods/noita-mp/files/scripts/util/guid.lua @@ -1,58 +1,11 @@ --- https://stackoverflow.com/questions/23013973/lua-pattern-for-guid --- https://gist.github.com/jrus/3197011 --- https://stackoverflow.com/a/32353223/3493998 - local util = require("util") -local logger = _G.logger +local socket = require("socket") +local uuid = require("uuid") local Guid = { cached_guid = {}, - getRandomRange_0_to_9 = function() - return math.random(0, 9) - end, - getRandomRange_aA_to_fF = function() - local chars = { "a", "b", "c", "d", "e", "f" } - local char_index = math.random(1, 6) - return string.upper(chars[char_index]) - end } ---- Get processor id and use it for unique player identification. ---- To be able to test networking locally, noita.exe or noita_dex.exe is added. ---- @return number number unique number of local computer -local function getUniqueness() - local command = nil - local file = nil - local result = nil - - if is_windows then - command = 'wmic CPU get ProcessorId' - else - command = "sudo dmidecode -t processor | grep -E ID | sed 's/.*: //'" - end - - file = io.popen(command, "r") - local count = 1 - if file then - for line in file:lines() do - if count == 2 then - result = line - break - end - count = count + 1 - end - file:close() - end - local number = "" - for i = 1, string.len(result) do - local char = string.sub(result, i, i) - number = number .. string.byte(char) - end - - ---@diagnostic disable-next-line: return-type-mismatch - return tonumber(number) -end - function Guid:getCachedGuids() return self.cached_guid end @@ -62,80 +15,24 @@ function Guid:addGuidToCache(guid) end --- Generates a pseudo GUID. Does not fulfil RFC standard! Should generate unique GUIDs, but repeats if there is a duplicate. +--- Based on https://github.com/Tieske/uuid ! --- @param inUsedGuids table? list of already used GUIDs --- @return string guid function Guid:getGuid(inUsedGuids) if not util.IsEmpty(inUsedGuids) and #inUsedGuids > 0 then ---@cast inUsedGuids table table.insertAllButNotDuplicates(self.cached_guid, inUsedGuids) + logger:debug(logger.channels.guid, ("Guid:getGuid() - inUsedGuids: %s"):format(util.ToString(inUsedGuids))) end - math.randomseed(getUniqueness()) - - local x = "x" - local t = { x:rep(8), x:rep(4), x:rep(4), x:rep(4), x:rep(12) } - local guid = table.concat(t, "-") - local is_valid = false - local is_unique = false - - local counter = 0 repeat - guid = string.gsub( - guid, - x, - function() - local is_digit = math.random(0, 1) - if is_digit == 1 then - return self.getRandomRange_0_to_9() - end - return self.getRandomRange_aA_to_fF() - end - ) - - --if counter == 99 then - -- if DebugGetIsDevBuild() then - -- guid = guid .. "noita_dev.exe" - -- else - -- guid = guid .. "noita.exe" - -- end - --end - - is_valid = self.isPatternValid(guid) - is_unique = self:isUnique(guid) - logger:debug(logger.channels.guid, - "GUID (%s) is valid=%s and unique=%s. Generating GUID run-number %s", - guid, - is_valid, - is_unique, - counter - ) - - counter = counter + 1 - - - -- make same exe (Noita.exe or Noita_dev.exe) playable on the same computer - -- is is executed when server guid is the same as clients - if not is_unique and not util.IsEmpty(inUsedGuids) then - logger:warn(logger.channels.guid, - "GUID is not unique, but ifSameAsServer is true. Adding simply counter to GUID.") - guid = guid .. counter - is_unique = self:isUnique(guid) - end - - if counter > 100 then - -- TODO: get rid of this! - local msg = string.format("Tried to generate GUID %s times. Stopped it for now! This is a serious bug!", - counter) - logger:error(msg) - error(msg, 2) - break - end - - until is_valid and is_unique + uuid.randomseed(socket.gettime() * 10000) + guid = uuid() + print("guid " .. guid) + until self:isUnique(guid) and self.isPatternValid(guid) table.insert(self.cached_guid, guid) - logger:debug(logger.channels.guid, - "guid.lua | guid = " .. guid .. " is valid = " .. tostring(is_valid) .. " and is unique = " .. tostring(is_unique)) + return guid end diff --git a/mods/noita-mp/lua_modules/bin/luacov-coveralls.bat b/mods/noita-mp/lua_modules/bin/luacov-coveralls.bat new file mode 100644 index 000000000..c0cff7336 --- /dev/null +++ b/mods/noita-mp/lua_modules/bin/luacov-coveralls.bat @@ -0,0 +1,5 @@ +@echo off +setlocal +set "LUAROCKS_SYSCONFDIR=C:\Program Files (x86)/luarocks" +"D:\______BACKUP\NoitaMP_repo\NoitaMP\LuaJIT-2.0.4\bin\luajit.exe" -e "package.path=\"D:\\______BACKUP\\NoitaMP_repo\\NoitaMP\\mods\\noita-mp/lua_modules/share/lua/5.1/?.lua;D:\\______BACKUP\\NoitaMP_repo\\NoitaMP\\mods\\noita-mp/lua_modules/share/lua/5.1/?/init.lua;\"..package.path;package.cpath=\"D:\\______BACKUP\\NoitaMP_repo\\NoitaMP\\mods\\noita-mp/lua_modules/lib/lua/5.1/?.dll;\"..package.cpath;local k,l,_=pcall(require,'luarocks.loader') _=k and l.add_context('luacov-coveralls','0.2.3-1')" "D:\______BACKUP\NoitaMP_repo\NoitaMP\mods\noita-mp\lua_modules\lib\luarocks\rocks-5.1\luacov-coveralls\0.2.3-1\bin\luacov-coveralls" %* +exit /b %ERRORLEVEL% diff --git a/mods/noita-mp/lua_modules/bin/luacov.bat b/mods/noita-mp/lua_modules/bin/luacov.bat new file mode 100644 index 000000000..2cd127676 --- /dev/null +++ b/mods/noita-mp/lua_modules/bin/luacov.bat @@ -0,0 +1,5 @@ +@echo off +setlocal +set "LUAROCKS_SYSCONFDIR=C:\Program Files (x86)/luarocks" +"D:\______BACKUP\NoitaMP_repo\NoitaMP\LuaJIT-2.0.4\bin\luajit.exe" -e "package.path=\"D:\\______BACKUP\\NoitaMP_repo\\NoitaMP\\mods\\noita-mp/lua_modules/share/lua/5.1/?.lua;D:\\______BACKUP\\NoitaMP_repo\\NoitaMP\\mods\\noita-mp/lua_modules/share/lua/5.1/?/init.lua;\"..package.path;package.cpath=\"D:\\______BACKUP\\NoitaMP_repo\\NoitaMP\\mods\\noita-mp/lua_modules/lib/lua/5.1/?.dll;\"..package.cpath;local k,l,_=pcall(require,'luarocks.loader') _=k and l.add_context('luacov','0.15.0-1')" "D:\______BACKUP\NoitaMP_repo\NoitaMP\mods\noita-mp\lua_modules\lib\luarocks\rocks-5.1\luacov\0.15.0-1\bin\luacov" %* +exit /b %ERRORLEVEL% diff --git a/mods/noita-mp/files/lib/external/dlls/enet-version b/mods/noita-mp/lua_modules/lib/lua/5.1/enet-version similarity index 100% rename from mods/noita-mp/files/lib/external/dlls/enet-version rename to mods/noita-mp/lua_modules/lib/lua/5.1/enet-version diff --git a/mods/noita-mp/files/lib/external/dlls/enet.dll b/mods/noita-mp/lua_modules/lib/lua/5.1/enet.dll similarity index 100% rename from mods/noita-mp/files/lib/external/dlls/enet.dll rename to mods/noita-mp/lua_modules/lib/lua/5.1/enet.dll diff --git a/mods/noita-mp/lua_modules/lib/lua/5.1/lfs.dll b/mods/noita-mp/lua_modules/lib/lua/5.1/lfs.dll new file mode 100644 index 000000000..9cc883710 Binary files /dev/null and b/mods/noita-mp/lua_modules/lib/lua/5.1/lfs.dll differ diff --git a/mods/noita-mp/files/lib/external/dlls/libzstd.dll b/mods/noita-mp/lua_modules/lib/lua/5.1/libzstd.dll similarity index 100% rename from mods/noita-mp/files/lib/external/dlls/libzstd.dll rename to mods/noita-mp/lua_modules/lib/lua/5.1/libzstd.dll diff --git a/mods/noita-mp/lua_modules/lib/lua/5.1/mime/core.dll b/mods/noita-mp/lua_modules/lib/lua/5.1/mime/core.dll new file mode 100644 index 000000000..ff2ab8967 Binary files /dev/null and b/mods/noita-mp/lua_modules/lib/lua/5.1/mime/core.dll differ diff --git a/mods/noita-mp/lua_modules/lib/lua/5.1/socket/core.dll b/mods/noita-mp/lua_modules/lib/lua/5.1/socket/core.dll new file mode 100644 index 000000000..8ebee9ac3 Binary files /dev/null and b/mods/noita-mp/lua_modules/lib/lua/5.1/socket/core.dll differ diff --git a/mods/noita-mp/files/lib/external/MessagePack.lua b/mods/noita-mp/lua_modules/share/lua/5.1/MessagePack.lua similarity index 100% rename from mods/noita-mp/files/lib/external/MessagePack.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/MessagePack.lua diff --git a/mods/noita-mp/files/lib/external/bitser.lua b/mods/noita-mp/lua_modules/share/lua/5.1/bitser.lua similarity index 100% rename from mods/noita-mp/files/lib/external/bitser.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/bitser.lua diff --git a/mods/noita-mp/files/lib/external/dkjson.lua b/mods/noita-mp/lua_modules/share/lua/5.1/dkjson.lua similarity index 100% rename from mods/noita-mp/files/lib/external/dkjson.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/dkjson.lua diff --git a/mods/noita-mp/files/lib/external/ezgui/EZGUI.lua b/mods/noita-mp/lua_modules/share/lua/5.1/ezgui/EZGUI.lua similarity index 100% rename from mods/noita-mp/files/lib/external/ezgui/EZGUI.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/ezgui/EZGUI.lua diff --git a/mods/noita-mp/files/lib/external/ezgui/build.lua b/mods/noita-mp/lua_modules/share/lua/5.1/ezgui/build.lua similarity index 100% rename from mods/noita-mp/files/lib/external/ezgui/build.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/ezgui/build.lua diff --git a/mods/noita-mp/files/lib/external/ezgui/changelog.txt b/mods/noita-mp/lua_modules/share/lua/5.1/ezgui/changelog.txt similarity index 100% rename from mods/noita-mp/files/lib/external/ezgui/changelog.txt rename to mods/noita-mp/lua_modules/share/lua/5.1/ezgui/changelog.txt diff --git a/mods/noita-mp/files/lib/external/ezgui/css.lua b/mods/noita-mp/lua_modules/share/lua/5.1/ezgui/css.lua similarity index 100% rename from mods/noita-mp/files/lib/external/ezgui/css.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/ezgui/css.lua diff --git a/mods/noita-mp/files/lib/external/ezgui/css_props.lua b/mods/noita-mp/lua_modules/share/lua/5.1/ezgui/css_props.lua similarity index 100% rename from mods/noita-mp/files/lib/external/ezgui/css_props.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/ezgui/css_props.lua diff --git a/mods/noita-mp/files/lib/external/ezgui/elements/Button.lua b/mods/noita-mp/lua_modules/share/lua/5.1/ezgui/elements/Button.lua similarity index 100% rename from mods/noita-mp/files/lib/external/ezgui/elements/Button.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/ezgui/elements/Button.lua diff --git a/mods/noita-mp/files/lib/external/ezgui/elements/DOMElement.lua b/mods/noita-mp/lua_modules/share/lua/5.1/ezgui/elements/DOMElement.lua similarity index 100% rename from mods/noita-mp/files/lib/external/ezgui/elements/DOMElement.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/ezgui/elements/DOMElement.lua diff --git a/mods/noita-mp/files/lib/external/ezgui/elements/Image.lua b/mods/noita-mp/lua_modules/share/lua/5.1/ezgui/elements/Image.lua similarity index 100% rename from mods/noita-mp/files/lib/external/ezgui/elements/Image.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/ezgui/elements/Image.lua diff --git a/mods/noita-mp/files/lib/external/ezgui/elements/Input.lua b/mods/noita-mp/lua_modules/share/lua/5.1/ezgui/elements/Input.lua similarity index 100% rename from mods/noita-mp/files/lib/external/ezgui/elements/Input.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/ezgui/elements/Input.lua diff --git a/mods/noita-mp/files/lib/external/ezgui/elements/Layout.lua b/mods/noita-mp/lua_modules/share/lua/5.1/ezgui/elements/Layout.lua similarity index 100% rename from mods/noita-mp/files/lib/external/ezgui/elements/Layout.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/ezgui/elements/Layout.lua diff --git a/mods/noita-mp/files/lib/external/ezgui/elements/Slider.lua b/mods/noita-mp/lua_modules/share/lua/5.1/ezgui/elements/Slider.lua similarity index 100% rename from mods/noita-mp/files/lib/external/ezgui/elements/Slider.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/ezgui/elements/Slider.lua diff --git a/mods/noita-mp/files/lib/external/ezgui/elements/Text.lua b/mods/noita-mp/lua_modules/share/lua/5.1/ezgui/elements/Text.lua similarity index 100% rename from mods/noita-mp/files/lib/external/ezgui/elements/Text.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/ezgui/elements/Text.lua diff --git a/mods/noita-mp/files/lib/external/ezgui/lib/luaunit.lua b/mods/noita-mp/lua_modules/share/lua/5.1/ezgui/lib/luaunit.lua similarity index 100% rename from mods/noita-mp/files/lib/external/ezgui/lib/luaunit.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/ezgui/lib/luaunit.lua diff --git a/mods/noita-mp/files/lib/external/ezgui/lib/nxml.lua b/mods/noita-mp/lua_modules/share/lua/5.1/ezgui/lib/nxml.lua similarity index 100% rename from mods/noita-mp/files/lib/external/ezgui/lib/nxml.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/ezgui/lib/nxml.lua diff --git a/mods/noita-mp/files/lib/external/ezgui/lib/pretty.lua b/mods/noita-mp/lua_modules/share/lua/5.1/ezgui/lib/pretty.lua similarity index 100% rename from mods/noita-mp/files/lib/external/ezgui/lib/pretty.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/ezgui/lib/pretty.lua diff --git a/mods/noita-mp/files/lib/external/ezgui/oop.lua b/mods/noita-mp/lua_modules/share/lua/5.1/ezgui/oop.lua similarity index 100% rename from mods/noita-mp/files/lib/external/ezgui/oop.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/ezgui/oop.lua diff --git a/mods/noita-mp/files/lib/external/ezgui/parsing_functions.lua b/mods/noita-mp/lua_modules/share/lua/5.1/ezgui/parsing_functions.lua similarity index 100% rename from mods/noita-mp/files/lib/external/ezgui/parsing_functions.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/ezgui/parsing_functions.lua diff --git a/mods/noita-mp/files/lib/external/ezgui/string_buffer.lua b/mods/noita-mp/lua_modules/share/lua/5.1/ezgui/string_buffer.lua similarity index 100% rename from mods/noita-mp/files/lib/external/ezgui/string_buffer.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/ezgui/string_buffer.lua diff --git a/mods/noita-mp/files/lib/external/ezgui/utils.lua b/mods/noita-mp/lua_modules/share/lua/5.1/ezgui/utils.lua similarity index 100% rename from mods/noita-mp/files/lib/external/ezgui/utils.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/ezgui/utils.lua diff --git a/mods/noita-mp/files/lib/external/json.lua b/mods/noita-mp/lua_modules/share/lua/5.1/json.lua similarity index 96% rename from mods/noita-mp/files/lib/external/json.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/json.lua index d9f5bc075..fa4cfc224 100644 --- a/mods/noita-mp/files/lib/external/json.lua +++ b/mods/noita-mp/lua_modules/share/lua/5.1/json.lua @@ -75,7 +75,7 @@ local function encode_table(val, stack) n = n + 1 end if n ~= #val then - logger:error(nil, "invalid table: sparse array")--error("invalid table: sparse array") + print("ERROR: invalid table: sparse array")--error("invalid table: sparse array") end -- Encode for i, v in ipairs(val) do @@ -88,9 +88,10 @@ local function encode_table(val, stack) -- Treat as an object for k, v in pairs(val) do if type(k) ~= "string" then - error("invalid table: mixed or invalid key types") + print(("ERROR: invalid table: mixed or invalid key types: k = %s"):format(k))--error(("invalid table: mixed or invalid key types: k = %s"):format(k)) + else + table.insert(res, encode(k, stack) .. ":" .. encode(v, stack)) end - table.insert(res, encode(k, stack) .. ":" .. encode(v, stack)) end stack[val] = nil return "{" .. table.concat(res, ",") .. "}" diff --git a/mods/noita-mp/files/lib/external/lfs.lua b/mods/noita-mp/lua_modules/share/lua/5.1/lfs.lua similarity index 100% rename from mods/noita-mp/files/lib/external/lfs.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/lfs.lua diff --git a/mods/noita-mp/files/lib/external/lfs_ffi.lua b/mods/noita-mp/lua_modules/share/lua/5.1/lfs_ffi.lua similarity index 100% rename from mods/noita-mp/files/lib/external/lfs_ffi.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/lfs_ffi.lua diff --git a/mods/noita-mp/files/lib/external/logging.lua b/mods/noita-mp/lua_modules/share/lua/5.1/logging.lua similarity index 100% rename from mods/noita-mp/files/lib/external/logging.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/logging.lua diff --git a/mods/noita-mp/files/lib/external/logging/console.lua b/mods/noita-mp/lua_modules/share/lua/5.1/logging/console.lua similarity index 100% rename from mods/noita-mp/files/lib/external/logging/console.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/logging/console.lua diff --git a/mods/noita-mp/files/lib/external/logging/email.lua b/mods/noita-mp/lua_modules/share/lua/5.1/logging/email.lua similarity index 100% rename from mods/noita-mp/files/lib/external/logging/email.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/logging/email.lua diff --git a/mods/noita-mp/files/lib/external/logging/file.lua b/mods/noita-mp/lua_modules/share/lua/5.1/logging/file.lua similarity index 100% rename from mods/noita-mp/files/lib/external/logging/file.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/logging/file.lua diff --git a/mods/noita-mp/files/lib/external/logging/nginx.lua b/mods/noita-mp/lua_modules/share/lua/5.1/logging/nginx.lua similarity index 100% rename from mods/noita-mp/files/lib/external/logging/nginx.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/logging/nginx.lua diff --git a/mods/noita-mp/files/lib/external/logging/rolling_file.lua b/mods/noita-mp/lua_modules/share/lua/5.1/logging/rolling_file.lua similarity index 100% rename from mods/noita-mp/files/lib/external/logging/rolling_file.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/logging/rolling_file.lua diff --git a/mods/noita-mp/files/lib/external/logging/socket.lua b/mods/noita-mp/lua_modules/share/lua/5.1/logging/socket.lua similarity index 100% rename from mods/noita-mp/files/lib/external/logging/socket.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/logging/socket.lua diff --git a/mods/noita-mp/files/lib/external/logging/sql.lua b/mods/noita-mp/lua_modules/share/lua/5.1/logging/sql.lua similarity index 100% rename from mods/noita-mp/files/lib/external/logging/sql.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/logging/sql.lua diff --git a/mods/noita-mp/lua_modules/share/lua/5.1/ltn12.lua b/mods/noita-mp/lua_modules/share/lua/5.1/ltn12.lua new file mode 100644 index 000000000..4cb17f53f --- /dev/null +++ b/mods/noita-mp/lua_modules/share/lua/5.1/ltn12.lua @@ -0,0 +1,318 @@ +----------------------------------------------------------------------------- +-- LTN12 - Filters, sources, sinks and pumps. +-- LuaSocket toolkit. +-- Author: Diego Nehab +----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- +-- Declare module +----------------------------------------------------------------------------- +local string = require("string") +local table = require("table") +local unpack = unpack or table.unpack +local base = _G +local select = select + +local _M = {} +if module then -- heuristic for exporting a global package table + ltn12 = _M -- luacheck: ignore +end +local filter,source,sink,pump = {},{},{},{} + +_M.filter = filter +_M.source = source +_M.sink = sink +_M.pump = pump + +-- 2048 seems to be better in windows... +_M.BLOCKSIZE = 2048 +_M._VERSION = "LTN12 1.0.3" + +----------------------------------------------------------------------------- +-- Filter stuff +----------------------------------------------------------------------------- +-- returns a high level filter that cycles a low-level filter +function filter.cycle(low, ctx, extra) + base.assert(low) + return function(chunk) + local ret + ret, ctx = low(ctx, chunk, extra) + return ret + end +end + +-- chains a bunch of filters together +-- (thanks to Wim Couwenberg) +function filter.chain(...) + local arg = {...} + local n = select('#',...) + local top, index = 1, 1 + local retry = "" + return function(chunk) + retry = chunk and retry + while true do + if index == top then + chunk = arg[index](chunk) + if chunk == "" or top == n then return chunk + elseif chunk then index = index + 1 + else + top = top+1 + index = top + end + else + chunk = arg[index](chunk or "") + if chunk == "" then + index = index - 1 + chunk = retry + elseif chunk then + if index == n then return chunk + else index = index + 1 end + else base.error("filter returned inappropriate nil") end + end + end + end +end + +----------------------------------------------------------------------------- +-- Source stuff +----------------------------------------------------------------------------- +-- create an empty source +local function empty() + return nil +end + +function source.empty() + return empty +end + +-- returns a source that just outputs an error +function source.error(err) + return function() + return nil, err + end +end + +-- creates a file source +function source.file(handle, io_err) + if handle then + return function() + local chunk = handle:read(_M.BLOCKSIZE) + if not chunk then handle:close() end + return chunk + end + else return source.error(io_err or "unable to open file") end +end + +-- turns a fancy source into a simple source +function source.simplify(src) + base.assert(src) + return function() + local chunk, err_or_new = src() + src = err_or_new or src + if not chunk then return nil, err_or_new + else return chunk end + end +end + +-- creates string source +function source.string(s) + if s then + local i = 1 + return function() + local chunk = string.sub(s, i, i+_M.BLOCKSIZE-1) + i = i + _M.BLOCKSIZE + if chunk ~= "" then return chunk + else return nil end + end + else return source.empty() end +end + +-- creates table source +function source.table(t) + base.assert('table' == type(t)) + local i = 0 + return function() + i = i + 1 + return t[i] + end +end + +-- creates rewindable source +function source.rewind(src) + base.assert(src) + local t = {} + return function(chunk) + if not chunk then + chunk = table.remove(t) + if not chunk then return src() + else return chunk end + else + table.insert(t, chunk) + end + end +end + +-- chains a source with one or several filter(s) +function source.chain(src, f, ...) + if ... then f=filter.chain(f, ...) end + base.assert(src and f) + local last_in, last_out = "", "" + local state = "feeding" + local err + return function() + if not last_out then + base.error('source is empty!', 2) + end + while true do + if state == "feeding" then + last_in, err = src() + if err then return nil, err end + last_out = f(last_in) + if not last_out then + if last_in then + base.error('filter returned inappropriate nil') + else + return nil + end + elseif last_out ~= "" then + state = "eating" + if last_in then last_in = "" end + return last_out + end + else + last_out = f(last_in) + if last_out == "" then + if last_in == "" then + state = "feeding" + else + base.error('filter returned ""') + end + elseif not last_out then + if last_in then + base.error('filter returned inappropriate nil') + else + return nil + end + else + return last_out + end + end + end + end +end + +-- creates a source that produces contents of several sources, one after the +-- other, as if they were concatenated +-- (thanks to Wim Couwenberg) +function source.cat(...) + local arg = {...} + local src = table.remove(arg, 1) + return function() + while src do + local chunk, err = src() + if chunk then return chunk end + if err then return nil, err end + src = table.remove(arg, 1) + end + end +end + +----------------------------------------------------------------------------- +-- Sink stuff +----------------------------------------------------------------------------- +-- creates a sink that stores into a table +function sink.table(t) + t = t or {} + local f = function(chunk, err) + if chunk then table.insert(t, chunk) end + return 1 + end + return f, t +end + +-- turns a fancy sink into a simple sink +function sink.simplify(snk) + base.assert(snk) + return function(chunk, err) + local ret, err_or_new = snk(chunk, err) + if not ret then return nil, err_or_new end + snk = err_or_new or snk + return 1 + end +end + +-- creates a file sink +function sink.file(handle, io_err) + if handle then + return function(chunk, err) + if not chunk then + handle:close() + return 1 + else return handle:write(chunk) end + end + else return sink.error(io_err or "unable to open file") end +end + +-- creates a sink that discards data +local function null() + return 1 +end + +function sink.null() + return null +end + +-- creates a sink that just returns an error +function sink.error(err) + return function() + return nil, err + end +end + +-- chains a sink with one or several filter(s) +function sink.chain(f, snk, ...) + if ... then + local args = { f, snk, ... } + snk = table.remove(args, #args) + f = filter.chain(unpack(args)) + end + base.assert(f and snk) + return function(chunk, err) + if chunk ~= "" then + local filtered = f(chunk) + local done = chunk and "" + while true do + local ret, snkerr = snk(filtered, err) + if not ret then return nil, snkerr end + if filtered == done then return 1 end + filtered = f(done) + end + else return 1 end + end +end + +----------------------------------------------------------------------------- +-- Pump stuff +----------------------------------------------------------------------------- +-- pumps one chunk from the source to the sink +function pump.step(src, snk) + local chunk, src_err = src() + local ret, snk_err = snk(chunk, src_err) + if chunk and ret then return 1 + else return nil, src_err or snk_err end +end + +-- pumps all data from a source to a sink, using a step function +function pump.all(src, snk, step) + base.assert(src and snk) + step = step or pump.step + while true do + local ret, err = step(src, snk) + if not ret then + if err then return nil, err + else return 1 end + end + end +end + +return _M diff --git a/mods/noita-mp/lua_modules/share/lua/5.1/luacov.lua b/mods/noita-mp/lua_modules/share/lua/5.1/luacov.lua new file mode 100644 index 000000000..8c8ce45fb --- /dev/null +++ b/mods/noita-mp/lua_modules/share/lua/5.1/luacov.lua @@ -0,0 +1,8 @@ +--- Loads `luacov.runner` and immediately starts it. +-- Useful for launching scripts from the command-line. Returns the `luacov.runner` module. +-- @class module +-- @name luacov +-- @usage lua -lluacov sometest.lua +local runner = require("luacov.runner") +runner.init() +return runner diff --git a/mods/noita-mp/lua_modules/share/lua/5.1/luacov/coveralls/CiInfo.lua b/mods/noita-mp/lua_modules/share/lua/5.1/luacov/coveralls/CiInfo.lua new file mode 100644 index 000000000..4fdbc33d4 --- /dev/null +++ b/mods/noita-mp/lua_modules/share/lua/5.1/luacov/coveralls/CiInfo.lua @@ -0,0 +1,163 @@ +local NULL = {} +setmetatable(NULL, {__index = function() return NULL end}) + +local function env(_, name) + if name == NULL then return nil end + + local v = os.getenv(name) + if v == "" then return nil end + return v +end + +local ENV = setmetatable({}, {__index = env}) + +local CI_CONFIG = { + ["travis-ci"] = { + branch = "TRAVIS_BRANCH"; + service_number = NULL; + pull_request = NULL; + job_id = "TRAVIS_JOB_ID"; + token = "COVERALLS_REPO_TOKEN"; + commit_id = "TRAVIS_COMMIT"; + author_name = NULL; + author_email = NULL; + committer_name = NULL; + committer_email = NULL; + message = NULL; + }; + + appveyor = { + branch = "APPVEYOR_REPO_BRANCH"; + service_number = "APPVEYOR_BUILD_NUMBER"; + pull_request = "APPVEYOR_PULL_REQUEST_NUMBER"; + job_id = "APPVEYOR_JOB_ID"; + token = "COVERALLS_REPO_TOKEN"; + commit_id = "APPVEYOR_REPO_COMMIT"; + author_name = "APPVEYOR_REPO_COMMIT_AUTHOR"; + author_email = "APPVEYOR_REPO_COMMIT_AUTHOR_EMAIL"; + committer_name = NULL; + committer_email = NULL; + message = "APPVEYOR_REPO_COMMIT_MESSAGE"; + }; + + codeship = { + branch = "CI_BRANCH"; + service_number = NULL; + pull_request = NULL; + job_id = "CI_BUILD_NUMBER"; + token = "COVERALLS_REPO_TOKEN"; + commit_id = "CI_COMMIT_ID"; + author_name = NULL; + author_email = NULL; + committer_name = "CI_COMMITTER_NAME"; + committer_email = "CI_COMMITTER_EMAIL"; + message = "CI_MESSAGE"; + }; + + circleci = { + branch = "CIRCLE_BRANCH"; + service_number = NULL; + pull_request = "CI_PULL_REQUEST"; + job_id = "CIRCLE_BUILD_NUM"; + token = "COVERALLS_REPO_TOKEN"; + commit_id = NULL; + author_name = NULL; + author_email = NULL; + committer_name = NULL; + committer_email = NULL; + message = NULL; + }; + + drone = { + branch = "DRONE_BRANCH"; + service_number = NULL; + pull_request = NULL; + job_id = "DRONE_BUILD_NUMBER"; + token = "COVERALLS_REPO_TOKEN"; + commit_id = "DRONE_COMMIT"; + author_name = NULL; + author_email = NULL; + committer_name = NULL; + committer_email = NULL; + message = NULL; + }; + + gitlab = { + branch = "CI_COMMIT_REF_NAME"; + service_number = "CI_PIPELINE_ID"; + pull_request = "CI_MERGE_REQUEST_ID"; + job_id = "CI_JOB_ID"; + token = "COVERALLS_REPO_TOKEN"; + commit_id = "CI_COMMIT_SHA"; + author_name = NULL; + author_email = NULL; + committer_name = NULL; + committer_email = NULL; + message = "CI_COMMIT_TITLE"; + }; + + github = { + branch = "GITHUB_REF"; + service_number = NULL; + pull_request = NULL; + job_id = "GITHUB_RUN_ID"; + token = "COVERALLS_REPO_TOKEN"; + commit_id = "GITHUB_SHA"; + author_name = NULL; + author_email = NULL; + committer_name = NULL; + committer_email = NULL; + message = NULL; + }; + +} + +local function is_ci() + local CIVAR = ENV.CI or ENV.GITHUB_ACTIONS + return CIVAR and CIVAR:lower() == "true" +end + +local function ci_name() + if not is_ci() then return end + + if (ENV.TRAVIS or ''):lower() == "true" then return "travis-ci" end + if (ENV.CI_NAME or ''):lower() == "codeship" then return "codeship" end + if (ENV.CIRCLECI or ''):lower() == "true" then return "circleci" end + if (ENV.APPVEYOR or ''):lower() == "true" then return "appveyor" end + if (ENV.DRONE or ''):lower() == "true" then return "drone" end + if (ENV.GITLAB_CI or ''):lower() == "true" then return "gitlab" end + if (ENV.GITHUB_ACTIONS or ''):lower() == "true" then return "github" end +end + +local function cfg() + local name = ci_name() + return CI_CONFIG[name] or NULL +end + +local function ci_branch () return ENV[cfg().branch ] end +local function ci_job_id () return ENV[cfg().job_id ] end +local function ci_service_number () return ENV[cfg().service_number ] end +local function ci_pull_request () return ENV[cfg().pull_request ] end +local function ci_token () return ENV[cfg().token ] end +local function ci_commit_id () return ENV[cfg().commit_id ] end +local function ci_author_name () return ENV[cfg().author_name ] end +local function ci_author_email () return ENV[cfg().author_email ] end +local function ci_committer_name () return ENV[cfg().committer_name ] end +local function ci_committer_email() return ENV[cfg().committer_email] end +local function ci_message () return ENV[cfg().message ] end + +return { + ENV = ENV; + name = ci_name; + branch = ci_branch; + service_number = ci_service_number; + pull_request = ci_pull_request; + job_id = ci_job_id; + token = ci_token; + commit_id = ci_commit_id; + author_name = ci_author_name; + author_email = ci_author_email; + committer_name = ci_committer_name; + committer_email = ci_committer_email; + message = ci_message; +} diff --git a/mods/noita-mp/lua_modules/share/lua/5.1/luacov/coveralls/CiRepo.lua b/mods/noita-mp/lua_modules/share/lua/5.1/luacov/coveralls/CiRepo.lua new file mode 100644 index 000000000..e4aea9f0a --- /dev/null +++ b/mods/noita-mp/lua_modules/share/lua/5.1/luacov/coveralls/CiRepo.lua @@ -0,0 +1,48 @@ +local GitRepo = require"luacov.coveralls.repo.git" +local ApvRepo = require"luacov.coveralls.repo.appveyor" +local ci = require"luacov.coveralls.CiInfo" + +local function try_any_repo(repo_path) + -- currenly support only git + local repo, err = GitRepo:new(repo_path) + if repo then return repo, "git" end + + repo, err = ApvRepo:new(repo_path) + if repo then return repo, err end + + local function dummy() end + return setmetatable({}, {__index = function() return dummy end}), "unknown" +end + +----------------------------------------------------------- +local CiRepoInfo = {} do +CiRepoInfo.__index = CiRepoInfo + +function CiRepoInfo:new(repo_path) + local repo, type = try_any_repo(repo_path) + local o = setmetatable({ + _repo = assert(repo); + _repo_type = assert(type); + }, self) + + return o +end + +CiRepoInfo.type = function(self) return self._repo_type end + +CiRepoInfo.path = function(self) return self._repo:path() end +CiRepoInfo.version = function(self) return self._repo:version() end + +CiRepoInfo.id = function(self) return self._repo:id() or ci.commit_id() end +CiRepoInfo.last_author_name = function(self) return self._repo:last_author_name() or ci.author_name() end +CiRepoInfo.last_author_email = function(self) return self._repo:last_author_email() or ci.author_email() end +CiRepoInfo.last_committer_name = function(self) return self._repo:last_committer_name() or ci.committer_name() end +CiRepoInfo.last_committer_email = function(self) return self._repo:last_committer_email() or ci.committer_email() end +CiRepoInfo.last_message = function(self) return self._repo:last_message() or ci.message() end +CiRepoInfo.current_branch = function(self) return self._repo:current_branch() or ci.branch() end +CiRepoInfo.remotes = function(self) return self._repo:remotes() end + +end +----------------------------------------------------------- + +return CiRepoInfo diff --git a/mods/noita-mp/lua_modules/share/lua/5.1/luacov/coveralls/repo/appveyor.lua b/mods/noita-mp/lua_modules/share/lua/5.1/luacov/coveralls/repo/appveyor.lua new file mode 100644 index 000000000..11bc2f355 --- /dev/null +++ b/mods/noita-mp/lua_modules/share/lua/5.1/luacov/coveralls/repo/appveyor.lua @@ -0,0 +1,45 @@ +local GitRepo = require"luacov.coveralls.repo.git" +local ci = require"luacov.coveralls.CiInfo" +local path = require"path" + +----------------------------------------------------------- +local AppveyorRepoInfo = {} do +AppveyorRepoInfo.__index = AppveyorRepoInfo + +function AppveyorRepoInfo:new(repo_path) + if ci.name() ~= 'appveyor' then + return nil, 'No appveyor CI' + end + + local build_dir = ci.ENV.APPVEYOR_BUILD_FOLDER + if build_dir then + local repo, err = GitRepo:new(build_dir) + if repo then return repo, "git" end + end + + local _repo_type = ci.ENV.APPVEYOR_REPO_SCM + if not _repo_type then _repo_type = 'unknown' + else _repo_type = _repo_type:lower() end + + local o = setmetatable({ + _path = build_dir or path.fullpath(repo_path); + }, self) + + return o, _repo_type +end + +AppveyorRepoInfo.path = function(self) return self._path end +AppveyorRepoInfo.version = function(self) end +AppveyorRepoInfo.id = function(self) return ci.commit_id() end +AppveyorRepoInfo.last_author_name = function(self) return ci.author_name() end +AppveyorRepoInfo.last_author_email = function(self) return ci.author_email() end +AppveyorRepoInfo.last_committer_name = function(self) return ci.committer_name() end +AppveyorRepoInfo.last_committer_email = function(self) return ci.committer_email() end +AppveyorRepoInfo.last_message = function(self) return ci.message() end +AppveyorRepoInfo.current_branch = function(self) return ci.branch() end +AppveyorRepoInfo.remotes = function(self) return end + +end +----------------------------------------------------------- + +return AppveyorRepoInfo diff --git a/mods/noita-mp/lua_modules/share/lua/5.1/luacov/coveralls/repo/git.lua b/mods/noita-mp/lua_modules/share/lua/5.1/luacov/coveralls/repo/git.lua new file mode 100644 index 000000000..d1ce936a8 --- /dev/null +++ b/mods/noita-mp/lua_modules/share/lua/5.1/luacov/coveralls/repo/git.lua @@ -0,0 +1,94 @@ +local utils = require "luacov.coveralls.utils" +local path = require "path" +local exec = utils.exec + +local function git_exec(cwd, ...) + local ok, status, msg = exec(cwd, 'git', ...) + if not ok then return ok, msg or status end + return msg or '' +end + +local function git_version() + local ver, err = git_exec('.', '--version') + if not ver then return nil, err end + return (ver:gsub("%s+$", "")) +end + +local function is_git_repo(cwd) + local ok, err = git_exec(cwd, 'status') + if not ok then return nil, err end + return true +end + +local function git_last_log(cwd, fmt) + return git_exec(cwd, '--no-pager log -1 --pretty=format:%s', fmt) +end + +local function make_git_log_getter(fmt) + return function(cwd) return git_last_log(cwd, fmt) end +end + +local git_id = make_git_log_getter'%H' +local git_last_author_name = make_git_log_getter'%aN' +local git_last_author_email = make_git_log_getter'%ae' +local git_last_committer_name = make_git_log_getter'%cN' +local git_last_committer_email = make_git_log_getter'%ce' +local git_last_message = make_git_log_getter'%s' +local git_current_branch = function (cwd) + local str, err = git_exec(cwd, 'rev-parse --abbrev-ref HEAD') + if not str then return nil, err end + return (str:match("^%s*(%S+)")) +end +local git_remotes = function (cwd) + local str, err = git_exec(cwd, 'remote -v') + if not str then return nil, err end + local res = {} + str:gsub("%s*(%S+)%s+([^\n\r]+)%((%a+)%)%s*\r?\n", function(name, url, mode) + if mode == 'fetch' then res[name] = url end + end) + return res +end + +----------------------------------------------------------- +local GitRepoInfo = {} do +GitRepoInfo.__index = GitRepoInfo + +function GitRepoInfo:new(repo_path) + repo_path = path.fullpath(repo_path) + + if not path.isdir(repo_path) then + return nil, 'git rep does not exists' + end + + local ver, err = git_version() + if not ver then + return nil, err + end + + local ok, err = is_git_repo(repo_path) + if not ok then + return nil, err + end + + local o = setmetatable({ + _path = repo_path + }, self) + + return o +end + +GitRepoInfo.path = function(self) return self._path end +GitRepoInfo.version = function(self) return git_version () end +GitRepoInfo.id = function(self) return git_id (self:path()) end +GitRepoInfo.last_author_name = function(self) return git_last_author_name (self:path()) end +GitRepoInfo.last_author_email = function(self) return git_last_author_email (self:path()) end +GitRepoInfo.last_committer_name = function(self) return git_last_committer_name (self:path()) end +GitRepoInfo.last_committer_email = function(self) return git_last_committer_email (self:path()) end +GitRepoInfo.last_message = function(self) return git_last_message (self:path()) end +GitRepoInfo.current_branch = function(self) return git_current_branch (self:path()) end +GitRepoInfo.remotes = function(self) return git_remotes (self:path()) end + +end +----------------------------------------------------------- + +return GitRepoInfo diff --git a/mods/noita-mp/lua_modules/share/lua/5.1/luacov/coveralls/utils.lua b/mods/noita-mp/lua_modules/share/lua/5.1/luacov/coveralls/utils.lua new file mode 100644 index 000000000..e33698bfa --- /dev/null +++ b/mods/noita-mp/lua_modules/share/lua/5.1/luacov/coveralls/utils.lua @@ -0,0 +1,183 @@ + +local function prequire(...) + local ok, mod = pcall(require, ...) + if not ok then return nil, mod end + return mod, ... +end + +local function vrequire(...) + local errors = {} + for i, n in ipairs{...} do + local mod, err = prequire(n) + if mod then return mod, err end + errors[#errors + 1] = err + end + error(table.concat(errors, "\n\n")) +end + +local path = require "path" + +local json, json_name = vrequire("json", "cjson.safe", "dkjson") + +local function read_file(n) + local f, e = io.open(n, "r") + if not f then return nil, e end + local d, e = f:read("*all") + f:close() + return d, e +end + +local function json_init_array(t) + if json.util and json.util.InitArray then + return json.util.InitArray(t) + end + return t +end + +local function json_encode(t) + return json.encode(t) +end + +local json_decode +if json_name == 'dkjson' then + assert(nil ~= json.null) + json_decode = function (t) + local ok, r1, r2 = pcall(json.decode, t, nil, json.null) + if ok then return r1, r2 end + return nil, r1 + end +else + json_decode = function (t) + local ok, r1, r2 = pcall(json.decode, t) + if ok then return r1, r2 end + return nil, r1 + end +end + +local function json_null() + if json.null then return json.null end + return json.decode('null') +end + +local function json_load_file(n) + local d, e = read_file(n) + if not d then return nil, e end + return json_decode(d) +end + +----------------------------------------------------------- +local exec do + +local lua_version_t +local function lua_version() + if not lua_version_t then + local version = rawget(_G,"_VERSION") + local maj,min = version:match("^Lua (%d+)%.(%d+)$") + if maj then lua_version_t = {tonumber(maj),tonumber(min)} + elseif not math.mod then lua_version_t = {5,2} + elseif table.pack and not pack then lua_version_t = {5,2} + else lua_version_t = {5,2} end + end + return lua_version_t[1], lua_version_t[2] +end + +local LUA_MAJOR, LUA_MINOR = lua_version() +local LUA_VERSION = LUA_MAJOR * 100 + LUA_MINOR +local LUA_52 = 502 + +exec = function(cwd, cmd, ...) + local tmpfile = path.tmpname() + if ... then cmd = cmd .. ' ' .. string.format(...) end + cmd = cmd .. ' >"' .. tmpfile .. '" 2>&1' + + local p + if cwd and (cwd ~= "") and (cwd ~= ".") then + p = path.currentdir() + path.chdir(cwd) + end + local res1,res2,res2 = os.execute(cmd) + if p then path.chdir(p) end + + local data = read_file(tmpfile) + path.remove(tmpfile) + + if res2 == nil then -- with Lua 5.1, os.execute returns only one value + return res1==0, res1, data + end + + return res1, res2, data +end + +end +----------------------------------------------------------- + +local function curl_json_upload_app(fname, url) + local path_name, base_name = path.splitpath(fname) + local tmp = path.tmpname() + local ok, status, msg = exec(path_name, "curl", '--output %s --form "json_file=@%s;type=application/json" %s', tmp, base_name, url) + local data = read_file(tmp) + path.remove(tmp) + + if not (ok and data) then return nil, msg or status end + + return true, data +end + +local function curl_json_upload_lib(fname, url) + local curl, curl_utils = prequire "cURL", prequire "cURL.utils" + if not (curl and curl_utils) then return curl_json_upload_app(fname, url) end + + local easy + local ok, ret = pcall(function() + local cainfo, capath = curl_utils.find_ca_bundle() + easy = curl.easy{ + url = url, + cainfo = cainfo, + capath = capath, + httppost = curl.form():add_file("json_file", fname, "application/json", "json_file"), + } + + if curl.version_info("features").SSL then + easy:setopt_ssl_verifypeer(true) + easy:setopt_ssl_verifyhost(2) + end + + local res = {} + easy + :setopt_writefunction(table.insert, res) + :perform() + return table.concat(res) + end) + + if easy then easy:close() end + if not ok then return nil, tostring(ret) end + return true, ret +end + +local curl_json_upload = curl_json_upload_lib + +local function upload_json_file(fname, url) + local ok, data = curl_json_upload(fname, url) + + if not ok then return nil, data end + + local resp, err = json_decode(data) + if not resp then return nil, "JSON decode error:\n" .. err .. "\n" .. data end + + if resp.error then return nil, resp.message, -1 end + + return resp, data +end + +return { + exec = exec; + read_file = read_file; + upload_json_file = upload_json_file; + json = { + encode = json_encode, + decode = json_decode, + init_array = json_init_array, + load_file = json_load_file, + null = json_null(), + }; +} diff --git a/mods/noita-mp/lua_modules/share/lua/5.1/luacov/defaults.lua b/mods/noita-mp/lua_modules/share/lua/5.1/luacov/defaults.lua new file mode 100644 index 000000000..66d8fd6e1 --- /dev/null +++ b/mods/noita-mp/lua_modules/share/lua/5.1/luacov/defaults.lua @@ -0,0 +1,76 @@ +--- Default values for configuration options. +-- For project specific configuration create '.luacov' file in your project +-- folder. It should be a Lua script setting various options as globals +-- or returning table of options. +-- @class module +-- @name luacov.defaults +return { + + --- Filename to store collected stats. Default: "luacov.stats.out". + statsfile = "luacov.stats.out", + + --- Filename to store report. Default: "luacov.report.out". + reportfile = "luacov.report.out", + + --- Enable saving coverage data after every `savestepsize` lines? + -- Setting this flag to `true` in config is equivalent to running LuaCov + -- using `luacov.tick` module. Default: false. + tick = false, + + --- Stats file updating frequency for `luacov.tick`. + -- The lower this value - the more frequently results will be written out to the stats file. + -- You may want to reduce this value (to, for example, 2) to avoid losing coverage data in + -- case your program may terminate without triggering luacov exit hooks that are supposed + -- to save the data. Default: 100. + savestepsize = 100, + + --- Run reporter on completion? Default: false. + runreport = false, + + --- Delete stats file after reporting? Default: false. + deletestats = false, + + --- Process Lua code loaded from raw strings? + -- That is, when the 'source' field in the debug info + -- does not start with '@'. Default: false. + codefromstrings = false, + + --- Lua patterns for files to include when reporting. + -- All will be included if nothing is listed. + -- Do not include the '.lua' extension. Path separator is always '/'. + -- Overruled by `exclude`. + -- @usage + -- include = { + -- "mymodule$", -- the main module + -- "mymodule%/.+$", -- and everything namespaced underneath it + -- } + include = {}, + + --- Lua patterns for files to exclude when reporting. + -- Nothing will be excluded if nothing is listed. + -- Do not include the '.lua' extension. Path separator is always '/'. + -- Overrules `include`. + exclude = {}, + + --- Table mapping names of modules to be included to their filenames. + -- Has no effect if empty. + -- Real filenames mentioned here will be used for reporting + -- even if the modules have been installed elsewhere. + -- Module name can contain '*' wildcard to match groups of modules, + -- in this case corresponding path will be used as a prefix directory + -- where modules from the group are located. + -- @usage + -- modules = { + -- ["some_rock"] = "src/some_rock.lua", + -- ["some_rock.*"] = "src" + -- } + modules = {}, + + --- Enable including untested files in report. + -- If `true`, all untested files in "." will be included. + -- If it is a table with directory and file paths, all untested files in these paths will be included. + -- Note that you are not allowed to use patterns in these paths. + -- Default: false. + includeuntestedfiles = false, + +} diff --git a/mods/noita-mp/lua_modules/share/lua/5.1/luacov/hook.lua b/mods/noita-mp/lua_modules/share/lua/5.1/luacov/hook.lua new file mode 100644 index 000000000..dd98cab43 --- /dev/null +++ b/mods/noita-mp/lua_modules/share/lua/5.1/luacov/hook.lua @@ -0,0 +1,81 @@ +------------------------ +-- Hook module, creates debug hook used by LuaCov. +-- @class module +-- @name luacov.hook +local hook = {} + +---------------------------------------------------------------- +local dir_sep = package.config:sub(1, 1) +if not dir_sep:find("[/\\]") then + dir_sep = "/" +end + +--- Creates a new debug hook. +-- @param runner runner module. +-- @return debug hook function that uses runner fields and functions +-- and sets `runner.data`. +function hook.new(runner) + local ignored_files = {} + local steps_after_save = 0 + + return function(_, line_nr, level) + -- Do not use string metamethods within the debug hook: + -- they may be absent if it's called from a sandboxed environment + -- or because of carelessly implemented monkey-patching. + level = level or 2 + if not runner.initialized then + return + end + + -- Get name of processed file. + local name = debug.getinfo(level, "S").source + local prefixed_name = string.match(name, "^@(.*)") + if prefixed_name then + name = prefixed_name:gsub("^%.[/\\]", ""):gsub("[/\\]", dir_sep) + elseif not runner.configuration.codefromstrings then + -- Ignore Lua code loaded from raw strings by default. + return + end + + local data = runner.data + local file = data[name] + + if not file then + -- New or ignored file. + if ignored_files[name] then + return + elseif runner.file_included(name) then + file = {max = 0, max_hits = 0} + data[name] = file + else + ignored_files[name] = true + return + end + end + + if line_nr > file.max then + file.max = line_nr + end + + local hits = (file[line_nr] or 0) + 1 + file[line_nr] = hits + + if hits > file.max_hits then + file.max_hits = hits + end + + if runner.tick then + steps_after_save = steps_after_save + 1 + + if steps_after_save == runner.configuration.savestepsize then + steps_after_save = 0 + + if not runner.paused then + runner.save_stats() + end + end + end + end +end + +return hook diff --git a/mods/noita-mp/lua_modules/share/lua/5.1/luacov/linescanner.lua b/mods/noita-mp/lua_modules/share/lua/5.1/luacov/linescanner.lua new file mode 100644 index 000000000..41f894031 --- /dev/null +++ b/mods/noita-mp/lua_modules/share/lua/5.1/luacov/linescanner.lua @@ -0,0 +1,338 @@ +local LineScanner = {} +LineScanner.__index = LineScanner + +function LineScanner:new() + return setmetatable({ + first = true, + comment = false, + after_function = false, + enabled = true + }, self) +end + +-- Raw version of string.gsub +local function replace(s, old, new) + old = old:gsub("%p", "%%%0") + new = new:gsub("%%", "%%%%") + return (s:gsub(old, new)) +end + +local fixups = { + { "=", " ?= ?" }, -- '=' may be surrounded by spaces + { "(", " ?%( ?" }, -- '(' may be surrounded by spaces + { ")", " ?%) ?" }, -- ')' may be surrounded by spaces + { "", "x ?[%[%.]? ?[ntfx0']* ?%]?" }, -- identifier, possibly indexed once + { "", "x ?, ?x[x, ]*" }, -- at least two comma-separated identifiers + { "", "%[? ?[ntfx0']+ ?%]?" }, -- field, possibly like ["this"] + { "", "[ %(]*" }, -- optional opening parentheses +} + +-- Utility function to make patterns more readable +local function fixup(pat) + for _, fixup_pair in ipairs(fixups) do + pat = replace(pat, fixup_pair[1], fixup_pair[2]) + end + + return pat +end + +--- Lines that are always excluded from accounting +local any_hits_exclusions = { + "", -- Empty line + "end[,; %)]*", -- Single "end" + "else", -- Single "else" + "repeat", -- Single "repeat" + "do", -- Single "do" + "if", -- Single "if" + "then", -- Single "then" + "while t do", -- "while true do" generates no code + "if t then", -- "if true then" generates no code + "local x", -- "local var" + fixup "local x=", -- "local var =" + fixup "local ", -- "local var1, ..., varN" + fixup "local =", -- "local var1, ..., varN =" + "local function x", -- "local function f (arg1, ..., argN)" +} + +--- Lines that are only excluded from accounting when they have 0 hits +local zero_hits_exclusions = { + "[ntfx0',= ]+,", -- "var1 var2," multi columns table stuff + "{ ?} ?,", -- Empty table before comma leaves no trace in tables and calls + fixup "=.+[,;]", -- "[123] = 23," "['foo'] = "asd"," + fixup "=function", -- "[123] = function(...)" + fixup "='", -- "[123] = [[", possibly with opening parens + "return function", -- "return function(arg1, ..., argN)" + "function", -- "function(arg1, ..., argN)" + "[ntfx0]", -- Single token expressions leave no trace in tables, function calls and sometimes assignments + "''", -- Same for strings + "{ ?}", -- Same for empty tables + fixup "", -- Same for local variables indexed once + fixup "local x=function", -- "local a = function(arg1, ..., argN)" + fixup "local x='", -- "local a = [[", possibly with opening parens + fixup "local x=(", -- "local a = (", possibly with several parens + fixup "local =(", -- "local a, b = (", possibly with several parens + fixup "local x=n", -- "local a = nil; local b = nil" produces no trace for the second statement + fixup "='", -- "a.b = [[", possibly with opening parens + fixup "=function", -- "a = function(arg1, ..., argN)" + "} ?,", -- "}," generates no trace if the table ends with a key-value pair + "} ?, ?function", -- same with "}, function(...)" + "break", -- "break" generates no trace in Lua 5.2+ + "{", -- "{" opening table + "}?[ %)]*", -- optional closing paren, possibly with several closing parens + "[ntf0']+ ?}[ %)]*" -- a constant at the end of a table, possibly with closing parens (for LuaJIT) +} + +local function excluded(exclusions, line) + for _, e in ipairs(exclusions) do + if line:match("^ *"..e.." *$") then + return true + end + end + + return false +end + +function LineScanner:find(pattern) + return self.line:find(pattern, self.i) +end + +-- Skips string literal with quote stored as self.quote. +-- @return boolean indicating success. +function LineScanner:skip_string() + -- Look for closing quote, possibly after even number of backslashes. + local _, quote_i = self:find("^(\\*)%1"..self.quote) + if not quote_i then + _, quote_i = self:find("[^\\](\\*)%1"..self.quote) + end + + if quote_i then + self.i = quote_i + 1 + self.quote = nil + table.insert(self.simple_line_buffer, "'") + return true + else + return false + end +end + +-- Skips long string literal with equal signs stored as self.equals. +-- @return boolean indicating success. +function LineScanner:skip_long_string() + local _, bracket_i = self:find("%]"..self.equals.."%]") + + if bracket_i then + self.i = bracket_i + 1 + self.equals = nil + + if self.comment then + self.comment = false + else + table.insert(self.simple_line_buffer, "'") + end + + return true + else + return false + end +end + +-- Skips function arguments. +-- @return boolean indicating success. +function LineScanner:skip_args() + local _, paren_i = self:find("%)") + + if paren_i then + self.i = paren_i + 1 + self.args = nil + return true + else + return false + end +end + +function LineScanner:skip_whitespace() + local next_i = self:find("%S") or #self.line + 1 + + if next_i ~= self.i then + self.i = next_i + table.insert(self.simple_line_buffer, " ") + end +end + +function LineScanner:skip_number() + if self:find("^0[xX]") then + self.i = self.i + 2 + end + + local _ + _, _, self.i = self:find("^[%x%.]*()") + + if self:find("^[eEpP][%+%-]") then + -- Skip exponent, too. + self.i = self.i + 2 + _, _, self.i = self:find("^[%x%.]*()") + end + + -- Skip LuaJIT number suffixes (i, ll, ull). + _, _, self.i = self:find("^[iull]*()") + table.insert(self.simple_line_buffer, "0") +end + +local keywords = {["nil"] = "n", ["true"] = "t", ["false"] = "f"} + +for _, keyword in ipairs({ + "and", "break", "do", "else", "elseif", "end", "for", "function", "goto", "if", + "in", "local", "not", "or", "repeat", "return", "then", "until", "while"}) do + keywords[keyword] = keyword +end + +function LineScanner:skip_name() + -- It is guaranteed that the first character matches "%a_". + local _, _, name = self:find("^([%w_]*)") + self.i = self.i + #name + + if keywords[name] then + name = keywords[name] + else + name = "x" + end + + table.insert(self.simple_line_buffer, name) + + if name == "function" then + -- This flag indicates that the next pair of parentheses (function args) must be skipped. + self.after_function = true + end +end + +-- Source lines can be explicitly ignored using `enable` and `disable` inline options. +-- An inline option is a simple comment: `-- luacov: enable` or `-- luacov: disable`. +-- Inline option parsing is not whitespace sensitive. +-- All lines starting from a line containing `disable` option and up to a line containing `enable` +-- option (or end of file) are excluded. + +function LineScanner:check_inline_options(comment_body) + if comment_body:find("^%s*luacov:%s*enable%s*$") then + self.enabled = true + elseif comment_body:find("^%s*luacov:%s*disable%s*$") then + self.enabled = false + end +end + +-- Consumes and analyzes a line. +-- @return boolean indicating whether line must be excluded. +-- @return boolean indicating whether line must be excluded if not hit. +function LineScanner:consume(line) + if self.first then + self.first = false + + if line:match("^#!") then + -- Ignore Unix hash-bang magic line. + return true, true + end + end + + self.line = line + -- As scanner goes through the line, it puts its simplified parts into buffer. + -- Punctuation is preserved. Whitespace is replaced with single space. + -- Literal strings are replaced with "''", so that a string literal + -- containing special characters does not confuse exclusion rules. + -- Numbers are replaced with "0". + -- Identifiers are replaced with "x". + -- Literal keywords (nil, true and false) are replaced with "n", "t" and "f", + -- other keywords are preserved. + -- Function declaration arguments are removed. + self.simple_line_buffer = {} + self.i = 1 + + while self.i <= #line do + -- One iteration of this loop handles one token, where + -- string literal start and end are considered distinct tokens. + if self.quote then + if not self:skip_string() then + -- String literal ends on another line. + break + end + elseif self.equals then + if not self:skip_long_string() then + -- Long string literal or comment ends on another line. + break + end + elseif self.args then + if not self:skip_args() then + -- Function arguments end on another line. + break + end + else + self:skip_whitespace() + + if self:find("^%.%d") then + self.i = self.i + 1 + end + + if self:find("^%d") then + self:skip_number() + elseif self:find("^[%a_]") then + self:skip_name() + else + if self:find("^%-%-") then + self.comment = true + self.i = self.i + 2 + end + + local _, bracket_i, equals = self:find("^%[(=*)%[") + if equals then + self.i = bracket_i + 1 + self.equals = equals + + if not self.comment then + table.insert(self.simple_line_buffer, "'") + end + elseif self.comment then + -- Simple comment, check if it contains inline options and skip line. + self.comment = false + local comment_body = self.line:sub(self.i) + self:check_inline_options(comment_body) + break + else + local char = line:sub(self.i, self.i) + + if char == "." then + -- Dot can't be saved as one character because of + -- ".." and "..." tokens and the fact that number literals + -- can start with one. + local _, _, dots = self:find("^(%.*)") + self.i = self.i + #dots + table.insert(self.simple_line_buffer, dots) + else + self.i = self.i + 1 + + if char == "'" or char == '"' then + table.insert(self.simple_line_buffer, "'") + self.quote = char + elseif self.after_function and char == "(" then + -- This is the opening parenthesis of function declaration args. + self.after_function = false + self.args = true + else + -- Save other punctuation literally. + -- This inserts an empty string when at the end of line, + -- which is fine. + table.insert(self.simple_line_buffer, char) + end + end + end + end + end + end + + if not self.enabled then + -- Disabled by inline options, always exclude the line. + return true, true + end + + local simple_line = table.concat(self.simple_line_buffer) + return excluded(any_hits_exclusions, simple_line), excluded(zero_hits_exclusions, simple_line) +end + +return LineScanner diff --git a/mods/noita-mp/lua_modules/share/lua/5.1/luacov/reporter.lua b/mods/noita-mp/lua_modules/share/lua/5.1/luacov/reporter.lua new file mode 100644 index 000000000..0aadce12b --- /dev/null +++ b/mods/noita-mp/lua_modules/share/lua/5.1/luacov/reporter.lua @@ -0,0 +1,510 @@ +------------------------ +-- Report module, will transform statistics file into a report. +-- @class module +-- @name luacov.reporter +local reporter = {} + +local LineScanner = require("luacov.linescanner") +local luacov = require("luacov.runner") +local util = require("luacov.util") +local lfs_ok, lfs = pcall(require, "lfs") + +---------------------------------------------------------------- +local dir_sep = package.config:sub(1, 1) +if not dir_sep:find("[/\\]") then + dir_sep = "/" +end + + +--- returns all files inside dir +--- @param dir directory to be listed +--- @treturn table with filenames and attributes +local function dirtree(dir) + assert(dir and dir ~= "", "Please pass directory parameter") + if dir:sub(-1):match("[/\\]") then + dir=string.sub(dir, 1, -2) + end + + dir = dir:gsub("[/\\]", dir_sep) + + local function yieldtree(directory) + for entry in lfs.dir(directory) do + if entry ~= "." and entry ~= ".." then + entry=directory..dir_sep..entry + local attr=lfs.attributes(entry) + coroutine.yield(entry,attr) + if attr.mode == "directory" then + yieldtree(entry) + end + end + end + end + + return coroutine.wrap(function() yieldtree(dir) end) +end + +---------------------------------------------------------------- +--- checks if string 'filename' has pattern 'pattern' +--- @param filename +--- @param pattern +--- @return boolean +local function fileMatches(filename, pattern) + return string.find(filename, pattern) +end + +---------------------------------------------------------------- +--- Basic reporter class stub. +-- Implements 'new', 'run' and 'close' methods required by `report`. +-- Provides some helper methods and stubs to be overridden by child classes. +-- @usage +-- local MyReporter = setmetatable({}, ReporterBase) +-- MyReporter.__index = MyReporter +-- function MyReporter:on_hit_line(...) +-- self:write(("File %s: hit line %s %d times"):format(...)) +-- end +-- @type ReporterBase +local ReporterBase = {} do +ReporterBase.__index = ReporterBase + +function ReporterBase:new(conf) + local stats = require("luacov.stats") + local data = stats.load(conf.statsfile) + + if not data then + return nil, "Could not load stats file " .. conf.statsfile .. "." + end + + local files = {} + local filtered_data = {} + local max_hits = 0 + + -- Several original paths can map to one real path, + -- their stats should be merged in this case. + for filename, file_stats in pairs(data) do + if luacov.file_included(filename) then + filename = luacov.real_name(filename) + + if filtered_data[filename] then + luacov.update_stats(filtered_data[filename], file_stats) + else + table.insert(files, filename) + filtered_data[filename] = file_stats + end + + max_hits = math.max(max_hits, filtered_data[filename].max_hits) + end + end + + -- including files without tests + -- only .lua files + if conf.includeuntestedfiles then + if not lfs_ok then + print("The option includeuntestedfiles requires the lfs module (from luafilesystem) to be installed.") + os.exit(1) + end + + local function add_empty_file_coverage_data(file_path) + + -- Leading "./" must be trimmed from the file paths because the paths of tested + -- files do not have a leading "./" either + if (file_path:match("^%.[/\\]")) then + file_path = file_path:sub(3) + end + + if luacov.file_included(file_path) then + local file_stats = { + max = 0, + max_hits = 0 + } + + local filename = luacov.real_name(file_path) + + if not filtered_data[filename] then + table.insert(files, filename) + filtered_data[filename] = file_stats + end + end + + end + + local function add_empty_dir_coverage_data(directory_path) + + for filename, attr in dirtree(directory_path) do + if attr.mode == "file" and fileMatches(filename, '.%.lua$') then + add_empty_file_coverage_data(filename) + end + end + + end + + if (conf.includeuntestedfiles == true) then + add_empty_dir_coverage_data("." .. dir_sep) + + elseif (type(conf.includeuntestedfiles) == "table" and conf.includeuntestedfiles[1]) then + for _, include_path in ipairs(conf.includeuntestedfiles) do + if (fileMatches(include_path, '.%.lua$')) then + add_empty_file_coverage_data(include_path) + else + add_empty_dir_coverage_data(include_path) + end + end + end + + end + + table.sort(files) + + local out, err = io.open(conf.reportfile, "w") + if not out then return nil, err end + + local o = setmetatable({ + _out = out, + _cfg = conf, + _data = filtered_data, + _files = files, + _mhit = max_hits, + }, self) + + return o +end + +--- Returns configuration table. +-- @see luacov.defaults +function ReporterBase:config() + return self._cfg +end + +--- Returns maximum number of hits per line in all coverage data. +function ReporterBase:max_hits() + return self._mhit +end + +--- Writes strings to report file. +-- @param ... strings. +function ReporterBase:write(...) + return self._out:write(...) +end + +function ReporterBase:close() + self._out:close() + self._private = nil +end + +--- Returns array of filenames to be reported. +function ReporterBase:files() + return self._files +end + +--- Returns coverage data for a file. +-- @param filename name of the file. +-- @see luacov.stats.load +function ReporterBase:stats(filename) + return self._data[filename] +end + +-- Stub methods follow. +-- luacheck: push no unused args + +--- Stub method called before reporting. +function ReporterBase:on_start() +end + +--- Stub method called before processing a file. +-- @param filename name of the file. +function ReporterBase:on_new_file(filename) +end + +--- Stub method called if a file couldn't be processed due to an error. +-- @param filename name of the file. +-- @param error_type "open", "read" or "load". +-- @param message error message. +function ReporterBase:on_file_error(filename, error_type, message) +end + +--- Stub method called for each empty source line +-- and other lines that can't be hit. +-- @param filename name of the file. +-- @param lineno line number. +-- @param line the line itself as a string. +function ReporterBase:on_empty_line(filename, lineno, line) +end + +--- Stub method called for each missed source line. +-- @param filename name of the file. +-- @param lineno line number. +-- @param line the line itself as a string. +function ReporterBase:on_mis_line(filename, lineno, line) +end + +--- Stub method called for each hit source line. +-- @param filename name of the file. +-- @param lineno line number. +-- @param line the line itself as a string. +-- @param hits number of times the line was hit. Should be positive. +function ReporterBase:on_hit_line(filename, lineno, line, hits) +end + +--- Stub method called after a file has been processed. +-- @param filename name of the file. +-- @param hits total number of hit lines in the file. +-- @param miss total number of missed lines in the file. +function ReporterBase:on_end_file(filename, hits, miss) +end + +--- Stub method called after reporting. +function ReporterBase:on_end() +end + +-- luacheck: pop + +local cluacov_ok = pcall(require, "cluacov.version") +local deepactivelines + +if cluacov_ok then + deepactivelines = require("cluacov.deepactivelines") +end + +function ReporterBase:_run_file(filename) + local file, open_err = io.open(filename) + + if not file then + self:on_file_error(filename, "open", util.unprefix(open_err, filename .. ": ")) + return + end + + local active_lines + + if cluacov_ok then + local src, read_err = file:read("*a") + + if not src then + self:on_file_error(filename, "read", read_err) + return + end + + src = src:gsub("^#![^\n]*", "") + local func, load_err = util.load_string(src, nil, "@file") + + if not func then + self:on_file_error(filename, "load", "line " .. util.unprefix(load_err, "file:")) + return + end + + active_lines = deepactivelines.get(func) + file:seek("set") + end + + self:on_new_file(filename) + local file_hits, file_miss = 0, 0 + local filedata = self:stats(filename) + + local line_nr = 1 + local scanner = LineScanner:new() + + while true do + local line = file:read("*l") + if not line then break end + + local always_excluded, excluded_when_not_hit = scanner:consume(line) + local hits = filedata[line_nr] or 0 + local included = not always_excluded and (not excluded_when_not_hit or hits ~= 0) + + if cluacov_ok then + included = included and active_lines[line_nr] + end + + if included then + if hits == 0 then + self:on_mis_line(filename, line_nr, line) + file_miss = file_miss + 1 + else + self:on_hit_line(filename, line_nr, line, hits) + file_hits = file_hits + 1 + end + else + self:on_empty_line(filename, line_nr, line) + end + + line_nr = line_nr + 1 + end + + file:close() + self:on_end_file(filename, file_hits, file_miss) +end + +function ReporterBase:run() + self:on_start() + + for _, filename in ipairs(self:files()) do + self:_run_file(filename) + end + + self:on_end() +end + +end +--- @section end +---------------------------------------------------------------- + +---------------------------------------------------------------- +local DefaultReporter = setmetatable({}, ReporterBase) do +DefaultReporter.__index = DefaultReporter + +function DefaultReporter:on_start() + local most_hits = self:max_hits() + local most_hits_length = #("%d"):format(most_hits) + + self._summary = {} + self._empty_format = (" "):rep(most_hits_length + 1) + self._zero_format = ("*"):rep(most_hits_length).."0" + self._count_format = ("%% %dd"):format(most_hits_length+1) + self._printed_first_header = false +end + +function DefaultReporter:on_new_file(filename) + self:write(("="):rep(78), "\n") + self:write(filename, "\n") + self:write(("="):rep(78), "\n") +end + +function DefaultReporter:on_file_error(filename, error_type, message) --luacheck: no self + io.stderr:write(("Couldn't %s %s: %s\n"):format(error_type, filename, message)) +end + +function DefaultReporter:on_empty_line(_, _, line) + if line == "" then + self:write("\n") + else + self:write(self._empty_format, " ", line, "\n") + end +end + +function DefaultReporter:on_mis_line(_, _, line) + self:write(self._zero_format, " ", line, "\n") +end + +function DefaultReporter:on_hit_line(_, _, line, hits) + self:write(self._count_format:format(hits), " ", line, "\n") +end + +function DefaultReporter:on_end_file(filename, hits, miss) + self._summary[filename] = { hits = hits, miss = miss } + self:write("\n") +end + +local function coverage_to_string(hits, missed) + local total = hits + missed + + if total == 0 then + total = 1 + end + + return ("%.2f%%"):format(hits/total*100.0) +end + +function DefaultReporter:on_end() + self:write(("="):rep(78), "\n") + self:write("Summary\n") + self:write(("="):rep(78), "\n") + self:write("\n") + + local lines = {{"File", "Hits", "Missed", "Coverage"}} + local total_hits, total_missed = 0, 0 + + for _, filename in ipairs(self:files()) do + local summary = self._summary[filename] + + if summary then + local hits, missed = summary.hits, summary.miss + + table.insert(lines, { + filename, + tostring(summary.hits), + tostring(summary.miss), + coverage_to_string(hits, missed) + }) + + total_hits = total_hits + hits + total_missed = total_missed + missed + end + end + + table.insert(lines, { + "Total", + tostring(total_hits), + tostring(total_missed), + coverage_to_string(total_hits, total_missed) + }) + + local max_column_lengths = {} + + for _, line in ipairs(lines) do + for column_nr, column in ipairs(line) do + max_column_lengths[column_nr] = math.max(max_column_lengths[column_nr] or -1, #column) + end + end + + local table_width = #max_column_lengths - 1 + + for _, column_length in ipairs(max_column_lengths) do + table_width = table_width + column_length + end + + + for line_nr, line in ipairs(lines) do + if line_nr == #lines or line_nr == 2 then + self:write(("-"):rep(table_width), "\n") + end + + for column_nr, column in ipairs(line) do + self:write(column) + + if column_nr == #line then + self:write("\n") + else + self:write((" "):rep(max_column_lengths[column_nr] - #column + 1)) + end + end + end +end + +end +---------------------------------------------------------------- + +--- Runs the report generator. +-- To load a config, use `luacov.runner.load_config` first. +-- @param[opt] reporter_class custom reporter class. Will be +-- instantiated using 'new' method with configuration +-- (see `luacov.defaults`) as the argument. It should +-- return nil + error if something went wrong. +-- After acquiring a reporter object its 'run' and 'close' +-- methods will be called. +-- The easiest way to implement a custom reporter class is to +-- extend `ReporterBase`. +function reporter.report(reporter_class) + local configuration = luacov.load_config() + + reporter_class = reporter_class or DefaultReporter + + local rep, err = reporter_class:new(configuration) + + if not rep then + print(err) + print("Run your Lua program with -lluacov and then rerun luacov.") + os.exit(1) + end + + rep:run() + + rep:close() + + if configuration.deletestats then + os.remove(configuration.statsfile) + end +end + +reporter.ReporterBase = ReporterBase + +reporter.DefaultReporter = DefaultReporter + +return reporter diff --git a/mods/noita-mp/lua_modules/share/lua/5.1/luacov/reporter/coveralls.lua b/mods/noita-mp/lua_modules/share/lua/5.1/luacov/reporter/coveralls.lua new file mode 100644 index 000000000..b06e72f3f --- /dev/null +++ b/mods/noita-mp/lua_modules/share/lua/5.1/luacov/reporter/coveralls.lua @@ -0,0 +1,325 @@ + +local coveralls = {} + +local luacov_reporter = require"luacov.reporter" +local utils = require"luacov.coveralls.utils" +local ci = require"luacov.coveralls.CiInfo" +local CiRepo = require"luacov.coveralls.CiRepo" + +local json = utils.json +local unix_path = require"path".new("/") + +local ReporterBase = luacov_reporter.ReporterBase + +---------------------------------------------------------------- +local CoverallsReporter = setmetatable({}, ReporterBase) do +CoverallsReporter.__index = CoverallsReporter + +local EMPTY = json.null +local ZERO = 0 + +local function debug_print(o, ...) + if not o._debug then return end + io.stdout:write(...) +end + +local function trace_json(o) + debug_print(o, "--------------------\n") + debug_print(o, "service_name : ", o._json.service_name or "", "\n") + debug_print(o, "repo_token : ", o._json.repo_token and "" or "", "\n") + debug_print(o, "service_number : ", o._json.service_number or "", "\n") + debug_print(o, "service_job_id : ", o._json.service_job_id or "", "\n") + debug_print(o, "service_pull_request : ", o._json.service_pull_request or "", "\n") + debug_print(o, "source_files : ", #o._json.source_files or "", "\n") + for _, source in ipairs(o._json.source_files) do + debug_print(o, " ", source.name, "\n") + end + if o._json.git then + debug_print(o, "git\n") + debug_print(o, " head\n") + debug_print(o, " id : ", o._json.git.head.id or "", "\n") + debug_print(o, " author_name : ", o._json.git.head.author_name or "", "\n") + debug_print(o, " author_email : ", o._json.git.head.author_email or "", "\n") + debug_print(o, " committer_name : ", o._json.git.head.committer_name or "", "\n") + debug_print(o, " committer_email: ", o._json.git.head.committer_email or "", "\n") + debug_print(o, " message : ", o._json.git.head.message or "", "\n") + debug_print(o, " branch : ", o._json.git.branch or "", "\n") + debug_print(o, " remotes\n") + for i, t in ipairs(o._json.git.remotes) do + debug_print(o, " ", t.name, " ", t.url, "\n") + end + end + debug_print(o, "--------------------\n") +end + +function CoverallsReporter:new(conf) + local o, err = ReporterBase.new(self, conf) + if not o then return nil, err end + + -- read coveralls specific configurations + local cc = conf.coveralls or {} + self._debug = not not cc.debug + if cc.merge then + self._source_files = {} + end + + local repo, err = CiRepo:new(cc.root or '.') + assert(repo, "LuaCov-covealls internal error :" .. tostring(err)) + + debug_print(o, "CI: \n") + debug_print(o, " name : ", ci.name () or "", "\n") + debug_print(o, " branch : ", ci.branch () or "", "\n") + debug_print(o, " service_number : ", ci.service_number () or "", "\n") + debug_print(o, " pull_request : ", ci.pull_request () or "", "\n") + debug_print(o, " job_id : ", ci.job_id () or "", "\n") + debug_print(o, " commit_id : ", ci.commit_id () or "", "\n") + debug_print(o, " author_name : ", ci.author_name () or "", "\n") + debug_print(o, " author_email : ", ci.author_email () or "", "\n") + debug_print(o, " committer_name : ", ci.committer_name () or "", "\n") + debug_print(o, " committer_email : ", ci.committer_email () or "", "\n") + debug_print(o, " message : ", ci.message () or "", "\n") + debug_print(o, " token : ", ci.token() and "" or "", "\n") + + debug_print(o, "Repository: \n") + debug_print(o, " type : ", repo:type (), "\n") + debug_print(o, " path : ", repo:path () or "", "\n") + debug_print(o, " version : ", repo:version () or "", "\n") + debug_print(o, " id : ", repo:id () or "", "\n") + debug_print(o, " author_name : ", repo:last_author_name () or "", "\n") + debug_print(o, " author_email : ", repo:last_author_email () or "", "\n") + debug_print(o, " committer_name : ", repo:last_committer_name () or "", "\n") + debug_print(o, " committer_email : ", repo:last_committer_email () or "", "\n") + debug_print(o, " message : ", repo:last_message () or "", "\n") + debug_print(o, " current_branch : ", repo:current_branch () or "", "\n") + + if cc.pathcorrect then + local pat = {} + -- @todo implement function as path converter? + for i, p in ipairs(cc.pathcorrect) do + assert(type(p) == "table") + assert(type(p[1]) == "string") + assert(type(p[2]) == "string") + pat[i] = {p[1], p[2]} + debug_print(o, "Add correct path: `", p[1], "` => `", p[2], "`\n") + end + o._correct_path_pat = pat + end + + local base_file + if cc.json then + local err + base_file, err = json.load_file(cc.json) + debug_print(o, "Load merge file ", tostring(cc.json), ": ", tostring((not not base_file) or err), "\n") + if base_file and base_file.source_files then + for _, source in ipairs(base_file.source_files) do + debug_print(o, " ", source.name, "\n") + end + debug_print(o, "--------------------\n") + end + if not base_file then + o:close() + return nil, "Can not merge with " .. cc.json .. ". Error: " .. (err or "") + end + end + + o._json = base_file or {} + + o._json.service_name = cc.service_name or ci.name() or o._json.service_name + o._json.repo_token = cc.repo_token or ci.token() or o._json.repo_token + o._json.service_number = o._json.service_number or ci.service_number() + o._json.service_job_id = o._json.service_job_id or ci.job_id() + o._json.source_files = o._json.source_files or json.init_array{} + o._json.service_pull_request = o._json.service_pull_request or ci.pull_request() + + if cc.build_number then + io.write("*****************************************************","\n") + io.write("WARNING! change build number is experimental feature", "\n") + io.write("and may be changed/excluded in future version!", "\n") + io.write("*****************************************************","\n") + assert(tonumber(cc.build_number)) + local sign = string.sub(cc.build_number, 1, 1) + if sign == '+' or sign == '-' then + if tonumber(o._json.service_number) then + local v = tonumber(o._json.service_number) + tonumber(cc.build_number) + debug_print(o, "change service_number from ", o._json.service_number, " to ", tostring(v), "\n") + o._json.service_number = tostring(v) + else + io.write("WARNING! can not change service_number from ", o._json.service_number, "\n") + end + else + debug_print(o, "set service_number to ", tostring(cc.build_number), "\n") + o._json.service_number = cc.build_number + end + end + + if repo:type() == 'git' then + o._json.git = o._json.git or {} + o._json.git.head = o._json.git.head or {} + + o._json.git.head.id = o._json.git.head.id or repo:id() + o._json.git.head.author_name = o._json.git.head.author_name or repo:last_author_name() + o._json.git.head.author_email = o._json.git.head.author_email or repo:last_author_email() + o._json.git.head.committer_name = o._json.git.head.committer_name or repo:last_committer_name() + o._json.git.head.committer_email = o._json.git.head.committer_email or repo:last_committer_email() + o._json.git.head.message = o._json.git.head.message or repo:last_message() + o._json.git.branch = o._json.git.branch or ci.branch() or repo:current_branch() + if not o._json.git.remotes then + o._json.git.remotes = json.init_array{} + local t = repo:remotes() + if t then for name, url in pairs(t) do + table.insert(o._json.git.remotes,{name=name,url=url}) + end end + end + end + + return o +end + +function CoverallsReporter:correct_path(path) + local before = path + + if self._correct_path_pat then + for _, pat in ipairs(self._correct_path_pat) do + path = path:gsub(pat[1], pat[2]) + end + end + + -- @todo check if we have path not relevant to repo + -- if is abs path then this is error path. + + path = unix_path:normolize(path) + + if before ~= path then + debug_print(self, "correct path: ", before, "=>", path, "\n") + end + + return path +end + +function CoverallsReporter:on_start() +end + +function CoverallsReporter:on_new_file(filename) + local name = self:correct_path(filename) + local source_file + + if self._source_files then + source_file = self._source_files[name] + end + + if source_file then + debug_print(self, "Merge duplicate file: ", filename, "\n") + assert(source_file.name == name, "Expected: " .. tostring(name) .. " got " .. tostring(source_file.name)) + source_file.count = 0 + source_file.hits = 0 + source_file.miss = 0 + else + source_file = { + name = name; + source = {}; + coverage = json.init_array{}; + count = 0; + hits = 0; + miss = 0; + } + end + + self._current_file = source_file; +end + +local function get_cov(self, i, line) + local cov = self._current_file.coverage[i] + if not self._source_files then + assert(cov == nil, tostring(cov)) + end + + if cov == nil then return nil end + + local exists_line = self._current_file.source[i] + if line ~= exists_line then + local pcov + if cov == EMPTY then pcov = '' + elseif cov == ZERO then pcov = '' + else pcov = tostring(cov) end + io.write("\nWARNING: try merge different files as ", tostring(self._current_file.name), "\n") + debug_print(self, "Line ", tostring(i), "(", pcov, ")\n") + debug_print(self, "- ", tostring(exists_line), "\n") + debug_print(self, "+ ", tostring(line), "\n") + end + + return cov +end + +function CoverallsReporter:on_empty_line(filename, lineno, line) + local i = self._current_file.count + 1 + local cov = get_cov(self, i, line) + + self._current_file.count = i + self._current_file.coverage[i] = cov or EMPTY + self._current_file.source[i] = line +end + +function CoverallsReporter:on_mis_line(filename, lineno, line) + local i = self._current_file.count + 1 + local cov = get_cov(self, i, line) + + self._current_file.count = i + self._current_file.miss = self._current_file.miss + 1 + self._current_file.coverage[i] = cov or ZERO + self._current_file.source[i] = line +end + +function CoverallsReporter:on_hit_line(filename, lineno, line, hits) + local i = self._current_file.count + 1 + local cov = tonumber(get_cov(self, i, line)) + + self._current_file.count = i + self._current_file.hits = self._current_file.hits + 1 + self._current_file.coverage[i] = (cov or 0) + hits + self._current_file.source[i] = line +end + +function CoverallsReporter:on_end_file(filename, hits, miss) + local source_file = self._current_file + + local total = source_file.hits + source_file.miss + local cover = 0 + if total ~= 0 then cover = 100 * (source_file.hits / total) end + + print( string.format("File '%s'", source_file.name) ) + print( string.format("Lines executed:%.2f%% of %d\n", cover, total) ) + + source_file.count = nil + source_file.hits = nil + source_file.miss = nil + + if self._source_files then + if self._source_files[source_file.name] then + return + end + self._source_files[source_file.name] = source_file + end + + table.insert(self._json.source_files, source_file) +end + +function CoverallsReporter:on_end() + for _, source_file in ipairs(self._json.source_files) do + if type(source_file.source) == 'table' then + source_file.source = table.concat(source_file.source, "\n") + end + end + + trace_json(self) + local msg = json.encode(self._json) + self:write(msg) +end + +end +---------------------------------------------------------------- + +function coveralls.report() + return luacov_reporter.report(CoverallsReporter) +end + +return coveralls diff --git a/mods/noita-mp/lua_modules/share/lua/5.1/luacov/reporter/default.lua b/mods/noita-mp/lua_modules/share/lua/5.1/luacov/reporter/default.lua new file mode 100644 index 000000000..f039e4425 --- /dev/null +++ b/mods/noita-mp/lua_modules/share/lua/5.1/luacov/reporter/default.lua @@ -0,0 +1 @@ +return require "luacov.reporter" \ No newline at end of file diff --git a/mods/noita-mp/lua_modules/share/lua/5.1/luacov/runner.lua b/mods/noita-mp/lua_modules/share/lua/5.1/luacov/runner.lua new file mode 100644 index 000000000..6be14e2e3 --- /dev/null +++ b/mods/noita-mp/lua_modules/share/lua/5.1/luacov/runner.lua @@ -0,0 +1,681 @@ +--------------------------------------------------- +-- Statistics collecting module. +-- Calling the module table is a shortcut to calling the `init` function. +-- @class module +-- @name luacov.runner + +local runner = {} +--- LuaCov version in `MAJOR.MINOR.PATCH` format. +runner.version = "0.15.0" + +local stats = require("luacov.stats") +local util = require("luacov.util") +runner.defaults = require("luacov.defaults") + +local debug = require("debug") +local raw_os_exit = os.exit + +local new_anchor = newproxy or function() return {} end -- luacheck: compat + +-- Returns an anchor that runs fn when collected. +local function on_exit_wrap(fn) + local anchor = new_anchor() + debug.setmetatable(anchor, {__gc = fn}) + return anchor +end + +runner.data = {} +runner.paused = true +runner.initialized = false +runner.tick = false + +-- Checks if a string matches at least one of patterns. +-- @param patterns array of patterns or nil +-- @param str string to match +-- @param on_empty return value in case of empty pattern array +local function match_any(patterns, str, on_empty) + if not patterns or not patterns[1] then + return on_empty + end + + for _, pattern in ipairs(patterns) do + if string.match(str, pattern) then + return true + end + end + + return false +end + +-------------------------------------------------- +-- Uses LuaCov's configuration to check if a file is included for +-- coverage data collection. +-- @param filename name of the file. +-- @return true if file is included, false otherwise. +function runner.file_included(filename) + -- Normalize file names before using patterns. + filename = string.gsub(filename, "\\", "/") + filename = string.gsub(filename, "%.lua$", "") + + -- If include list is empty, everything is included by default. + -- If exclude list is empty, nothing is excluded by default. + return match_any(runner.configuration.include, filename, true) and + not match_any(runner.configuration.exclude, filename, false) +end + +-------------------------------------------------- +-- Adds stats to an existing file stats table. +-- @param old_stats stats to be updated. +-- @param extra_stats another stats table, will be broken during update. +function runner.update_stats(old_stats, extra_stats) + old_stats.max = math.max(old_stats.max, extra_stats.max) + + -- Remove string keys so that they do not appear when iterating + -- over 'extra_stats'. + extra_stats.max = nil + extra_stats.max_hits = nil + + for line_nr, run_nr in pairs(extra_stats) do + old_stats[line_nr] = (old_stats[line_nr] or 0) + run_nr + old_stats.max_hits = math.max(old_stats.max_hits, old_stats[line_nr]) + end +end + +-- Adds accumulated stats to existing stats file or writes a new one, then resets data. +function runner.save_stats() + local loaded = stats.load(runner.configuration.statsfile) or {} + + for name, file_data in pairs(runner.data) do + if loaded[name] then + runner.update_stats(loaded[name], file_data) + else + loaded[name] = file_data + end + end + + stats.save(runner.configuration.statsfile, loaded) + runner.data = {} +end + +local cluacov_ok = pcall(require, "cluacov.version") + +-------------------------------------------------- +-- Debug hook set by LuaCov. +-- Acknowledges that a line is executed, but does nothing +-- if called manually before coverage gathering is started. +-- @param _ event type, should always be "line". +-- @param line_nr line number. +-- @param[opt] level passed to debug.getinfo to get name of processed file, +-- 2 by default. Increase it if this function is called manually +-- from another debug hook. +-- @usage +-- local function custom_hook(_, line) +-- runner.debug_hook(_, line, 3) +-- extra_processing(line) +-- end +-- @function debug_hook +runner.debug_hook = require(cluacov_ok and "cluacov.hook" or "luacov.hook").new(runner) + +------------------------------------------------------ +-- Runs the reporter specified in configuration. +-- @param[opt] configuration if string, filename of config file (used to call `load_config`). +-- If table then config table (see file `luacov.default.lua` for an example). +-- If `configuration.reporter` is not set, runs the default reporter; +-- otherwise, it must be a module name in 'luacov.reporter' namespace. +-- The module must contain 'report' function, which is called without arguments. +function runner.run_report(configuration) + configuration = runner.load_config(configuration) + local reporter = "luacov.reporter" + + if configuration.reporter then + reporter = reporter .. "." .. configuration.reporter + end + + require(reporter).report() +end + +local on_exit_run_once = false + +local function on_exit() + -- Lua >= 5.2 could call __gc when user call os.exit + -- so this method could be called twice + if on_exit_run_once then return end + on_exit_run_once = true + runner.save_stats() + + if runner.configuration.runreport then + runner.run_report(runner.configuration) + end +end + +local dir_sep = package.config:sub(1, 1) +local wildcard_expansion = "[^/]+" + +if not dir_sep:find("[/\\]") then + dir_sep = "/" +end + +local function escape_module_punctuation(ch) + if ch == "." then + return "/" + elseif ch == "*" then + return wildcard_expansion + else + return "%" .. ch + end +end + +local function reversed_module_name_parts(name) + local parts = {} + + for part in name:gmatch("[^%.]+") do + table.insert(parts, 1, part) + end + + return parts +end + +-- This function is used for sorting module names. +-- More specific names should come first. +-- E.g. rule for 'foo.bar' should override rule for 'foo.*', +-- rule for 'foo.*' should override rule for 'foo.*.*', +-- and rule for 'a.b' should override rule for 'b'. +-- To be more precise, because names become patterns that are matched +-- from the end, the name that has the first (from the end) literal part +-- (and the corresponding part for the other name is not literal) +-- is considered more specific. +local function compare_names(name1, name2) + local parts1 = reversed_module_name_parts(name1) + local parts2 = reversed_module_name_parts(name2) + + for i = 1, math.max(#parts1, #parts2) do + if not parts1[i] then return false end + if not parts2[i] then return true end + + local is_literal1 = not parts1[i]:find("%*") + local is_literal2 = not parts2[i]:find("%*") + + if is_literal1 ~= is_literal2 then + return is_literal1 + end + end + + -- Names are at the same level of specificness, + -- fall back to lexicographical comparison. + return name1 < name2 +end + +-- Sets runner.modules using runner.configuration.modules. +-- Produces arrays of module patterns and filenames and sets +-- them as runner.modules.patterns and runner.modules.filenames. +-- Appends these patterns to the include list. +local function acknowledge_modules() + runner.modules = {patterns = {}, filenames = {}} + + if not runner.configuration.modules then + return + end + + if not runner.configuration.include then + runner.configuration.include = {} + end + + local names = {} + + for name in pairs(runner.configuration.modules) do + table.insert(names, name) + end + + table.sort(names, compare_names) + + for _, name in ipairs(names) do + local pattern = name:gsub("%p", escape_module_punctuation) .. "$" + local filename = runner.configuration.modules[name]:gsub("[/\\]", dir_sep) + table.insert(runner.modules.patterns, pattern) + table.insert(runner.configuration.include, pattern) + table.insert(runner.modules.filenames, filename) + + if filename:match("init%.lua$") then + pattern = pattern:gsub("$$", "/init$") + table.insert(runner.modules.patterns, pattern) + table.insert(runner.configuration.include, pattern) + table.insert(runner.modules.filenames, filename) + end + end +end + +-------------------------------------------------- +-- Returns real name for a source file name +-- using `luacov.defaults.modules` option. +-- @param filename name of the file. +function runner.real_name(filename) + local orig_filename = filename + -- Normalize file names before using patterns. + filename = filename:gsub("\\", "/"):gsub("%.lua$", "") + + for i, pattern in ipairs(runner.modules.patterns) do + local match = filename:match(pattern) + + if match then + local new_filename = runner.modules.filenames[i] + + if pattern:find(wildcard_expansion, 1, true) then + -- Given a prefix directory, join it + -- with matched part of source file name. + if not new_filename:match("/$") then + new_filename = new_filename .. "/" + end + + new_filename = new_filename .. match .. ".lua" + end + + -- Switch slashes back to native. + return (new_filename:gsub("^%.[/\\]", ""):gsub("[/\\]", dir_sep)) + end + end + + return orig_filename +end + +-- Always exclude luacov's own files. +local luacov_excludes = { + "luacov$", + "luacov/hook$", + "luacov/reporter$", + "luacov/reporter/default$", + "luacov/defaults$", + "luacov/runner$", + "luacov/stats$", + "luacov/tick$", + "luacov/util$", + "cluacov/version$" +} + +local function is_absolute(path) + if path:sub(1, 1) == dir_sep or path:sub(1, 1) == "/" then + return true + end + + if dir_sep == "\\" and path:find("^%a:") then + return true + end + + return false +end + +local function get_cur_dir() + local pwd_cmd = dir_sep == "\\" and "cd 2>nul" or "pwd 2>/dev/null" + local handler = io.popen(pwd_cmd, "r") + local cur_dir = handler:read() + handler:close() + cur_dir = cur_dir:gsub("\r?\n$", "") + + if cur_dir:sub(-1) ~= dir_sep and cur_dir:sub(-1) ~= "/" then + cur_dir = cur_dir .. dir_sep + end + + return cur_dir +end + +-- Sets configuration. If some options are missing, default values are used instead. +local function set_config(configuration) + runner.configuration = {} + + for option, default_value in pairs(runner.defaults) do + runner.configuration[option] = default_value + end + + for option, value in pairs(configuration) do + runner.configuration[option] = value + end + + -- Program using LuaCov may change directory during its execution. + -- Convert path options to absolute paths to use correct paths anyway. + local cur_dir + + for _, option in ipairs({"statsfile", "reportfile"}) do + local path = runner.configuration[option] + + if not is_absolute(path) then + cur_dir = cur_dir or get_cur_dir() + runner.configuration[option] = cur_dir .. path + end + end + + acknowledge_modules() + + for _, patt in ipairs(luacov_excludes) do + table.insert(runner.configuration.exclude, patt) + end + + runner.tick = runner.tick or runner.configuration.tick +end + +local function load_config_file(name, is_default) + local conf = setmetatable({}, {__index = _G}) + + local ok, ret, error_msg = util.load_config(name, conf) + + if ok then + if type(ret) == "table" then + for key, value in pairs(ret) do + if conf[key] == nil then + conf[key] = value + end + end + end + + return conf + end + + local error_type = ret + + if error_type == "read" and is_default then + return nil + end + + io.stderr:write(("Error: couldn't %s config file %s: %s\n"):format(error_type, name, error_msg)) + raw_os_exit(1) +end + +local default_config_file = ".luacov" + +------------------------------------------------------ +-- Loads a valid configuration. +-- @param[opt] configuration user provided config (config-table or filename) +-- @return existing configuration if already set, otherwise loads a new +-- config from the provided data or the defaults. +-- When loading a new config, if some options are missing, default values +-- from `luacov.defaults` are used instead. +function runner.load_config(configuration) + if not runner.configuration then + if not configuration then + -- Nothing provided, load from default location if possible. + set_config(load_config_file(default_config_file, true) or runner.defaults) + elseif type(configuration) == "string" then + set_config(load_config_file(configuration)) + elseif type(configuration) == "table" then + set_config(configuration) + else + error("Expected filename, config table or nil. Got " .. type(configuration)) + end + end + + return runner.configuration +end + +-------------------------------------------------- +-- Pauses saving data collected by LuaCov's runner. +-- Allows other processes to write to the same stats file. +-- Data is still collected during pause. +function runner.pause() + runner.paused = true +end + +-------------------------------------------------- +-- Resumes saving data collected by LuaCov's runner. +function runner.resume() + runner.paused = false +end + +local hook_per_thread + +-- Determines whether debug hooks are separate for each thread. +local function has_hook_per_thread() + if hook_per_thread == nil then + local old_hook, old_mask, old_count = debug.gethook() + local noop = function() end + debug.sethook(noop, "l") + local thread_hook = coroutine.wrap(function() return debug.gethook() end)() + hook_per_thread = thread_hook ~= noop + debug.sethook(old_hook, old_mask, old_count) + end + + return hook_per_thread +end + +-------------------------------------------------- +-- Wraps a function, enabling coverage gathering in it explicitly. +-- LuaCov gathers coverage using a debug hook, and patches coroutine +-- library to set it on created threads when under standard Lua, where each +-- coroutine has its own hook. If a coroutine is created using Lua C API +-- or before the monkey-patching, this wrapper should be applied to the +-- main function of the coroutine. Under LuaJIT this function is redundant, +-- as there is only one, global debug hook. +-- @param f a function +-- @return a function that enables coverage gathering and calls the original function. +-- @usage +-- local coro = coroutine.create(runner.with_luacov(func)) +function runner.with_luacov(f) + return function(...) + if has_hook_per_thread() then + debug.sethook(runner.debug_hook, "l") + end + + return f(...) + end +end + +-------------------------------------------------- +-- Initializes LuaCov runner to start collecting data. +-- @param[opt] configuration if string, filename of config file (used to call `load_config`). +-- If table then config table (see file `luacov.default.lua` for an example) +function runner.init(configuration) + runner.configuration = runner.load_config(configuration) + + -- metatable trick on filehandle won't work if Lua exits through + -- os.exit() hence wrap that with exit code as well + os.exit = function(...) -- luacheck: no global + on_exit() + raw_os_exit(...) + end + + debug.sethook(runner.debug_hook, "l") + + if has_hook_per_thread() then + -- debug must be set for each coroutine separately + -- hence wrap coroutine function to set the hook there + -- as well + local rawcoroutinecreate = coroutine.create + coroutine.create = function(...) -- luacheck: no global + local co = rawcoroutinecreate(...) + debug.sethook(co, runner.debug_hook, "l") + return co + end + + -- Version of assert which handles non-string errors properly. + local function safeassert(ok, ...) + if ok then + return ... + else + error(..., 0) + end + end + + coroutine.wrap = function(...) -- luacheck: no global + local co = rawcoroutinecreate(...) + debug.sethook(co, runner.debug_hook, "l") + return function(...) + return safeassert(coroutine.resume(co, ...)) + end + end + end + + if not runner.tick then + runner.on_exit_trick = on_exit_wrap(on_exit) + end + + runner.initialized = true + runner.paused = false +end + +-------------------------------------------------- +-- Shuts down LuaCov's runner. +-- This should only be called from daemon processes or sandboxes which have +-- disabled os.exit and other hooks that are used to determine shutdown. +function runner.shutdown() + on_exit() +end + +-- Gets the sourcefilename from a function. +-- @param func function to lookup. +-- @return sourcefilename or nil when not found. +local function getsourcefile(func) + assert(type(func) == "function") + local d = debug.getinfo(func).source + if d and d:sub(1, 1) == "@" then + return d:sub(2) + end +end + +-- Looks for a function inside a table. +-- @param searched set of already checked tables. +local function findfunction(t, searched) + if searched[t] then + return + end + + searched[t] = true + + for _, v in pairs(t) do + if type(v) == "function" then + return v + elseif type(v) == "table" then + local func = findfunction(v, searched) + if func then return func end + end + end +end + +-- Gets source filename from a file name, module name, function or table. +-- @param name string; filename, +-- string; modulename as passed to require(), +-- function; where containing file is looked up, +-- table; module table where containing file is looked up +-- @raise error message if could not find source filename. +-- @return source filename. +local function getfilename(name) + if type(name) == "function" then + local sourcefile = getsourcefile(name) + + if not sourcefile then + error("Could not infer source filename") + end + + return sourcefile + elseif type(name) == "table" then + local func = findfunction(name, {}) + + if not func then + error("Could not find a function within " .. tostring(name)) + end + + return getfilename(func) + else + if type(name) ~= "string" then + error("Bad argument: " .. tostring(name)) + end + + if util.file_exists(name) then + return name + end + + local success, result = pcall(require, name) + + if not success then + error("Module/file '" .. name .. "' was not found") + end + + if type(result) ~= "table" and type(result) ~= "function" then + error("Module '" .. name .. "' did not return a result to lookup its file name") + end + + return getfilename(result) + end +end + +-- Escapes a filename. +-- Escapes magic pattern characters, removes .lua extension +-- and replaces dir seps by '/'. +local function escapefilename(name) + return name:gsub("%.lua$", ""):gsub("[%%%^%$%.%(%)%[%]%+%*%-%?]","%%%0"):gsub("\\", "/") +end + +local function addfiletolist(name, list) + local f = "^"..escapefilename(getfilename(name)).."$" + table.insert(list, f) + return f +end + +local function addtreetolist(name, level, list) + local f = escapefilename(getfilename(name)) + + if level or f:match("/init$") then + -- chop the last backslash and everything after it + f = f:match("^(.*)/") or f + end + + local t = "^"..f.."/" -- the tree behind the file + f = "^"..f.."$" -- the file + table.insert(list, f) + table.insert(list, t) + return f, t +end + +-- Returns a pcall result, with the initial 'true' value removed +-- and 'false' replaced with nil. +local function checkresult(ok, ...) + if ok then + return ... -- success, strip 'true' value + else + return nil, ... -- failure; nil + error + end +end + +------------------------------------------------------------------- +-- Adds a file to the exclude list (see `luacov.defaults`). +-- If passed a function, then through debuginfo the source filename is collected. In case of a table +-- it will recursively search the table for a function, which is then resolved to a filename through debuginfo. +-- If the parameter is a string, it will first check if a file by that name exists. If it doesn't exist +-- it will call `require(name)` to load a module by that name, and the result of require (function or +-- table expected) is used as described above to get the sourcefile. +-- @param name +-- * string; literal filename, +-- * string; modulename as passed to require(), +-- * function; where containing file is looked up, +-- * table; module table where containing file is looked up +-- @return the pattern as added to the list, or nil + error +function runner.excludefile(name) + return checkresult(pcall(addfiletolist, name, runner.configuration.exclude)) +end +------------------------------------------------------------------- +-- Adds a file to the include list (see `luacov.defaults`). +-- @param name see `excludefile` +-- @return the pattern as added to the list, or nil + error +function runner.includefile(name) + return checkresult(pcall(addfiletolist, name, runner.configuration.include)) +end +------------------------------------------------------------------- +-- Adds a tree to the exclude list (see `luacov.defaults`). +-- If `name = 'luacov'` and `level = nil` then +-- module 'luacov' (luacov.lua) and the tree 'luacov' (containing `luacov/runner.lua` etc.) is excluded. +-- If `name = 'pl.path'` and `level = true` then +-- module 'pl' (pl.lua) and the tree 'pl' (containing `pl/path.lua` etc.) is excluded. +-- NOTE: in case of an 'init.lua' file, the 'level' parameter will always be set +-- @param name see `excludefile` +-- @param level if truthy then one level up is added, including the tree +-- @return the 2 patterns as added to the list (file and tree), or nil + error +function runner.excludetree(name, level) + return checkresult(pcall(addtreetolist, name, level, runner.configuration.exclude)) +end +------------------------------------------------------------------- +-- Adds a tree to the include list (see `luacov.defaults`). +-- @param name see `excludefile` +-- @param level see `includetree` +-- @return the 2 patterns as added to the list (file and tree), or nil + error +function runner.includetree(name, level) + return checkresult(pcall(addtreetolist, name, level, runner.configuration.include)) +end + + +return setmetatable(runner, {__call = function(_, configfile) runner.init(configfile) end}) diff --git a/mods/noita-mp/lua_modules/share/lua/5.1/luacov/stats.lua b/mods/noita-mp/lua_modules/share/lua/5.1/luacov/stats.lua new file mode 100644 index 000000000..c40c0c022 --- /dev/null +++ b/mods/noita-mp/lua_modules/share/lua/5.1/luacov/stats.lua @@ -0,0 +1,80 @@ +----------------------------------------------------- +-- Manages the file with statistics (being) collected. +-- @class module +-- @name luacov.stats +local stats = {} + +----------------------------------------------------- +-- Loads the stats file. +-- @param statsfile path to the stats file. +-- @return table with data or nil if couldn't load. +-- The table maps filenames to stats tables. +-- Per-file tables map line numbers to hits or nils when there are no hits. +-- Additionally, .max field contains maximum line number +-- and .max_hits contains maximum number of hits in the file. +function stats.load(statsfile) + local data = {} + local fd = io.open(statsfile, "r") + if not fd then + return nil + end + while true do + local max = fd:read("*n") + if not max then + break + end + if fd:read(1) ~= ":" then + break + end + local filename = fd:read("*l") + if not filename then + break + end + data[filename] = { + max = max, + max_hits = 0 + } + for i = 1, max do + local hits = fd:read("*n") + if not hits then + break + end + if fd:read(1) ~= " " then + break + end + if hits > 0 then + data[filename][i] = hits + data[filename].max_hits = math.max(data[filename].max_hits, hits) + end + end + end + fd:close() + return data +end + +----------------------------------------------------- +-- Saves data to the stats file. +-- @param statsfile path to the stats file. +-- @param data data to store. +function stats.save(statsfile, data) + local fd = assert(io.open(statsfile, "w")) + + local filenames = {} + for filename in pairs(data) do + table.insert(filenames, filename) + end + table.sort(filenames) + + for _, filename in ipairs(filenames) do + local filedata = data[filename] + fd:write(filedata.max, ":", filename, "\n") + + for i = 1, filedata.max do + fd:write(tostring(filedata[i] or 0), " ") + end + fd:write("\n") + end + fd:close() +end + +return stats diff --git a/mods/noita-mp/lua_modules/share/lua/5.1/luacov/tick.lua b/mods/noita-mp/lua_modules/share/lua/5.1/luacov/tick.lua new file mode 100644 index 000000000..bdb9f481e --- /dev/null +++ b/mods/noita-mp/lua_modules/share/lua/5.1/luacov/tick.lua @@ -0,0 +1,11 @@ + +--- Load luacov using this if you want it to periodically +-- save the stats file. This is useful if your script is +-- a daemon (i.e., does not properly terminate). +-- @class module +-- @name luacov.tick +-- @see luacov.defaults.savestepsize +local runner = require("luacov.runner") +runner.tick = true +runner.init() +return {} diff --git a/mods/noita-mp/lua_modules/share/lua/5.1/luacov/util.lua b/mods/noita-mp/lua_modules/share/lua/5.1/luacov/util.lua new file mode 100644 index 000000000..c4a4d3d63 --- /dev/null +++ b/mods/noita-mp/lua_modules/share/lua/5.1/luacov/util.lua @@ -0,0 +1,103 @@ +--------------------------------------------------- +-- Utility module. +-- @class module +-- @name luacov.util +local util = {} + +--- Removes a prefix from a string if it's present. +-- @param str a string. +-- @param prefix a prefix string. +-- @return original string if does not start with prefix +-- or string without prefix. +function util.unprefix(str, prefix) + if str:sub(1, #prefix) == prefix then + return str:sub(#prefix + 1) + else + return str + end +end + +-- Returns contents of a file or nil + error message. +local function read_file(name) + local f, open_err = io.open(name, "rb") + + if not f then + return nil, util.unprefix(open_err, name .. ": ") + end + + local contents, read_err = f:read("*a") + f:close() + + if contents then + return contents + else + return nil, read_err + end +end + +--- Loads a string. +-- @param str a string. +-- @param[opt] env environment table. +-- @param[opt] chunkname chunk name. +function util.load_string(str, env, chunkname) + if _VERSION:find("5%.1") then + local func, err = loadstring(str, chunkname) -- luacheck: compat + + if not func then + return nil, err + end + + if env then + setfenv(func, env) -- luacheck: compat + end + + return func + else + return load(str, chunkname, "bt", env or _ENV) -- luacheck: compat + end +end + +--- Load a config file. +-- Reads, loads and runs a Lua file in an environment. +-- @param name file name. +-- @param env environment table. +-- @return true and the first return value of config on success, +-- nil + error type + error message on failure, where error type +-- can be "read", "load" or "run". +function util.load_config(name, env) + local src, read_err = read_file(name) + + if not src then + return nil, "read", read_err + end + + local func, load_err = util.load_string(src, env, "@config") + + if not func then + return nil, "load", "line " .. util.unprefix(load_err, "config:") + end + + local ok, ret = pcall(func) + + if not ok then + return nil, "run", "line " .. util.unprefix(ret, "config:") + end + + return true, ret +end + +--- Checks if a file exists. +-- @param name file name. +-- @return true if file can be opened, false otherwise. +function util.file_exists(name) + local f = io.open(name) + + if f then + f:close() + return true + else + return false + end +end + +return util diff --git a/mods/noita-mp/lua_modules/share/lua/5.1/luafilesystem_ffi_scm_1-lfs.lua b/mods/noita-mp/lua_modules/share/lua/5.1/luafilesystem_ffi_scm_1-lfs.lua new file mode 100644 index 000000000..91aea2c1c --- /dev/null +++ b/mods/noita-mp/lua_modules/share/lua/5.1/luafilesystem_ffi_scm_1-lfs.lua @@ -0,0 +1,694 @@ +local bit = require "bit" +local ffi = require "ffi" + + +local pairs = pairs +local tonumber = tonumber +local type = type +local band = bit.band +local rshift = bit.rshift +local io_type = io.type +local lib = ffi.C +local ffi_errno = ffi.errno +local ffi_new = ffi.new +local ffi_str = ffi.string +local concat = table.concat +local has_table_new, new_tab = pcall(require, "table.new") +if not has_table_new or type(new_tab) ~= "function" then + new_tab = function () return {} end +end + + +local _M = { + _VERSION = "0.3", +} + +-- common utils/constants +local IS_64_BIT = ffi.abi('64bit') +local ERANGE = 'Result too large' + +if not pcall(ffi.typeof, "ssize_t") then + -- LuaJIT 2.0 doesn't have ssize_t as a builtin type, let's define it + ffi.cdef("typedef intptr_t ssize_t") +end + +ffi.cdef([[ + char* strerror(int errnum); +]]) + +local function errno() + return ffi_str(lib.strerror(ffi_errno())) +end + +local OS = ffi.os +if OS == "Windows" then + error("Windows is not supported anymore. Use https://github.com/sonoro1234/luafilesystem instead.") +end + +-- sys/syslimits.h +local MAXPATH +if OS == 'Linux' then + MAXPATH = 4096 +else + MAXPATH = 1024 +end + +-- misc +ffi.cdef([[ + char *getcwd(char *buf, size_t size); + int chdir(const char *path); + int rmdir(const char *pathname); + typedef unsigned int mode_t; + int mkdir(const char *pathname, mode_t mode); + typedef size_t time_t; + struct utimebuf { + time_t actime; + time_t modtime; + }; + int utime(const char *file, const struct utimebuf *times); + int link(const char *oldpath, const char *newpath); + int symlink(const char *oldpath, const char *newpath); +]]) + +function _M.chdir(path) + if lib.chdir(path) == 0 then + return true + end + return nil, errno() +end + +function _M.currentdir() + local size = MAXPATH + while true do + local buf = ffi_new("char[?]", size) + if lib.getcwd(buf, size) ~= nil then + return ffi_str(buf) + end + local err = errno() + if err ~= ERANGE then + return nil, err + end + size = size * 2 + end +end + +function _M.mkdir(path, mode) + if lib.mkdir(path, mode or 509) == 0 then + return true + end + return nil, errno() +end + +function _M.rmdir(path) + if lib.rmdir(path) == 0 then + return true + end + return nil, errno() +end + +function _M.touch(path, actime, modtime) + local buf + + if type(actime) == "number" then + modtime = modtime or actime + buf = ffi_new("struct utimebuf") + buf.actime = actime + buf.modtime = modtime + end + + local p = ffi_new("unsigned char[?]", #path + 1, path) + if lib.utime(p, buf) == 0 then + return true + end + return nil, errno() +end + +function _M.setmode() + return true, "binary" +end + +function _M.link(old, new, symlink) + local f = symlink and lib.symlink or lib.link + if f(old, new) == 0 then + return true + end + return nil, errno() +end + +local dirent_def +if OS == 'OSX' or OS == 'BSD' then + dirent_def = [[ + /* _DARWIN_FEATURE_64_BIT_INODE is NOT defined here? */ + struct dirent { + uint32_t d_ino; + uint16_t d_reclen; + uint8_t d_type; + uint8_t d_namlen; + char d_name[256]; + }; + ]] +else + dirent_def = [[ + struct dirent { + int64_t d_ino; + size_t d_off; + unsigned short d_reclen; + unsigned char d_type; + char d_name[256]; + }; + ]] +end + +ffi.cdef(dirent_def .. [[ + typedef struct __dirstream DIR; + DIR *opendir(const char *name); + struct dirent *readdir(DIR *dirp); + int closedir(DIR *dirp); +]]) + +local function close(dir) + if dir._dentry ~= nil then + lib.closedir(dir._dentry) + dir._dentry = nil + dir.closed = true + end +end + +local function iterator(dir) + if dir.closed ~= false then error("closed directory") end + + local entry = lib.readdir(dir._dentry) + if entry ~= nil then + return ffi_str(entry.d_name) + else + close(dir) + return nil + end +end + +local dir_obj_type = ffi.metatype([[ + struct { + DIR *_dentry; + bool closed; + } +]], +{__index = { + next = iterator, + close = close, +}, __gc = close +}) + +function _M.dir(path) + local dentry = lib.opendir(path) + if dentry == nil then + error("cannot open "..path.." : "..errno()) + end + local dir_obj = ffi_new(dir_obj_type) + dir_obj._dentry = dentry + dir_obj.closed = false; + return iterator, dir_obj +end + +local SEEK_SET = 0 +local F_SETLK = (OS == 'Linux') and 6 or 8 +local mode_ltype_map +local flock_def +if OS == 'Linux' then + flock_def = [[ + struct flock { + short int l_type; + short int l_whence; + int64_t l_start; + int64_t l_len; + int l_pid; + }; + ]] + mode_ltype_map = { + r = 0, -- F_RDLCK + w = 1, -- F_WRLCK + u = 2, -- F_UNLCK + } +else + flock_def = [[ + struct flock { + int64_t l_start; + int64_t l_len; + int32_t l_pid; + short l_type; + short l_whence; + }; + ]] + mode_ltype_map = { + r = 1, -- F_RDLCK + u = 2, -- F_UNLCK + w = 3, -- F_WRLCK + } +end + +ffi.cdef(flock_def..[[ + int fileno(struct FILE *stream); + int fcntl(int fd, int cmd, ... /* arg */ ); + int unlink(const char *path); +]]) + +local function lock(fd, mode, start, len) + local flock = ffi_new('struct flock') + flock.l_type = mode_ltype_map[mode] + flock.l_whence = SEEK_SET + flock.l_start = start or 0 + flock.l_len = len or 0 + if lib.fcntl(fd, F_SETLK, flock) == -1 then + return nil, errno() + end + return true +end + +function _M.lock(filehandle, mode, start, length) + if mode ~= 'r' and mode ~= 'w' then + error("lock: invalid mode") + end + if io_type(filehandle) ~= 'file' then + error("lock: invalid file") + end + local fd = lib.fileno(filehandle) + local ok, err = lock(fd, mode, start, length) + if not ok then + return nil, err + end + return true +end + +function _M.unlock(filehandle, start, length) + if io_type(filehandle) ~= 'file' then + error("unlock: invalid file") + end + local fd = lib.fileno(filehandle) + local ok, err = lock(fd, 'u', start, length) + if not ok then + return nil, err + end + return true +end + +-- lock related +local dir_lock_struct = 'struct {char *lockname;}' +local function create_lockfile(dir_lock, path, lockname) + dir_lock.lockname = ffi_new('char[?]', #lockname + 1, lockname) + return lib.symlink(path, lockname) == 0 +end + +local function delete_lockfile(dir_lock) + return lib.unlink(dir_lock.lockname) +end + +local function unlock_dir(dir_lock) + if dir_lock.lockname ~= nil then + dir_lock:delete_lockfile() + dir_lock.lockname = nil + end + return true +end + +local dir_lock_type = ffi.metatype(dir_lock_struct, + {__gc = unlock_dir, + __index = { + free = unlock_dir, + create_lockfile = create_lockfile, + delete_lockfile = delete_lockfile, + }} +) + +function _M.lock_dir(path, _) + -- It's interesting that the lock_dir from vanilla lfs just ignores second parameter. + -- So, I follow this behavior too :) + local dir_lock = ffi_new(dir_lock_type) + local lockname = path .. '/lockfile.lfs' + if not dir_lock:create_lockfile(path, lockname) then + return nil, errno() + end + return dir_lock +end + +-- stat related +local stat_func +local lstat_func +if OS == 'Linux' then + ffi.cdef([[ + long syscall(int number, ...); + ]]) + local ARCH = ffi.arch + -- Taken from justincormack/ljsyscall + local stat_syscall_num + local lstat_syscall_num + if ARCH == 'x64' then + ffi.cdef([[ + typedef struct { + unsigned long st_dev; + unsigned long st_ino; + unsigned long st_nlink; + unsigned int st_mode; + unsigned int st_uid; + unsigned int st_gid; + unsigned int __pad0; + unsigned long st_rdev; + long st_size; + long st_blksize; + long st_blocks; + unsigned long st_atime; + unsigned long st_atime_nsec; + unsigned long st_mtime; + unsigned long st_mtime_nsec; + unsigned long st_ctime; + unsigned long st_ctime_nsec; + long __unused[3]; + } stat; + ]]) + stat_syscall_num = 4 + lstat_syscall_num = 6 + elseif ARCH == 'x86' then + ffi.cdef([[ + typedef struct { + unsigned long long st_dev; + unsigned char __pad0[4]; + unsigned long __st_ino; + unsigned int st_mode; + unsigned int st_nlink; + unsigned long st_uid; + unsigned long st_gid; + unsigned long long st_rdev; + unsigned char __pad3[4]; + long long st_size; + unsigned long st_blksize; + unsigned long long st_blocks; + unsigned long st_atime; + unsigned long st_atime_nsec; + unsigned long st_mtime; + unsigned int st_mtime_nsec; + unsigned long st_ctime; + unsigned long st_ctime_nsec; + unsigned long long st_ino; + } stat; + ]]) + stat_syscall_num = IS_64_BIT and 106 or 195 + lstat_syscall_num = IS_64_BIT and 107 or 196 + elseif ARCH == 'arm' then + if IS_64_BIT then + ffi.cdef([[ + typedef struct { + unsigned long st_dev; + unsigned long st_ino; + unsigned int st_mode; + unsigned int st_nlink; + unsigned int st_uid; + unsigned int st_gid; + unsigned long st_rdev; + unsigned long __pad1; + long st_size; + int st_blksize; + int __pad2; + long st_blocks; + long st_atime; + unsigned long st_atime_nsec; + long st_mtime; + unsigned long st_mtime_nsec; + long st_ctime; + unsigned long st_ctime_nsec; + unsigned int __unused4; + unsigned int __unused5; + } stat; + ]]) + stat_syscall_num = 106 + lstat_syscall_num = 107 + else + ffi.cdef([[ + typedef struct { + unsigned long long st_dev; + unsigned char __pad0[4]; + unsigned long __st_ino; + unsigned int st_mode; + unsigned int st_nlink; + unsigned long st_uid; + unsigned long st_gid; + unsigned long long st_rdev; + unsigned char __pad3[4]; + long long st_size; + unsigned long st_blksize; + unsigned long long st_blocks; + unsigned long st_atime; + unsigned long st_atime_nsec; + unsigned long st_mtime; + unsigned int st_mtime_nsec; + unsigned long st_ctime; + unsigned long st_ctime_nsec; + unsigned long long st_ino; + } stat; + ]]) + stat_syscall_num = 195 + lstat_syscall_num = 196 + end + elseif ARCH == 'ppc' or ARCH == 'ppcspe' then + ffi.cdef([[ + typedef struct { + unsigned long long st_dev; + unsigned long long st_ino; + unsigned int st_mode; + unsigned int st_nlink; + unsigned int st_uid; + unsigned int st_gid; + unsigned long long st_rdev; + unsigned long long __pad1; + long long st_size; + int st_blksize; + int __pad2; + long long st_blocks; + int st_atime; + unsigned int st_atime_nsec; + int st_mtime; + unsigned int st_mtime_nsec; + int st_ctime; + unsigned int st_ctime_nsec; + unsigned int __unused4; + unsigned int __unused5; + } stat; + ]]) + stat_syscall_num = IS_64_BIT and 106 or 195 + lstat_syscall_num = IS_64_BIT and 107 or 196 + elseif ARCH == 'mips' or ARCH == 'mipsel' then + ffi.cdef([[ + typedef struct { + unsigned long st_dev; + unsigned long __st_pad0[3]; + unsigned long long st_ino; + mode_t st_mode; + nlink_t st_nlink; + uid_t st_uid; + gid_t st_gid; + unsigned long st_rdev; + unsigned long __st_pad1[3]; + long long st_size; + time_t st_atime; + unsigned long st_atime_nsec; + time_t st_mtime; + unsigned long st_mtime_nsec; + time_t st_ctime; + unsigned long st_ctime_nsec; + unsigned long st_blksize; + unsigned long __st_pad2; + long long st_blocks; + long __st_padding4[14]; + } stat; + ]]) + stat_syscall_num = IS_64_BIT and 4106 or 4213 + lstat_syscall_num = IS_64_BIT and 4107 or 4214 + end + + if stat_syscall_num then + stat_func = function(filepath, buf) + return lib.syscall(stat_syscall_num, filepath, buf) + end + lstat_func = function(filepath, buf) + return lib.syscall(lstat_syscall_num, filepath, buf) + end + else + ffi.cdef('typedef struct {} stat;') + stat_func = function() error("TODO support other Linux architectures") end + lstat_func = stat_func + end + +elseif OS == 'OSX' then + ffi.cdef([[ + struct timespec { + time_t tv_sec; + long tv_nsec; + }; + typedef struct { + uint32_t st_dev; + uint16_t st_mode; + uint16_t st_nlink; + uint64_t st_ino; + uint32_t st_uid; + uint32_t st_gid; + uint32_t st_rdev; + struct timespec st_atimespec; + struct timespec st_mtimespec; + struct timespec st_ctimespec; + struct timespec st_birthtimespec; + int64_t st_size; + int64_t st_blocks; + int32_t st_blksize; + uint32_t st_flags; + uint32_t st_gen; + int32_t st_lspare; + int64_t st_qspare[2]; + } stat; + int stat64(const char *path, stat *buf); + int lstat64(const char *path, stat *buf); + ]]) + stat_func = lib.stat64 + lstat_func = lib.lstat64 +else + ffi.cdef('typedef struct {} stat;') + stat_func = function() error('TODO: support other posix system') end + lstat_func = stat_func +end + +local STAT = { + FMT = 0xF000, + FSOCK = 0xC000, + FLNK = 0xA000, + FREG = 0x8000, + FBLK = 0x6000, + FDIR = 0x4000, + FCHR = 0x2000, + FIFO = 0x1000, +} + +local ftype_name_map = { + [STAT.FREG] = 'file', + [STAT.FDIR] = 'directory', + [STAT.FLNK] = 'link', + [STAT.FSOCK] = 'socket', + [STAT.FCHR] = 'char device', + [STAT.FBLK] = "block device", + [STAT.FIFO] = "named pipe", +} + +local function mode_to_ftype(mode) + local ftype = band(mode, STAT.FMT) + return ftype_name_map[ftype] or 'other' +end + +local function mode_to_perm(mode) + local perm_bits = band(mode, tonumber(777, 8)) + local perm = new_tab(9, 0) + local i = 9 + while i > 0 do + local perm_bit = band(perm_bits, 7) + perm[i] = (band(perm_bit, 1) > 0 and 'x' or '-') + perm[i-1] = (band(perm_bit, 2) > 0 and 'w' or '-') + perm[i-2] = (band(perm_bit, 4) > 0 and 'r' or '-') + i = i - 3 + perm_bits = rshift(perm_bits, 3) + end + return concat(perm) +end + +local function time_or_timespec(time, timespec) + local t = tonumber(time) + if not t and timespec then + t = tonumber(timespec.tv_sec) + end + return t +end + +local attr_handlers = { + access = function(st) return time_or_timespec(st.st_atime, st.st_atimespec) end, + blksize = function(st) return tonumber(st.st_blksize) end, + blocks = function(st) return tonumber(st.st_blocks) end, + change = function(st) return time_or_timespec(st.st_ctime, st.st_ctimespec) end, + dev = function(st) return tonumber(st.st_dev) end, + gid = function(st) return tonumber(st.st_gid) end, + ino = function(st) return tonumber(st.st_ino) end, + mode = function(st) return mode_to_ftype(st.st_mode) end, + modification = function(st) return time_or_timespec(st.st_mtime, st.st_mtimespec) end, + nlink = function(st) return tonumber(st.st_nlink) end, + permissions = function(st) return mode_to_perm(st.st_mode) end, + rdev = function(st) return tonumber(st.st_rdev) end, + size = function(st) return tonumber(st.st_size) end, + uid = function(st) return tonumber(st.st_uid) end, +} +local mt = { + __index = function(self, attr_name) + local func = attr_handlers[attr_name] + return func and func(self) + end +} +local stat_type = ffi.metatype('stat', mt) + +-- Add target field for symlinkattributes, which is the absolute path of linked target +local get_link_target_path +if OS == 'Windows' then + local ENOSYS = 40 + function get_link_target_path() + return nil, "could not obtain link target: Function not implemented ",ENOSYS + end +else + ffi.cdef('ssize_t readlink(const char *path, char *buf, size_t bufsize);') + function get_link_target_path(link_path, statbuf) + local size = statbuf.st_size + size = size == 0 and MAXPATH or size + local buf = ffi.new('char[?]', size + 1) + local read = lib.readlink(link_path, buf, size) + if read == -1 then + return nil, "could not obtain link target: "..errno(), ffi.errno() + end + if read > size then + return nil, "not enought size for readlink: "..errno(), ffi.errno() + end + buf[size] = 0 + return ffi_str(buf) + end +end + +local stat_buf = ffi.new(stat_type) +local function attributes(filepath, attr, follow_symlink) + local func = follow_symlink and stat_func or lstat_func + if func(filepath, stat_buf) == -1 then + return nil, string.format("cannot obtain information from file '%s' : %s", + tostring(filepath),errno()), ffi.errno() + end + + local atype = type(attr) + if atype == 'string' then + local value, err, errn + if attr == 'target' and not follow_symlink then + value, err, errn = get_link_target_path(filepath, stat_buf) + return value, err, errn + else + value = stat_buf[attr] + end + if value == nil then + error("invalid attribute name '" .. attr .. "'") + end + return value + else + local tab = (atype == 'table') and attr or {} + for k, _ in pairs(attr_handlers) do + tab[k] = stat_buf[k] + end + if not follow_symlink then + tab.target = get_link_target_path(filepath, stat_buf) + end + return tab + end +end + +function _M.attributes(filepath, attr) + return attributes(filepath, attr, true) +end + +function _M.symlinkattributes(filepath, attr) + return attributes(filepath, attr, false) +end + +return _M diff --git a/mods/noita-mp/files/lib/external/luaunit.lua b/mods/noita-mp/lua_modules/share/lua/5.1/luaunit.lua similarity index 99% rename from mods/noita-mp/files/lib/external/luaunit.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/luaunit.lua index 8c904059f..4741478bc 100644 --- a/mods/noita-mp/files/lib/external/luaunit.lua +++ b/mods/noita-mp/lua_modules/share/lua/5.1/luaunit.lua @@ -264,7 +264,7 @@ local function strsplit(delimiter, text) return nil end - local list, pos, first, last = {}, 1, nil, nil + local list, pos, first, last = {}, 1 while true do first, last = text:find(delimiter, pos, true) if first then -- found? @@ -2664,7 +2664,7 @@ end for i, cmdArg in ipairs(cmdLine) do if state ~= nil then - setArg( cmdArg, state ) + setArg( cmdArg, state, result ) state = nil else if cmdArg:sub(1,1) == '-' then @@ -3416,7 +3416,7 @@ end return self.result.notSuccessCount end - function M.LuaUnit:runSuiteByInstances( listOfNameAndInst ) + function M.LuaUnit:runSuiteByInstances( listOfNameAndInst, commandLineArguments ) --[[ Run all test functions or tables provided as input. @@ -3426,7 +3426,7 @@ end return the number of failures and errors, 0 meaning success ]] -- parse the command-line arguments - testNames = self:initFromArguments() + testNames = self:initFromArguments( commandLineArguments ) self:registerSuite() self:internalRunSuiteByInstances( listOfNameAndInst ) self:unregisterSuite() diff --git a/mods/noita-mp/lua_modules/share/lua/5.1/mime.lua b/mods/noita-mp/lua_modules/share/lua/5.1/mime.lua new file mode 100644 index 000000000..93539de69 --- /dev/null +++ b/mods/noita-mp/lua_modules/share/lua/5.1/mime.lua @@ -0,0 +1,81 @@ +----------------------------------------------------------------------------- +-- MIME support for the Lua language. +-- Author: Diego Nehab +-- Conforming to RFCs 2045-2049 +----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- +-- Declare module and import dependencies +----------------------------------------------------------------------------- +local base = _G +local ltn12 = require("ltn12") +local mime = require("mime.core") +local _M = mime + +-- encode, decode and wrap algorithm tables +local encodet, decodet, wrapt = {},{},{} + +_M.encodet = encodet +_M.decodet = decodet +_M.wrapt = wrapt + +-- creates a function that chooses a filter by name from a given table +local function choose(table) + return function(name, opt1, opt2) + if base.type(name) ~= "string" then + name, opt1, opt2 = "default", name, opt1 + end + local f = table[name or "nil"] + if not f then + base.error("unknown key (" .. base.tostring(name) .. ")", 3) + else return f(opt1, opt2) end + end +end + +-- define the encoding filters +encodet['base64'] = function() + return ltn12.filter.cycle(_M.b64, "") +end + +encodet['quoted-printable'] = function(mode) + return ltn12.filter.cycle(_M.qp, "", + (mode == "binary") and "=0D=0A" or "\r\n") +end + +-- define the decoding filters +decodet['base64'] = function() + return ltn12.filter.cycle(_M.unb64, "") +end + +decodet['quoted-printable'] = function() + return ltn12.filter.cycle(_M.unqp, "") +end + +-- define the line-wrap filters +wrapt['text'] = function(length) + length = length or 76 + return ltn12.filter.cycle(_M.wrp, length, length) +end +wrapt['base64'] = wrapt['text'] +wrapt['default'] = wrapt['text'] + +wrapt['quoted-printable'] = function() + return ltn12.filter.cycle(_M.qpwrp, 76, 76) +end + +-- function that choose the encoding, decoding or wrap algorithm +_M.encode = choose(encodet) +_M.decode = choose(decodet) +_M.wrap = choose(wrapt) + +-- define the end-of-line normalization filter +function _M.normalize(marker) + return ltn12.filter.cycle(_M.eol, 0, marker) +end + +-- high level stuffing filter +function _M.stuff() + return ltn12.filter.cycle(_M.dot, 2) +end + +return _M diff --git a/mods/noita-mp/files/lib/external/nxml.lua b/mods/noita-mp/lua_modules/share/lua/5.1/nxml.lua similarity index 100% rename from mods/noita-mp/files/lib/external/nxml.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/nxml.lua diff --git a/mods/noita-mp/files/lib/external/os_name.lua b/mods/noita-mp/lua_modules/share/lua/5.1/os_name.lua similarity index 100% rename from mods/noita-mp/files/lib/external/os_name.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/os_name.lua diff --git a/mods/noita-mp/files/lib/external/plotly.lua b/mods/noita-mp/lua_modules/share/lua/5.1/plotly.lua similarity index 100% rename from mods/noita-mp/files/lib/external/plotly.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/plotly.lua diff --git a/mods/noita-mp/files/lib/external/pprint.lua b/mods/noita-mp/lua_modules/share/lua/5.1/pprint.lua similarity index 100% rename from mods/noita-mp/files/lib/external/pprint.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/pprint.lua diff --git a/mods/noita-mp/files/lib/external/profiler.lua b/mods/noita-mp/lua_modules/share/lua/5.1/profiler.lua similarity index 100% rename from mods/noita-mp/files/lib/external/profiler.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/profiler.lua diff --git a/mods/noita-mp/files/lib/external/sock.lua b/mods/noita-mp/lua_modules/share/lua/5.1/sock.lua similarity index 100% rename from mods/noita-mp/files/lib/external/sock.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/sock.lua diff --git a/mods/noita-mp/lua_modules/share/lua/5.1/socket.lua b/mods/noita-mp/lua_modules/share/lua/5.1/socket.lua new file mode 100644 index 000000000..d1c0b1649 --- /dev/null +++ b/mods/noita-mp/lua_modules/share/lua/5.1/socket.lua @@ -0,0 +1,149 @@ +----------------------------------------------------------------------------- +-- LuaSocket helper module +-- Author: Diego Nehab +----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- +-- Declare module and import dependencies +----------------------------------------------------------------------------- +local base = _G +local string = require("string") +local math = require("math") +local socket = require("socket.core") + +local _M = socket + +----------------------------------------------------------------------------- +-- Exported auxiliar functions +----------------------------------------------------------------------------- +function _M.connect4(address, port, laddress, lport) + return socket.connect(address, port, laddress, lport, "inet") +end + +function _M.connect6(address, port, laddress, lport) + return socket.connect(address, port, laddress, lport, "inet6") +end + +function _M.bind(host, port, backlog) + if host == "*" then host = "0.0.0.0" end + local addrinfo, err = socket.dns.getaddrinfo(host); + if not addrinfo then return nil, err end + local sock, res + err = "no info on address" + for i, alt in base.ipairs(addrinfo) do + if alt.family == "inet" then + sock, err = socket.tcp4() + else + sock, err = socket.tcp6() + end + if not sock then return nil, err end + sock:setoption("reuseaddr", true) + res, err = sock:bind(alt.addr, port) + if not res then + sock:close() + else + res, err = sock:listen(backlog) + if not res then + sock:close() + else + return sock + end + end + end + return nil, err +end + +_M.try = _M.newtry() + +function _M.choose(table) + return function(name, opt1, opt2) + if base.type(name) ~= "string" then + name, opt1, opt2 = "default", name, opt1 + end + local f = table[name or "nil"] + if not f then base.error("unknown key (".. base.tostring(name) ..")", 3) + else return f(opt1, opt2) end + end +end + +----------------------------------------------------------------------------- +-- Socket sources and sinks, conforming to LTN12 +----------------------------------------------------------------------------- +-- create namespaces inside LuaSocket namespace +local sourcet, sinkt = {}, {} +_M.sourcet = sourcet +_M.sinkt = sinkt + +_M.BLOCKSIZE = 2048 + +sinkt["close-when-done"] = function(sock) + return base.setmetatable({ + getfd = function() return sock:getfd() end, + dirty = function() return sock:dirty() end + }, { + __call = function(self, chunk, err) + if not chunk then + sock:close() + return 1 + else return sock:send(chunk) end + end + }) +end + +sinkt["keep-open"] = function(sock) + return base.setmetatable({ + getfd = function() return sock:getfd() end, + dirty = function() return sock:dirty() end + }, { + __call = function(self, chunk, err) + if chunk then return sock:send(chunk) + else return 1 end + end + }) +end + +sinkt["default"] = sinkt["keep-open"] + +_M.sink = _M.choose(sinkt) + +sourcet["by-length"] = function(sock, length) + return base.setmetatable({ + getfd = function() return sock:getfd() end, + dirty = function() return sock:dirty() end + }, { + __call = function() + if length <= 0 then return nil end + local size = math.min(socket.BLOCKSIZE, length) + local chunk, err = sock:receive(size) + if err then return nil, err end + length = length - string.len(chunk) + return chunk + end + }) +end + +sourcet["until-closed"] = function(sock) + local done + return base.setmetatable({ + getfd = function() return sock:getfd() end, + dirty = function() return sock:dirty() end + }, { + __call = function() + if done then return nil end + local chunk, err, partial = sock:receive(socket.BLOCKSIZE) + if not err then return chunk + elseif err == "closed" then + sock:close() + done = 1 + return partial + else return nil, err end + end + }) +end + + +sourcet["default"] = sourcet["until-closed"] + +_M.source = _M.choose(sourcet) + +return _M diff --git a/mods/noita-mp/lua_modules/share/lua/5.1/socket/ftp.lua b/mods/noita-mp/lua_modules/share/lua/5.1/socket/ftp.lua new file mode 100644 index 000000000..0ebc50869 --- /dev/null +++ b/mods/noita-mp/lua_modules/share/lua/5.1/socket/ftp.lua @@ -0,0 +1,329 @@ +----------------------------------------------------------------------------- +-- FTP support for the Lua language +-- LuaSocket toolkit. +-- Author: Diego Nehab +----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- +-- Declare module and import dependencies +----------------------------------------------------------------------------- +local base = _G +local table = require("table") +local string = require("string") +local math = require("math") +local socket = require("socket") +local url = require("socket.url") +local tp = require("socket.tp") +local ltn12 = require("ltn12") +socket.ftp = {} +local _M = socket.ftp +----------------------------------------------------------------------------- +-- Program constants +----------------------------------------------------------------------------- +-- timeout in seconds before the program gives up on a connection +_M.TIMEOUT = 60 +-- default port for ftp service +local PORT = 21 +-- this is the default anonymous password. used when no password is +-- provided in url. should be changed to your e-mail. +_M.USER = "ftp" +_M.PASSWORD = "anonymous@anonymous.org" + +----------------------------------------------------------------------------- +-- Low level FTP API +----------------------------------------------------------------------------- +local metat = { __index = {} } + +function _M.open(server, port, create) + local tp = socket.try(tp.connect(server, port or PORT, _M.TIMEOUT, create)) + local f = base.setmetatable({ tp = tp }, metat) + -- make sure everything gets closed in an exception + f.try = socket.newtry(function() f:close() end) + return f +end + +function metat.__index:portconnect() + self.try(self.server:settimeout(_M.TIMEOUT)) + self.data = self.try(self.server:accept()) + self.try(self.data:settimeout(_M.TIMEOUT)) +end + +function metat.__index:pasvconnect() + self.data = self.try(socket.tcp()) + self.try(self.data:settimeout(_M.TIMEOUT)) + self.try(self.data:connect(self.pasvt.address, self.pasvt.port)) +end + +function metat.__index:login(user, password) + self.try(self.tp:command("user", user or _M.USER)) + local code, _ = self.try(self.tp:check{"2..", 331}) + if code == 331 then + self.try(self.tp:command("pass", password or _M.PASSWORD)) + self.try(self.tp:check("2..")) + end + return 1 +end + +function metat.__index:pasv() + self.try(self.tp:command("pasv")) + local _, reply = self.try(self.tp:check("2..")) + local pattern = "(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)" + local a, b, c, d, p1, p2 = socket.skip(2, string.find(reply, pattern)) + self.try(a and b and c and d and p1 and p2, reply) + self.pasvt = { + address = string.format("%d.%d.%d.%d", a, b, c, d), + port = p1*256 + p2 + } + if self.server then + self.server:close() + self.server = nil + end + return self.pasvt.address, self.pasvt.port +end + +function metat.__index:epsv() + self.try(self.tp:command("epsv")) + local _, reply = self.try(self.tp:check("229")) + local pattern = "%((.)(.-)%1(.-)%1(.-)%1%)" + local _, _, _, port = string.match(reply, pattern) + self.try(port, "invalid epsv response") + self.pasvt = { + address = self.tp:getpeername(), + port = port + } + if self.server then + self.server:close() + self.server = nil + end + return self.pasvt.address, self.pasvt.port +end + + +function metat.__index:port(address, port) + self.pasvt = nil + if not address then + address = self.try(self.tp:getsockname()) + self.server = self.try(socket.bind(address, 0)) + address, port = self.try(self.server:getsockname()) + self.try(self.server:settimeout(_M.TIMEOUT)) + end + local pl = math.mod(port, 256) + local ph = (port - pl)/256 + local arg = string.gsub(string.format("%s,%d,%d", address, ph, pl), "%.", ",") + self.try(self.tp:command("port", arg)) + self.try(self.tp:check("2..")) + return 1 +end + +function metat.__index:eprt(family, address, port) + self.pasvt = nil + if not address then + address = self.try(self.tp:getsockname()) + self.server = self.try(socket.bind(address, 0)) + address, port = self.try(self.server:getsockname()) + self.try(self.server:settimeout(_M.TIMEOUT)) + end + local arg = string.format("|%s|%s|%d|", family, address, port) + self.try(self.tp:command("eprt", arg)) + self.try(self.tp:check("2..")) + return 1 +end + + +function metat.__index:send(sendt) + self.try(self.pasvt or self.server, "need port or pasv first") + -- if there is a pasvt table, we already sent a PASV command + -- we just get the data connection into self.data + if self.pasvt then self:pasvconnect() end + -- get the transfer argument and command + local argument = sendt.argument or + url.unescape(string.gsub(sendt.path or "", "^[/\\]", "")) + if argument == "" then argument = nil end + local command = sendt.command or "stor" + -- send the transfer command and check the reply + self.try(self.tp:command(command, argument)) + local code, _ = self.try(self.tp:check{"2..", "1.."}) + -- if there is not a pasvt table, then there is a server + -- and we already sent a PORT command + if not self.pasvt then self:portconnect() end + -- get the sink, source and step for the transfer + local step = sendt.step or ltn12.pump.step + local readt = { self.tp } + local checkstep = function(src, snk) + -- check status in control connection while downloading + local readyt = socket.select(readt, nil, 0) + if readyt[tp] then code = self.try(self.tp:check("2..")) end + return step(src, snk) + end + local sink = socket.sink("close-when-done", self.data) + -- transfer all data and check error + self.try(ltn12.pump.all(sendt.source, sink, checkstep)) + if string.find(code, "1..") then self.try(self.tp:check("2..")) end + -- done with data connection + self.data:close() + -- find out how many bytes were sent + local sent = socket.skip(1, self.data:getstats()) + self.data = nil + return sent +end + +function metat.__index:receive(recvt) + self.try(self.pasvt or self.server, "need port or pasv first") + if self.pasvt then self:pasvconnect() end + local argument = recvt.argument or + url.unescape(string.gsub(recvt.path or "", "^[/\\]", "")) + if argument == "" then argument = nil end + local command = recvt.command or "retr" + self.try(self.tp:command(command, argument)) + local code,reply = self.try(self.tp:check{"1..", "2.."}) + if (code >= 200) and (code <= 299) then + recvt.sink(reply) + return 1 + end + if not self.pasvt then self:portconnect() end + local source = socket.source("until-closed", self.data) + local step = recvt.step or ltn12.pump.step + self.try(ltn12.pump.all(source, recvt.sink, step)) + if string.find(code, "1..") then self.try(self.tp:check("2..")) end + self.data:close() + self.data = nil + return 1 +end + +function metat.__index:cwd(dir) + self.try(self.tp:command("cwd", dir)) + self.try(self.tp:check(250)) + return 1 +end + +function metat.__index:type(type) + self.try(self.tp:command("type", type)) + self.try(self.tp:check(200)) + return 1 +end + +function metat.__index:greet() + local code = self.try(self.tp:check{"1..", "2.."}) + if string.find(code, "1..") then self.try(self.tp:check("2..")) end + return 1 +end + +function metat.__index:quit() + self.try(self.tp:command("quit")) + self.try(self.tp:check("2..")) + return 1 +end + +function metat.__index:close() + if self.data then self.data:close() end + if self.server then self.server:close() end + return self.tp:close() +end + +----------------------------------------------------------------------------- +-- High level FTP API +----------------------------------------------------------------------------- +local function override(t) + if t.url then + local u = url.parse(t.url) + for i,v in base.pairs(t) do + u[i] = v + end + return u + else return t end +end + +local function tput(putt) + putt = override(putt) + socket.try(putt.host, "missing hostname") + local f = _M.open(putt.host, putt.port, putt.create) + f:greet() + f:login(putt.user, putt.password) + if putt.type then f:type(putt.type) end + f:epsv() + local sent = f:send(putt) + f:quit() + f:close() + return sent +end + +local default = { + path = "/", + scheme = "ftp" +} + +local function genericform(u) + local t = socket.try(url.parse(u, default)) + socket.try(t.scheme == "ftp", "wrong scheme '" .. t.scheme .. "'") + socket.try(t.host, "missing hostname") + local pat = "^type=(.)$" + if t.params then + t.type = socket.skip(2, string.find(t.params, pat)) + socket.try(t.type == "a" or t.type == "i", + "invalid type '" .. t.type .. "'") + end + return t +end + +_M.genericform = genericform + +local function sput(u, body) + local putt = genericform(u) + putt.source = ltn12.source.string(body) + return tput(putt) +end + +_M.put = socket.protect(function(putt, body) + if base.type(putt) == "string" then return sput(putt, body) + else return tput(putt) end +end) + +local function tget(gett) + gett = override(gett) + socket.try(gett.host, "missing hostname") + local f = _M.open(gett.host, gett.port, gett.create) + f:greet() + f:login(gett.user, gett.password) + if gett.type then f:type(gett.type) end + f:epsv() + f:receive(gett) + f:quit() + return f:close() +end + +local function sget(u) + local gett = genericform(u) + local t = {} + gett.sink = ltn12.sink.table(t) + tget(gett) + return table.concat(t) +end + +_M.command = socket.protect(function(cmdt) + cmdt = override(cmdt) + socket.try(cmdt.host, "missing hostname") + socket.try(cmdt.command, "missing command") + local f = _M.open(cmdt.host, cmdt.port, cmdt.create) + f:greet() + f:login(cmdt.user, cmdt.password) + if type(cmdt.command) == "table" then + local argument = cmdt.argument or {} + local check = cmdt.check or {} + for i,cmd in ipairs(cmdt.command) do + f.try(f.tp:command(cmd, argument[i])) + if check[i] then f.try(f.tp:check(check[i])) end + end + else + f.try(f.tp:command(cmdt.command, cmdt.argument)) + if cmdt.check then f.try(f.tp:check(cmdt.check)) end + end + f:quit() + return f:close() +end) + +_M.get = socket.protect(function(gett) + if base.type(gett) == "string" then return sget(gett) + else return tget(gett) end +end) + +return _M diff --git a/mods/noita-mp/lua_modules/share/lua/5.1/socket/headers.lua b/mods/noita-mp/lua_modules/share/lua/5.1/socket/headers.lua new file mode 100644 index 000000000..1eb8223b9 --- /dev/null +++ b/mods/noita-mp/lua_modules/share/lua/5.1/socket/headers.lua @@ -0,0 +1,104 @@ +----------------------------------------------------------------------------- +-- Canonic header field capitalization +-- LuaSocket toolkit. +-- Author: Diego Nehab +----------------------------------------------------------------------------- +local socket = require("socket") +socket.headers = {} +local _M = socket.headers + +_M.canonic = { + ["accept"] = "Accept", + ["accept-charset"] = "Accept-Charset", + ["accept-encoding"] = "Accept-Encoding", + ["accept-language"] = "Accept-Language", + ["accept-ranges"] = "Accept-Ranges", + ["action"] = "Action", + ["alternate-recipient"] = "Alternate-Recipient", + ["age"] = "Age", + ["allow"] = "Allow", + ["arrival-date"] = "Arrival-Date", + ["authorization"] = "Authorization", + ["bcc"] = "Bcc", + ["cache-control"] = "Cache-Control", + ["cc"] = "Cc", + ["comments"] = "Comments", + ["connection"] = "Connection", + ["content-description"] = "Content-Description", + ["content-disposition"] = "Content-Disposition", + ["content-encoding"] = "Content-Encoding", + ["content-id"] = "Content-ID", + ["content-language"] = "Content-Language", + ["content-length"] = "Content-Length", + ["content-location"] = "Content-Location", + ["content-md5"] = "Content-MD5", + ["content-range"] = "Content-Range", + ["content-transfer-encoding"] = "Content-Transfer-Encoding", + ["content-type"] = "Content-Type", + ["cookie"] = "Cookie", + ["date"] = "Date", + ["diagnostic-code"] = "Diagnostic-Code", + ["dsn-gateway"] = "DSN-Gateway", + ["etag"] = "ETag", + ["expect"] = "Expect", + ["expires"] = "Expires", + ["final-log-id"] = "Final-Log-ID", + ["final-recipient"] = "Final-Recipient", + ["from"] = "From", + ["host"] = "Host", + ["if-match"] = "If-Match", + ["if-modified-since"] = "If-Modified-Since", + ["if-none-match"] = "If-None-Match", + ["if-range"] = "If-Range", + ["if-unmodified-since"] = "If-Unmodified-Since", + ["in-reply-to"] = "In-Reply-To", + ["keywords"] = "Keywords", + ["last-attempt-date"] = "Last-Attempt-Date", + ["last-modified"] = "Last-Modified", + ["location"] = "Location", + ["max-forwards"] = "Max-Forwards", + ["message-id"] = "Message-ID", + ["mime-version"] = "MIME-Version", + ["original-envelope-id"] = "Original-Envelope-ID", + ["original-recipient"] = "Original-Recipient", + ["pragma"] = "Pragma", + ["proxy-authenticate"] = "Proxy-Authenticate", + ["proxy-authorization"] = "Proxy-Authorization", + ["range"] = "Range", + ["received"] = "Received", + ["received-from-mta"] = "Received-From-MTA", + ["references"] = "References", + ["referer"] = "Referer", + ["remote-mta"] = "Remote-MTA", + ["reply-to"] = "Reply-To", + ["reporting-mta"] = "Reporting-MTA", + ["resent-bcc"] = "Resent-Bcc", + ["resent-cc"] = "Resent-Cc", + ["resent-date"] = "Resent-Date", + ["resent-from"] = "Resent-From", + ["resent-message-id"] = "Resent-Message-ID", + ["resent-reply-to"] = "Resent-Reply-To", + ["resent-sender"] = "Resent-Sender", + ["resent-to"] = "Resent-To", + ["retry-after"] = "Retry-After", + ["return-path"] = "Return-Path", + ["sender"] = "Sender", + ["server"] = "Server", + ["smtp-remote-recipient"] = "SMTP-Remote-Recipient", + ["status"] = "Status", + ["subject"] = "Subject", + ["te"] = "TE", + ["to"] = "To", + ["trailer"] = "Trailer", + ["transfer-encoding"] = "Transfer-Encoding", + ["upgrade"] = "Upgrade", + ["user-agent"] = "User-Agent", + ["vary"] = "Vary", + ["via"] = "Via", + ["warning"] = "Warning", + ["will-retry-until"] = "Will-Retry-Until", + ["www-authenticate"] = "WWW-Authenticate", + ["x-mailer"] = "X-Mailer", +} + +return _M \ No newline at end of file diff --git a/mods/noita-mp/lua_modules/share/lua/5.1/socket/http.lua b/mods/noita-mp/lua_modules/share/lua/5.1/socket/http.lua new file mode 100644 index 000000000..1330355f4 --- /dev/null +++ b/mods/noita-mp/lua_modules/share/lua/5.1/socket/http.lua @@ -0,0 +1,424 @@ +----------------------------------------------------------------------------- +-- HTTP/1.1 client support for the Lua language. +-- LuaSocket toolkit. +-- Author: Diego Nehab +----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- +-- Declare module and import dependencies +------------------------------------------------------------------------------- +local socket = require("socket") +local url = require("socket.url") +local ltn12 = require("ltn12") +local mime = require("mime") +local string = require("string") +local headers = require("socket.headers") +local base = _G +local table = require("table") +socket.http = {} +local _M = socket.http + +----------------------------------------------------------------------------- +-- Program constants +----------------------------------------------------------------------------- +-- connection timeout in seconds +_M.TIMEOUT = 60 +-- user agent field sent in request +_M.USERAGENT = socket._VERSION + +-- supported schemes and their particulars +local SCHEMES = { + http = { + port = 80 + , create = function(t) + return socket.tcp end } + , https = { + port = 443 + , create = function(t) + local https = assert( + require("ssl.https"), 'LuaSocket: LuaSec not found') + local tcp = assert( + https.tcp, 'LuaSocket: Function tcp() not available from LuaSec') + return tcp(t) end }} + +----------------------------------------------------------------------------- +-- Reads MIME headers from a connection, unfolding where needed +----------------------------------------------------------------------------- +local function receiveheaders(sock, headers) + local line, name, value, err + headers = headers or {} + -- get first line + line, err = sock:receive() + if err then return nil, err end + -- headers go until a blank line is found + while line ~= "" do + -- get field-name and value + name, value = socket.skip(2, string.find(line, "^(.-):%s*(.*)")) + if not (name and value) then return nil, "malformed reponse headers" end + name = string.lower(name) + -- get next line (value might be folded) + line, err = sock:receive() + if err then return nil, err end + -- unfold any folded values + while string.find(line, "^%s") do + value = value .. line + line = sock:receive() + if err then return nil, err end + end + -- save pair in table + if headers[name] then headers[name] = headers[name] .. ", " .. value + else headers[name] = value end + end + return headers +end + +----------------------------------------------------------------------------- +-- Extra sources and sinks +----------------------------------------------------------------------------- +socket.sourcet["http-chunked"] = function(sock, headers) + return base.setmetatable({ + getfd = function() return sock:getfd() end, + dirty = function() return sock:dirty() end + }, { + __call = function() + -- get chunk size, skip extention + local line, err = sock:receive() + if err then return nil, err end + local size = base.tonumber(string.gsub(line, ";.*", ""), 16) + if not size then return nil, "invalid chunk size" end + -- was it the last chunk? + if size > 0 then + -- if not, get chunk and skip terminating CRLF + local chunk, err, _ = sock:receive(size) + if chunk then sock:receive() end + return chunk, err + else + -- if it was, read trailers into headers table + headers, err = receiveheaders(sock, headers) + if not headers then return nil, err end + end + end + }) +end + +socket.sinkt["http-chunked"] = function(sock) + return base.setmetatable({ + getfd = function() return sock:getfd() end, + dirty = function() return sock:dirty() end + }, { + __call = function(self, chunk, err) + if not chunk then return sock:send("0\r\n\r\n") end + local size = string.format("%X\r\n", string.len(chunk)) + return sock:send(size .. chunk .. "\r\n") + end + }) +end + +----------------------------------------------------------------------------- +-- Low level HTTP API +----------------------------------------------------------------------------- +local metat = { __index = {} } + +function _M.open(host, port, create) + -- create socket with user connect function, or with default + local c = socket.try(create()) + local h = base.setmetatable({ c = c }, metat) + -- create finalized try + h.try = socket.newtry(function() h:close() end) + -- set timeout before connecting + h.try(c:settimeout(_M.TIMEOUT)) + h.try(c:connect(host, port)) + -- here everything worked + return h +end + +function metat.__index:sendrequestline(method, uri) + local reqline = string.format("%s %s HTTP/1.1\r\n", method or "GET", uri) + return self.try(self.c:send(reqline)) +end + +function metat.__index:sendheaders(tosend) + local canonic = headers.canonic + local h = "\r\n" + for f, v in base.pairs(tosend) do + h = (canonic[f] or f) .. ": " .. v .. "\r\n" .. h + end + self.try(self.c:send(h)) + return 1 +end + +function metat.__index:sendbody(headers, source, step) + source = source or ltn12.source.empty() + step = step or ltn12.pump.step + -- if we don't know the size in advance, send chunked and hope for the best + local mode = "http-chunked" + if headers["content-length"] then mode = "keep-open" end + return self.try(ltn12.pump.all(source, socket.sink(mode, self.c), step)) +end + +function metat.__index:receivestatusline() + local status,ec = self.try(self.c:receive(5)) + -- identify HTTP/0.9 responses, which do not contain a status line + -- this is just a heuristic, but is what the RFC recommends + if status ~= "HTTP/" then + if ec == "timeout" then + return 408 + end + return nil, status + end + -- otherwise proceed reading a status line + status = self.try(self.c:receive("*l", status)) + local code = socket.skip(2, string.find(status, "HTTP/%d*%.%d* (%d%d%d)")) + return self.try(base.tonumber(code), status) +end + +function metat.__index:receiveheaders() + return self.try(receiveheaders(self.c)) +end + +function metat.__index:receivebody(headers, sink, step) + sink = sink or ltn12.sink.null() + step = step or ltn12.pump.step + local length = base.tonumber(headers["content-length"]) + local t = headers["transfer-encoding"] -- shortcut + local mode = "default" -- connection close + if t and t ~= "identity" then mode = "http-chunked" + elseif base.tonumber(headers["content-length"]) then mode = "by-length" end + return self.try(ltn12.pump.all(socket.source(mode, self.c, length), + sink, step)) +end + +function metat.__index:receive09body(status, sink, step) + local source = ltn12.source.rewind(socket.source("until-closed", self.c)) + source(status) + return self.try(ltn12.pump.all(source, sink, step)) +end + +function metat.__index:close() + return self.c:close() +end + +----------------------------------------------------------------------------- +-- High level HTTP API +----------------------------------------------------------------------------- +local function adjusturi(reqt) + local u = reqt + -- if there is a proxy, we need the full url. otherwise, just a part. + if not reqt.proxy and not _M.PROXY then + u = { + path = socket.try(reqt.path, "invalid path 'nil'"), + params = reqt.params, + query = reqt.query, + fragment = reqt.fragment + } + end + return url.build(u) +end + +local function adjustproxy(reqt) + local proxy = reqt.proxy or _M.PROXY + if proxy then + proxy = url.parse(proxy) + return proxy.host, proxy.port or 3128 + else + return reqt.host, reqt.port + end +end + +local function adjustheaders(reqt) + -- default headers + local host = reqt.host + local port = tostring(reqt.port) + if port ~= tostring(SCHEMES[reqt.scheme].port) then + host = host .. ':' .. port end + local lower = { + ["user-agent"] = _M.USERAGENT, + ["host"] = host, + ["connection"] = "close, TE", + ["te"] = "trailers" + } + -- if we have authentication information, pass it along + if reqt.user and reqt.password then + lower["authorization"] = + "Basic " .. (mime.b64(reqt.user .. ":" .. + url.unescape(reqt.password))) + end + -- if we have proxy authentication information, pass it along + local proxy = reqt.proxy or _M.PROXY + if proxy then + proxy = url.parse(proxy) + if proxy.user and proxy.password then + lower["proxy-authorization"] = + "Basic " .. (mime.b64(proxy.user .. ":" .. proxy.password)) + end + end + -- override with user headers + for i,v in base.pairs(reqt.headers or lower) do + lower[string.lower(i)] = v + end + return lower +end + +-- default url parts +local default = { + path ="/" + , scheme = "http" +} + +local function adjustrequest(reqt) + -- parse url if provided + local nreqt = reqt.url and url.parse(reqt.url, default) or {} + -- explicit components override url + for i,v in base.pairs(reqt) do nreqt[i] = v end + -- default to scheme particulars + local schemedefs, host, port, method + = SCHEMES[nreqt.scheme], nreqt.host, nreqt.port, nreqt.method + if not nreqt.create then nreqt.create = schemedefs.create(nreqt) end + if not (port and port ~= '') then nreqt.port = schemedefs.port end + if not (method and method ~= '') then nreqt.method = 'GET' end + if not (host and host ~= "") then + socket.try(nil, "invalid host '" .. base.tostring(nreqt.host) .. "'") + end + -- compute uri if user hasn't overriden + nreqt.uri = reqt.uri or adjusturi(nreqt) + -- adjust headers in request + nreqt.headers = adjustheaders(nreqt) + if nreqt.source + and not nreqt.headers["content-length"] + and not nreqt.headers["transfer-encoding"] + then + nreqt.headers["transfer-encoding"] = "chunked" + end + + -- ajust host and port if there is a proxy + nreqt.host, nreqt.port = adjustproxy(nreqt) + return nreqt +end + +local function shouldredirect(reqt, code, headers) + local location = headers.location + if not location then return false end + location = string.gsub(location, "%s", "") + if location == "" then return false end + local scheme = url.parse(location).scheme + if scheme and (not SCHEMES[scheme]) then return false end + -- avoid https downgrades + if ('https' == reqt.scheme) and ('https' ~= scheme) then return false end + return (reqt.redirect ~= false) and + (code == 301 or code == 302 or code == 303 or code == 307) and + (not reqt.method or reqt.method == "GET" or reqt.method == "HEAD") + and ((false == reqt.maxredirects) + or ((reqt.nredirects or 0) + < (reqt.maxredirects or 5))) +end + +local function shouldreceivebody(reqt, code) + if reqt.method == "HEAD" then return nil end + if code == 204 or code == 304 then return nil end + if code >= 100 and code < 200 then return nil end + return 1 +end + +-- forward declarations +local trequest, tredirect + +--[[local]] function tredirect(reqt, location) + -- the RFC says the redirect URL has to be absolute, but some + -- servers do not respect that + local newurl = url.absolute(reqt.url, location) + -- if switching schemes, reset port and create function + if url.parse(newurl).scheme ~= reqt.scheme then + reqt.port = nil + reqt.create = nil end + -- make new request + local result, code, headers, status = trequest { + url = newurl, + source = reqt.source, + sink = reqt.sink, + headers = reqt.headers, + proxy = reqt.proxy, + maxredirects = reqt.maxredirects, + nredirects = (reqt.nredirects or 0) + 1, + create = reqt.create + } + -- pass location header back as a hint we redirected + headers = headers or {} + headers.location = headers.location or location + return result, code, headers, status +end + +--[[local]] function trequest(reqt) + -- we loop until we get what we want, or + -- until we are sure there is no way to get it + local nreqt = adjustrequest(reqt) + local h = _M.open(nreqt.host, nreqt.port, nreqt.create) + -- send request line and headers + h:sendrequestline(nreqt.method, nreqt.uri) + h:sendheaders(nreqt.headers) + -- if there is a body, send it + if nreqt.source then + h:sendbody(nreqt.headers, nreqt.source, nreqt.step) + end + local code, status = h:receivestatusline() + -- if it is an HTTP/0.9 server, simply get the body and we are done + if not code then + h:receive09body(status, nreqt.sink, nreqt.step) + return 1, 200 + elseif code == 408 then + return 1, code + end + local headers + -- ignore any 100-continue messages + while code == 100 do + h:receiveheaders() + code, status = h:receivestatusline() + end + headers = h:receiveheaders() + -- at this point we should have a honest reply from the server + -- we can't redirect if we already used the source, so we report the error + if shouldredirect(nreqt, code, headers) and not nreqt.source then + h:close() + return tredirect(reqt, headers.location) + end + -- here we are finally done + if shouldreceivebody(nreqt, code) then + h:receivebody(headers, nreqt.sink, nreqt.step) + end + h:close() + return 1, code, headers, status +end + +-- turns an url and a body into a generic request +local function genericform(u, b) + local t = {} + local reqt = { + url = u, + sink = ltn12.sink.table(t), + target = t + } + if b then + reqt.source = ltn12.source.string(b) + reqt.headers = { + ["content-length"] = string.len(b), + ["content-type"] = "application/x-www-form-urlencoded" + } + reqt.method = "POST" + end + return reqt +end + +_M.genericform = genericform + +local function srequest(u, b) + local reqt = genericform(u, b) + local _, code, headers, status = trequest(reqt) + return table.concat(reqt.target), code, headers, status +end + +_M.request = socket.protect(function(reqt, body) + if base.type(reqt) == "string" then return srequest(reqt, body) + else return trequest(reqt) end +end) + +_M.schemes = SCHEMES +return _M diff --git a/mods/noita-mp/lua_modules/share/lua/5.1/socket/smtp.lua b/mods/noita-mp/lua_modules/share/lua/5.1/socket/smtp.lua new file mode 100644 index 000000000..b113d0067 --- /dev/null +++ b/mods/noita-mp/lua_modules/share/lua/5.1/socket/smtp.lua @@ -0,0 +1,256 @@ +----------------------------------------------------------------------------- +-- SMTP client support for the Lua language. +-- LuaSocket toolkit. +-- Author: Diego Nehab +----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- +-- Declare module and import dependencies +----------------------------------------------------------------------------- +local base = _G +local coroutine = require("coroutine") +local string = require("string") +local math = require("math") +local os = require("os") +local socket = require("socket") +local tp = require("socket.tp") +local ltn12 = require("ltn12") +local headers = require("socket.headers") +local mime = require("mime") + +socket.smtp = {} +local _M = socket.smtp + +----------------------------------------------------------------------------- +-- Program constants +----------------------------------------------------------------------------- +-- timeout for connection +_M.TIMEOUT = 60 +-- default server used to send e-mails +_M.SERVER = "localhost" +-- default port +_M.PORT = 25 +-- domain used in HELO command and default sendmail +-- If we are under a CGI, try to get from environment +_M.DOMAIN = os.getenv("SERVER_NAME") or "localhost" +-- default time zone (means we don't know) +_M.ZONE = "-0000" + +--------------------------------------------------------------------------- +-- Low level SMTP API +----------------------------------------------------------------------------- +local metat = { __index = {} } + +function metat.__index:greet(domain) + self.try(self.tp:check("2..")) + self.try(self.tp:command("EHLO", domain or _M.DOMAIN)) + return socket.skip(1, self.try(self.tp:check("2.."))) +end + +function metat.__index:mail(from) + self.try(self.tp:command("MAIL", "FROM:" .. from)) + return self.try(self.tp:check("2..")) +end + +function metat.__index:rcpt(to) + self.try(self.tp:command("RCPT", "TO:" .. to)) + return self.try(self.tp:check("2..")) +end + +function metat.__index:data(src, step) + self.try(self.tp:command("DATA")) + self.try(self.tp:check("3..")) + self.try(self.tp:source(src, step)) + self.try(self.tp:send("\r\n.\r\n")) + return self.try(self.tp:check("2..")) +end + +function metat.__index:quit() + self.try(self.tp:command("QUIT")) + return self.try(self.tp:check("2..")) +end + +function metat.__index:close() + return self.tp:close() +end + +function metat.__index:login(user, password) + self.try(self.tp:command("AUTH", "LOGIN")) + self.try(self.tp:check("3..")) + self.try(self.tp:send(mime.b64(user) .. "\r\n")) + self.try(self.tp:check("3..")) + self.try(self.tp:send(mime.b64(password) .. "\r\n")) + return self.try(self.tp:check("2..")) +end + +function metat.__index:plain(user, password) + local auth = "PLAIN " .. mime.b64("\0" .. user .. "\0" .. password) + self.try(self.tp:command("AUTH", auth)) + return self.try(self.tp:check("2..")) +end + +function metat.__index:auth(user, password, ext) + if not user or not password then return 1 end + if string.find(ext, "AUTH[^\n]+LOGIN") then + return self:login(user, password) + elseif string.find(ext, "AUTH[^\n]+PLAIN") then + return self:plain(user, password) + else + self.try(nil, "authentication not supported") + end +end + +-- send message or throw an exception +function metat.__index:send(mailt) + self:mail(mailt.from) + if base.type(mailt.rcpt) == "table" then + for i,v in base.ipairs(mailt.rcpt) do + self:rcpt(v) + end + else + self:rcpt(mailt.rcpt) + end + self:data(ltn12.source.chain(mailt.source, mime.stuff()), mailt.step) +end + +function _M.open(server, port, create) + local tp = socket.try(tp.connect(server or _M.SERVER, port or _M.PORT, + _M.TIMEOUT, create)) + local s = base.setmetatable({tp = tp}, metat) + -- make sure tp is closed if we get an exception + s.try = socket.newtry(function() + s:close() + end) + return s +end + +-- convert headers to lowercase +local function lower_headers(headers) + local lower = {} + for i,v in base.pairs(headers or lower) do + lower[string.lower(i)] = v + end + return lower +end + +--------------------------------------------------------------------------- +-- Multipart message source +----------------------------------------------------------------------------- +-- returns a hopefully unique mime boundary +local seqno = 0 +local function newboundary() + seqno = seqno + 1 + return string.format('%s%05d==%05u', os.date('%d%m%Y%H%M%S'), + math.random(0, 99999), seqno) +end + +-- send_message forward declaration +local send_message + +-- yield the headers all at once, it's faster +local function send_headers(tosend) + local canonic = headers.canonic + local h = "\r\n" + for f,v in base.pairs(tosend) do + h = (canonic[f] or f) .. ': ' .. v .. "\r\n" .. h + end + coroutine.yield(h) +end + +-- yield multipart message body from a multipart message table +local function send_multipart(mesgt) + -- make sure we have our boundary and send headers + local bd = newboundary() + local headers = lower_headers(mesgt.headers or {}) + headers['content-type'] = headers['content-type'] or 'multipart/mixed' + headers['content-type'] = headers['content-type'] .. + '; boundary="' .. bd .. '"' + send_headers(headers) + -- send preamble + if mesgt.body.preamble then + coroutine.yield(mesgt.body.preamble) + coroutine.yield("\r\n") + end + -- send each part separated by a boundary + for i, m in base.ipairs(mesgt.body) do + coroutine.yield("\r\n--" .. bd .. "\r\n") + send_message(m) + end + -- send last boundary + coroutine.yield("\r\n--" .. bd .. "--\r\n\r\n") + -- send epilogue + if mesgt.body.epilogue then + coroutine.yield(mesgt.body.epilogue) + coroutine.yield("\r\n") + end +end + +-- yield message body from a source +local function send_source(mesgt) + -- make sure we have a content-type + local headers = lower_headers(mesgt.headers or {}) + headers['content-type'] = headers['content-type'] or + 'text/plain; charset="iso-8859-1"' + send_headers(headers) + -- send body from source + while true do + local chunk, err = mesgt.body() + if err then coroutine.yield(nil, err) + elseif chunk then coroutine.yield(chunk) + else break end + end +end + +-- yield message body from a string +local function send_string(mesgt) + -- make sure we have a content-type + local headers = lower_headers(mesgt.headers or {}) + headers['content-type'] = headers['content-type'] or + 'text/plain; charset="iso-8859-1"' + send_headers(headers) + -- send body from string + coroutine.yield(mesgt.body) +end + +-- message source +function send_message(mesgt) + if base.type(mesgt.body) == "table" then send_multipart(mesgt) + elseif base.type(mesgt.body) == "function" then send_source(mesgt) + else send_string(mesgt) end +end + +-- set defaul headers +local function adjust_headers(mesgt) + local lower = lower_headers(mesgt.headers) + lower["date"] = lower["date"] or + os.date("!%a, %d %b %Y %H:%M:%S ") .. (mesgt.zone or _M.ZONE) + lower["x-mailer"] = lower["x-mailer"] or socket._VERSION + -- this can't be overriden + lower["mime-version"] = "1.0" + return lower +end + +function _M.message(mesgt) + mesgt.headers = adjust_headers(mesgt) + -- create and return message source + local co = coroutine.create(function() send_message(mesgt) end) + return function() + local ret, a, b = coroutine.resume(co) + if ret then return a, b + else return nil, a end + end +end + +--------------------------------------------------------------------------- +-- High level SMTP API +----------------------------------------------------------------------------- +_M.send = socket.protect(function(mailt) + local s = _M.open(mailt.server, mailt.port, mailt.create) + local ext = s:greet(mailt.domain) + s:auth(mailt.user, mailt.password, ext) + s:send(mailt) + s:quit() + return s:close() +end) + +return _M \ No newline at end of file diff --git a/mods/noita-mp/lua_modules/share/lua/5.1/socket/tp.lua b/mods/noita-mp/lua_modules/share/lua/5.1/socket/tp.lua new file mode 100644 index 000000000..b8ebc56d1 --- /dev/null +++ b/mods/noita-mp/lua_modules/share/lua/5.1/socket/tp.lua @@ -0,0 +1,134 @@ +----------------------------------------------------------------------------- +-- Unified SMTP/FTP subsystem +-- LuaSocket toolkit. +-- Author: Diego Nehab +----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- +-- Declare module and import dependencies +----------------------------------------------------------------------------- +local base = _G +local string = require("string") +local socket = require("socket") +local ltn12 = require("ltn12") + +socket.tp = {} +local _M = socket.tp + +----------------------------------------------------------------------------- +-- Program constants +----------------------------------------------------------------------------- +_M.TIMEOUT = 60 + +----------------------------------------------------------------------------- +-- Implementation +----------------------------------------------------------------------------- +-- gets server reply (works for SMTP and FTP) +local function get_reply(c) + local code, current, sep + local line, err = c:receive() + local reply = line + if err then return nil, err end + code, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)")) + if not code then return nil, "invalid server reply" end + if sep == "-" then -- reply is multiline + repeat + line, err = c:receive() + if err then return nil, err end + current, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)")) + reply = reply .. "\n" .. line + -- reply ends with same code + until code == current and sep == " " + end + return code, reply +end + +-- metatable for sock object +local metat = { __index = {} } + +function metat.__index:getpeername() + return self.c:getpeername() +end + +function metat.__index:getsockname() + return self.c:getpeername() +end + +function metat.__index:check(ok) + local code, reply = get_reply(self.c) + if not code then return nil, reply end + if base.type(ok) ~= "function" then + if base.type(ok) == "table" then + for i, v in base.ipairs(ok) do + if string.find(code, v) then + return base.tonumber(code), reply + end + end + return nil, reply + else + if string.find(code, ok) then return base.tonumber(code), reply + else return nil, reply end + end + else return ok(base.tonumber(code), reply) end +end + +function metat.__index:command(cmd, arg) + cmd = string.upper(cmd) + if arg then + return self.c:send(cmd .. " " .. arg.. "\r\n") + else + return self.c:send(cmd .. "\r\n") + end +end + +function metat.__index:sink(snk, pat) + local chunk, err = self.c:receive(pat) + return snk(chunk, err) +end + +function metat.__index:send(data) + return self.c:send(data) +end + +function metat.__index:receive(pat) + return self.c:receive(pat) +end + +function metat.__index:getfd() + return self.c:getfd() +end + +function metat.__index:dirty() + return self.c:dirty() +end + +function metat.__index:getcontrol() + return self.c +end + +function metat.__index:source(source, step) + local sink = socket.sink("keep-open", self.c) + local ret, err = ltn12.pump.all(source, sink, step or ltn12.pump.step) + return ret, err +end + +-- closes the underlying c +function metat.__index:close() + self.c:close() + return 1 +end + +-- connect with server and return c object +function _M.connect(host, port, timeout, create) + local c, e = (create or socket.tcp)() + if not c then return nil, e end + c:settimeout(timeout or _M.TIMEOUT) + local r, e = c:connect(host, port) + if not r then + c:close() + return nil, e + end + return base.setmetatable({c = c}, metat) +end + +return _M diff --git a/mods/noita-mp/lua_modules/share/lua/5.1/socket/url.lua b/mods/noita-mp/lua_modules/share/lua/5.1/socket/url.lua new file mode 100644 index 000000000..8e0dc5ceb --- /dev/null +++ b/mods/noita-mp/lua_modules/share/lua/5.1/socket/url.lua @@ -0,0 +1,331 @@ +----------------------------------------------------------------------------- +-- URI parsing, composition and relative URL resolution +-- LuaSocket toolkit. +-- Author: Diego Nehab +----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- +-- Declare module +----------------------------------------------------------------------------- +local string = require("string") +local base = _G +local table = require("table") +local socket = require("socket") + +socket.url = {} +local _M = socket.url + +----------------------------------------------------------------------------- +-- Module version +----------------------------------------------------------------------------- +_M._VERSION = "URL 1.0.3" + +----------------------------------------------------------------------------- +-- Encodes a string into its escaped hexadecimal representation +-- Input +-- s: binary string to be encoded +-- Returns +-- escaped representation of string binary +----------------------------------------------------------------------------- +function _M.escape(s) + return (string.gsub(s, "([^A-Za-z0-9_])", function(c) + return string.format("%%%02x", string.byte(c)) + end)) +end + +----------------------------------------------------------------------------- +-- Protects a path segment, to prevent it from interfering with the +-- url parsing. +-- Input +-- s: binary string to be encoded +-- Returns +-- escaped representation of string binary +----------------------------------------------------------------------------- +local function make_set(t) + local s = {} + for i,v in base.ipairs(t) do + s[t[i]] = 1 + end + return s +end + +-- these are allowed within a path segment, along with alphanum +-- other characters must be escaped +local segment_set = make_set { + "-", "_", ".", "!", "~", "*", "'", "(", + ")", ":", "@", "&", "=", "+", "$", ",", +} + +local function protect_segment(s) + return string.gsub(s, "([^A-Za-z0-9_])", function (c) + if segment_set[c] then return c + else return string.format("%%%02X", string.byte(c)) end + end) +end + +----------------------------------------------------------------------------- +-- Unencodes a escaped hexadecimal string into its binary representation +-- Input +-- s: escaped hexadecimal string to be unencoded +-- Returns +-- unescaped binary representation of escaped hexadecimal binary +----------------------------------------------------------------------------- +function _M.unescape(s) + return (string.gsub(s, "%%(%x%x)", function(hex) + return string.char(base.tonumber(hex, 16)) + end)) +end + +----------------------------------------------------------------------------- +-- Removes '..' and '.' components appropriately from a path. +-- Input +-- path +-- Returns +-- dot-normalized path +local function remove_dot_components(path) + local marker = string.char(1) + repeat + local was = path + path = path:gsub('//', '/'..marker..'/', 1) + until path == was + repeat + local was = path + path = path:gsub('/%./', '/', 1) + until path == was + repeat + local was = path + path = path:gsub('[^/]+/%.%./([^/]+)', '%1', 1) + until path == was + path = path:gsub('[^/]+/%.%./*$', '') + path = path:gsub('/%.%.$', '/') + path = path:gsub('/%.$', '/') + path = path:gsub('^/%.%./', '/') + path = path:gsub(marker, '') + return path +end + +----------------------------------------------------------------------------- +-- Builds a path from a base path and a relative path +-- Input +-- base_path +-- relative_path +-- Returns +-- corresponding absolute path +----------------------------------------------------------------------------- +local function absolute_path(base_path, relative_path) + if string.sub(relative_path, 1, 1) == "/" then + return remove_dot_components(relative_path) end + base_path = base_path:gsub("[^/]*$", "") + if not base_path:find'/$' then base_path = base_path .. '/' end + local path = base_path .. relative_path + path = remove_dot_components(path) + return path +end + +----------------------------------------------------------------------------- +-- Parses a url and returns a table with all its parts according to RFC 2396 +-- The following grammar describes the names given to the URL parts +-- ::= :///;?# +-- ::= @: +-- ::= [:] +-- :: = {/} +-- Input +-- url: uniform resource locator of request +-- default: table with default values for each field +-- Returns +-- table with the following fields, where RFC naming conventions have +-- been preserved: +-- scheme, authority, userinfo, user, password, host, port, +-- path, params, query, fragment +-- Obs: +-- the leading '/' in {/} is considered part of +----------------------------------------------------------------------------- +function _M.parse(url, default) + -- initialize default parameters + local parsed = {} + for i,v in base.pairs(default or parsed) do parsed[i] = v end + -- empty url is parsed to nil + if not url or url == "" then return nil, "invalid url" end + -- remove whitespace + -- url = string.gsub(url, "%s", "") + -- get scheme + url = string.gsub(url, "^([%w][%w%+%-%.]*)%:", + function(s) parsed.scheme = s; return "" end) + -- get authority + url = string.gsub(url, "^//([^/]*)", function(n) + parsed.authority = n + return "" + end) + -- get fragment + url = string.gsub(url, "#(.*)$", function(f) + parsed.fragment = f + return "" + end) + -- get query string + url = string.gsub(url, "%?(.*)", function(q) + parsed.query = q + return "" + end) + -- get params + url = string.gsub(url, "%;(.*)", function(p) + parsed.params = p + return "" + end) + -- path is whatever was left + if url ~= "" then parsed.path = url end + local authority = parsed.authority + if not authority then return parsed end + authority = string.gsub(authority,"^([^@]*)@", + function(u) parsed.userinfo = u; return "" end) + authority = string.gsub(authority, ":([^:%]]*)$", + function(p) parsed.port = p; return "" end) + if authority ~= "" then + -- IPv6? + parsed.host = string.match(authority, "^%[(.+)%]$") or authority + end + local userinfo = parsed.userinfo + if not userinfo then return parsed end + userinfo = string.gsub(userinfo, ":([^:]*)$", + function(p) parsed.password = p; return "" end) + parsed.user = userinfo + return parsed +end + +----------------------------------------------------------------------------- +-- Rebuilds a parsed URL from its components. +-- Components are protected if any reserved or unallowed characters are found +-- Input +-- parsed: parsed URL, as returned by parse +-- Returns +-- a stringing with the corresponding URL +----------------------------------------------------------------------------- +function _M.build(parsed) + --local ppath = _M.parse_path(parsed.path or "") + --local url = _M.build_path(ppath) + local url = parsed.path or "" + if parsed.params then url = url .. ";" .. parsed.params end + if parsed.query then url = url .. "?" .. parsed.query end + local authority = parsed.authority + if parsed.host then + authority = parsed.host + if string.find(authority, ":") then -- IPv6? + authority = "[" .. authority .. "]" + end + if parsed.port then authority = authority .. ":" .. base.tostring(parsed.port) end + local userinfo = parsed.userinfo + if parsed.user then + userinfo = parsed.user + if parsed.password then + userinfo = userinfo .. ":" .. parsed.password + end + end + if userinfo then authority = userinfo .. "@" .. authority end + end + if authority then url = "//" .. authority .. url end + if parsed.scheme then url = parsed.scheme .. ":" .. url end + if parsed.fragment then url = url .. "#" .. parsed.fragment end + -- url = string.gsub(url, "%s", "") + return url +end + +----------------------------------------------------------------------------- +-- Builds a absolute URL from a base and a relative URL according to RFC 2396 +-- Input +-- base_url +-- relative_url +-- Returns +-- corresponding absolute url +----------------------------------------------------------------------------- +function _M.absolute(base_url, relative_url) + local base_parsed + if base.type(base_url) == "table" then + base_parsed = base_url + base_url = _M.build(base_parsed) + else + base_parsed = _M.parse(base_url) + end + local result + local relative_parsed = _M.parse(relative_url) + if not base_parsed then + result = relative_url + elseif not relative_parsed then + result = base_url + elseif relative_parsed.scheme then + result = relative_url + else + relative_parsed.scheme = base_parsed.scheme + if not relative_parsed.authority then + relative_parsed.authority = base_parsed.authority + if not relative_parsed.path then + relative_parsed.path = base_parsed.path + if not relative_parsed.params then + relative_parsed.params = base_parsed.params + if not relative_parsed.query then + relative_parsed.query = base_parsed.query + end + end + else + relative_parsed.path = absolute_path(base_parsed.path or "", + relative_parsed.path) + end + end + result = _M.build(relative_parsed) + end + return remove_dot_components(result) +end + +----------------------------------------------------------------------------- +-- Breaks a path into its segments, unescaping the segments +-- Input +-- path +-- Returns +-- segment: a table with one entry per segment +----------------------------------------------------------------------------- +function _M.parse_path(path) + local parsed = {} + path = path or "" + --path = string.gsub(path, "%s", "") + string.gsub(path, "([^/]+)", function (s) table.insert(parsed, s) end) + for i = 1, #parsed do + parsed[i] = _M.unescape(parsed[i]) + end + if string.sub(path, 1, 1) == "/" then parsed.is_absolute = 1 end + if string.sub(path, -1, -1) == "/" then parsed.is_directory = 1 end + return parsed +end + +----------------------------------------------------------------------------- +-- Builds a path component from its segments, escaping protected characters. +-- Input +-- parsed: path segments +-- unsafe: if true, segments are not protected before path is built +-- Returns +-- path: corresponding path stringing +----------------------------------------------------------------------------- +function _M.build_path(parsed, unsafe) + local path = "" + local n = #parsed + if unsafe then + for i = 1, n-1 do + path = path .. parsed[i] + path = path .. "/" + end + if n > 0 then + path = path .. parsed[n] + if parsed.is_directory then path = path .. "/" end + end + else + for i = 1, n-1 do + path = path .. protect_segment(parsed[i]) + path = path .. "/" + end + if n > 0 then + path = path .. protect_segment(parsed[n]) + if parsed.is_directory then path = path .. "/" end + end + end + if parsed.is_absolute then path = "/" .. path end + return path +end + +return _M diff --git a/mods/noita-mp/lua_modules/share/lua/5.1/uuid.lua b/mods/noita-mp/lua_modules/share/lua/5.1/uuid.lua new file mode 100644 index 000000000..f205a4839 --- /dev/null +++ b/mods/noita-mp/lua_modules/share/lua/5.1/uuid.lua @@ -0,0 +1,216 @@ +--------------------------------------------------------------------------------------- +-- Copyright 2012 Rackspace (original), 2013-2021 Thijs Schreijer (modifications) +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS-IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- see http://www.ietf.org/rfc/rfc4122.txt +-- +-- Note that this is not a true version 4 (random) UUID. Since `os.time()` precision is only 1 second, it would be hard +-- to guarantee spacial uniqueness when two hosts generate a uuid after being seeded during the same second. This +-- is solved by using the node field from a version 1 UUID. It represents the mac address. +-- +-- 28-apr-2013 modified by Thijs Schreijer from the original [Rackspace code](https://github.com/kans/zirgo/blob/807250b1af6725bad4776c931c89a784c1e34db2/util/uuid.lua) as a generic Lua module. +-- Regarding the above mention on `os.time()`; the modifications use the `socket.gettime()` function from LuaSocket +-- if available and hence reduce that problem (provided LuaSocket has been loaded before uuid). +-- +-- **Important:** the random seed is a global piece of data. Hence setting it is +-- an application level responsibility, libraries should never set it! +-- +-- See this issue; [https://github.com/Kong/kong/issues/478](https://github.com/Kong/kong/issues/478) +-- It demonstrates the problem of using time as a random seed. Specifically when used from multiple processes. +-- So make sure to seed only once, application wide. And to not have multiple processes do that +-- simultaneously. + + +local M = {} +local math = require('math') +local os = require('os') +local string = require('string') + +local bitsize = 32 -- bitsize assumed for Lua VM. See randomseed function below. +local lua_version = tonumber(_VERSION:match("%d%.*%d*")) -- grab Lua version used + +local MATRIX_AND = {{0,0},{0,1} } +local MATRIX_OR = {{0,1},{1,1}} +local HEXES = '0123456789abcdef' + +local math_floor = math.floor +local math_random = math.random +local math_abs = math.abs +local string_sub = string.sub +local to_number = tonumber +local assert = assert +local type = type + +-- performs the bitwise operation specified by truth matrix on two numbers. +local function BITWISE(x, y, matrix) + local z = 0 + local pow = 1 + while x > 0 or y > 0 do + z = z + (matrix[x%2+1][y%2+1] * pow) + pow = pow * 2 + x = math_floor(x/2) + y = math_floor(y/2) + end + return z +end + +local function INT2HEX(x) + local s,base = '',16 + local d + while x > 0 do + d = x % base + 1 + x = math_floor(x/base) + s = string_sub(HEXES, d, d)..s + end + while #s < 2 do s = "0" .. s end + return s +end + +---------------------------------------------------------------------------- +-- Creates a new uuid. Either provide a unique hex string, or make sure the +-- random seed is properly set. The module table itself is a shortcut to this +-- function, so `my_uuid = uuid.new()` equals `my_uuid = uuid()`. +-- +-- For proper use there are 3 options; +-- +-- 1. first require `luasocket`, then call `uuid.seed()`, and request a uuid using no +-- parameter, eg. `my_uuid = uuid()` +-- 2. use `uuid` without `luasocket`, set a random seed using `uuid.randomseed(some_good_seed)`, +-- and request a uuid using no parameter, eg. `my_uuid = uuid()` +-- 3. use `uuid` without `luasocket`, and request a uuid using an unique hex string, +-- eg. `my_uuid = uuid(my_networkcard_macaddress)` +-- +-- @return a properly formatted uuid string +-- @param hwaddr (optional) string containing a unique hex value (e.g.: `00:0c:29:69:41:c6`), to be used to compensate for the lesser `math_random()` function. Use a mac address for solid results. If omitted, a fully randomized uuid will be generated, but then you must ensure that the random seed is set properly! +-- @usage +-- local uuid = require("uuid") +-- print("here's a new uuid: ",uuid()) +function M.new(hwaddr) + -- bytes are treated as 8bit unsigned bytes. + local bytes = { + math_random(0, 255), + math_random(0, 255), + math_random(0, 255), + math_random(0, 255), + math_random(0, 255), + math_random(0, 255), + math_random(0, 255), + math_random(0, 255), + math_random(0, 255), + math_random(0, 255), + math_random(0, 255), + math_random(0, 255), + math_random(0, 255), + math_random(0, 255), + math_random(0, 255), + math_random(0, 255) + } + + if hwaddr then + assert(type(hwaddr)=="string", "Expected hex string, got "..type(hwaddr)) + -- Cleanup provided string, assume mac address, so start from back and cleanup until we've got 12 characters + local i,str = #hwaddr, hwaddr + hwaddr = "" + while i>0 and #hwaddr<12 do + local c = str:sub(i,i):lower() + if HEXES:find(c, 1, true) then + -- valid HEX character, so append it + hwaddr = c..hwaddr + end + i = i - 1 + end + assert(#hwaddr == 12, "Provided string did not contain at least 12 hex characters, retrieved '"..hwaddr.."' from '"..str.."'") + + -- no split() in lua. :( + bytes[11] = to_number(hwaddr:sub(1, 2), 16) + bytes[12] = to_number(hwaddr:sub(3, 4), 16) + bytes[13] = to_number(hwaddr:sub(5, 6), 16) + bytes[14] = to_number(hwaddr:sub(7, 8), 16) + bytes[15] = to_number(hwaddr:sub(9, 10), 16) + bytes[16] = to_number(hwaddr:sub(11, 12), 16) + end + + -- set the version + bytes[7] = BITWISE(bytes[7], 0x0f, MATRIX_AND) + bytes[7] = BITWISE(bytes[7], 0x40, MATRIX_OR) + -- set the variant + bytes[9] = BITWISE(bytes[9], 0x3f, MATRIX_AND) + bytes[9] = BITWISE(bytes[9], 0x80, MATRIX_OR) + return INT2HEX(bytes[1])..INT2HEX(bytes[2])..INT2HEX(bytes[3])..INT2HEX(bytes[4]).."-".. + INT2HEX(bytes[5])..INT2HEX(bytes[6]).."-".. + INT2HEX(bytes[7])..INT2HEX(bytes[8]).."-".. + INT2HEX(bytes[9])..INT2HEX(bytes[10]).."-".. + INT2HEX(bytes[11])..INT2HEX(bytes[12])..INT2HEX(bytes[13])..INT2HEX(bytes[14])..INT2HEX(bytes[15])..INT2HEX(bytes[16]) +end + +---------------------------------------------------------------------------- +-- Improved randomseed function. +-- Lua 5.1 and 5.2 both truncate the seed given if it exceeds the integer +-- range. If this happens, the seed will be 0 or 1 and all randomness will +-- be gone (each application run will generate the same sequence of random +-- numbers in that case). This improved version drops the most significant +-- bits in those cases to get the seed within the proper range again. +-- @param seed the random seed to set (integer from 0 - 2^32, negative values will be made positive) +-- @return the (potentially modified) seed used +-- @usage +-- local socket = require("socket") -- gettime() has higher precision than os.time() +-- local uuid = require("uuid") +-- -- see also example at uuid.seed() +-- uuid.randomseed(socket.gettime()*10000) +-- print("here's a new uuid: ",uuid()) +function M.randomseed(seed) + seed = math_floor(math_abs(seed)) + if seed >= (2^bitsize) then + -- integer overflow, so reduce to prevent a bad seed + seed = seed - math_floor(seed / 2^bitsize) * (2^bitsize) + end + if lua_version < 5.2 then + -- 5.1 uses (incorrect) signed int + math.randomseed(seed - 2^(bitsize-1)) + else + -- 5.2 uses (correct) unsigned int + math.randomseed(seed) + end + return seed +end + +---------------------------------------------------------------------------- +-- Seeds the random generator. +-- It does so in 3 possible ways; +-- +-- 1. if in ngx_lua, use `ngx.time() + ngx.worker.pid()` to ensure a unique seed +-- for each worker. It should ideally be called from the `init_worker` context. +-- 2. use luasocket `gettime()` function, but it only does so when LuaSocket +-- has been required already. +-- 3. use `os.time()`: this only offers resolution to one second (used when +-- LuaSocket hasn't been loaded) +-- +-- **Important:** the random seed is a global piece of data. Hence setting it is +-- an application level responsibility, libraries should never set it! +-- @usage +-- local socket = require("socket") -- gettime() has higher precision than os.time() +-- -- LuaSocket loaded, so below line does the same as the example from randomseed() +-- uuid.seed() +-- print("here's a new uuid: ",uuid()) +function M.seed() + if _G.ngx ~= nil then + return M.randomseed(ngx.time() + ngx.worker.pid()) + elseif package.loaded["socket"] and package.loaded["socket"].gettime then + return M.randomseed(package.loaded["socket"].gettime()*10000) + else + return M.randomseed(os.time()) + end +end + +return setmetatable( M, { __call = function(self, hwaddr) return self.new(hwaddr) end} ) diff --git a/mods/noita-mp/files/lib/external/watcher.lua b/mods/noita-mp/lua_modules/share/lua/5.1/watcher.lua similarity index 100% rename from mods/noita-mp/files/lib/external/watcher.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/watcher.lua diff --git a/mods/noita-mp/files/lib/external/zstd.lua b/mods/noita-mp/lua_modules/share/lua/5.1/zstd.lua similarity index 100% rename from mods/noita-mp/files/lib/external/zstd.lua rename to mods/noita-mp/lua_modules/share/lua/5.1/zstd.lua diff --git a/mods/noita-mp/noita-mp-2.7.0-3.rockspec b/mods/noita-mp/noita-mp-2.7.0-3.rockspec new file mode 100644 index 000000000..1447d1b41 --- /dev/null +++ b/mods/noita-mp/noita-mp-2.7.0-3.rockspec @@ -0,0 +1,75 @@ +rockspec_format = "3.0" +package = "noita-mp" +version = "2.7.0-3" -- Needs to be updated manually and the same as in `.version` file. +source = { + url = "git+https://github.com/Ismoh/NoitaMP.git" +} +description = { + homepage = "https://github.com/Ismoh/NoitaMP", + license = "GNU GPL v3" +} +dependencies = { + "lua ~> 5.1", + "luafilesystem = 1.8.0-1", + "luafilesystem-ffi = scm-1", + "luaunit = 3.4-1", +} +build = { + type = "builtin", + modules = { -- change this to copy_directories? Does package path work without `modules`? + config = "config.lua", + ["files.scripts.DefaultBiomeMap"] = "files/scripts/DefaultBiomeMap.lua", + ["files.scripts.Ui"] = "files/scripts/Ui.lua", + ["files.scripts.biome.testingRoom"] = "files/scripts/biome/testingRoom.lua", + ["files.scripts.extensions.ffi_extensions"] = "files/scripts/extensions/ffi_extensions.lua", + ["files.scripts.extensions.globalExtensions"] = "files/scripts/extensions/globalExtensions.lua", + ["files.scripts.extensions.mathExtensions"] = "files/scripts/extensions/mathExtensions.lua", + ["files.scripts.extensions.string_extensions"] = "files/scripts/extensions/string_extensions.lua", + ["files.scripts.extensions.table_extensions"] = "files/scripts/extensions/table_extensions.lua", + ["files.scripts.init.init_"] = "files/scripts/init/init_.lua", + ["files.scripts.init.init_logger"] = "files/scripts/init/init_logger.lua", + ["files.scripts.init.init_package_loading"] = "files/scripts/init/init_package_loading.lua", + ["files.scripts.net.Client"] = "files/scripts/net/Client.lua", + ["files.scripts.net.Server"] = "files/scripts/net/Server.lua", + ["files.scripts.noita-components.dump_logger"] = "files/scripts/noita-components/dump_logger.lua", + ["files.scripts.noita-components.lua_component_enabler"] = "files/scripts/noita-components/lua_component_enabler.lua", + ["files.scripts.noita-components.name_tags"] = "files/scripts/noita-components/name_tags.lua", + ["files.scripts.noita-components.nuid_debug"] = "files/scripts/noita-components/nuid_debug.lua", + ["files.scripts.noita-components.nuid_updater"] = "files/scripts/noita-components/nuid_updater.lua", + ["files.scripts.util.CoroutineUtils"] = "files/scripts/util/CoroutineUtils.lua", + ["files.scripts.util.CustomProfiler"] = "files/scripts/util/CustomProfiler.lua", + ["files.scripts.util.EntityUtils"] = "files/scripts/util/EntityUtils.lua", + ["files.scripts.util.GlobalsUtils"] = "files/scripts/util/GlobalsUtils.lua", + ["files.scripts.util.NetworkUtils"] = "files/scripts/util/NetworkUtils.lua", + ["files.scripts.util.NetworkVscUtils"] = "files/scripts/util/NetworkVscUtils.lua", + ["files.scripts.util.NoitaComponentUtils"] = "files/scripts/util/NoitaComponentUtils.lua", + ["files.scripts.util.NuidUtils"] = "files/scripts/util/NuidUtils.lua", + ["files.scripts.util.file_util"] = "files/scripts/util/file_util.lua", + ["files.scripts.util.guid"] = "files/scripts/util/guid.lua", + ["files.scripts.util.util"] = "files/scripts/util/util.lua", + init = "init.lua", + modSettingsUpdater = "modSettingsUpdater.lua", + settings = "settings.lua", + ["tests.config_test"] = "tests/config_test.lua", + ["tests.files.scripts.extensions.string_extensions_test"] = "tests/files/scripts/extensions/string_extensions_test.lua", + ["tests.files.scripts.extensions.table_extensions_test"] = "tests/files/scripts/extensions/table_extensions_test.lua", + ["tests.files.scripts.init.init__test"] = "tests/files/scripts/init/init__test.lua", + ["tests.files.scripts.init.init_logger_test"] = "tests/files/scripts/init/init_logger_test.lua", + ["tests.files.scripts.init.init_package_loading_test"] = "tests/files/scripts/init/init_package_loading_test.lua", + ["tests.files.scripts.net.Server_test"] = "tests/files/scripts/net/Server_test.lua", + ["tests.files.scripts.util.EntityUtils_test"] = "tests/files/scripts/util/EntityUtils_test.lua", + ["tests.files.scripts.util.GlobalsUtils_test"] = "tests/files/scripts/util/GlobalsUtils_test.lua", + ["tests.files.scripts.util.NetworkUtils_test"] = "tests/files/scripts/util/NetworkUtils_test.lua", + ["tests.files.scripts.util.NetworkVscUtils_test"] = "tests/files/scripts/util/NetworkVscUtils_test.lua", + ["tests.files.scripts.util.NuidUtils_test"] = "tests/files/scripts/util/NuidUtils_test.lua", + ["tests.files.scripts.util.file_util_test"] = "tests/files/scripts/util/file_util_test.lua", + ["tests.files.scripts.util.guid_test"] = "tests/files/scripts/util/guid_test.lua", + ["tests.files.scripts.util.util_test"] = "tests/files/scripts/util/util_test.lua", + ["tests.init_test"] = "tests/init_test.lua", + ["tests.startUnitTests"] = "tests/startUnitTests.lua" + }, +} +test = { + type = "command", + script = "tests/startUnitTests.lua", +} diff --git a/mods/noita-mp/settings.lua b/mods/noita-mp/settings.lua index 13312b48f..0f662823b 100644 --- a/mods/noita-mp/settings.lua +++ b/mods/noita-mp/settings.lua @@ -326,12 +326,12 @@ Error: You will only see errors.]], ui_name = "Log level related to Globals", ui_description = [[Set the current log level, for printing messages into console. Debug: You will see debug, warning, info and errors. -Warning: You will see warnings, info and errors. Info: You will see info and errors. +Warning: You will see warnings, info and errors. Error: You will only see errors.]], value_default = "error", values = { - { "debug, warn, info, error", "Debug" }, { "warn, info, error", "Warning" }, { "info, error", "Info" }, { "error", "Error" } + { "debug, info, warn, error", "Debug" }, { "info, warn, error", "Info" }, { "warn, error", "Warning" }, { "error", "Error" } }, scope = MOD_SETTING_SCOPE_RUNTIME, change_fn = mod_setting_change_callback, -- Called when the user interact with the settings widget. @@ -341,12 +341,12 @@ Error: You will only see errors.]], ui_name = "Log level related to Guids", ui_description = [[Set the current log level, for printing messages into console. Debug: You will see debug, warning, info and errors. -Warning: You will see warnings, info and errors. Info: You will see info and errors. +Warning: You will see warnings, info and errors. Error: You will only see errors.]], value_default = "error", values = { - { "debug, warn, info, error", "Debug" }, { "warn, info, error", "Warning" }, { "info, error", "Info" }, { "error", "Error" } + { "debug, info, warn, error", "Debug" }, { "info, warn, error", "Info" }, { "warn, error", "Warning" }, { "error", "Error" } }, scope = MOD_SETTING_SCOPE_RUNTIME, change_fn = mod_setting_change_callback, -- Called when the user interact with the settings widget. @@ -356,12 +356,12 @@ Error: You will only see errors.]], ui_name = "Log level related to Client and Server", ui_description = [[Set the current log level, for printing messages into console. Debug: You will see debug, warning, info and errors. -Warning: You will see warnings, info and errors. Info: You will see info and errors. +Warning: You will see warnings, info and errors. Error: You will only see errors.]], value_default = "error", values = { - { "debug, warn, info, error", "Debug" }, { "warn, info, error", "Warning" }, { "info, error", "Info" }, { "error", "Error" } + { "debug, info, warn, error", "Debug" }, { "info, warn, error", "Info" }, { "warn, error", "Warning" }, { "error", "Error" } }, scope = MOD_SETTING_SCOPE_RUNTIME, change_fn = mod_setting_change_callback, -- Called when the user interact with the settings widget. @@ -371,12 +371,12 @@ Error: You will only see errors.]], ui_name = "Log level related to Nuids", ui_description = [[Set the current log level, for printing messages into console. Debug: You will see debug, warning, info and errors. -Warning: You will see warnings, info and errors. Info: You will see info and errors. +Warning: You will see warnings, info and errors. Error: You will only see errors.]], value_default = "error", values = { - { "debug, warn, info, error", "Debug" }, { "warn, info, error", "Warning" }, { "info, error", "Info" }, { "error", "Error" } + { "debug, info, warn, error", "Debug" }, { "info, warn, error", "Info" }, { "warn, error", "Warning" }, { "error", "Error" } }, scope = MOD_SETTING_SCOPE_RUNTIME, change_fn = mod_setting_change_callback, -- Called when the user interact with the settings widget. @@ -385,12 +385,12 @@ Error: You will only see errors.]], ui_name = "Log level related to Network VariableStorageComponents", ui_description = [[Set the current log level, for printing messages into console. Debug: You will see debug, warning, info and errors. -Warning: You will see warnings, info and errors. Info: You will see info and errors. +Warning: You will see warnings, info and errors. Error: You will only see errors.]], value_default = "error", values = { - { "debug, warn, info, error", "Debug" }, { "warn, info, error", "Warning" }, { "info, error", "Info" }, { "error", "Error" } + { "debug, info, warn, error", "Debug" }, { "info, warn, error", "Info" }, { "warn, error", "Warning" }, { "error", "Error" } }, scope = MOD_SETTING_SCOPE_RUNTIME, change_fn = mod_setting_change_callback, -- Called when the user interact with the settings widget. diff --git a/mods/noita-mp/tests/config_test.lua b/mods/noita-mp/tests/config_test.lua new file mode 100644 index 000000000..dc7690ad4 --- /dev/null +++ b/mods/noita-mp/tests/config_test.lua @@ -0,0 +1,15 @@ +local params = ... + +local lu = require("luaunit") + +TestConfig = {} + +function TestConfig:setUp() + +end + +function TestConfig:tearDown() + +end + +lu.LuaUnit.run(params) diff --git a/.testing/tests/mods/noita-mp/files/scripts/extensions/string_extensions_test.lua b/mods/noita-mp/tests/files/scripts/extensions/string_extensions_test.lua similarity index 60% rename from .testing/tests/mods/noita-mp/files/scripts/extensions/string_extensions_test.lua rename to mods/noita-mp/tests/files/scripts/extensions/string_extensions_test.lua index 047fd952c..548f3c850 100644 --- a/.testing/tests/mods/noita-mp/files/scripts/extensions/string_extensions_test.lua +++ b/mods/noita-mp/tests/files/scripts/extensions/string_extensions_test.lua @@ -1,27 +1,22 @@ -dofile("mods/noita-mp/files/scripts/init/init_.lua") +local params = ... local lu = require("luaunit") TestStringExtensions = {} function TestStringExtensions:setUp() - print("\nsetUp") + end function TestStringExtensions:tearDown() - print("tearDown\n") + end function TestStringExtensions:testExtendAndCutStringToLength() - lu.assertErrorMsgEquals("var is not a string.", string.ExtendOrCutStringToLength, 1) + lu.assertErrorMsgEquals("length is not a number.", string.ExtendOrCutStringToLength, 1) lu.assertErrorMsgEquals("length is not a number.", string.ExtendOrCutStringToLength, "var", "length") - lu.assertErrorMsgContains( - "char is not a character. string.len(char) > 1 = ", - string.ExtendOrCutStringToLength, - "var", - 1, - "character" - ) + lu.assertErrorMsgContains("char is not a character. string.len(char) > 1 = ", + string.ExtendOrCutStringToLength, "var", 1, "character") local expected = "12345" local actual = string.ExtendOrCutStringToLength("12345678910", 5, " ") @@ -32,4 +27,4 @@ function TestStringExtensions:testExtendAndCutStringToLength() lu.assertEquals(actual2, expected2) end -os.exit(lu.LuaUnit.run()) +lu.LuaUnit.run(params) diff --git a/.testing/tests/mods/noita-mp/files/scripts/extensions/table_extensions_test.lua b/mods/noita-mp/tests/files/scripts/extensions/table_extensions_test.lua similarity index 91% rename from .testing/tests/mods/noita-mp/files/scripts/extensions/table_extensions_test.lua rename to mods/noita-mp/tests/files/scripts/extensions/table_extensions_test.lua index b12fd4021..803ed7dfa 100644 --- a/.testing/tests/mods/noita-mp/files/scripts/extensions/table_extensions_test.lua +++ b/mods/noita-mp/tests/files/scripts/extensions/table_extensions_test.lua @@ -1,16 +1,15 @@ -#!/usr/bin/env lua -dofile("mods/noita-mp/files/scripts/init/init_.lua") +local params = ... local lu = require("luaunit") TestTableExtensions = {} function TestTableExtensions:setUp() - print("\nsetUp") + end function TestTableExtensions:tearDown() - print("tearDown\n") + end function TestTableExtensions:testTableContains() @@ -83,8 +82,8 @@ function TestTableExtensions:testSetNoitaMpDefaultMetaMethods() logger:debug(nil, tostring(t2)) lu.assertEquals(t2[1], 1) - lu.assertEquals(#t2, 4) - lu.assertEquals(t2[5], nil) + lu.assertEquals(#t2, 5) + lu.assertEquals(t2[5], 7) end -os.exit(lu.LuaUnit.run()) +lu.LuaUnit.run(params) diff --git a/mods/noita-mp/tests/files/scripts/init/init__test.lua b/mods/noita-mp/tests/files/scripts/init/init__test.lua new file mode 100644 index 000000000..34849eb0e --- /dev/null +++ b/mods/noita-mp/tests/files/scripts/init/init__test.lua @@ -0,0 +1,15 @@ +local params = ... + +local lu = require("luaunit") + +TestInit_ = {} + +function TestInit_:setUp() + +end + +function TestInit_:tearDown() + +end + +lu.LuaUnit.run(params) diff --git a/.testing/tests/mods/noita-mp/files/scripts/init/init_logger_test.lua b/mods/noita-mp/tests/files/scripts/init/init_logger_test.lua similarity index 51% rename from .testing/tests/mods/noita-mp/files/scripts/init/init_logger_test.lua rename to mods/noita-mp/tests/files/scripts/init/init_logger_test.lua index 175ae4a37..c3f84168a 100644 --- a/.testing/tests/mods/noita-mp/files/scripts/init/init_logger_test.lua +++ b/mods/noita-mp/tests/files/scripts/init/init_logger_test.lua @@ -1,15 +1,15 @@ -dofile("mods/noita-mp/files/scripts/init/init_.lua") +local params = ... local lu = require("luaunit") TestInitLogger = {} function TestInitLogger:setUp() - print("\nsetUp") + end function TestInitLogger:tearDown() - print("tearDown\n") + end -os.exit(lu.LuaUnit.run()) +lu.LuaUnit.run(params) diff --git a/.testing/tests/mods/noita-mp/files/scripts/init/init_package_loading_test.lua b/mods/noita-mp/tests/files/scripts/init/init_package_loading_test.lua similarity index 55% rename from .testing/tests/mods/noita-mp/files/scripts/init/init_package_loading_test.lua rename to mods/noita-mp/tests/files/scripts/init/init_package_loading_test.lua index 2ec2d7c50..78ed3e7dd 100644 --- a/.testing/tests/mods/noita-mp/files/scripts/init/init_package_loading_test.lua +++ b/mods/noita-mp/tests/files/scripts/init/init_package_loading_test.lua @@ -1,15 +1,15 @@ -dofile("mods/noita-mp/files/scripts/init/init_.lua") +local params = ... local lu = require("luaunit") TestInitPackageLoading = {} function TestInitPackageLoading:setUp() - print("\nsetUp") + end function TestInitPackageLoading:tearDown() - print("tearDown\n") + end -os.exit(lu.LuaUnit.run()) +lu.LuaUnit.run(params) diff --git a/mods/noita-mp/tests/files/scripts/net/Server_test.lua b/mods/noita-mp/tests/files/scripts/net/Server_test.lua new file mode 100644 index 000000000..3d3d72753 --- /dev/null +++ b/mods/noita-mp/tests/files/scripts/net/Server_test.lua @@ -0,0 +1,19 @@ +local params = ... + +local lu = require("luaunit") + +TestServer = {} + +function TestServer:setUp() + +end + +function TestServer:tearDown() + +end + +function TestServer:test() + -- +end + +lu.LuaUnit.run(params) \ No newline at end of file diff --git a/mods/noita-mp/tests/files/scripts/util/EntityUtils_test.lua b/mods/noita-mp/tests/files/scripts/util/EntityUtils_test.lua new file mode 100644 index 000000000..503953a83 --- /dev/null +++ b/mods/noita-mp/tests/files/scripts/util/EntityUtils_test.lua @@ -0,0 +1,15 @@ +local params = ... + +local lu = require("luaunit") + +TestEntityUtils = {} + +function TestEntityUtils:setUp() + +end + +function TestEntityUtils:tearDown() + +end + +lu.LuaUnit.run(params) diff --git a/mods/noita-mp/tests/files/scripts/util/GlobalsUtils_test.lua b/mods/noita-mp/tests/files/scripts/util/GlobalsUtils_test.lua new file mode 100644 index 000000000..2b8be53a7 --- /dev/null +++ b/mods/noita-mp/tests/files/scripts/util/GlobalsUtils_test.lua @@ -0,0 +1,15 @@ +local params = ... + +local lu = require("luaunit") + +TestGlobalsUtils = {} + +function TestGlobalsUtils:setUp() + +end + +function TestGlobalsUtils:tearDown() + +end + +lu.LuaUnit.run(params) diff --git a/mods/noita-mp/tests/files/scripts/util/NetworkUtils_test.lua b/mods/noita-mp/tests/files/scripts/util/NetworkUtils_test.lua new file mode 100644 index 000000000..b67113524 --- /dev/null +++ b/mods/noita-mp/tests/files/scripts/util/NetworkUtils_test.lua @@ -0,0 +1,47 @@ +local params = ... + +local lu = require("luaunit") +local NetworkUtils = require("NetworkUtils") +local sock = require("sock") + +TestNetworkUtils = {} + +function TestNetworkUtils:setUp() + +end + +function TestNetworkUtils:tearDown() + +end + +function TestNetworkUtils:testAlreadySent() + --local event = NetworkUtils.events.newNuid.name + --local data = { + -- networkMessageId = 367, + -- owner = { "ownerName", "ownerGuid" }, + -- localEntityId = 4673, + -- newNuid = 4, + -- x = 0.25, + -- y = 3.55, + -- rotation = 49, + -- velocity = { x = 0, y = 3 }, + -- filename = "/mods/", + -- health = { current = 123, max = 125 }, + -- isPolymorphed = false + --} + -- + --local server = sock.newServer("*", 22122) + --local client = sock.newClient("*", 22122) + -- + --client.connect("*", 22122) + -- + --local result = NetworkUtils.alreadySent(client, event, data) + --lu.assertIsFalse(result) + -- + --server.send(client, event, data) + -- + --local result = NetworkUtils.alreadySent(client, event, data) + --lu.assertIsTrue(result) +end + +lu.LuaUnit.run(params) \ No newline at end of file diff --git a/mods/noita-mp/tests/files/scripts/util/NetworkVscUtils_test.lua b/mods/noita-mp/tests/files/scripts/util/NetworkVscUtils_test.lua new file mode 100644 index 000000000..ed98fe9d2 --- /dev/null +++ b/mods/noita-mp/tests/files/scripts/util/NetworkVscUtils_test.lua @@ -0,0 +1,15 @@ +local params = ... + +local lu = require("luaunit") + +TestNetworkVscUtils = {} + +function TestNetworkVscUtils:setUp() + +end + +function TestNetworkVscUtils:tearDown() + +end + +lu.LuaUnit.run(params) diff --git a/mods/noita-mp/tests/files/scripts/util/NuidUtils_test.lua b/mods/noita-mp/tests/files/scripts/util/NuidUtils_test.lua new file mode 100644 index 000000000..bab5b6cb5 --- /dev/null +++ b/mods/noita-mp/tests/files/scripts/util/NuidUtils_test.lua @@ -0,0 +1,15 @@ +local params = ... + +local lu = require("luaunit") + +TestNuidUtils = {} + +function TestNuidUtils:setUp() + +end + +function TestNuidUtils:tearDown() + +end + +lu.LuaUnit.run(params) diff --git a/.testing/tests/mods/noita-mp/files/scripts/util/file_util_test.lua b/mods/noita-mp/tests/files/scripts/util/file_util_test.lua similarity index 76% rename from .testing/tests/mods/noita-mp/files/scripts/util/file_util_test.lua rename to mods/noita-mp/tests/files/scripts/util/file_util_test.lua index b2830af78..2743463dd 100644 --- a/.testing/tests/mods/noita-mp/files/scripts/util/file_util_test.lua +++ b/mods/noita-mp/tests/files/scripts/util/file_util_test.lua @@ -1,16 +1,14 @@ -#!/usr/bin/env lua +local params = ... -dofile("mods/noita-mp/files/scripts/init/init_.lua") - -local lu = require("luaunit") -local fu = require("file_util") +local lu = require("luaunit") +local fu = require("file_util") TestFileUtil = {} function TestFileUtil:setUp() - print("\nsetUp") + -- Mock Noita Api global functions - _G.DebugGetIsDevBuild = function () + _G.DebugGetIsDevBuild = function() return false end @@ -20,7 +18,7 @@ function TestFileUtil:setUp() end function TestFileUtil:tearDown() - print("tearDown\n") + end ---------------------------------------------------------------------------------------------------- @@ -28,60 +26,60 @@ end ---------------------------------------------------------------------------------------------------- function TestFileUtil:testReplacePathSeparatorOnWindows() - local old_is_windows = _G.is_windows - local old_is_linux = _G.is_linux + local old_is_windows = _G.is_windows + local old_is_linux = _G.is_linux local old_path_separator = _G.path_separator - _G.is_windows = true -- TODO: is there a better way to mock? - _G.is_linux = false -- TODO: is there a better way to mock? - _G.path_separator = "\\" -- TODO: is there a better way to mock? + _G.is_windows = true -- TODO: is there a better way to mock? + _G.is_linux = false -- TODO: is there a better way to mock? + _G.path_separator = "\\" -- TODO: is there a better way to mock? - local path_unix = "/test/path/123" - local path_windows = fu.ReplacePathSeparator(path_unix) + local path_unix = "/test/path/123" + local path_windows = fu.ReplacePathSeparator(path_unix) lu.assertNotEquals(path_unix, path_windows) lu.assertEquals([[\test\path\123]], path_windows) - _G.is_windows = old_is_windows - _G.is_linux = old_is_linux + _G.is_windows = old_is_windows + _G.is_linux = old_is_linux _G.path_separator = old_path_separator end function TestFileUtil:testReplacePathSeparatorOnUnix() - local old_is_windows = _G.is_windows - local old_is_linux = _G.is_linux + local old_is_windows = _G.is_windows + local old_is_linux = _G.is_linux local old_path_separator = _G.path_separator - _G.is_windows = false -- TODO: is there a better way to mock? - _G.is_linux = true -- TODO: is there a better way to mock? - _G.path_separator = "/" -- TODO: is there a better way to mock? + _G.is_windows = false -- TODO: is there a better way to mock? + _G.is_linux = true -- TODO: is there a better way to mock? + _G.path_separator = "/" -- TODO: is there a better way to mock? - local path_windows = "\\test\\path\\123" - local path_unix = fu.ReplacePathSeparator(path_windows) + local path_windows = "\\test\\path\\123" + local path_unix = fu.ReplacePathSeparator(path_windows) lu.assertNotEquals(path_windows, path_unix) lu.assertEquals("/test/path/123", path_unix) - _G.is_windows = old_is_windows - _G.is_linux = old_is_linux + _G.is_windows = old_is_windows + _G.is_linux = old_is_linux _G.path_separator = old_path_separator end function TestFileUtil:testReplacePathSeparatorUnkownOs() local old_is_windows = _G.is_windows - local old_is_linux = _G.is_linux + local old_is_linux = _G.is_linux - _G.is_windows = false -- TODO: is there a better way to mock? - _G.is_linux = false -- TODO: is there a better way to mock? + _G.is_windows = false -- TODO: is there a better way to mock? + _G.is_linux = false -- TODO: is there a better way to mock? lu.assertErrorMsgContains("file_util.lua | Unable to detect OS", fu.ReplacePathSeparator, "path doesnt matter") _G.is_windows = old_is_windows - _G.is_linux = old_is_linux + _G.is_linux = old_is_linux end function TestFileUtil:testRemoveTrailingPathSeparator() - local path = tostring(_G.path_separator .. "persistent" .. _G.path_separator .. "flags" .. _G.path_separator) + local path = tostring(_G.path_separator .. "persistent" .. _G.path_separator .. "flags" .. _G.path_separator) local result = fu.RemoveTrailingPathSeparator(path) lu.assertNotEquals(path, result) @@ -99,15 +97,16 @@ end function TestFileUtil:testSetAbsolutePathOfNoitaRootDirectoryUnkownOs() local old_is_windows = _G.is_windows - local old_is_linux = _G.is_linux + local old_is_linux = _G.is_linux - _G.is_windows = false -- TODO: is there a better way to mock? - _G.is_linux = false -- TODO: is there a better way to mock? + _G.is_windows = false -- TODO: is there a better way to mock? + _G.is_linux = false -- TODO: is there a better way to mock? - lu.assertErrorMsgContains("file_util.lua | Unable to detect OS", fu.SetAbsolutePathOfNoitaRootDirectory, "path doesnt matter") + lu.assertErrorMsgContains("file_util.lua | Unable to detect OS", fu.SetAbsolutePathOfNoitaRootDirectory, + "path doesnt matter") _G.is_windows = old_is_windows - _G.is_linux = old_is_linux + _G.is_linux = old_is_linux end function TestFileUtil:testGetAbsolutePathOfNoitaRootDirectory() @@ -176,7 +175,7 @@ end function TestFileUtil:testGetAbsoluteDirectoryPathOfMods() local actual_path = fu.GetAbsoluteDirectoryPathOfMods() - local expected = fu.ReplacePathSeparator(_G.noita_root_directory_path .. "/mods/noita-mp") + local expected = fu.ReplacePathSeparator(_G.noita_root_directory_path .. "/mods/noita-mp") lu.assertEquals(actual_path, expected) end @@ -190,8 +189,8 @@ end function TestFileUtil:testGetAbsoluteDirectoryPathOfRequiredLibs() _G.noita_root_directory_path = nil -- TODO: is there a better way to mock? - local actual_path = fu.GetAbsoluteDirectoryPathOfRequiredLibs() - local expected = fu.ReplacePathSeparator(_G.noita_root_directory_path .. "/mods/noita-mp/files/libs") + local actual_path = fu.GetAbsoluteDirectoryPathOfRequiredLibs() + local expected = fu.ReplacePathSeparator(_G.noita_root_directory_path .. "/mods/noita-mp/files/libs") lu.assertEquals(actual_path, expected) end @@ -202,13 +201,13 @@ end function TestFileUtil:testExists() lu.assertNotIsTrue(fu.Exists("nonexistingfile.asdf")) lu.assertErrorMsgContains("is not type of string!", fu.Exists) - lu.assertIsTrue(fu.Exists(_G.noita_root_directory_path .. "/.gitignore")) + lu.assertIsTrue(fu.Exists(_G.noita_root_directory_path .. "/mod.xml")) end function TestFileUtil:testIsFile() lu.assertNotIsTrue(fu.IsFile("nonexistingfile.asdf")) lu.assertErrorMsgContains("is not type of string!", fu.IsFile) - lu.assertIsTrue(fu.IsFile(_G.noita_root_directory_path .. "/.gitignore")) + lu.assertIsTrue(fu.IsFile(_G.noita_root_directory_path .. "/mod.xml")) end function TestFileUtil:testIsDirectory() @@ -221,39 +220,41 @@ function TestFileUtil:testReadBinaryFile() lu.assertErrorMsgContains("is not type of string!", fu.ReadBinaryFile) lu.assertErrorMsgContains("Unable to open and read file: ", fu.ReadBinaryFile, "nonexistingfile.asdf") - local content = fu.ReadBinaryFile(_G.noita_root_directory_path .. "/.gitignore") + local content = fu.ReadBinaryFile(_G.noita_root_directory_path .. "/mod.xml") lu.assertNotNil(content) end function TestFileUtil:testWriteBinaryFile() lu.assertErrorMsgContains("is not type of string!", fu.WriteBinaryFile) - local full_path = _G.noita_root_directory_path .. "/.testing/write-temporary-binary-test-file.txt" + local full_path = _G.noita_root_directory_path .. "/write-temporary-binary-test-file.txt" fu.WriteBinaryFile(full_path, "File Content") lu.assertIsTrue(fu.Exists(full_path)) + os.remove(full_path) end function TestFileUtil:testReadFile() lu.assertErrorMsgContains("is not type of string!", fu.ReadFile) lu.assertErrorMsgContains("Unable to open and read file: ", fu.ReadFile, "nonexistingfile.asdf") - local content = fu.ReadFile(_G.noita_root_directory_path .. "/.gitignore") + local content = fu.ReadFile(_G.noita_root_directory_path .. "/mod.xml") lu.assertNotNil(content) end function TestFileUtil:testWriteFile() lu.assertErrorMsgContains("is not type of string!", fu.WriteFile) - local full_path = _G.noita_root_directory_path .. "/.testing/write-temporary-test-file.txt" + local full_path = _G.noita_root_directory_path .. "/write-temporary-test-file.txt" fu.WriteFile(full_path, "File Content") lu.assertIsTrue(fu.Exists(full_path)) + os.remove(full_path) end function TestFileUtil:testMkDir() lu.assertErrorMsgContains("is not type of string!", fu.MkDir) -- TODO: windows - -- local dir_path = _G.noita_root_directory_path .. "/.testing/temp-test-dir" + -- local dir_path = _G.noita_root_directory_path .. "/tests/temp-test-dir" -- fu.MkDir(dir_path) -- lu.assertIsTrue(fu.Exists(dir_path)) -- lu.assertIsTrue(fu.IsDirectory(dir_path)) @@ -264,7 +265,7 @@ function TestFileUtil:testFind7zipExecutable() end function TestFileUtil:testExists7zip() - local old = _G.seven_zip + local old = _G.seven_zip _G.seven_zip = false -- mock lu.assertNotIsTrue(fu.Exists7zip()) _G.seven_zip = true -- mock @@ -276,4 +277,4 @@ function TestFileUtil:testCreate7zipArchive() --fu.Create7zipArchive() end -os.exit(lu.LuaUnit.run()) \ No newline at end of file +lu.LuaUnit.run(params) \ No newline at end of file diff --git a/.testing/tests/mods/noita-mp/files/scripts/util/guid_test.lua b/mods/noita-mp/tests/files/scripts/util/guid_test.lua similarity index 76% rename from .testing/tests/mods/noita-mp/files/scripts/util/guid_test.lua rename to mods/noita-mp/tests/files/scripts/util/guid_test.lua index 6e6a1381e..cbfa1af45 100644 --- a/.testing/tests/mods/noita-mp/files/scripts/util/guid_test.lua +++ b/mods/noita-mp/tests/files/scripts/util/guid_test.lua @@ -1,14 +1,12 @@ ----@diagnostic disable: param-type-mismatch -#!/usr/bin/env lua -dofile("mods/noita-mp/files/scripts/init/init_.lua") +local params = ... -local lu = require("luaunit") +local lu = require("luaunit") local Guid = require("guid") -TestGuid = {} +TestGuid = {} function TestGuid:setUp() - print("\nsetUp") + -- Mock Noita Api global functions _G.DebugGetIsDevBuild = function() return false @@ -17,13 +15,13 @@ function TestGuid:setUp() --- Mocked in guid_test.lua --- @param id string --- @return nil nil Returns nil in this case. - _G.ModSettingGet = function(id) + _G.ModSettingGet = function(id) return nil end end function TestGuid:tearDown() - print("tearDown\n") + end function TestGuid:testGetGuid() @@ -47,4 +45,4 @@ function TestGuid:testRandomness() end end -os.exit(lu.LuaUnit.run()) +lu.LuaUnit.run(params) diff --git a/.testing/tests/mods/noita-mp/files/scripts/util/util_test.lua b/mods/noita-mp/tests/files/scripts/util/util_test.lua similarity index 77% rename from .testing/tests/mods/noita-mp/files/scripts/util/util_test.lua rename to mods/noita-mp/tests/files/scripts/util/util_test.lua index 5146cb28b..9e900e3a5 100644 --- a/.testing/tests/mods/noita-mp/files/scripts/util/util_test.lua +++ b/mods/noita-mp/tests/files/scripts/util/util_test.lua @@ -1,13 +1,12 @@ -#!/usr/bin/env lua -dofile("mods/noita-mp/files/scripts/init/init_.lua") +local params = ... -local lu = require("luaunit") +local lu = require("luaunit") local util = require("util") -TestUtil = {} +TestUtil = {} function TestUtil:setUp() - print("\nsetUp") + --- Mocked in guid_test.lua --- @param id string @@ -18,17 +17,17 @@ function TestUtil:setUp() end function TestUtil:tearDown() - print("tearDown\n") + end function TestUtil:testSleep() lu.assertErrorMsgContains("Unable to wait if parameter 'seconds' isn't a number:", util.Sleep, "seconds") - local seconds_to_wait = 4 + local seconds_to_wait = 4 local timestamp_before = os.clock() util.Sleep(seconds_to_wait) local timestamp_after = os.clock() - local diff = timestamp_before + seconds_to_wait + local diff = timestamp_before + seconds_to_wait logger:debug("timestamp_before=%s, timestamp_after=%s, diff=%s", timestamp_before, timestamp_after, diff) lu.almostEquals(diff, timestamp_after, 0.1) end @@ -43,4 +42,4 @@ function TestUtil:testIsEmpty() lu.assertIsTrue(util.IsEmpty({})) end -os.exit(lu.LuaUnit.run()) +lu.LuaUnit.run(params) diff --git a/mods/noita-mp/tests/init_test.lua b/mods/noita-mp/tests/init_test.lua new file mode 100644 index 000000000..d21eeed7a --- /dev/null +++ b/mods/noita-mp/tests/init_test.lua @@ -0,0 +1,15 @@ +local params = ... + +local lu = require("luaunit") + +TestInit = {} + +function TestInit:setUp() + +end + +function TestInit:tearDown() + +end + +lu.LuaUnit.run(params) diff --git a/mods/noita-mp/tests/startUnitTests.lua b/mods/noita-mp/tests/startUnitTests.lua new file mode 100644 index 000000000..86eb839c9 --- /dev/null +++ b/mods/noita-mp/tests/startUnitTests.lua @@ -0,0 +1,78 @@ +dofile("../noita-mp/files/scripts/init/init_package_loading.lua") + +local lfs = require("lfs") + +--- Returns a list of all files in a directory +function getAllFilesInside(folder) + local files = {} + for entry in lfs.dir(folder) do + if entry ~= "." and entry ~= ".." and not entry:find("startUnitTests") then + local path = folder .. "/" .. entry + local mode = lfs.attributes(path, "mode") + if mode == "file" then + table.insert(files, path) + print("Found file: " .. path) + elseif mode == "directory" then + --print("Found directory: " .. path) + local subfiles = getAllFilesInside(path) + for _, subfile in ipairs(subfiles) do + print("Found file: " .. subfile) + table.insert(files, subfile) + end + end + end + end + return files +end + +local testFiles = getAllFilesInside(lfs.currentdir() .. "/tests") + +local init = true +local gPrint = print +local gDofile = dofile +if not ModSettingGet then + --print = function(...) + -- local noitaMpRootDir = lfs.currentdir() + -- local filePath = noitaMpRootDir .. "/tests/result.log" + -- + -- if init then + -- local createFile = io.open(filePath, "w") + -- createFile:write(os.clock()) + -- createFile:close() + -- init = false + -- end + -- + -- local file, err = io.open(filePath, "r+") + -- if err then + -- gPrint("Error opening file: " .. err) + -- end + -- --local content = file:read("*a") + -- file:write("\n" .. content .. "\n" .. ...) + -- file:flush() + -- file:close() + -- gPrint(...) + --end + + local pathToMods = lfs.currentdir() .. "/../.." + print("pathToMods: " .. pathToMods) + dofile = function(path) + if path:sub(1, 4) == "mods" then + local pathToMod = pathToMods .. "/" .. path + print("dofile path: " .. pathToMod) + return gDofile(pathToMod) + else + return gDofile(path) + end + end +end + +dofile("mods/noita-mp/files/scripts/init/init_.lua") + +for _, testFile in ipairs(testFiles) do + print("") + print("") + print("##################################################") + print("Running test: " .. testFile) + --dofile(testFile) + assert(loadfile(testFile))("--verbose", "--error", "--failure") +end \ No newline at end of file