├── .gitattributes ├── .gitignore ├── .npmignore ├── .travis.yml ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── .vscodeignore ├── LICENSE ├── README.md ├── bin └── luafmt.ts ├── gulpfile.js ├── package.json ├── src ├── comments.ts ├── docBuilder.ts ├── docPrinter.ts ├── docUtils.ts ├── fastPath.ts ├── index.ts ├── options.ts ├── printer.ts ├── testPrinter.ts └── util.ts ├── test ├── comments │ ├── __snapshots__ │ │ └── comments.test.ts.snap │ ├── comments.test.ts │ ├── do.lua │ ├── for.lua │ ├── function.lua │ ├── if.lua │ ├── repeat.lua │ └── table.lua ├── function │ ├── __snapshots__ │ │ └── function.test.ts.snap │ ├── function.test.ts │ └── functions.lua ├── linewrap │ ├── __snapshots__ │ │ └── linewrap.test.ts.snap │ ├── assignment.lua │ └── linewrap.test.ts ├── lua-5.3.4-tests │ ├── LICENSE │ ├── all.lua │ ├── api.lua │ ├── attrib.lua │ ├── big.lua │ ├── bitwise.lua │ ├── calls.lua │ ├── closure.lua │ ├── code.lua │ ├── constructs.lua │ ├── coroutine.lua │ ├── db.lua │ ├── errors.lua │ ├── events.lua │ ├── files.lua │ ├── gc.lua │ ├── goto.lua │ ├── literals.lua │ ├── locals.lua │ ├── main.lua │ ├── math.lua │ ├── nextvar.lua │ ├── out.lua │ ├── pm.lua │ ├── sort.lua │ ├── strings.lua │ ├── tpack.lua │ ├── utf8.lua │ ├── vararg.lua │ └── verybig.lua ├── lua-5.3.4.test.ts ├── quotes │ ├── __snapshots__ │ │ └── quotes.test.ts.snap │ ├── keep_quotemark.lua │ └── quotes.test.ts ├── shebang │ ├── __snapshots__ │ │ └── shebang.test.ts.snap │ ├── keep_shebang.lua │ └── shebang.test.ts └── util.ts ├── tsconfig.json ├── tslint.json └── typings ├── index.d.ts └── modules └── luaparse └── index.d.ts /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | ide 3 | test_files/ 4 | dist/ 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | .vscodeignore 3 | test/ 4 | src/ 5 | bin/ 6 | typings/ 7 | dist/testPrinter.* 8 | .gitattributes 9 | .gitignore 10 | gulpfile.js 11 | tsconfig.json 12 | tslint.json 13 | test_files/ 14 | ide/ 15 | lua*-env/ -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | os: 3 | - linux 4 | language: node_js 5 | 6 | node_js: 7 | - 6.3.1 8 | 9 | before_install: 10 | - pip install --user hererocks 11 | - mkdir lua-bins 12 | 13 | - hererocks lua53-env -l5.3 # Install Lua 5.3 14 | - ln -s $PWD/lua53-env/bin/lua lua-bins/lua53 # Link lua-bins/lua53 to the 5.3 binary 15 | 16 | - export PATH=$PATH:$PWD/lua-bins # Expose the binary path to the PATH 17 | 18 | script: 19 | - npm install -g gulp 20 | - gulp 21 | - gulp test 22 | 23 | deploy: 24 | provider: npm 25 | email: me@trix.nz 26 | api_key: 27 | secure: jDK0d3GY48OEtcuBKnGjv6VdZenWIYTwZSYPmNiPFpIN49HEBuGpwpgS1xNt2LfIUjLFHxcf1Rqrlm31qY00MeLMoOJkXmzT0sRmM2HeKiY3f+/SgvqW3KEcMEeEr32Pg3rUMtWBEh9Xd4PwysVUIyH7qfVa+YpzcKXdOzhg0Rr84sItjWl9DIPPKOER75Det/QofAF/RnfWpmPT83C2HxQ1CRI3jQlE4tn6Q+0UFrAAkc9jw/dInHgYDbZkF8u0SfVyrAYeXVwJBTIqWmBFaXm3uIe3rVL09iafOcdZMTAwVtxJCNCCsSv5GCB9npwxqCdfPiZOR9Xt/YwoASEa7fQgsdzew2yk4n7S/KjyMk9v1bZt8b2iSYFhHir4wKJQVqdVfkWGeellexso/hWR4QPLpsKIu82cdfKZ3iv/RNhofLFGJhNh4+mzc84Dv331yJm+GnI5yEKr7HLAv/QhLdGtBaeE4SmW5xY7p0XtSvU5C/LRBdDZX53fFtuOcpSL1tM2JQjxGSThjd5JOIBhrLSYhHnU0mqeRhjnfAJOfm5kTq2rOJQ//kwbTjOGuaQ5bEatl/onpVrhGW2dd0lqSpu+mVCYefGjiNJi7nlGTGRUHtZTAMvAY+ORE9jy9GUOpLBltWZX/Wn4vBx9niLqRZGFmlB0rbmm75OARQzyjuo= 28 | skip_cleanup: true 29 | on: 30 | tags: true 31 | repo: trixnz/lua-fmt 32 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | // A launch configuration that compiles the extension and then opens it inside a new window 2 | { 3 | "version": "0.1.0", 4 | "configurations": [ 5 | { 6 | "name": "Launch", 7 | "type": "node", 8 | "request": "launch", 9 | "program": "${workspaceRoot}/src/testPrinter.ts", 10 | "stopOnEntry": false, 11 | "args": [], 12 | "cwd": "${workspaceRoot}", 13 | "preLaunchTask": null, 14 | "runtimeExecutable": null, 15 | "runtimeArgs": [ 16 | "--nolazy" 17 | ], 18 | "env": { 19 | "NODE_ENV": "\"development\"" 20 | }, 21 | "console": "internalConsole", 22 | "sourceMaps": true, 23 | "outFiles": [ 24 | "${workspaceRoot}/dist/**/*.js" 25 | ] 26 | } 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | "**/.git": true, 4 | "**/out": true, 5 | "**/node_modules": true 6 | }, 7 | "search.exclude": { 8 | "**/node_modules": true, 9 | "**/bower_components": true, 10 | "dist": true 11 | }, 12 | "vsicons.presets.angular": false, 13 | "editor.rulers": [ 14 | 120 15 | ], 16 | "files.eol": "\n", 17 | "files.insertFinalNewline": true, 18 | "files.trimTrailingWhitespace": true, 19 | "typescript.tsdk": "./node_modules/typescript/lib", 20 | "typescript.format.enable": true, 21 | "typescript.format.insertSpaceAfterCommaDelimiter": true, 22 | "typescript.format.insertSpaceAfterSemicolonInForStatements": true, 23 | "typescript.format.insertSpaceBeforeAndAfterBinaryOperators": true, 24 | "typescript.format.insertSpaceAfterKeywordsInControlFlowStatements": true, 25 | "typescript.format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": true, 26 | "typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis": false, 27 | "typescript.format.insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets": false, 28 | "typescript.format.placeOpenBraceOnNewLineForFunctions": false, 29 | "typescript.format.placeOpenBraceOnNewLineForControlBlocks": false, 30 | "typescript.format.insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces": false, 31 | "typescript.format.insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces": false 32 | } 33 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | // Available variables which can be used inside of strings. 2 | // ${workspaceRoot}: the root folder of the team 3 | // ${file}: the current opened file 4 | // ${fileBasename}: the current opened file's basename 5 | // ${fileDirname}: the current opened file's dirname 6 | // ${fileExtname}: the current opened file's extension 7 | // ${cwd}: the current working directory of the spawned process 8 | 9 | // A task runner that calls a custom npm script that compiles the extension. 10 | { 11 | "version": "0.1.0", 12 | 13 | // we want to run npm 14 | "command": "npm", 15 | 16 | // the command is a shell script 17 | "isShellCommand": true, 18 | 19 | // show the output window only if unrecognized errors occur. 20 | "showOutput": "silent", 21 | 22 | // we run the custom script "compile" as defined in package.json 23 | "args": ["run", "compile", "--loglevel", "silent"], 24 | 25 | // The tsc compiler is started in watching mode 26 | "isWatching": true, 27 | 28 | // use the standard tsc in watch mode problem matcher to find compile problems in the output. 29 | "problemMatcher": "$tsc-watch" 30 | } -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | out/test/** 4 | test/** 5 | src/** 6 | **/*.map 7 | .gitignore 8 | tsconfig.json 9 | vsc-extension-quickstart.md 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 trixnz (me@trix.nz) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/trixnz/lua-fmt.svg?branch=master)](https://travis-ci.org/trixnz/lua-fmt) [![NPM Package](https://img.shields.io/npm/v/lua-fmt.svg)](https://www.npmjs.com/package/lua-fmt) 2 | 3 | # Code Formatter for Lua 4 | `lua-fmt` is pretty-printer for [Lua](https://www.lua.org/) code, written in [TypeScript](https://www.typescriptlang.org/) and deeply inspired by [prettier](https://github.com/prettier/prettier). `lua-fmt` provides an interface to format Lua code that conforms to a single and consistent standard. 5 | 6 | While not implemented yet, the interface will be customizable to tailor the output to the user's preferences: linebreaks, string style, etc. 7 | 8 | ## Installing 9 | * `npm install lua-fmt` 10 | 11 | ## Usage 12 | ### API 13 | ```TypeScript 14 | import {formatText} from 'lua-fmt'; 15 | console.log(formatText('local hello = "Hello"; print(hello .. " world!")')) 16 | ``` 17 | 18 | ### Command Line 19 | Format a single file: 20 | * `luafmt test/lua-5.3.4-tests/calls.lua` 21 | 22 | Format a stream from `stdin`: 23 | * `cat test/lua-5.3.4-tests/calls.lua | luafmt --stdin` 24 | 25 | ## TODO 26 | - [ ] Add support for a `.luafmt` preferences file 27 | 28 | ## Testing 29 | `lua-fmt` uses [jest](https://facebook.github.io/jest/) for automated testing. 30 | 31 | Among the user-created tests in the `test/` folder, a copy of the `lua-5.3.4` tests are executed after formatting to ensure the code remains syntactically correct after formatting. For this reason, please do not modify the `lua-5.3.4-tests` folder unless updating with new tests from the official Lua tests. To run these tests, `lua53` is expected to be available on the `PATH`. 32 | 33 | When contributing changes, please consider writing tests to ensure they do not regress. 34 | 35 | ## License 36 | 37 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. 38 | 39 | ## Acknowledgments 40 | * [Oskar Schöldström](https://github.com/oxyc) - [luaparse](https://github.com/oxyc/luaparse): A Lua parser written in JavaScript 41 | * [Christopher Chedeau](https://github.com/vjeux) - [prettier](https://github.com/prettier/prettier): Prettier is an opinionated JavaScript formatter. 42 | * [Ben Newman](https://github.com/benjamn) - [recast](https://github.com/benjamn/recast): JavaScript syntax tree transformer, nondestructive pretty-printer, and automatic source map generator. 43 | -------------------------------------------------------------------------------- /bin/luafmt.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const pkg = require('../../package.json'); 4 | 5 | import * as program from 'commander'; 6 | import * as getStdin from 'get-stdin'; 7 | import { readFileSync, writeFileSync } from 'fs'; 8 | 9 | import { formatText, producePatch } from '../src/index'; 10 | import { UserOptions, defaultOptions, WriteMode } from '../src/options'; 11 | 12 | function myParseInt(inputString: string, defaultValue: number) { 13 | const int = parseInt(inputString, 10); 14 | 15 | if (isNaN(int)) { 16 | return defaultValue; 17 | } 18 | 19 | return int; 20 | } 21 | 22 | function parseWriteMode(inputString: string, defaultValue: WriteMode) { 23 | for (const key of Object.keys(WriteMode)) { 24 | if (WriteMode[key] === inputString) { return inputString; } 25 | } 26 | 27 | return defaultValue; 28 | } 29 | 30 | function printFormattedDocument(filename: string, originalDocument: string, formattedDocument: string, 31 | options: UserOptions) { 32 | switch (options.writeMode) { 33 | case 'stdout': 34 | process.stdout.write(formattedDocument); 35 | break; 36 | 37 | case 'diff': 38 | process.stdout.write(producePatch(filename, originalDocument, formattedDocument)); 39 | break; 40 | 41 | case 'replace': 42 | if (filename === '') { 43 | printError(filename, new Error('Write mode \'replace\' is incompatible with --stdin')); 44 | } 45 | 46 | try { 47 | writeFileSync(filename, formattedDocument); 48 | } catch (err) { 49 | printError(filename, err); 50 | } 51 | break; 52 | } 53 | } 54 | 55 | program 56 | .version(pkg.version) 57 | .usage('[options] [file]') 58 | .option('--stdin', 'Read code from stdin') 59 | .option('-l, --line-width ', 'Maximum length of a line before it will be wrapped', 60 | myParseInt, defaultOptions.lineWidth) 61 | .option('-i, --indent-count ', 'Number of characters to indent', myParseInt, defaultOptions.indentCount) 62 | .option('--use-tabs', 'Use tabs instead of spaces for indentation') 63 | .option('-w, --write-mode ', 'Mode for output', parseWriteMode, defaultOptions.writeMode); 64 | 65 | program.parse(process.argv); 66 | 67 | function printError(filename: string, err: Error) { 68 | if (err instanceof SyntaxError) { 69 | console.error(`Failed to parse ${filename}:`, err); 70 | process.exit(2); 71 | } else { 72 | console.error(`Failed to format ${filename}:`, err); 73 | process.exit(3); 74 | } 75 | } 76 | 77 | const customOptions: UserOptions = { 78 | lineWidth: program.lineWidth, 79 | indentCount: program.indentCount, 80 | useTabs: program.useTabs, 81 | writeMode: program.writeMode 82 | }; 83 | 84 | if (program.stdin) { 85 | getStdin().then(input => { 86 | printFormattedDocument('', input, formatText(input, customOptions), customOptions); 87 | }).catch((err: Error) => { 88 | printError('', err); 89 | }); 90 | } else { 91 | if (program.args.length === 0) { 92 | console.error('Expected '); 93 | program.outputHelp(); 94 | process.exit(1); 95 | } 96 | 97 | const filename = program.args[0]; 98 | let input = ''; 99 | 100 | try { 101 | input = readFileSync(filename).toString(); 102 | } catch (err) { 103 | printError(filename, err); 104 | } 105 | 106 | try { 107 | const formatted = formatText(input, customOptions); 108 | 109 | printFormattedDocument(filename, input, formatted, customOptions); 110 | } catch (err) { 111 | printError(filename, err); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var tslint = require('gulp-tslint'); 3 | var shell = require('gulp-shell'); 4 | 5 | var bump = require('gulp-bump') 6 | var git = require('gulp-git'); 7 | var tag_version = require('gulp-tag-version'); 8 | 9 | var files = { 10 | src: [ 11 | './src/**/*.ts', 12 | './bin/**/*.ts' 13 | ], 14 | }; 15 | 16 | function bumpVersion(ver) { 17 | return gulp.src(['./package.json']) 18 | .pipe(bump({ type: ver })) 19 | .pipe(gulp.dest('./')) 20 | .pipe(git.commit('Bump package version')) 21 | .pipe(tag_version()); 22 | } 23 | 24 | gulp.task('compile', shell.task([ 25 | 'npm run compile' 26 | ])); 27 | 28 | gulp.task('tslint', function () { 29 | return gulp.src(files.src) 30 | .pipe(tslint({ 31 | formatter: "verbose" 32 | })) 33 | .pipe(tslint.report()) 34 | }); 35 | 36 | gulp.task('test', shell.task([ 37 | 'npm test' 38 | ])); 39 | 40 | gulp.task('patch', ['default'], function () { return bumpVersion('patch'); }) 41 | gulp.task('minor', ['default'], function () { return bumpVersion('minor'); }) 42 | gulp.task('major', ['default'], function () { return bumpVersion('major'); }) 43 | 44 | gulp.task('default', ['compile', 'tslint']); 45 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lua-fmt", 3 | "version": "2.6.0", 4 | "description": "Format Lua code", 5 | "author": "trixnz", 6 | "homepage": "https://github.com/trixnz/lua-fmt", 7 | "bugs": "https://github.com/trixnz/lua-fmt/issues", 8 | "license": "MIT", 9 | "keywords": [ 10 | "lua", 11 | "format", 12 | "lua-fmt", 13 | "formatter" 14 | ], 15 | "repository": { 16 | "type": "git", 17 | "url": "trixnz/lua-fmt" 18 | }, 19 | "main": "dist/src/index.js", 20 | "bin": { 21 | "luafmt": "dist/bin/luafmt.js" 22 | }, 23 | "typings": "dist/src/index.js", 24 | "watch": { 25 | "test-run": { 26 | "patterns": [ 27 | "dist", 28 | "test_files" 29 | ], 30 | "extensions": [ 31 | "js", 32 | "lua" 33 | ], 34 | "quiet": true 35 | } 36 | }, 37 | "scripts": { 38 | "compile": "tsc -p .", 39 | "test-run": "node dist/src/testPrinter.js", 40 | "watch": "tsc -p . -w", 41 | "watch-and-run": "npm-watch", 42 | "test": "jest" 43 | }, 44 | "jest": { 45 | "transform": { 46 | ".(ts|tsx)": "/node_modules/ts-jest/preprocessor.js" 47 | }, 48 | "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$", 49 | "moduleFileExtensions": [ 50 | "ts", 51 | "tsx", 52 | "js" 53 | ] 54 | }, 55 | "devDependencies": { 56 | "@types/jest": "^19.2.2", 57 | "@types/node": "^7.0.8", 58 | "gulp": "^3.9.1", 59 | "gulp-bump": "^2.7.0", 60 | "gulp-git": "^2.1.0", 61 | "gulp-shell": "^0.6.1", 62 | "gulp-tag-version": "^1.3.0", 63 | "gulp-tslint": "^7.1.0", 64 | "jest": "^19.0.2", 65 | "npm-watch": "^0.1.8", 66 | "raw-loader": "^0.5.1", 67 | "source-map-support": "^0.4.11", 68 | "ts-jest": "^19.0.6", 69 | "ts-loader": "^2.0.1", 70 | "tslint": "^4.5.1", 71 | "typescript": "^2.2.1", 72 | "uglify-js": "mishoo/UglifyJS2#harmony", 73 | "uglifyjs-webpack-plugin": "^0.3.0", 74 | "webpack": "^2.2.1", 75 | "webpack-dev-server": "^2.4.1" 76 | }, 77 | "dependencies": { 78 | "@types/commander": "^2.3.31", 79 | "@types/diff": "^3.2.0", 80 | "@types/get-stdin": "^5.0.0", 81 | "commander": "^2.9.0", 82 | "diff": "^3.3.0", 83 | "get-stdin": "^5.0.1", 84 | "luaparse": "oxyc/luaparse#ac42a00ebf4020b8c9d3219e4b0f84bf7ce6e802" 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/docBuilder.ts: -------------------------------------------------------------------------------- 1 | export interface Concat { 2 | type: 'concat'; 3 | parts: Doc[]; 4 | } 5 | 6 | export interface Line { 7 | type: 'line'; 8 | soft: boolean; 9 | hard: boolean; 10 | } 11 | 12 | export interface Indent { 13 | type: 'indent'; 14 | content: Doc; 15 | } 16 | 17 | export interface LineSuffix { 18 | type: 'lineSuffix'; 19 | content: Doc; 20 | } 21 | 22 | export interface Group { 23 | type: 'group'; 24 | content: Doc; 25 | willBreak: boolean; 26 | } 27 | 28 | export interface BreakParent { 29 | type: 'breakParent'; 30 | } 31 | 32 | export type Doc = string | Concat | Line | Indent | LineSuffix | Group | BreakParent; 33 | 34 | export function concat(parts: Doc[]): Doc { 35 | return { 36 | type: 'concat', 37 | parts 38 | }; 39 | } 40 | 41 | export function join(separator: Doc, parts: Doc[]) { 42 | const result: Doc[] = []; 43 | parts.forEach((val, i) => { 44 | if (i > 0) { 45 | result.push(separator); 46 | } 47 | 48 | result.push(val); 49 | }); 50 | 51 | return concat(result); 52 | } 53 | 54 | export const line: Line = { 55 | type: 'line', 56 | hard: false, 57 | soft: false 58 | }; 59 | 60 | export const hardline: Line = { 61 | type: 'line', 62 | hard: true, 63 | soft: false 64 | }; 65 | 66 | export const softline: Line = { 67 | type: 'line', 68 | hard: false, 69 | soft: true 70 | }; 71 | 72 | export function indent(content: Doc): Indent { 73 | return { 74 | type: 'indent', 75 | content 76 | }; 77 | } 78 | 79 | export function lineSuffix(content: Doc): LineSuffix { 80 | return { 81 | type: 'lineSuffix', 82 | content 83 | }; 84 | } 85 | 86 | export function group(content: Doc, willBreak: boolean = false): Group { 87 | return { 88 | type: 'group', 89 | content, 90 | willBreak 91 | }; 92 | } 93 | 94 | export const breakParent: BreakParent = { 95 | type: 'breakParent' 96 | }; 97 | 98 | export function isEmpty(instruction: Doc) { 99 | return typeof (instruction) === 'string' && instruction.length === 0; 100 | } 101 | -------------------------------------------------------------------------------- /src/docPrinter.ts: -------------------------------------------------------------------------------- 1 | import { Doc, LineSuffix } from './docBuilder'; 2 | import { Options } from './options'; 3 | 4 | enum Mode { 5 | Flat, 6 | Break 7 | }; 8 | 9 | interface State { 10 | options: Options; 11 | indentation: number; 12 | currentLineLength: number; 13 | mode: Mode; 14 | lineSuffixes: LineSuffix[]; 15 | renderedText: string; 16 | } 17 | 18 | export function printDocToString(doc: Doc, options: Options) { 19 | const state = { 20 | options, 21 | indentation: 0, 22 | currentLineLength: 0, 23 | mode: Mode.Break, 24 | lineSuffixes: [], 25 | renderedText: '' 26 | }; 27 | 28 | printDocToStringWithState(doc, state); 29 | 30 | return state.renderedText; 31 | } 32 | 33 | function canFitOnSingleLine(doc: Doc, state: State): boolean { 34 | function fits(text: string) { 35 | if (state.currentLineLength + text.length <= state.options.lineWidth) { 36 | state.currentLineLength += text.length; 37 | return true; 38 | } 39 | 40 | return false; 41 | } 42 | 43 | if (typeof (doc) === 'string') { 44 | return fits(doc); 45 | } 46 | 47 | switch (doc.type) { 48 | case 'concat': 49 | return doc.parts.every((part) => canFitOnSingleLine(part, state)); 50 | 51 | case 'indent': 52 | state.indentation++; 53 | 54 | if (canFitOnSingleLine(doc.content, state)) { 55 | state.indentation--; 56 | return true; 57 | } 58 | 59 | state.indentation--; 60 | 61 | return false; 62 | 63 | case 'group': 64 | if (doc.willBreak) { 65 | state.mode = Mode.Break; 66 | } 67 | 68 | return canFitOnSingleLine(doc.content, state); 69 | 70 | case 'line': 71 | if (state.mode === Mode.Flat) { 72 | if (!doc.hard) { 73 | if (!doc.soft) { 74 | return fits(' '); 75 | } 76 | 77 | return true; 78 | } 79 | } 80 | 81 | state.currentLineLength = state.indentation; 82 | 83 | return true; 84 | 85 | case 'lineSuffix': 86 | return true; 87 | } 88 | 89 | return false; 90 | } 91 | 92 | function printDocToStringWithState(doc: Doc, state: State) { 93 | if (typeof (doc) === 'string') { 94 | state.renderedText += doc; 95 | state.currentLineLength += doc.length; 96 | } else { 97 | switch (doc.type) { 98 | case 'concat': 99 | for (const part of doc.parts) { 100 | printDocToStringWithState(part, state); 101 | } 102 | break; 103 | 104 | case 'line': 105 | if (state.mode === Mode.Flat) { 106 | if (!doc.hard) { 107 | if (!doc.soft) { 108 | state.renderedText += ' '; 109 | state.currentLineLength += 1; 110 | } 111 | 112 | break; 113 | } 114 | } 115 | 116 | if (state.lineSuffixes.length > 0) { 117 | // Consume all of the line suffixes now so child calls to printDocToStringWithState don't take them 118 | // into account when printing lines. 119 | const suffixes = [...state.lineSuffixes]; 120 | state.lineSuffixes.length = 0; 121 | 122 | for (const suffix of suffixes) { 123 | printDocToStringWithState(suffix.content, state); 124 | } 125 | } 126 | 127 | // Strip trailing whitespace.. this is probably rather inefficient as the string will progressively get 128 | // bigger and bigger.. 129 | if (state.renderedText.length > 0) { 130 | state.renderedText = state.renderedText.replace( 131 | /[^\S\n]*$/, 132 | '' 133 | ); 134 | } 135 | 136 | const renderedIndentation = state.options.useTabs 137 | ? '\t'.repeat(state.indentation) 138 | : ' '.repeat(state.indentation * state.options.indentCount); 139 | 140 | state.renderedText += '\n' + renderedIndentation; 141 | state.currentLineLength = renderedIndentation.length; 142 | break; 143 | 144 | case 'indent': 145 | { 146 | state.indentation++; 147 | printDocToStringWithState(doc.content, state); 148 | state.indentation--; 149 | break; 150 | } 151 | 152 | case 'lineSuffix': 153 | state.lineSuffixes.push(doc); 154 | break; 155 | 156 | case 'group': 157 | const canFit = canFitOnSingleLine(doc, { ...state, mode: Mode.Flat }); 158 | const oldMode = state.mode; 159 | 160 | if (!doc.willBreak && canFit) { 161 | state.mode = Mode.Flat; 162 | } else { 163 | state.mode = Mode.Break; 164 | } 165 | 166 | printDocToStringWithState(doc.content, state); 167 | state.mode = oldMode; 168 | 169 | break; 170 | } 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /src/docUtils.ts: -------------------------------------------------------------------------------- 1 | import { Doc, Group } from './docBuilder'; 2 | 3 | type Callback = (instruction: Doc) => boolean; 4 | 5 | function visitInstructions(insn: Doc, onEnter: Callback, onExit?: Callback) { 6 | let abort = false; 7 | 8 | const visitInstruction = (ins: Doc) => { 9 | if (onEnter(ins)) { 10 | abort = true; 11 | return; 12 | } 13 | 14 | if (abort) { 15 | return; 16 | } 17 | 18 | if (typeof ins === 'string') { 19 | return; 20 | } 21 | 22 | switch (ins.type) { 23 | case 'concat': 24 | ins.parts.forEach(visitInstruction); 25 | break; 26 | 27 | case 'indent': 28 | case 'group': 29 | case 'lineSuffix': 30 | visitInstruction(ins.content); 31 | break; 32 | } 33 | 34 | if (onExit) { 35 | onExit(ins); 36 | } 37 | }; 38 | 39 | visitInstruction(insn); 40 | } 41 | 42 | function any(insn: Doc, callback: Callback) { 43 | let result = false; 44 | 45 | visitInstructions(insn, (instruction) => { 46 | if (callback(instruction)) { 47 | result = true; 48 | return true; 49 | } 50 | 51 | return false; 52 | }); 53 | 54 | return result; 55 | } 56 | 57 | export function willBreak(insn: Doc) { 58 | return any(insn, (instruction) => { 59 | if (typeof instruction === 'string') { 60 | return false; 61 | } 62 | 63 | switch (instruction.type) { 64 | case 'line': 65 | if (instruction.hard) { 66 | return true; 67 | } 68 | break; 69 | 70 | case 'group': 71 | if (instruction.willBreak) { 72 | return true; 73 | } 74 | } 75 | 76 | return false; 77 | }); 78 | } 79 | 80 | function breakParentGroup(stack: Group[]) { 81 | if (stack.length > 0) { 82 | stack[stack.length - 1].willBreak = true; 83 | } 84 | } 85 | 86 | export function propagateBreaks(insn: Doc) { 87 | const groupStack: Group[] = []; 88 | visitInstructions(insn, 89 | (instruction: Doc) => { 90 | if (typeof instruction === 'string') { 91 | return false; 92 | } 93 | 94 | switch (instruction.type) { 95 | case 'breakParent': 96 | breakParentGroup(groupStack); 97 | break; 98 | 99 | case 'group': 100 | groupStack.push(instruction); 101 | break; 102 | } 103 | 104 | return false; 105 | }, 106 | (instruction: Doc) => { 107 | if (typeof instruction === 'string') { 108 | return false; 109 | } 110 | 111 | if (instruction.type === 'group') { 112 | const group = groupStack.pop(); 113 | if (group && group.willBreak) { 114 | breakParentGroup(groupStack); 115 | } 116 | } 117 | 118 | return false; 119 | }); 120 | } 121 | -------------------------------------------------------------------------------- /src/fastPath.ts: -------------------------------------------------------------------------------- 1 | import { Doc } from './docBuilder'; 2 | import { isNode } from './util'; 3 | 4 | import * as luaparse from 'luaparse'; 5 | 6 | export type Callback = (path: FastPath) => Doc; 7 | export type CallbackForEach = (path: FastPath, index: number) => void; 8 | export type CallbackMap = (path: FastPath, index: number) => Doc; 9 | 10 | export class FastPath { 11 | private stack: any[]; 12 | 13 | public constructor(ast: luaparse.Chunk) { 14 | this.stack = [ast]; 15 | } 16 | 17 | public getValue() { 18 | return this.stack[this.stack.length - 1]; 19 | } 20 | 21 | public getNodeAtDepth(depth: number) { 22 | for (let i = this.stack.length - 1; i >= 0; i -= 2) { 23 | const value = this.stack[i]; 24 | 25 | if (isNode(value) && --depth < 0) { 26 | return value; 27 | } 28 | } 29 | 30 | return null; 31 | } 32 | 33 | public getParent(depth: number = 0) { 34 | return this.getNodeAtDepth(depth + 1); 35 | } 36 | 37 | public call(callback: Callback, field: string) { 38 | const node = this.getValue(); 39 | const origLength = this.stack.length; 40 | 41 | this.stack.push(field, node[field]); 42 | const result = callback(this); 43 | this.stack.length = origLength; 44 | 45 | return result; 46 | } 47 | 48 | public forEach(callback: CallbackForEach, field: string | null = null) { 49 | let value = this.getValue(); 50 | 51 | const origLength = this.stack.length; 52 | 53 | if (field) { 54 | value = value[field]; 55 | this.stack.push(value); 56 | } 57 | 58 | for (let i = 0; i < value.length; ++i) { 59 | this.stack.push(i, value[i]); 60 | callback(this, i); 61 | this.stack.length -= 2; 62 | } 63 | 64 | this.stack.length = origLength; 65 | } 66 | 67 | public map(callback: (path: FastPath, index: number) => Doc, field: string) { 68 | const node = this.getValue()[field]; 69 | 70 | if (!Array.isArray(node)) { 71 | return []; 72 | } 73 | 74 | const result: Doc[] = []; 75 | const origLength = this.stack.length; 76 | 77 | this.stack.push(field, node); 78 | 79 | node.forEach((val, i) => { 80 | this.stack.push(i, val); 81 | result.push(callback(this, i)); 82 | this.stack.length -= 2; 83 | }); 84 | 85 | this.stack.length = origLength; 86 | 87 | return result; 88 | } 89 | 90 | public needsParens() { 91 | const parent = this.getParent() as luaparse.Node; 92 | const value = this.getValue() as luaparse.Node; 93 | 94 | let inParens = false; 95 | switch (value.type) { 96 | case 'FunctionDeclaration': 97 | case 'Chunk': 98 | case 'Identifier': 99 | case 'BooleanLiteral': 100 | case 'NilLiteral': 101 | case 'NumericLiteral': 102 | case 'StringLiteral': 103 | case 'VarargLiteral': 104 | case 'TableConstructorExpression': 105 | case 'BinaryExpression': 106 | case 'LogicalExpression': 107 | case 'UnaryExpression': 108 | case 'MemberExpression': 109 | case 'IndexExpression': 110 | case 'CallExpression': 111 | case 'TableCallExpression': 112 | case 'StringCallExpression': 113 | inParens = value.inParens || false; 114 | } 115 | 116 | if (parent) { 117 | /* 118 | If this UnaryExpression is nested below another UnaryExpression, wrap the nested expression in 119 | parens. This not only improves readability of complex expressions, but also prevents `- -1` from 120 | becoming `--1`, which would result in a comment. 121 | */ 122 | if (value.type === 'UnaryExpression' && parent.type === 'UnaryExpression') { 123 | inParens = true; 124 | } 125 | } 126 | 127 | return inParens; 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | if (process.env.NODE_ENV === 'development') { 2 | require('source-map-support').install(); 3 | } 4 | 5 | import { attachComments, injectShebang } from './comments'; 6 | import { buildDocFromAst } from './printer'; 7 | import { printDocToString } from './docPrinter'; 8 | import { UserOptions, defaultOptions } from './options'; 9 | 10 | import { parse } from 'luaparse'; 11 | import { createPatch } from 'diff'; 12 | 13 | export { UserOptions, defaultOptions, WriteMode } from './options'; 14 | 15 | export function formatText(text: string, userOptions?: UserOptions) { 16 | const ast = parse(text, { 17 | comments: true, 18 | locations: true, 19 | ranges: true, 20 | luaVersion: '5.3' 21 | }); 22 | 23 | // Change the chunk range to contain the whole source file so we can attach comments to it 24 | ast.range[0] = 0; 25 | ast.range[1] = text.length; 26 | 27 | const mergedOptions = Object.assign({}, defaultOptions, userOptions); 28 | 29 | const options = { 30 | ...mergedOptions, 31 | sourceText: text 32 | }; 33 | 34 | injectShebang(ast, options); 35 | attachComments(ast, options); 36 | 37 | const doc = buildDocFromAst(ast, options); 38 | const formattedText = printDocToString(doc, options); 39 | 40 | return formattedText; 41 | } 42 | 43 | export function producePatch(filename: string, originalDocument: string, formattedDocument: string) { 44 | return createPatch(filename, originalDocument, formattedDocument, 'original', 'formatted'); 45 | } 46 | -------------------------------------------------------------------------------- /src/options.ts: -------------------------------------------------------------------------------- 1 | export type Quotemark = 'single' | 'double'; 2 | export enum WriteMode { 3 | StdOut = 'stdout', 4 | Replace = 'replace', 5 | Diff = 'diff' 6 | } 7 | 8 | export interface Options { 9 | sourceText: string; 10 | lineWidth: number; 11 | indentCount: number; 12 | useTabs: boolean; 13 | linebreakMultipleAssignments: boolean; 14 | quotemark: Quotemark; 15 | writeMode: WriteMode; 16 | } 17 | 18 | export type UserOptions = Partial; 19 | 20 | export const defaultOptions: Options = { 21 | sourceText: '', 22 | lineWidth: 120, 23 | indentCount: 4, 24 | useTabs: false, 25 | linebreakMultipleAssignments: false, 26 | quotemark: 'double', 27 | writeMode: WriteMode.StdOut 28 | }; 29 | 30 | /** Returns the quotation mark to use from the provided option. */ 31 | export function getStringQuotemark(quotemark: Quotemark) { 32 | return quotemark === 'single' ? '\'' : '"'; 33 | } 34 | 35 | /** 36 | * Returns the alternative quotation mark to use from the provided option. 37 | * 38 | * i.e: If the quotemark is 'single', then this will return a double quote. 39 | */ 40 | export function getAlternativeStringQuotemark(quotemark: Quotemark) { 41 | return quotemark === 'single' ? '"' : '\''; 42 | } 43 | -------------------------------------------------------------------------------- /src/testPrinter.ts: -------------------------------------------------------------------------------- 1 | import * as luafmt from './index'; 2 | 3 | import * as fs from 'fs'; 4 | 5 | const file = fs.readFileSync('test/lua-5.3.4-tests/calls.lua'); 6 | 7 | const formatted = luafmt.formatText(file.toString(), { 8 | lineWidth: 60, 9 | quotemark: 'single' 10 | }); 11 | 12 | console.log(formatted); 13 | -------------------------------------------------------------------------------- /src/util.ts: -------------------------------------------------------------------------------- 1 | import { Node } from 'luaparse'; 2 | 3 | export function locStart(node: Node) { 4 | return node.range[0]; 5 | } 6 | 7 | export function locEnd(node: Node) { 8 | return node.range[1]; 9 | } 10 | 11 | export function isNode(value: any) { 12 | if (!value || typeof (value.type) !== 'string') { 13 | return false; 14 | } 15 | 16 | switch (value.type) { 17 | case 'LabelStatement': 18 | case 'BreakStatement': 19 | case 'GotoStatement': 20 | case 'ReturnStatement': 21 | case 'IfStatement': 22 | case 'IfClause': 23 | case 'ElseifClause': 24 | case 'ElseClause': 25 | case 'WhileStatement': 26 | case 'DoStatement': 27 | case 'RepeatStatement': 28 | case 'LocalStatement': 29 | case 'AssignmentStatement': 30 | case 'CallStatement': 31 | case 'FunctionDeclaration': 32 | case 'ForNumericStatement': 33 | case 'ForGenericStatement': 34 | case 'Chunk': 35 | case 'Identifier': 36 | case 'BooleanLiteral': 37 | case 'NilLiteral': 38 | case 'NumericLiteral': 39 | case 'StringLiteral': 40 | case 'VarargLiteral': 41 | case 'TableKey': 42 | case 'TableKeyString': 43 | case 'TableValue': 44 | case 'TableConstructorExpression': 45 | case 'BinaryExpression': 46 | case 'LogicalExpression': 47 | case 'UnaryExpression': 48 | case 'MemberExpression': 49 | case 'IndexExpression': 50 | case 'CallExpression': 51 | case 'TableCallExpression': 52 | case 'StringCallExpression': 53 | case 'Comment': 54 | return true; 55 | 56 | default: 57 | return false; 58 | } 59 | } 60 | 61 | export interface SearchOptions { 62 | searchBackwards?: boolean; 63 | }; 64 | 65 | export function skipOnce(text: string, idx: number, sequences: string[], searchOptions: SearchOptions = {}) { 66 | let skipCount = 0; 67 | sequences.forEach(seq => { 68 | const searchText = searchOptions.searchBackwards 69 | ? text.substring(idx - seq.length, idx) 70 | : text.substring(idx, idx + seq.length); 71 | 72 | if (searchText === seq) { 73 | skipCount = seq.length; 74 | return; 75 | } 76 | }); 77 | 78 | return idx + (searchOptions.searchBackwards ? -skipCount : skipCount); 79 | } 80 | 81 | export function skipMany(text: string, idx: number, sequences: string[], searchOptions: SearchOptions = {}) { 82 | let oldIdx = null; 83 | 84 | while (oldIdx !== idx) { 85 | oldIdx = idx; 86 | idx = skipOnce(text, idx, sequences, searchOptions); 87 | } 88 | 89 | return idx; 90 | } 91 | 92 | export function skipNewLine(text: string, idx: number, searchOptions: SearchOptions = {}) { 93 | return skipOnce(text, idx, ['\n', '\r\n'], searchOptions); 94 | } 95 | 96 | export function skipSpaces(text: string, idx: number, searchOptions: SearchOptions = {}) { 97 | return skipMany(text, idx, [' ', '\t'], searchOptions); 98 | } 99 | 100 | export function skipToLineEnd(text: string, idx: number, searchOptions: SearchOptions = {}) { 101 | return skipMany(text, skipSpaces(text, idx), [';'], searchOptions); 102 | } 103 | 104 | export function hasNewLine(text: string, idx: number, searchOptions: SearchOptions = {}) { 105 | const endOfLineIdx = skipSpaces(text, idx, searchOptions); 106 | const nextLineIdx = skipNewLine(text, endOfLineIdx, searchOptions); 107 | 108 | return endOfLineIdx !== nextLineIdx; 109 | } 110 | 111 | export function hasNewLineInRange(text: string, start: number, end: number) { 112 | return text.substr(start, end - start).indexOf('\n') !== -1; 113 | } 114 | 115 | export function isPreviousLineEmpty(text: string, idx: number) { 116 | idx = skipSpaces(text, idx, { searchBackwards: true }); 117 | idx = skipNewLine(text, idx, { searchBackwards: true }); 118 | 119 | idx = skipSpaces(text, idx, { searchBackwards: true }); 120 | const previousLine = skipNewLine(text, idx, { searchBackwards: true }); 121 | 122 | return idx !== previousLine; 123 | } 124 | 125 | export function skipTrailingComment(text: string, idx: number) { 126 | if (text.charAt(idx) === '-' && text.charAt(idx + 1) === '-') { 127 | idx += 2; 128 | 129 | while (idx >= 0 && idx < text.length) { 130 | if (text.charAt(idx) === '\n') { 131 | return idx; 132 | } 133 | 134 | if (text.charAt(idx) === '\r' && text.charAt(idx + 1) === '\n') { 135 | return idx; 136 | } 137 | 138 | idx++; 139 | } 140 | } 141 | 142 | return idx; 143 | } 144 | 145 | export function isNextLineEmpty(text: string, idx: number, searchOptions: SearchOptions = { 146 | searchBackwards: false 147 | }) { 148 | idx = skipToLineEnd(text, idx, searchOptions); 149 | 150 | let oldIdx = null; 151 | while (idx !== oldIdx) { 152 | oldIdx = idx; 153 | idx = skipSpaces(text, idx, searchOptions); 154 | } 155 | 156 | idx = skipTrailingComment(text, idx); 157 | idx = skipNewLine(text, idx, searchOptions); 158 | 159 | return hasNewLine(text, idx); 160 | } 161 | -------------------------------------------------------------------------------- /test/comments/__snapshots__/comments.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`do.lua 1`] = ` 4 | "do -- Dangling Begin DoStatement 5 | end -- Dangling End DoStatement 6 | 7 | -- leading DoStatement 8 | do -- Dangling Begin DoStatement 9 | -- body DoStatement 10 | end -- Dangling End DoStatement 11 | -- trailing DoStatement 12 | 13 | -- leading DoStatement 14 | do -- Dangling Begin DoStatement 15 | end -- Dangling End DoStatement 16 | -- trailing DoStatement 17 | " 18 | `; 19 | 20 | exports[`for.lua 1`] = ` 21 | "for i = 0, 1, 2 do -- dangling Begin ForNumericStatement 22 | end -- Dangling End ForNumericStatement 23 | 24 | -- leading ForNumericStatement 25 | for i = 0, 1, 2 do -- dangling Begin ForNumericStatement 26 | end -- Dangling End ForNumericStatement 27 | -- trailing ForNumericStatement 28 | 29 | -- leading ForNumericStatement 30 | for i = 0, 1, 2 do -- dangling Begin ForNumericStatement 31 | --body ForNumericStatement 32 | end -- Dangling End ForNumericStatement 33 | -- trailing ForNumericStatement 34 | 35 | for i in pairs(v) do -- dangling Begin ForNumericStatement 36 | end -- Dangling End ForNumericStatement 37 | 38 | -- leading ForNumericStatement 39 | for i in pairs(v) do -- dangling Begin ForNumericStatement 40 | end -- Dangling End ForNumericStatement 41 | -- trailing ForNumericStatement 42 | 43 | -- leading ForNumericStatement 44 | for i in pairs(v) do -- dangling Begin ForNumericStatement 45 | --body ForNumericStatement 46 | end -- Dangling End ForNumericStatement 47 | -- trailing ForNumericStatement 48 | " 49 | `; 50 | 51 | exports[`function.lua 1`] = ` 52 | "function test() -- dangling Begin FunctionDeclaration 53 | end -- dangling FunctionDeclaration 54 | 55 | function test() 56 | -- Function body 57 | end 58 | 59 | -- leading FunctionDeclaration 60 | function test() -- dangling Begin FunctionDeclaration 61 | -- FunctionDeclaration body 62 | end -- dangling FunctionDeclaration 63 | -- trailing End FunctionDeclaration 64 | 65 | function test(arg) -- dangling Begin FunctionDeclaration 66 | end -- dangling FunctionDeclaration 67 | 68 | function test(arg) 69 | -- Function body 70 | end 71 | 72 | -- leading FunctionDeclaration 73 | function test(arg) -- dangling Begin FunctionDeclaration 74 | -- FunctionDeclaration body 75 | end -- dangling FunctionDeclaration 76 | -- trailing End FunctionDeclaration 77 | " 78 | `; 79 | 80 | exports[`if.lua 1`] = ` 81 | "if 1 then -- dangling IfClause 82 | elseif 1 then -- dangling ElseIfClause 83 | else -- dangling ElseClause 84 | end -- dangling IfStatement 85 | 86 | -- leading IfClause 87 | if 1 then 88 | -- leading ElseIfClause 89 | elseif 1 then 90 | -- leading ElseClause 91 | else 92 | -- trailing ElseClause 93 | end 94 | 95 | -- leading IfStatement 96 | if 1 --[[if 1]] then -- dangling IfClause 97 | -- leading ElseIfClause 98 | elseif 1 --[[elseif 1]] then -- dangling ElseIfClause 99 | -- leading ElseClause 100 | else -- dangling ElseClause 101 | -- body ElseClause 102 | end -- dangling End IfStatement 103 | -- trailing IfStatement 104 | " 105 | `; 106 | 107 | exports[`repeat.lua 1`] = ` 108 | "repeat -- Dangling Begin RepeatStatement 109 | until true -- Dangling End RepeatStatement 110 | 111 | -- leading RepeatStatement 112 | repeat -- Dangling Begin RepeatStatement 113 | until true -- Dangling End RepeatStatement 114 | -- trailing RepeatStatement 115 | 116 | -- leading RepeatStatement 117 | repeat -- Dangling Begin RepeatStatement 118 | -- body RepeatStatement 119 | until true -- Dangling End RepeatStatement 120 | -- trailing RepeatStatement 121 | " 122 | `; 123 | 124 | exports[`table.lua 1`] = ` 125 | "-- Simple example 126 | a = { 127 | b = true 128 | -- Trailing comment should be indented 129 | } 130 | 131 | -- Deep example 132 | film = { 133 | scene = { 134 | object = { 135 | name = \\"Swallow\\", 136 | carrying = \\"Coconut\\", 137 | origin = \\"Africa\\" 138 | -- velocity = ??, 139 | } 140 | } 141 | } 142 | " 143 | `; 144 | -------------------------------------------------------------------------------- /test/comments/comments.test.ts: -------------------------------------------------------------------------------- 1 | import { runTest } from '../util'; 2 | 3 | runTest(__dirname); 4 | -------------------------------------------------------------------------------- /test/comments/do.lua: -------------------------------------------------------------------------------- 1 | do -- Dangling Begin DoStatement 2 | end -- Dangling End DoStatement 3 | 4 | -- leading DoStatement 5 | do -- Dangling Begin DoStatement 6 | -- body DoStatement 7 | end -- Dangling End DoStatement 8 | -- trailing DoStatement 9 | 10 | -- leading DoStatement 11 | do -- Dangling Begin DoStatement 12 | end -- Dangling End DoStatement 13 | -- trailing DoStatement 14 | -------------------------------------------------------------------------------- /test/comments/for.lua: -------------------------------------------------------------------------------- 1 | for i = 0, 1, 2 do -- dangling Begin ForNumericStatement 2 | end -- Dangling End ForNumericStatement 3 | 4 | -- leading ForNumericStatement 5 | for i = 0, 1, 2 do -- dangling Begin ForNumericStatement 6 | end -- Dangling End ForNumericStatement 7 | -- trailing ForNumericStatement 8 | 9 | -- leading ForNumericStatement 10 | for i = 0, 1, 2 do -- dangling Begin ForNumericStatement 11 | --body ForNumericStatement 12 | end -- Dangling End ForNumericStatement 13 | -- trailing ForNumericStatement 14 | 15 | for i in pairs(v) do -- dangling Begin ForNumericStatement 16 | end -- Dangling End ForNumericStatement 17 | 18 | -- leading ForNumericStatement 19 | for i in pairs(v) do -- dangling Begin ForNumericStatement 20 | end -- Dangling End ForNumericStatement 21 | -- trailing ForNumericStatement 22 | 23 | -- leading ForNumericStatement 24 | for i in pairs(v) do -- dangling Begin ForNumericStatement 25 | --body ForNumericStatement 26 | end -- Dangling End ForNumericStatement 27 | -- trailing ForNumericStatement 28 | -------------------------------------------------------------------------------- /test/comments/function.lua: -------------------------------------------------------------------------------- 1 | function test() -- dangling Begin FunctionDeclaration 2 | end -- dangling FunctionDeclaration 3 | 4 | function test() 5 | -- Function body 6 | end 7 | 8 | -- leading FunctionDeclaration 9 | function test() -- dangling Begin FunctionDeclaration 10 | -- FunctionDeclaration body 11 | end -- dangling FunctionDeclaration 12 | -- trailing End FunctionDeclaration 13 | 14 | function test(arg) -- dangling Begin FunctionDeclaration 15 | end -- dangling FunctionDeclaration 16 | 17 | function test(arg) 18 | -- Function body 19 | end 20 | 21 | -- leading FunctionDeclaration 22 | function test(arg) -- dangling Begin FunctionDeclaration 23 | -- FunctionDeclaration body 24 | end -- dangling FunctionDeclaration 25 | -- trailing End FunctionDeclaration 26 | -------------------------------------------------------------------------------- /test/comments/if.lua: -------------------------------------------------------------------------------- 1 | if 1 then -- dangling IfClause 2 | elseif 1 then -- dangling ElseIfClause 3 | else -- dangling ElseClause 4 | end -- dangling IfStatement 5 | 6 | -- leading IfClause 7 | if 1 then 8 | -- leading ElseIfClause 9 | elseif 1 then 10 | -- leading ElseClause 11 | else 12 | -- trailing ElseClause 13 | end 14 | 15 | -- leading IfStatement 16 | if 1 --[[if 1]] then -- dangling IfClause 17 | -- leading ElseIfClause 18 | elseif 1 --[[elseif 1]] then -- dangling ElseIfClause 19 | -- leading ElseClause 20 | else -- dangling ElseClause 21 | -- body ElseClause 22 | end -- dangling End IfStatement 23 | -- trailing IfStatement 24 | -------------------------------------------------------------------------------- /test/comments/repeat.lua: -------------------------------------------------------------------------------- 1 | repeat -- Dangling Begin RepeatStatement 2 | until true -- Dangling End RepeatStatement 3 | 4 | -- leading RepeatStatement 5 | repeat -- Dangling Begin RepeatStatement 6 | until true -- Dangling End RepeatStatement 7 | -- trailing RepeatStatement 8 | 9 | -- leading RepeatStatement 10 | repeat -- Dangling Begin RepeatStatement 11 | -- body RepeatStatement 12 | until true -- Dangling End RepeatStatement 13 | -- trailing RepeatStatement 14 | -------------------------------------------------------------------------------- /test/comments/table.lua: -------------------------------------------------------------------------------- 1 | -- Simple example 2 | a = { 3 | b = true 4 | -- Trailing comment should be indented 5 | } 6 | 7 | -- Deep example 8 | film = { 9 | scene = { 10 | object = { 11 | name = "Swallow", 12 | carrying = "Coconut", 13 | origin = "Africa" 14 | -- velocity = ??, 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/function/__snapshots__/function.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`functions.lua 1`] = ` 4 | "function test() 5 | end 6 | function test(arg) 7 | end 8 | function test(arg, ...) 9 | end 10 | function test(...) 11 | end 12 | 13 | local function test() 14 | end 15 | local function test(arg) 16 | end 17 | local function test(arg, ...) 18 | end 19 | local function test(...) 20 | end 21 | 22 | local test = function() 23 | end 24 | local test = function(arg) 25 | end 26 | local test = function(arg, ...) 27 | end 28 | local test = function(...) 29 | end 30 | 31 | function foo() 32 | if true then 33 | return 34 | end 35 | end 36 | 37 | function foo() 38 | local a = true 39 | 40 | print(a) 41 | end 42 | 43 | local ok, err = pcall(foo) 44 | 45 | local ok, err = 46 | pcall( 47 | function() 48 | end 49 | ) 50 | " 51 | `; 52 | -------------------------------------------------------------------------------- /test/function/function.test.ts: -------------------------------------------------------------------------------- 1 | import { runTest } from '../util'; 2 | 3 | runTest(__dirname); 4 | -------------------------------------------------------------------------------- /test/function/functions.lua: -------------------------------------------------------------------------------- 1 | function test() end 2 | function test(arg) end 3 | function test(arg, ...) end 4 | function test(...) end 5 | 6 | local function test() end 7 | local function test(arg) end 8 | local function test(arg, ...) end 9 | local function test(...) end 10 | 11 | local test = function() end 12 | local test = function(arg) end 13 | local test = function(arg, ...) end 14 | local test = function(...) end 15 | 16 | function foo() if true then return end end 17 | 18 | function foo() 19 | local a = true 20 | 21 | print(a) 22 | end 23 | 24 | local ok, err = pcall(foo) 25 | 26 | local ok, err = pcall(function() end) 27 | -------------------------------------------------------------------------------- /test/linewrap/__snapshots__/linewrap.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`assignment.lua 1`] = ` 4 | "bbbbbbbbbbbbbbbbbbbbbbb = true 5 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = 6 | bbbbbbbbbbbbbbbbbbbbbbb 7 | 8 | local function foo() 9 | return 1, 2, 3 10 | end 11 | local a, 12 | bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, 13 | c = foo() 14 | print( 15 | a, 16 | bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, 17 | c 18 | ) 19 | 20 | local a, 21 | bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, 22 | cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc = 23 | foo() 24 | 25 | local a, b, c, d, e, f = emptyFunction() 26 | 27 | local a, b, c, d, e, f = emptyFunction(), emptyFunction() 28 | 29 | local a, b, c, d, e, f = emptyFunction(), emptyFunction(), emptyFunction() 30 | 31 | local a, b, c, d, e, f = 32 | emptyFunction(), 33 | emptyFunction( 34 | function() 35 | return true 36 | end 37 | ) 38 | 39 | local a, b, c, d, e, f = 40 | emptyFunction( 41 | function() 42 | return true 43 | end 44 | ) 45 | 46 | local function object() 47 | local self = {} 48 | 49 | function self:test() 50 | end 51 | 52 | self.test = function() 53 | end 54 | 55 | self.test = function() 56 | -- Reaaaaally long comment, goes on forever and ever and ever and ever and ever and ever and ever and ever and ever and ever and ever and ever and ever and ever and ever and ever and ever and ever and ever and ever 57 | end 58 | 59 | return self 60 | end 61 | " 62 | `; 63 | -------------------------------------------------------------------------------- /test/linewrap/assignment.lua: -------------------------------------------------------------------------------- 1 | bbbbbbbbbbbbbbbbbbbbbbb = true 2 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = bbbbbbbbbbbbbbbbbbbbbbb 3 | 4 | local function foo() 5 | return 1, 2, 3 6 | end 7 | local a, bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, c = foo() 8 | print(a, bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, c) 9 | 10 | local a, bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc = foo() 11 | 12 | local a, b, c, d, e, f = emptyFunction() 13 | 14 | local a, b, c, d, e, f = emptyFunction(), emptyFunction() 15 | 16 | local a, b, c, d, e, f = emptyFunction(), emptyFunction(), emptyFunction() 17 | 18 | local a, b, c, d, e, f = emptyFunction(), emptyFunction(function() return true end) 19 | 20 | local a, b, c, d, e, f = emptyFunction(function() return true end) 21 | 22 | local function object() 23 | local self = {} 24 | 25 | function self:test() 26 | end 27 | 28 | self.test = function() 29 | end 30 | 31 | self.test = function() 32 | -- Reaaaaally long comment, goes on forever and ever and ever and ever and ever and ever and ever and ever and ever and ever and ever and ever and ever and ever and ever and ever and ever and ever and ever and ever 33 | end 34 | 35 | return self 36 | end 37 | -------------------------------------------------------------------------------- /test/linewrap/linewrap.test.ts: -------------------------------------------------------------------------------- 1 | import { runTest } from '../util'; 2 | 3 | runTest(__dirname, { lineWidth: 80 }); 4 | -------------------------------------------------------------------------------- /test/lua-5.3.4-tests/LICENSE: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trixnz/lua-fmt/3cbb57c38b12b849711286dda4f43b62e09f806d/test/lua-5.3.4-tests/LICENSE -------------------------------------------------------------------------------- /test/lua-5.3.4-tests/all.lua: -------------------------------------------------------------------------------- 1 | #!../lua 2 | -- $Id: all.lua,v 1.95 2016/11/07 13:11:28 roberto Exp $ 3 | -- See Copyright Notice at the end of this file 4 | 5 | 6 | local version = "Lua 5.3" 7 | if _VERSION ~= version then 8 | io.stderr:write("\nThis test suite is for ", version, ", not for ", _VERSION, 9 | "\nExiting tests\n") 10 | return 11 | end 12 | 13 | 14 | _G._ARG = arg -- save arg for other tests 15 | 16 | 17 | -- next variables control the execution of some tests 18 | -- true means no test (so an undefined variable does not skip a test) 19 | -- defaults are for Linux; test everything. 20 | -- Make true to avoid long or memory consuming tests 21 | _soft = rawget(_G, "_soft") or false 22 | -- Make true to avoid non-portable tests 23 | _port = rawget(_G, "_port") or false 24 | -- Make true to avoid messages about tests not performed 25 | _nomsg = rawget(_G, "_nomsg") or false 26 | 27 | 28 | local usertests = rawget(_G, "_U") 29 | 30 | if usertests then 31 | -- tests for sissies ;) Avoid problems 32 | _soft = true 33 | _port = true 34 | _nomsg = true 35 | end 36 | 37 | -- tests should require debug when needed 38 | debug = nil 39 | 40 | if usertests then 41 | T = nil -- no "internal" tests for user tests 42 | else 43 | T = rawget(_G, "T") -- avoid problems with 'strict' module 44 | end 45 | 46 | math.randomseed(0) 47 | 48 | --[=[ 49 | example of a long [comment], 50 | [[spanning several [lines]]] 51 | 52 | ]=] 53 | 54 | print("current path:\n****" .. package.path .. "****\n") 55 | 56 | 57 | local initclock = os.clock() 58 | local lastclock = initclock 59 | local walltime = os.time() 60 | 61 | local collectgarbage = collectgarbage 62 | 63 | do -- ( 64 | 65 | -- track messages for tests not performed 66 | local msgs = {} 67 | function Message (m) 68 | if not _nomsg then 69 | print(m) 70 | msgs[#msgs+1] = string.sub(m, 3, -3) 71 | end 72 | end 73 | 74 | assert(os.setlocale"C") 75 | 76 | local T,print,format,write,assert,type,unpack,floor = 77 | T,print,string.format,io.write,assert,type,table.unpack,math.floor 78 | 79 | -- use K for 1000 and M for 1000000 (not 2^10 -- 2^20) 80 | local function F (m) 81 | local function round (m) 82 | m = m + 0.04999 83 | return format("%.1f", m) -- keep one decimal digit 84 | end 85 | if m < 1000 then return m 86 | else 87 | m = m / 1000 88 | if m < 1000 then return round(m).."K" 89 | else 90 | return round(m/1000).."M" 91 | end 92 | end 93 | end 94 | 95 | local showmem 96 | if not T then 97 | local max = 0 98 | showmem = function () 99 | local m = collectgarbage("count") * 1024 100 | max = (m > max) and m or max 101 | print(format(" ---- total memory: %s, max memory: %s ----\n", 102 | F(m), F(max))) 103 | end 104 | else 105 | showmem = function () 106 | T.checkmemory() 107 | local total, numblocks, maxmem = T.totalmem() 108 | local count = collectgarbage("count") 109 | print(format( 110 | "\n ---- total memory: %s (%.0fK), max use: %s, blocks: %d\n", 111 | F(total), count, F(maxmem), numblocks)) 112 | print(format("\t(strings: %d, tables: %d, functions: %d, ".. 113 | "\n\tudata: %d, threads: %d)", 114 | T.totalmem"string", T.totalmem"table", T.totalmem"function", 115 | T.totalmem"userdata", T.totalmem"thread")) 116 | end 117 | end 118 | 119 | 120 | -- 121 | -- redefine dofile to run files through dump/undump 122 | -- 123 | local function report (n) print("\n***** FILE '"..n.."'*****") end 124 | local olddofile = dofile 125 | local dofile = function (n, strip) 126 | showmem() 127 | local c = os.clock() 128 | print(string.format("time: %g (+%g)", c - initclock, c - lastclock)) 129 | lastclock = c 130 | report(n) 131 | local f = assert(loadfile(n)) 132 | local b = string.dump(f, strip) 133 | f = assert(load(b)) 134 | return f() 135 | end 136 | 137 | dofile('main.lua') 138 | 139 | do 140 | local next, setmetatable, stderr = next, setmetatable, io.stderr 141 | -- track collections 142 | local mt = {} 143 | -- each time a table is collected, remark it for finalization 144 | -- on next cycle 145 | mt.__gc = function (o) 146 | stderr:write'.' -- mark progress 147 | local n = setmetatable(o, mt) -- remark it 148 | end 149 | local n = setmetatable({}, mt) -- create object 150 | end 151 | 152 | report"gc.lua" 153 | local f = assert(loadfile('gc.lua')) 154 | f() 155 | 156 | dofile('db.lua') 157 | assert(dofile('calls.lua') == deep and deep) 158 | olddofile('strings.lua') 159 | olddofile('literals.lua') 160 | dofile('tpack.lua') 161 | assert(dofile('attrib.lua') == 27) 162 | 163 | assert(dofile('locals.lua') == 5) 164 | dofile('constructs.lua') 165 | dofile('code.lua', true) 166 | if not _G._soft then 167 | report('big.lua') 168 | local f = coroutine.wrap(assert(loadfile('big.lua'))) 169 | assert(f() == 'b') 170 | assert(f() == 'a') 171 | end 172 | dofile('nextvar.lua') 173 | dofile('pm.lua') 174 | dofile('utf8.lua') 175 | dofile('api.lua') 176 | assert(dofile('events.lua') == 12) 177 | dofile('vararg.lua') 178 | dofile('closure.lua') 179 | dofile('coroutine.lua') 180 | dofile('goto.lua', true) 181 | dofile('errors.lua') 182 | dofile('math.lua') 183 | dofile('sort.lua', true) 184 | dofile('bitwise.lua') 185 | assert(dofile('verybig.lua', true) == 10); collectgarbage() 186 | dofile('files.lua') 187 | 188 | if #msgs > 0 then 189 | print("\ntests not performed:") 190 | for i=1,#msgs do 191 | print(msgs[i]) 192 | end 193 | print() 194 | end 195 | 196 | -- no test module should define 'debug' 197 | assert(debug == nil) 198 | 199 | local debug = require "debug" 200 | 201 | print(string.format("%d-bit integers, %d-bit floats", 202 | string.packsize("j") * 8, string.packsize("n") * 8)) 203 | 204 | debug.sethook(function (a) assert(type(a) == 'string') end, "cr") 205 | 206 | -- to survive outside block 207 | _G.showmem = showmem 208 | 209 | end --) 210 | 211 | local _G, showmem, print, format, clock, time, difftime, assert, open = 212 | _G, showmem, print, string.format, os.clock, os.time, os.difftime, 213 | assert, io.open 214 | 215 | -- file with time of last performed test 216 | local fname = T and "time-debug.txt" or "time.txt" 217 | local lasttime 218 | 219 | if not usertests then 220 | -- open file with time of last performed test 221 | local f = io.open(fname) 222 | if f then 223 | lasttime = assert(tonumber(f:read'a')) 224 | f:close(); 225 | else -- no such file; assume it is recording time for first time 226 | lasttime = nil 227 | end 228 | end 229 | 230 | -- erase (almost) all globals 231 | print('cleaning all!!!!') 232 | for n in pairs(_G) do 233 | if not ({___Glob = 1, tostring = 1})[n] then 234 | _G[n] = nil 235 | end 236 | end 237 | 238 | 239 | collectgarbage() 240 | collectgarbage() 241 | collectgarbage() 242 | collectgarbage() 243 | collectgarbage() 244 | collectgarbage();showmem() 245 | 246 | local clocktime = clock() - initclock 247 | walltime = difftime(time(), walltime) 248 | 249 | print(format("\n\ntotal time: %.2fs (wall time: %gs)\n", clocktime, walltime)) 250 | 251 | if not usertests then 252 | lasttime = lasttime or clocktime -- if no last time, ignore difference 253 | -- check whether current test time differs more than 5% from last time 254 | local diff = (clocktime - lasttime) / lasttime 255 | local tolerance = 0.05 -- 5% 256 | if (diff >= tolerance or diff <= -tolerance) then 257 | print(format("WARNING: time difference from previous test: %+.1f%%", 258 | diff * 100)) 259 | end 260 | assert(open(fname, "w")):write(clocktime):close() 261 | end 262 | 263 | print("final OK !!!") 264 | 265 | 266 | 267 | --[[ 268 | ***************************************************************************** 269 | * Copyright (C) 1994-2016 Lua.org, PUC-Rio. 270 | * 271 | * Permission is hereby granted, free of charge, to any person obtaining 272 | * a copy of this software and associated documentation files (the 273 | * "Software"), to deal in the Software without restriction, including 274 | * without limitation the rights to use, copy, modify, merge, publish, 275 | * distribute, sublicense, and/or sell copies of the Software, and to 276 | * permit persons to whom the Software is furnished to do so, subject to 277 | * the following conditions: 278 | * 279 | * The above copyright notice and this permission notice shall be 280 | * included in all copies or substantial portions of the Software. 281 | * 282 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 283 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 284 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 285 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 286 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 287 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 288 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 289 | ***************************************************************************** 290 | ]] 291 | 292 | -------------------------------------------------------------------------------- /test/lua-5.3.4-tests/attrib.lua: -------------------------------------------------------------------------------- 1 | -- $Id: attrib.lua,v 1.65 2016/11/07 13:11:28 roberto Exp $ 2 | -- See Copyright Notice in file all.lua 3 | 4 | print "testing require" 5 | 6 | assert(require"string" == string) 7 | assert(require"math" == math) 8 | assert(require"table" == table) 9 | assert(require"io" == io) 10 | assert(require"os" == os) 11 | assert(require"coroutine" == coroutine) 12 | 13 | assert(type(package.path) == "string") 14 | assert(type(package.cpath) == "string") 15 | assert(type(package.loaded) == "table") 16 | assert(type(package.preload) == "table") 17 | 18 | assert(type(package.config) == "string") 19 | print("package config: "..string.gsub(package.config, "\n", "|")) 20 | 21 | do 22 | -- create a path with 'max' templates, 23 | -- each with 1-10 repetitions of '?' 24 | local max = _soft and 100 or 2000 25 | local t = {} 26 | for i = 1,max do t[i] = string.rep("?", i%10 + 1) end 27 | t[#t + 1] = ";" -- empty template 28 | local path = table.concat(t, ";") 29 | -- use that path in a search 30 | local s, err = package.searchpath("xuxu", path) 31 | -- search fails; check that message has an occurence of 32 | -- '??????????' with ? replaced by xuxu and at least 'max' lines 33 | assert(not s and 34 | string.find(err, string.rep("xuxu", 10)) and 35 | #string.gsub(err, "[^\n]", "") >= max) 36 | -- path with one very long template 37 | local path = string.rep("?", max) 38 | local s, err = package.searchpath("xuxu", path) 39 | assert(not s and string.find(err, string.rep('xuxu', max))) 40 | end 41 | 42 | do 43 | local oldpath = package.path 44 | package.path = {} 45 | local s, err = pcall(require, "no-such-file") 46 | assert(not s and string.find(err, "package.path")) 47 | package.path = oldpath 48 | end 49 | 50 | print('+') 51 | 52 | 53 | -- The next tests for 'require' assume some specific directories and 54 | -- libraries. 55 | 56 | if not _port then --[ 57 | 58 | local dirsep = string.match(package.config, "^([^\n]+)\n") 59 | 60 | -- auxiliary directory with C modules and temporary files 61 | local DIR = "libs" .. dirsep 62 | 63 | -- prepend DIR to a name and correct directory separators 64 | local function D (x) 65 | x = string.gsub(x, "/", dirsep) 66 | return DIR .. x 67 | end 68 | 69 | -- prepend DIR and pospend proper C lib. extension to a name 70 | local function DC (x) 71 | local ext = (dirsep == '\\') and ".dll" or ".so" 72 | return D(x .. ext) 73 | end 74 | 75 | 76 | local function createfiles (files, preextras, posextras) 77 | for n,c in pairs(files) do 78 | io.output(D(n)) 79 | io.write(string.format(preextras, n)) 80 | io.write(c) 81 | io.write(string.format(posextras, n)) 82 | io.close(io.output()) 83 | end 84 | end 85 | 86 | function removefiles (files) 87 | for n in pairs(files) do 88 | os.remove(D(n)) 89 | end 90 | end 91 | 92 | local files = { 93 | ["names.lua"] = "do return {...} end\n", 94 | ["err.lua"] = "B = 15; a = a + 1;", 95 | ["synerr.lua"] = "B =", 96 | ["A.lua"] = "", 97 | ["B.lua"] = "assert(...=='B');require 'A'", 98 | ["A.lc"] = "", 99 | ["A"] = "", 100 | ["L"] = "", 101 | ["XXxX"] = "", 102 | ["C.lua"] = "package.loaded[...] = 25; require'C'", 103 | } 104 | 105 | AA = nil 106 | local extras = [[ 107 | NAME = '%s' 108 | REQUIRED = ... 109 | return AA]] 110 | 111 | createfiles(files, "", extras) 112 | 113 | -- testing explicit "dir" separator in 'searchpath' 114 | assert(package.searchpath("C.lua", D"?", "", "") == D"C.lua") 115 | assert(package.searchpath("C.lua", D"?", ".", ".") == D"C.lua") 116 | assert(package.searchpath("--x-", D"?", "-", "X") == D"XXxX") 117 | assert(package.searchpath("---xX", D"?", "---", "XX") == D"XXxX") 118 | assert(package.searchpath(D"C.lua", "?", dirsep) == D"C.lua") 119 | assert(package.searchpath(".\\C.lua", D"?", "\\") == D"./C.lua") 120 | 121 | local oldpath = package.path 122 | 123 | package.path = string.gsub("D/?.lua;D/?.lc;D/?;D/??x?;D/L", "D/", DIR) 124 | 125 | local try = function (p, n, r) 126 | NAME = nil 127 | local rr = require(p) 128 | assert(NAME == n) 129 | assert(REQUIRED == p) 130 | assert(rr == r) 131 | end 132 | 133 | a = require"names" 134 | assert(a[1] == "names" and a[2] == D"names.lua") 135 | 136 | _G.a = nil 137 | local st, msg = pcall(require, "err") 138 | assert(not st and string.find(msg, "arithmetic") and B == 15) 139 | st, msg = pcall(require, "synerr") 140 | assert(not st and string.find(msg, "error loading module")) 141 | 142 | assert(package.searchpath("C", package.path) == D"C.lua") 143 | assert(require"C" == 25) 144 | assert(require"C" == 25) 145 | AA = nil 146 | try('B', 'B.lua', true) 147 | assert(package.loaded.B) 148 | assert(require"B" == true) 149 | assert(package.loaded.A) 150 | assert(require"C" == 25) 151 | package.loaded.A = nil 152 | try('B', nil, true) -- should not reload package 153 | try('A', 'A.lua', true) 154 | package.loaded.A = nil 155 | os.remove(D'A.lua') 156 | AA = {} 157 | try('A', 'A.lc', AA) -- now must find second option 158 | assert(package.searchpath("A", package.path) == D"A.lc") 159 | assert(require("A") == AA) 160 | AA = false 161 | try('K', 'L', false) -- default option 162 | try('K', 'L', false) -- default option (should reload it) 163 | assert(rawget(_G, "_REQUIREDNAME") == nil) 164 | 165 | AA = "x" 166 | try("X", "XXxX", AA) 167 | 168 | 169 | removefiles(files) 170 | 171 | 172 | -- testing require of sub-packages 173 | 174 | local _G = _G 175 | 176 | package.path = string.gsub("D/?.lua;D/?/init.lua", "D/", DIR) 177 | 178 | files = { 179 | ["P1/init.lua"] = "AA = 10", 180 | ["P1/xuxu.lua"] = "AA = 20", 181 | } 182 | 183 | createfiles(files, "_ENV = {}\n", "\nreturn _ENV\n") 184 | AA = 0 185 | 186 | local m = assert(require"P1") 187 | assert(AA == 0 and m.AA == 10) 188 | assert(require"P1" == m) 189 | assert(require"P1" == m) 190 | 191 | assert(package.searchpath("P1.xuxu", package.path) == D"P1/xuxu.lua") 192 | m.xuxu = assert(require"P1.xuxu") 193 | assert(AA == 0 and m.xuxu.AA == 20) 194 | assert(require"P1.xuxu" == m.xuxu) 195 | assert(require"P1.xuxu" == m.xuxu) 196 | assert(require"P1" == m and m.AA == 10) 197 | 198 | 199 | removefiles(files) 200 | 201 | 202 | package.path = "" 203 | assert(not pcall(require, "file_does_not_exist")) 204 | package.path = "??\0?" 205 | assert(not pcall(require, "file_does_not_exist1")) 206 | 207 | package.path = oldpath 208 | 209 | -- check 'require' error message 210 | local fname = "file_does_not_exist2" 211 | local m, err = pcall(require, fname) 212 | for t in string.gmatch(package.path..";"..package.cpath, "[^;]+") do 213 | t = string.gsub(t, "?", fname) 214 | assert(string.find(err, t, 1, true)) 215 | end 216 | 217 | do -- testing 'package.searchers' not being a table 218 | local searchers = package.searchers 219 | package.searchers = 3 220 | local st, msg = pcall(require, 'a') 221 | assert(not st and string.find(msg, "must be a table")) 222 | package.searchers = searchers 223 | end 224 | 225 | local function import(...) 226 | local f = {...} 227 | return function (m) 228 | for i=1, #f do m[f[i]] = _G[f[i]] end 229 | end 230 | end 231 | 232 | -- cannot change environment of a C function 233 | assert(not pcall(module, 'XUXU')) 234 | 235 | 236 | 237 | -- testing require of C libraries 238 | 239 | 240 | local p = "" -- On Mac OS X, redefine this to "_" 241 | 242 | -- check whether loadlib works in this system 243 | local st, err, when = package.loadlib(DC"lib1", "*") 244 | if not st then 245 | local f, err, when = package.loadlib("donotexist", p.."xuxu") 246 | assert(not f and type(err) == "string" and when == "absent") 247 | ;(Message or print)('\n >>> cannot load dynamic library <<<\n') 248 | print(err, when) 249 | else 250 | -- tests for loadlib 251 | local f = assert(package.loadlib(DC"lib1", p.."onefunction")) 252 | local a, b = f(15, 25) 253 | assert(a == 25 and b == 15) 254 | 255 | f = assert(package.loadlib(DC"lib1", p.."anotherfunc")) 256 | assert(f(10, 20) == "10%20\n") 257 | 258 | -- check error messages 259 | local f, err, when = package.loadlib(DC"lib1", p.."xuxu") 260 | assert(not f and type(err) == "string" and when == "init") 261 | f, err, when = package.loadlib("donotexist", p.."xuxu") 262 | assert(not f and type(err) == "string" and when == "open") 263 | 264 | -- symbols from 'lib1' must be visible to other libraries 265 | f = assert(package.loadlib(DC"lib11", p.."luaopen_lib11")) 266 | assert(f() == "exported") 267 | 268 | -- test C modules with prefixes in names 269 | package.cpath = DC"?" 270 | local lib2 = require"lib2-v2" 271 | -- check correct access to global environment and correct 272 | -- parameters 273 | assert(_ENV.x == "lib2-v2" and _ENV.y == DC"lib2-v2") 274 | assert(lib2.id("x") == "x") 275 | 276 | -- test C submodules 277 | local fs = require"lib1.sub" 278 | assert(_ENV.x == "lib1.sub" and _ENV.y == DC"lib1") 279 | assert(fs.id(45) == 45) 280 | end 281 | 282 | _ENV = _G 283 | 284 | 285 | -- testing preload 286 | 287 | do 288 | local p = package 289 | package = {} 290 | p.preload.pl = function (...) 291 | local _ENV = {...} 292 | function xuxu (x) return x+20 end 293 | return _ENV 294 | end 295 | 296 | local pl = require"pl" 297 | assert(require"pl" == pl) 298 | assert(pl.xuxu(10) == 30) 299 | assert(pl[1] == "pl" and pl[2] == nil) 300 | 301 | package = p 302 | assert(type(package.path) == "string") 303 | end 304 | 305 | print('+') 306 | 307 | end --] 308 | 309 | print("testing assignments, logical operators, and constructors") 310 | 311 | local res, res2 = 27 312 | 313 | a, b = 1, 2+3 314 | assert(a==1 and b==5) 315 | a={} 316 | function f() return 10, 11, 12 end 317 | a.x, b, a[1] = 1, 2, f() 318 | assert(a.x==1 and b==2 and a[1]==10) 319 | a[f()], b, a[f()+3] = f(), a, 'x' 320 | assert(a[10] == 10 and b == a and a[13] == 'x') 321 | 322 | do 323 | local f = function (n) local x = {}; for i=1,n do x[i]=i end; 324 | return table.unpack(x) end; 325 | local a,b,c 326 | a,b = 0, f(1) 327 | assert(a == 0 and b == 1) 328 | A,b = 0, f(1) 329 | assert(A == 0 and b == 1) 330 | a,b,c = 0,5,f(4) 331 | assert(a==0 and b==5 and c==1) 332 | a,b,c = 0,5,f(0) 333 | assert(a==0 and b==5 and c==nil) 334 | end 335 | 336 | a, b, c, d = 1 and nil, 1 or nil, (1 and (nil or 1)), 6 337 | assert(not a and b and c and d==6) 338 | 339 | d = 20 340 | a, b, c, d = f() 341 | assert(a==10 and b==11 and c==12 and d==nil) 342 | a,b = f(), 1, 2, 3, f() 343 | assert(a==10 and b==1) 344 | 345 | assert(ab == true) 346 | assert((10 and 2) == 2) 347 | assert((10 or 2) == 10) 348 | assert((10 or assert(nil)) == 10) 349 | assert(not (nil and assert(nil))) 350 | assert((nil or "alo") == "alo") 351 | assert((nil and 10) == nil) 352 | assert((false and 10) == false) 353 | assert((true or 10) == true) 354 | assert((false or 10) == 10) 355 | assert(false ~= nil) 356 | assert(nil ~= false) 357 | assert(not nil == true) 358 | assert(not not nil == false) 359 | assert(not not 1 == true) 360 | assert(not not a == true) 361 | assert(not not (6 or nil) == true) 362 | assert(not not (nil and 56) == false) 363 | assert(not not (nil and true) == false) 364 | assert(not 10 == false) 365 | assert(not {} == false) 366 | assert(not 0.5 == false) 367 | assert(not "x" == false) 368 | 369 | assert({} ~= {}) 370 | print('+') 371 | 372 | a = {} 373 | a[true] = 20 374 | a[false] = 10 375 | assert(a[1<2] == 20 and a[1>2] == 10) 376 | 377 | function f(a) return a end 378 | 379 | local a = {} 380 | for i=3000,-3000,-1 do a[i + 0.0] = i; end 381 | a[10e30] = "alo"; a[true] = 10; a[false] = 20 382 | assert(a[10e30] == 'alo' and a[not 1] == 20 and a[10<20] == 10) 383 | for i=3000,-3000,-1 do assert(a[i] == i); end 384 | a[print] = assert 385 | a[f] = print 386 | a[a] = a 387 | assert(a[a][a][a][a][print] == assert) 388 | a[print](a[a[f]] == a[print]) 389 | assert(not pcall(function () local a = {}; a[nil] = 10 end)) 390 | assert(not pcall(function () local a = {[nil] = 10} end)) 391 | assert(a[nil] == nil) 392 | a = nil 393 | 394 | a = {10,9,8,7,6,5,4,3,2; [-3]='a', [f]=print, a='a', b='ab'} 395 | a, a.x, a.y = a, a[-3] 396 | assert(a[1]==10 and a[-3]==a.a and a[f]==print and a.x=='a' and not a.y) 397 | a[1], f(a)[2], b, c = {['alo']=assert}, 10, a[1], a[f], 6, 10, 23, f(a), 2 398 | a[1].alo(a[2]==10 and b==10 and c==print) 399 | 400 | 401 | -- test of large float/integer indices 402 | 403 | -- compute maximum integer where all bits fit in a float 404 | local maxint = math.maxinteger 405 | 406 | while maxint - 1.0 == maxint - 0.0 do -- trim (if needed) to fit in a float 407 | maxint = maxint // 2 408 | end 409 | 410 | maxintF = maxint + 0.0 -- float version 411 | 412 | assert(math.type(maxintF) == "float" and maxintF >= 2.0^14) 413 | 414 | -- floats and integers must index the same places 415 | a[maxintF] = 10; a[maxintF - 1.0] = 11; 416 | a[-maxintF] = 12; a[-maxintF + 1.0] = 13; 417 | 418 | assert(a[maxint] == 10 and a[maxint - 1] == 11 and 419 | a[-maxint] == 12 and a[-maxint + 1] == 13) 420 | 421 | a[maxint] = 20 422 | a[-maxint] = 22 423 | 424 | assert(a[maxintF] == 20 and a[maxintF - 1.0] == 11 and 425 | a[-maxintF] == 22 and a[-maxintF + 1.0] == 13) 426 | 427 | a = nil 428 | 429 | 430 | -- test conflicts in multiple assignment 431 | do 432 | local a,i,j,b 433 | a = {'a', 'b'}; i=1; j=2; b=a 434 | i, a[i], a, j, a[j], a[i+j] = j, i, i, b, j, i 435 | assert(i == 2 and b[1] == 1 and a == 1 and j == b and b[2] == 2 and 436 | b[3] == 1) 437 | end 438 | 439 | -- repeat test with upvalues 440 | do 441 | local a,i,j,b 442 | a = {'a', 'b'}; i=1; j=2; b=a 443 | local function foo () 444 | i, a[i], a, j, a[j], a[i+j] = j, i, i, b, j, i 445 | end 446 | foo() 447 | assert(i == 2 and b[1] == 1 and a == 1 and j == b and b[2] == 2 and 448 | b[3] == 1) 449 | local t = {} 450 | (function (a) t[a], a = 10, 20 end)(1); 451 | assert(t[1] == 10) 452 | end 453 | 454 | -- bug in 5.2 beta 455 | local function foo () 456 | local a 457 | return function () 458 | local b 459 | a, b = 3, 14 -- local and upvalue have same index 460 | return a, b 461 | end 462 | end 463 | 464 | local a, b = foo()() 465 | assert(a == 3 and b == 14) 466 | 467 | print('OK') 468 | 469 | return res 470 | 471 | -------------------------------------------------------------------------------- /test/lua-5.3.4-tests/big.lua: -------------------------------------------------------------------------------- 1 | -- $Id: big.lua,v 1.32 2016/11/07 13:11:28 roberto Exp $ 2 | -- See Copyright Notice in file all.lua 3 | 4 | if _soft then 5 | return 'a' 6 | end 7 | 8 | print "testing large tables" 9 | 10 | local debug = require"debug" 11 | 12 | local lim = 2^18 + 1000 13 | local prog = { "local y = {0" } 14 | for i = 1, lim do prog[#prog + 1] = i end 15 | prog[#prog + 1] = "}\n" 16 | prog[#prog + 1] = "X = y\n" 17 | prog[#prog + 1] = ("assert(X[%d] == %d)"):format(lim - 1, lim - 2) 18 | prog[#prog + 1] = "return 0" 19 | prog = table.concat(prog, ";") 20 | 21 | local env = {string = string, assert = assert} 22 | local f = assert(load(prog, nil, nil, env)) 23 | 24 | f() 25 | assert(env.X[lim] == lim - 1 and env.X[lim + 1] == lim) 26 | for k in pairs(env) do env[k] = nil end 27 | 28 | -- yields during accesses larger than K (in RK) 29 | setmetatable(env, { 30 | __index = function (t, n) coroutine.yield('g'); return _G[n] end, 31 | __newindex = function (t, n, v) coroutine.yield('s'); _G[n] = v end, 32 | }) 33 | 34 | X = nil 35 | co = coroutine.wrap(f) 36 | assert(co() == 's') 37 | assert(co() == 'g') 38 | assert(co() == 'g') 39 | assert(co() == 0) 40 | 41 | assert(X[lim] == lim - 1 and X[lim + 1] == lim) 42 | 43 | -- errors in accesses larger than K (in RK) 44 | getmetatable(env).__index = function () end 45 | getmetatable(env).__newindex = function () end 46 | local e, m = pcall(f) 47 | assert(not e and m:find("global 'X'")) 48 | 49 | -- errors in metamethods 50 | getmetatable(env).__newindex = function () error("hi") end 51 | local e, m = xpcall(f, debug.traceback) 52 | assert(not e and m:find("'__newindex'")) 53 | 54 | f, X = nil 55 | 56 | coroutine.yield'b' 57 | 58 | if 2^32 == 0 then -- (small integers) { 59 | 60 | print "testing string length overflow" 61 | 62 | local repstrings = 192 -- number of strings to be concatenated 63 | local ssize = math.ceil(2.0^32 / repstrings) + 1 -- size of each string 64 | 65 | assert(repstrings * ssize > 2.0^32) -- it should be larger than maximum size 66 | 67 | local longs = string.rep("\0", ssize) -- create one long string 68 | 69 | -- create function to concatentate 'repstrings' copies of its argument 70 | local rep = assert(load( 71 | "local a = ...; return " .. string.rep("a", repstrings, ".."))) 72 | 73 | local a, b = pcall(rep, longs) -- call that function 74 | 75 | -- it should fail without creating string (result would be too large) 76 | assert(not a and string.find(b, "overflow")) 77 | 78 | end -- } 79 | 80 | print'OK' 81 | 82 | return 'a' 83 | -------------------------------------------------------------------------------- /test/lua-5.3.4-tests/bitwise.lua: -------------------------------------------------------------------------------- 1 | -- $Id: bitwise.lua,v 1.26 2016/11/07 13:11:28 roberto Exp $ 2 | -- See Copyright Notice in file all.lua 3 | 4 | print("testing bitwise operations") 5 | 6 | local numbits = string.packsize('j') * 8 7 | 8 | assert(~0 == -1) 9 | 10 | assert((1 << (numbits - 1)) == math.mininteger) 11 | 12 | -- basic tests for bitwise operators; 13 | -- use variables to avoid constant folding 14 | local a, b, c, d 15 | a = 0xFFFFFFFFFFFFFFFF 16 | assert(a == -1 and a & -1 == a and a & 35 == 35) 17 | a = 0xF0F0F0F0F0F0F0F0 18 | assert(a | -1 == -1) 19 | assert(a ~ a == 0 and a ~ 0 == a and a ~ ~a == -1) 20 | assert(a >> 4 == ~a) 21 | a = 0xF0; b = 0xCC; c = 0xAA; d = 0xFD 22 | assert(a | b ~ c & d == 0xF4) 23 | 24 | a = 0xF0.0; b = 0xCC.0; c = "0xAA.0"; d = "0xFD.0" 25 | assert(a | b ~ c & d == 0xF4) 26 | 27 | a = 0xF0000000; b = 0xCC000000; 28 | c = 0xAA000000; d = 0xFD000000 29 | assert(a | b ~ c & d == 0xF4000000) 30 | assert(~~a == a and ~a == -1 ~ a and -d == ~d + 1) 31 | 32 | a = a << 32 33 | b = b << 32 34 | c = c << 32 35 | d = d << 32 36 | assert(a | b ~ c & d == 0xF4000000 << 32) 37 | assert(~~a == a and ~a == -1 ~ a and -d == ~d + 1) 38 | 39 | assert(-1 >> 1 == (1 << (numbits - 1)) - 1 and 1 << 31 == 0x80000000) 40 | assert(-1 >> (numbits - 1) == 1) 41 | assert(-1 >> numbits == 0 and 42 | -1 >> -numbits == 0 and 43 | -1 << numbits == 0 and 44 | -1 << -numbits == 0) 45 | 46 | assert((2^30 - 1) << 2^30 == 0) 47 | assert((2^30 - 1) >> 2^30 == 0) 48 | 49 | assert(1 >> -3 == 1 << 3 and 1000 >> 5 == 1000 << -5) 50 | 51 | 52 | -- coercion from strings to integers 53 | assert("0xffffffffffffffff" | 0 == -1) 54 | assert("0xfffffffffffffffe" & "-1" == -2) 55 | assert(" \t-0xfffffffffffffffe\n\t" & "-1" == 2) 56 | assert(" \n -45 \t " >> " -2 " == -45 * 4) 57 | 58 | -- out of range number 59 | assert(not pcall(function () return "0xffffffffffffffff.0" | 0 end)) 60 | 61 | -- embedded zeros 62 | assert(not pcall(function () return "0xffffffffffffffff\0" | 0 end)) 63 | 64 | print'+' 65 | 66 | 67 | package.preload.bit32 = function () --{ 68 | 69 | -- no built-in 'bit32' library: implement it using bitwise operators 70 | 71 | local bit = {} 72 | 73 | function bit.bnot (a) 74 | return ~a & 0xFFFFFFFF 75 | end 76 | 77 | 78 | -- 79 | -- in all vararg functions, avoid creating 'arg' table when there are 80 | -- only 2 (or less) parameters, as 2 parameters is the common case 81 | -- 82 | 83 | function bit.band (x, y, z, ...) 84 | if not z then 85 | return ((x or -1) & (y or -1)) & 0xFFFFFFFF 86 | else 87 | local arg = {...} 88 | local res = x & y & z 89 | for i = 1, #arg do res = res & arg[i] end 90 | return res & 0xFFFFFFFF 91 | end 92 | end 93 | 94 | function bit.bor (x, y, z, ...) 95 | if not z then 96 | return ((x or 0) | (y or 0)) & 0xFFFFFFFF 97 | else 98 | local arg = {...} 99 | local res = x | y | z 100 | for i = 1, #arg do res = res | arg[i] end 101 | return res & 0xFFFFFFFF 102 | end 103 | end 104 | 105 | function bit.bxor (x, y, z, ...) 106 | if not z then 107 | return ((x or 0) ~ (y or 0)) & 0xFFFFFFFF 108 | else 109 | local arg = {...} 110 | local res = x ~ y ~ z 111 | for i = 1, #arg do res = res ~ arg[i] end 112 | return res & 0xFFFFFFFF 113 | end 114 | end 115 | 116 | function bit.btest (...) 117 | return bit.band(...) ~= 0 118 | end 119 | 120 | function bit.lshift (a, b) 121 | return ((a & 0xFFFFFFFF) << b) & 0xFFFFFFFF 122 | end 123 | 124 | function bit.rshift (a, b) 125 | return ((a & 0xFFFFFFFF) >> b) & 0xFFFFFFFF 126 | end 127 | 128 | function bit.arshift (a, b) 129 | a = a & 0xFFFFFFFF 130 | if b <= 0 or (a & 0x80000000) == 0 then 131 | return (a >> b) & 0xFFFFFFFF 132 | else 133 | return ((a >> b) | ~(0xFFFFFFFF >> b)) & 0xFFFFFFFF 134 | end 135 | end 136 | 137 | function bit.lrotate (a ,b) 138 | b = b & 31 139 | a = a & 0xFFFFFFFF 140 | a = (a << b) | (a >> (32 - b)) 141 | return a & 0xFFFFFFFF 142 | end 143 | 144 | function bit.rrotate (a, b) 145 | return bit.lrotate(a, -b) 146 | end 147 | 148 | local function checkfield (f, w) 149 | w = w or 1 150 | assert(f >= 0, "field cannot be negative") 151 | assert(w > 0, "width must be positive") 152 | assert(f + w <= 32, "trying to access non-existent bits") 153 | return f, ~(-1 << w) 154 | end 155 | 156 | function bit.extract (a, f, w) 157 | local f, mask = checkfield(f, w) 158 | return (a >> f) & mask 159 | end 160 | 161 | function bit.replace (a, v, f, w) 162 | local f, mask = checkfield(f, w) 163 | v = v & mask 164 | a = (a & ~(mask << f)) | (v << f) 165 | return a & 0xFFFFFFFF 166 | end 167 | 168 | return bit 169 | 170 | end --} 171 | 172 | 173 | print("testing bitwise library") 174 | 175 | local bit32 = require'bit32' 176 | 177 | assert(bit32.band() == bit32.bnot(0)) 178 | assert(bit32.btest() == true) 179 | assert(bit32.bor() == 0) 180 | assert(bit32.bxor() == 0) 181 | 182 | assert(bit32.band() == bit32.band(0xffffffff)) 183 | assert(bit32.band(1,2) == 0) 184 | 185 | 186 | -- out-of-range numbers 187 | assert(bit32.band(-1) == 0xffffffff) 188 | assert(bit32.band((1 << 33) - 1) == 0xffffffff) 189 | assert(bit32.band(-(1 << 33) - 1) == 0xffffffff) 190 | assert(bit32.band((1 << 33) + 1) == 1) 191 | assert(bit32.band(-(1 << 33) + 1) == 1) 192 | assert(bit32.band(-(1 << 40)) == 0) 193 | assert(bit32.band(1 << 40) == 0) 194 | assert(bit32.band(-(1 << 40) - 2) == 0xfffffffe) 195 | assert(bit32.band((1 << 40) - 4) == 0xfffffffc) 196 | 197 | assert(bit32.lrotate(0, -1) == 0) 198 | assert(bit32.lrotate(0, 7) == 0) 199 | assert(bit32.lrotate(0x12345678, 0) == 0x12345678) 200 | assert(bit32.lrotate(0x12345678, 32) == 0x12345678) 201 | assert(bit32.lrotate(0x12345678, 4) == 0x23456781) 202 | assert(bit32.rrotate(0x12345678, -4) == 0x23456781) 203 | assert(bit32.lrotate(0x12345678, -8) == 0x78123456) 204 | assert(bit32.rrotate(0x12345678, 8) == 0x78123456) 205 | assert(bit32.lrotate(0xaaaaaaaa, 2) == 0xaaaaaaaa) 206 | assert(bit32.lrotate(0xaaaaaaaa, -2) == 0xaaaaaaaa) 207 | for i = -50, 50 do 208 | assert(bit32.lrotate(0x89abcdef, i) == bit32.lrotate(0x89abcdef, i%32)) 209 | end 210 | 211 | assert(bit32.lshift(0x12345678, 4) == 0x23456780) 212 | assert(bit32.lshift(0x12345678, 8) == 0x34567800) 213 | assert(bit32.lshift(0x12345678, -4) == 0x01234567) 214 | assert(bit32.lshift(0x12345678, -8) == 0x00123456) 215 | assert(bit32.lshift(0x12345678, 32) == 0) 216 | assert(bit32.lshift(0x12345678, -32) == 0) 217 | assert(bit32.rshift(0x12345678, 4) == 0x01234567) 218 | assert(bit32.rshift(0x12345678, 8) == 0x00123456) 219 | assert(bit32.rshift(0x12345678, 32) == 0) 220 | assert(bit32.rshift(0x12345678, -32) == 0) 221 | assert(bit32.arshift(0x12345678, 0) == 0x12345678) 222 | assert(bit32.arshift(0x12345678, 1) == 0x12345678 // 2) 223 | assert(bit32.arshift(0x12345678, -1) == 0x12345678 * 2) 224 | assert(bit32.arshift(-1, 1) == 0xffffffff) 225 | assert(bit32.arshift(-1, 24) == 0xffffffff) 226 | assert(bit32.arshift(-1, 32) == 0xffffffff) 227 | assert(bit32.arshift(-1, -1) == bit32.band(-1 * 2, 0xffffffff)) 228 | 229 | assert(0x12345678 << 4 == 0x123456780) 230 | assert(0x12345678 << 8 == 0x1234567800) 231 | assert(0x12345678 << -4 == 0x01234567) 232 | assert(0x12345678 << -8 == 0x00123456) 233 | assert(0x12345678 << 32 == 0x1234567800000000) 234 | assert(0x12345678 << -32 == 0) 235 | assert(0x12345678 >> 4 == 0x01234567) 236 | assert(0x12345678 >> 8 == 0x00123456) 237 | assert(0x12345678 >> 32 == 0) 238 | assert(0x12345678 >> -32 == 0x1234567800000000) 239 | 240 | print("+") 241 | -- some special cases 242 | local c = {0, 1, 2, 3, 10, 0x80000000, 0xaaaaaaaa, 0x55555555, 243 | 0xffffffff, 0x7fffffff} 244 | 245 | for _, b in pairs(c) do 246 | assert(bit32.band(b) == b) 247 | assert(bit32.band(b, b) == b) 248 | assert(bit32.band(b, b, b, b) == b) 249 | assert(bit32.btest(b, b) == (b ~= 0)) 250 | assert(bit32.band(b, b, b) == b) 251 | assert(bit32.band(b, b, b, ~b) == 0) 252 | assert(bit32.btest(b, b, b) == (b ~= 0)) 253 | assert(bit32.band(b, bit32.bnot(b)) == 0) 254 | assert(bit32.bor(b, bit32.bnot(b)) == bit32.bnot(0)) 255 | assert(bit32.bor(b) == b) 256 | assert(bit32.bor(b, b) == b) 257 | assert(bit32.bor(b, b, b) == b) 258 | assert(bit32.bor(b, b, 0, ~b) == 0xffffffff) 259 | assert(bit32.bxor(b) == b) 260 | assert(bit32.bxor(b, b) == 0) 261 | assert(bit32.bxor(b, b, b) == b) 262 | assert(bit32.bxor(b, b, b, b) == 0) 263 | assert(bit32.bxor(b, 0) == b) 264 | assert(bit32.bnot(b) ~= b) 265 | assert(bit32.bnot(bit32.bnot(b)) == b) 266 | assert(bit32.bnot(b) == (1 << 32) - 1 - b) 267 | assert(bit32.lrotate(b, 32) == b) 268 | assert(bit32.rrotate(b, 32) == b) 269 | assert(bit32.lshift(bit32.lshift(b, -4), 4) == bit32.band(b, bit32.bnot(0xf))) 270 | assert(bit32.rshift(bit32.rshift(b, 4), -4) == bit32.band(b, bit32.bnot(0xf))) 271 | end 272 | 273 | -- for this test, use at most 24 bits (mantissa of a single float) 274 | c = {0, 1, 2, 3, 10, 0x800000, 0xaaaaaa, 0x555555, 0xffffff, 0x7fffff} 275 | for _, b in pairs(c) do 276 | for i = -40, 40 do 277 | local x = bit32.lshift(b, i) 278 | local y = math.floor(math.fmod(b * 2.0^i, 2.0^32)) 279 | assert(math.fmod(x - y, 2.0^32) == 0) 280 | end 281 | end 282 | 283 | assert(not pcall(bit32.band, {})) 284 | assert(not pcall(bit32.bnot, "a")) 285 | assert(not pcall(bit32.lshift, 45)) 286 | assert(not pcall(bit32.lshift, 45, print)) 287 | assert(not pcall(bit32.rshift, 45, print)) 288 | 289 | print("+") 290 | 291 | 292 | -- testing extract/replace 293 | 294 | assert(bit32.extract(0x12345678, 0, 4) == 8) 295 | assert(bit32.extract(0x12345678, 4, 4) == 7) 296 | assert(bit32.extract(0xa0001111, 28, 4) == 0xa) 297 | assert(bit32.extract(0xa0001111, 31, 1) == 1) 298 | assert(bit32.extract(0x50000111, 31, 1) == 0) 299 | assert(bit32.extract(0xf2345679, 0, 32) == 0xf2345679) 300 | 301 | assert(not pcall(bit32.extract, 0, -1)) 302 | assert(not pcall(bit32.extract, 0, 32)) 303 | assert(not pcall(bit32.extract, 0, 0, 33)) 304 | assert(not pcall(bit32.extract, 0, 31, 2)) 305 | 306 | assert(bit32.replace(0x12345678, 5, 28, 4) == 0x52345678) 307 | assert(bit32.replace(0x12345678, 0x87654321, 0, 32) == 0x87654321) 308 | assert(bit32.replace(0, 1, 2) == 2^2) 309 | assert(bit32.replace(0, -1, 4) == 2^4) 310 | assert(bit32.replace(-1, 0, 31) == (1 << 31) - 1) 311 | assert(bit32.replace(-1, 0, 1, 2) == (1 << 32) - 7) 312 | 313 | 314 | -- testing conversion of floats 315 | 316 | assert(bit32.bor(3.0) == 3) 317 | assert(bit32.bor(-4.0) == 0xfffffffc) 318 | 319 | -- large floats and large-enough integers? 320 | if 2.0^50 < 2.0^50 + 1.0 and 2.0^50 < (-1 >> 1) then 321 | assert(bit32.bor(2.0^32 - 5.0) == 0xfffffffb) 322 | assert(bit32.bor(-2.0^32 - 6.0) == 0xfffffffa) 323 | assert(bit32.bor(2.0^48 - 5.0) == 0xfffffffb) 324 | assert(bit32.bor(-2.0^48 - 6.0) == 0xfffffffa) 325 | end 326 | 327 | print'OK' 328 | 329 | -------------------------------------------------------------------------------- /test/lua-5.3.4-tests/calls.lua: -------------------------------------------------------------------------------- 1 | -- $Id: calls.lua,v 1.60 2016/11/07 13:11:28 roberto Exp $ 2 | -- See Copyright Notice in file all.lua 3 | 4 | print("testing functions and calls") 5 | 6 | local debug = require "debug" 7 | 8 | -- get the opportunity to test 'type' too ;) 9 | 10 | assert(type(1<2) == 'boolean') 11 | assert(type(true) == 'boolean' and type(false) == 'boolean') 12 | assert(type(nil) == 'nil' 13 | and type(-3) == 'number' 14 | and type'x' == 'string' 15 | and type{} == 'table' 16 | and type(type) == 'function') 17 | 18 | assert(type(assert) == type(print)) 19 | function f (x) return a:x (x) end 20 | assert(type(f) == 'function') 21 | assert(not pcall(type)) 22 | 23 | 24 | do -- test error in 'print' too... 25 | local tostring = _ENV.tostring 26 | 27 | _ENV.tostring = nil 28 | local st, msg = pcall(print, 1) 29 | assert(st == false and string.find(msg, "attempt to call a nil value")) 30 | 31 | _ENV.tostring = function () return {} end 32 | local st, msg = pcall(print, 1) 33 | assert(st == false and string.find(msg, "must return a string")) 34 | 35 | _ENV.tostring = tostring 36 | end 37 | 38 | 39 | -- testing local-function recursion 40 | fact = false 41 | do 42 | local res = 1 43 | local function fact (n) 44 | if n==0 then return res 45 | else return n*fact(n-1) 46 | end 47 | end 48 | assert(fact(5) == 120) 49 | end 50 | assert(fact == false) 51 | 52 | -- testing declarations 53 | a = {i = 10} 54 | self = 20 55 | function a:x (x) return x+self.i end 56 | function a.y (x) return x+self end 57 | 58 | assert(a:x(1)+10 == a.y(1)) 59 | 60 | a.t = {i=-100} 61 | a["t"].x = function (self, a,b) return self.i+a+b end 62 | 63 | assert(a.t:x(2,3) == -95) 64 | 65 | do 66 | local a = {x=0} 67 | function a:add (x) self.x, a.y = self.x+x, 20; return self end 68 | assert(a:add(10):add(20):add(30).x == 60 and a.y == 20) 69 | end 70 | 71 | local a = {b={c={}}} 72 | 73 | function a.b.c.f1 (x) return x+1 end 74 | function a.b.c:f2 (x,y) self[x] = y end 75 | assert(a.b.c.f1(4) == 5) 76 | a.b.c:f2('k', 12); assert(a.b.c.k == 12) 77 | 78 | print('+') 79 | 80 | t = nil -- 'declare' t 81 | function f(a,b,c) local d = 'a'; t={a,b,c,d} end 82 | 83 | f( -- this line change must be valid 84 | 1,2) 85 | assert(t[1] == 1 and t[2] == 2 and t[3] == nil and t[4] == 'a') 86 | f(1,2, -- this one too 87 | 3,4) 88 | assert(t[1] == 1 and t[2] == 2 and t[3] == 3 and t[4] == 'a') 89 | 90 | function fat(x) 91 | if x <= 1 then return 1 92 | else return x*load("return fat(" .. x-1 .. ")", "")() 93 | end 94 | end 95 | 96 | assert(load "load 'assert(fat(6)==720)' () ")() 97 | a = load('return fat(5), 3') 98 | a,b = a() 99 | assert(a == 120 and b == 3) 100 | print('+') 101 | 102 | function err_on_n (n) 103 | if n==0 then error(); exit(1); 104 | else err_on_n (n-1); exit(1); 105 | end 106 | end 107 | 108 | do 109 | function dummy (n) 110 | if n > 0 then 111 | assert(not pcall(err_on_n, n)) 112 | dummy(n-1) 113 | end 114 | end 115 | end 116 | 117 | dummy(10) 118 | 119 | function deep (n) 120 | if n>0 then deep(n-1) end 121 | end 122 | deep(10) 123 | deep(200) 124 | 125 | -- testing tail call 126 | function deep (n) if n>0 then return deep(n-1) else return 101 end end 127 | assert(deep(30000) == 101) 128 | a = {} 129 | function a:deep (n) if n>0 then return self:deep(n-1) else return 101 end end 130 | assert(a:deep(30000) == 101) 131 | 132 | print('+') 133 | 134 | 135 | a = nil 136 | (function (x) a=x end)(23) 137 | assert(a == 23 and (function (x) return x*2 end)(20) == 40) 138 | 139 | 140 | -- testing closures 141 | 142 | -- fixed-point operator 143 | Z = function (le) 144 | local function a (f) 145 | return le(function (x) return f(f)(x) end) 146 | end 147 | return a(a) 148 | end 149 | 150 | 151 | -- non-recursive factorial 152 | 153 | F = function (f) 154 | return function (n) 155 | if n == 0 then return 1 156 | else return n*f(n-1) end 157 | end 158 | end 159 | 160 | fat = Z(F) 161 | 162 | assert(fat(0) == 1 and fat(4) == 24 and Z(F)(5)==5*Z(F)(4)) 163 | 164 | local function g (z) 165 | local function f (a,b,c,d) 166 | return function (x,y) return a+b+c+d+a+x+y+z end 167 | end 168 | return f(z,z+1,z+2,z+3) 169 | end 170 | 171 | f = g(10) 172 | assert(f(9, 16) == 10+11+12+13+10+9+16+10) 173 | 174 | Z, F, f = nil 175 | print('+') 176 | 177 | -- testing multiple returns 178 | 179 | function unlpack (t, i) 180 | i = i or 1 181 | if (i <= #t) then 182 | return t[i], unlpack(t, i+1) 183 | end 184 | end 185 | 186 | function equaltab (t1, t2) 187 | assert(#t1 == #t2) 188 | for i = 1, #t1 do 189 | assert(t1[i] == t2[i]) 190 | end 191 | end 192 | 193 | local pack = function (...) return (table.pack(...)) end 194 | 195 | function f() return 1,2,30,4 end 196 | function ret2 (a,b) return a,b end 197 | 198 | local a,b,c,d = unlpack{1,2,3} 199 | assert(a==1 and b==2 and c==3 and d==nil) 200 | a = {1,2,3,4,false,10,'alo',false,assert} 201 | equaltab(pack(unlpack(a)), a) 202 | equaltab(pack(unlpack(a), -1), {1,-1}) 203 | a,b,c,d = ret2(f()), ret2(f()) 204 | assert(a==1 and b==1 and c==2 and d==nil) 205 | a,b,c,d = unlpack(pack(ret2(f()), ret2(f()))) 206 | assert(a==1 and b==1 and c==2 and d==nil) 207 | a,b,c,d = unlpack(pack(ret2(f()), (ret2(f())))) 208 | assert(a==1 and b==1 and c==nil and d==nil) 209 | 210 | a = ret2{ unlpack{1,2,3}, unlpack{3,2,1}, unlpack{"a", "b"}} 211 | assert(a[1] == 1 and a[2] == 3 and a[3] == "a" and a[4] == "b") 212 | 213 | 214 | -- testing calls with 'incorrect' arguments 215 | rawget({}, "x", 1) 216 | rawset({}, "x", 1, 2) 217 | assert(math.sin(1,2) == math.sin(1)) 218 | table.sort({10,9,8,4,19,23,0,0}, function (a,b) return a 10 or a[i]() ~= x 161 | assert(i == 11 and a[1]() == 1 and a[3]() == 3 and i == 4) 162 | 163 | 164 | -- testing closures created in 'then' and 'else' parts of 'if's 165 | a = {} 166 | for i = 1, 10 do 167 | if i % 3 == 0 then 168 | local y = 0 169 | a[i] = function (x) local t = y; y = x; return t end 170 | elseif i % 3 == 1 then 171 | goto L1 172 | error'not here' 173 | ::L1:: 174 | local y = 1 175 | a[i] = function (x) local t = y; y = x; return t end 176 | elseif i % 3 == 2 then 177 | local t 178 | goto l4 179 | ::l4a:: a[i] = t; goto l4b 180 | error("should never be here!") 181 | ::l4:: 182 | local y = 2 183 | t = function (x) local t = y; y = x; return t end 184 | goto l4a 185 | error("should never be here!") 186 | ::l4b:: 187 | end 188 | end 189 | 190 | for i = 1, 10 do 191 | assert(a[i](i * 10) == i % 3 and a[i]() == i * 10) 192 | end 193 | 194 | print'+' 195 | 196 | 197 | -- test for correctly closing upvalues in tail calls of vararg functions 198 | local function t () 199 | local function c(a,b) assert(a=="test" and b=="OK") end 200 | local function v(f, ...) c("test", f() ~= 1 and "FAILED" or "OK") end 201 | local x = 1 202 | return v(function() return x end) 203 | end 204 | t() 205 | 206 | 207 | -- test for debug manipulation of upvalues 208 | local debug = require'debug' 209 | 210 | do 211 | local a , b, c = 3, 5, 7 212 | foo1 = function () return a+b end; 213 | foo2 = function () return b+a end; 214 | do 215 | local a = 10 216 | foo3 = function () return a+b end; 217 | end 218 | end 219 | 220 | assert(debug.upvalueid(foo1, 1)) 221 | assert(debug.upvalueid(foo1, 2)) 222 | assert(not pcall(debug.upvalueid, foo1, 3)) 223 | assert(debug.upvalueid(foo1, 1) == debug.upvalueid(foo2, 2)) 224 | assert(debug.upvalueid(foo1, 2) == debug.upvalueid(foo2, 1)) 225 | assert(debug.upvalueid(foo3, 1)) 226 | assert(debug.upvalueid(foo1, 1) ~= debug.upvalueid(foo3, 1)) 227 | assert(debug.upvalueid(foo1, 2) == debug.upvalueid(foo3, 2)) 228 | 229 | assert(debug.upvalueid(string.gmatch("x", "x"), 1) ~= nil) 230 | 231 | assert(foo1() == 3 + 5 and foo2() == 5 + 3) 232 | debug.upvaluejoin(foo1, 2, foo2, 2) 233 | assert(foo1() == 3 + 3 and foo2() == 5 + 3) 234 | assert(foo3() == 10 + 5) 235 | debug.upvaluejoin(foo3, 2, foo2, 1) 236 | assert(foo3() == 10 + 5) 237 | debug.upvaluejoin(foo3, 2, foo2, 2) 238 | assert(foo3() == 10 + 3) 239 | 240 | assert(not pcall(debug.upvaluejoin, foo1, 3, foo2, 1)) 241 | assert(not pcall(debug.upvaluejoin, foo1, 1, foo2, 3)) 242 | assert(not pcall(debug.upvaluejoin, foo1, 0, foo2, 1)) 243 | assert(not pcall(debug.upvaluejoin, print, 1, foo2, 1)) 244 | assert(not pcall(debug.upvaluejoin, {}, 1, foo2, 1)) 245 | assert(not pcall(debug.upvaluejoin, foo1, 1, print, 1)) 246 | 247 | print'OK' 248 | -------------------------------------------------------------------------------- /test/lua-5.3.4-tests/code.lua: -------------------------------------------------------------------------------- 1 | -- $Id: code.lua,v 1.42 2016/11/07 13:04:32 roberto Exp $ 2 | -- See Copyright Notice in file all.lua 3 | 4 | if T==nil then 5 | (Message or print)('\n >>> testC not active: skipping opcode tests <<<\n') 6 | return 7 | end 8 | print "testing code generation and optimizations" 9 | 10 | 11 | -- this code gave an error for the code checker 12 | do 13 | local function f (a) 14 | for k,v,w in a do end 15 | end 16 | end 17 | 18 | 19 | -- testing reuse in constant table 20 | local function checkKlist (func, list) 21 | local k = T.listk(func) 22 | assert(#k == #list) 23 | for i = 1, #k do 24 | assert(k[i] == list[i] and math.type(k[i]) == math.type(list[i])) 25 | end 26 | end 27 | 28 | local function foo () 29 | local a 30 | a = 3; 31 | a = 0; a = 0.0; a = -7 + 7 32 | a = 3.78/4; a = 3.78/4 33 | a = -3.78/4; a = 3.78/4; a = -3.78/4 34 | a = -3.79/4; a = 0.0; a = -0; 35 | a = 3; a = 3.0; a = 3; a = 3.0 36 | end 37 | 38 | checkKlist(foo, {3, 0, 0.0, 3.78/4, -3.78/4, -3.79/4, 3.0}) 39 | 40 | 41 | -- testing opcodes 42 | 43 | function check (f, ...) 44 | local arg = {...} 45 | local c = T.listcode(f) 46 | for i=1, #arg do 47 | -- print(arg[i], c[i]) 48 | assert(string.find(c[i], '- '..arg[i]..' *%d')) 49 | end 50 | assert(c[#arg+2] == nil) 51 | end 52 | 53 | 54 | function checkequal (a, b) 55 | a = T.listcode(a) 56 | b = T.listcode(b) 57 | for i = 1, #a do 58 | a[i] = string.gsub(a[i], '%b()', '') -- remove line number 59 | b[i] = string.gsub(b[i], '%b()', '') -- remove line number 60 | assert(a[i] == b[i]) 61 | end 62 | end 63 | 64 | 65 | -- some basic instructions 66 | check(function () 67 | (function () end){f()} 68 | end, 'CLOSURE', 'NEWTABLE', 'GETTABUP', 'CALL', 'SETLIST', 'CALL', 'RETURN') 69 | 70 | 71 | -- sequence of LOADNILs 72 | check(function () 73 | local a,b,c 74 | local d; local e; 75 | local f,g,h; 76 | d = nil; d=nil; b=nil; a=nil; c=nil; 77 | end, 'LOADNIL', 'RETURN') 78 | 79 | check(function () 80 | local a,b,c,d = 1,1,1,1 81 | d=nil;c=nil;b=nil;a=nil 82 | end, 'LOADK', 'LOADK', 'LOADK', 'LOADK', 'LOADNIL', 'RETURN') 83 | 84 | do 85 | local a,b,c,d = 1,1,1,1 86 | d=nil;c=nil;b=nil;a=nil 87 | assert(a == nil and b == nil and c == nil and d == nil) 88 | end 89 | 90 | 91 | -- single return 92 | check (function (a,b,c) return a end, 'RETURN') 93 | 94 | 95 | -- infinite loops 96 | check(function () while true do local a = -1 end end, 97 | 'LOADK', 'JMP', 'RETURN') 98 | 99 | check(function () while 1 do local a = -1 end end, 100 | 'LOADK', 'JMP', 'RETURN') 101 | 102 | check(function () repeat local x = 1 until true end, 103 | 'LOADK', 'RETURN') 104 | 105 | 106 | -- concat optimization 107 | check(function (a,b,c,d) return a..b..c..d end, 108 | 'MOVE', 'MOVE', 'MOVE', 'MOVE', 'CONCAT', 'RETURN') 109 | 110 | -- not 111 | check(function () return not not nil end, 'LOADBOOL', 'RETURN') 112 | check(function () return not not false end, 'LOADBOOL', 'RETURN') 113 | check(function () return not not true end, 'LOADBOOL', 'RETURN') 114 | check(function () return not not 1 end, 'LOADBOOL', 'RETURN') 115 | 116 | -- direct access to locals 117 | check(function () 118 | local a,b,c,d 119 | a = b*2 120 | c[2], a[b] = -((a + d/2 - a[b]) ^ a.x), b 121 | end, 122 | 'LOADNIL', 123 | 'MUL', 124 | 'DIV', 'ADD', 'GETTABLE', 'SUB', 'GETTABLE', 'POW', 125 | 'UNM', 'SETTABLE', 'SETTABLE', 'RETURN') 126 | 127 | 128 | -- direct access to constants 129 | check(function () 130 | local a,b 131 | a.x = 3.2 132 | a.x = b 133 | a[b] = 'x' 134 | end, 135 | 'LOADNIL', 'SETTABLE', 'SETTABLE', 'SETTABLE', 'RETURN') 136 | 137 | check(function () 138 | local a,b 139 | a = 1 - a 140 | b = 1/a 141 | b = 5-4 142 | end, 143 | 'LOADNIL', 'SUB', 'DIV', 'LOADK', 'RETURN') 144 | 145 | check(function () 146 | local a,b 147 | a[true] = false 148 | end, 149 | 'LOADNIL', 'SETTABLE', 'RETURN') 150 | 151 | 152 | -- constant folding 153 | local function checkK (func, val) 154 | check(func, 'LOADK', 'RETURN') 155 | local k = T.listk(func) 156 | assert(#k == 1 and k[1] == val and math.type(k[1]) == math.type(val)) 157 | assert(func() == val) 158 | end 159 | checkK(function () return 0.0 end, 0.0) 160 | checkK(function () return 0 end, 0) 161 | checkK(function () return -0//1 end, 0) 162 | checkK(function () return 3^-1 end, 1/3) 163 | checkK(function () return (1 + 1)^(50 + 50) end, 2^100) 164 | checkK(function () return (-2)^(31 - 2) end, -0x20000000 + 0.0) 165 | checkK(function () return (-3^0 + 5) // 3.0 end, 1.0) 166 | checkK(function () return -3 % 5 end, 2) 167 | checkK(function () return -((2.0^8 + -(-1)) % 8)/2 * 4 - 3 end, -5.0) 168 | checkK(function () return -((2^8 + -(-1)) % 8)//2 * 4 - 3 end, -7.0) 169 | checkK(function () return 0xF0.0 | 0xCC.0 ~ 0xAA & 0xFD end, 0xF4) 170 | checkK(function () return ~(~0xFF0 | 0xFF0) end, 0) 171 | checkK(function () return ~~-100024.0 end, -100024) 172 | checkK(function () return ((100 << 6) << -4) >> 2 end, 100) 173 | 174 | 175 | -- no foldings 176 | check(function () return -0.0 end, 'LOADK', 'UNM', 'RETURN') 177 | check(function () return 3/0 end, 'DIV', 'RETURN') 178 | check(function () return 0%0 end, 'MOD', 'RETURN') 179 | check(function () return -4//0 end, 'IDIV', 'RETURN') 180 | 181 | -- bug in constant folding for 5.1 182 | check(function () return -nil end, 'LOADNIL', 'UNM', 'RETURN') 183 | 184 | 185 | check(function () 186 | local a,b,c 187 | b[c], a = c, b 188 | b[a], a = c, b 189 | a, b = c, a 190 | a = a 191 | end, 192 | 'LOADNIL', 193 | 'MOVE', 'MOVE', 'SETTABLE', 194 | 'MOVE', 'MOVE', 'MOVE', 'SETTABLE', 195 | 'MOVE', 'MOVE', 'MOVE', 196 | -- no code for a = a 197 | 'RETURN') 198 | 199 | 200 | -- x == nil , x ~= nil 201 | checkequal(function () if (a==nil) then a=1 end; if a~=nil then a=1 end end, 202 | function () if (a==9) then a=1 end; if a~=9 then a=1 end end) 203 | 204 | check(function () if a==nil then a='a' end end, 205 | 'GETTABUP', 'EQ', 'JMP', 'SETTABUP', 'RETURN') 206 | 207 | -- de morgan 208 | checkequal(function () local a; if not (a or b) then b=a end end, 209 | function () local a; if (not a and not b) then b=a end end) 210 | 211 | checkequal(function (l) local a; return 0 <= a and a <= l end, 212 | function (l) local a; return not (not(a >= 0) or not(a <= l)) end) 213 | 214 | 215 | -- if-goto optimizations 216 | check(function (a, b, c, d, e) 217 | if a == b then goto l1 218 | elseif a == c then goto l2 219 | elseif a == d then goto l2 220 | else if a == e then goto l3 221 | else goto l3 222 | end 223 | end 224 | ::l1:: ::l2:: ::l3:: ::l4:: 225 | end, 'EQ', 'JMP', 'EQ', 'JMP', 'EQ', 'JMP', 'EQ', 'JMP', 'JMP', 'RETURN') 226 | 227 | checkequal( 228 | function (a) while a < 10 do a = a + 1 end end, 229 | function (a) ::L2:: if not(a < 10) then goto L1 end; a = a + 1; 230 | goto L2; ::L1:: end 231 | ) 232 | 233 | checkequal( 234 | function (a) while a < 10 do a = a + 1 end end, 235 | function (a) while true do if not(a < 10) then break end; a = a + 1; end end 236 | ) 237 | 238 | print 'OK' 239 | 240 | -------------------------------------------------------------------------------- /test/lua-5.3.4-tests/constructs.lua: -------------------------------------------------------------------------------- 1 | -- $Id: constructs.lua,v 1.41 2016/11/07 13:11:28 roberto Exp $ 2 | -- See Copyright Notice in file all.lua 3 | 4 | ;;print "testing syntax";; 5 | 6 | local debug = require "debug" 7 | 8 | 9 | local function checkload (s, msg) 10 | assert(string.find(select(2, load(s)), msg)) 11 | end 12 | 13 | -- testing semicollons 14 | do ;;; end 15 | ; do ; a = 3; assert(a == 3) end; 16 | ; 17 | 18 | 19 | -- invalid operations should not raise errors when not executed 20 | if false then a = 3 // 0; a = 0 % 0 end 21 | 22 | 23 | -- testing priorities 24 | 25 | assert(2^3^2 == 2^(3^2)); 26 | assert(2^3*4 == (2^3)*4); 27 | assert(2.0^-2 == 1/4 and -2^- -2 == - - -4); 28 | assert(not nil and 2 and not(2>3 or 3<2)); 29 | assert(-3-1-5 == 0+0-9); 30 | assert(-2^2 == -4 and (-2)^2 == 4 and 2*2-3-1 == 0); 31 | assert(-3%5 == 2 and -3+5 == 2) 32 | assert(2*1+3/3 == 3 and 1+2 .. 3*1 == "33"); 33 | assert(not(2+1 > 3*1) and "a".."b" > "a"); 34 | 35 | assert("7" .. 3 << 1 == 146) 36 | assert(10 >> 1 .. "9" == 0) 37 | assert(10 | 1 .. "9" == 27) 38 | 39 | assert(0xF0 | 0xCC ~ 0xAA & 0xFD == 0xF4) 40 | assert(0xFD & 0xAA ~ 0xCC | 0xF0 == 0xF4) 41 | assert(0xF0 & 0x0F + 1 == 0x10) 42 | 43 | assert(3^4//2^3//5 == 2) 44 | 45 | assert(-3+4*5//2^3^2//9+4%10/3 == (-3)+(((4*5)//(2^(3^2)))//9)+((4%10)/3)) 46 | 47 | assert(not ((true or false) and nil)) 48 | assert( true or false and nil) 49 | 50 | -- old bug 51 | assert((((1 or false) and true) or false) == true) 52 | assert((((nil and true) or false) and true) == false) 53 | 54 | local a,b = 1,nil; 55 | assert(-(1 or 2) == -1 and (1 and 2)+(-1.25 or -4) == 0.75); 56 | x = ((b or a)+1 == 2 and (10 or a)+1 == 11); assert(x); 57 | x = (((2<3) or 1) == true and (2<3 and 4) == 4); assert(x); 58 | 59 | x,y=1,2; 60 | assert((x>y) and x or y == 2); 61 | x,y=2,1; 62 | assert((x>y) and x or y == 2); 63 | 64 | assert(1234567890 == tonumber('1234567890') and 1234567890+1 == 1234567891) 65 | 66 | 67 | -- silly loops 68 | repeat until 1; repeat until true; 69 | while false do end; while nil do end; 70 | 71 | do -- test old bug (first name could not be an `upvalue') 72 | local a; function f(x) x={a=1}; x={x=1}; x={G=1} end 73 | end 74 | 75 | function f (i) 76 | if type(i) ~= 'number' then return i,'jojo'; end; 77 | if i > 0 then return i, f(i-1); end; 78 | end 79 | 80 | x = {f(3), f(5), f(10);}; 81 | assert(x[1] == 3 and x[2] == 5 and x[3] == 10 and x[4] == 9 and x[12] == 1); 82 | assert(x[nil] == nil) 83 | x = {f'alo', f'xixi', nil}; 84 | assert(x[1] == 'alo' and x[2] == 'xixi' and x[3] == nil); 85 | x = {f'alo'..'xixi'}; 86 | assert(x[1] == 'aloxixi') 87 | x = {f{}} 88 | assert(x[2] == 'jojo' and type(x[1]) == 'table') 89 | 90 | 91 | local f = function (i) 92 | if i < 10 then return 'a'; 93 | elseif i < 20 then return 'b'; 94 | elseif i < 30 then return 'c'; 95 | end; 96 | end 97 | 98 | assert(f(3) == 'a' and f(12) == 'b' and f(26) == 'c' and f(100) == nil) 99 | 100 | for i=1,1000 do break; end; 101 | n=100; 102 | i=3; 103 | t = {}; 104 | a=nil 105 | while not a do 106 | a=0; for i=1,n do for i=i,1,-1 do a=a+1; t[i]=1; end; end; 107 | end 108 | assert(a == n*(n+1)/2 and i==3); 109 | assert(t[1] and t[n] and not t[0] and not t[n+1]) 110 | 111 | function f(b) 112 | local x = 1; 113 | repeat 114 | local a; 115 | if b==1 then local b=1; x=10; break 116 | elseif b==2 then x=20; break; 117 | elseif b==3 then x=30; 118 | else local a,b,c,d=math.sin(1); x=x+1; 119 | end 120 | until x>=12; 121 | return x; 122 | end; 123 | 124 | assert(f(1) == 10 and f(2) == 20 and f(3) == 30 and f(4)==12) 125 | 126 | 127 | local f = function (i) 128 | if i < 10 then return 'a' 129 | elseif i < 20 then return 'b' 130 | elseif i < 30 then return 'c' 131 | else return 8 132 | end 133 | end 134 | 135 | assert(f(3) == 'a' and f(12) == 'b' and f(26) == 'c' and f(100) == 8) 136 | 137 | local a, b = nil, 23 138 | x = {f(100)*2+3 or a, a or b+2} 139 | assert(x[1] == 19 and x[2] == 25) 140 | x = {f=2+3 or a, a = b+2} 141 | assert(x.f == 5 and x.a == 25) 142 | 143 | a={y=1} 144 | x = {a.y} 145 | assert(x[1] == 1) 146 | 147 | function f(i) 148 | while 1 do 149 | if i>0 then i=i-1; 150 | else return; end; 151 | end; 152 | end; 153 | 154 | function g(i) 155 | while 1 do 156 | if i>0 then i=i-1 157 | else return end 158 | end 159 | end 160 | 161 | f(10); g(10); 162 | 163 | do 164 | function f () return 1,2,3; end 165 | local a, b, c = f(); 166 | assert(a==1 and b==2 and c==3) 167 | a, b, c = (f()); 168 | assert(a==1 and b==nil and c==nil) 169 | end 170 | 171 | local a,b = 3 and f(); 172 | assert(a==1 and b==nil) 173 | 174 | function g() f(); return; end; 175 | assert(g() == nil) 176 | function g() return nil or f() end 177 | a,b = g() 178 | assert(a==1 and b==nil) 179 | 180 | print'+'; 181 | 182 | 183 | f = [[ 184 | return function ( a , b , c , d , e ) 185 | local x = a >= b or c or ( d and e ) or nil 186 | return x 187 | end , { a = 1 , b = 2 >= 1 , } or { 1 }; 188 | ]] 189 | f = string.gsub(f, "%s+", "\n"); -- force a SETLINE between opcodes 190 | f,a = load(f)(); 191 | assert(a.a == 1 and a.b) 192 | 193 | function g (a,b,c,d,e) 194 | if not (a>=b or c or d and e or nil) then return 0; else return 1; end; 195 | end 196 | 197 | function h (a,b,c,d,e) 198 | while (a>=b or c or (d and e) or nil) do return 1; end; 199 | return 0; 200 | end; 201 | 202 | assert(f(2,1) == true and g(2,1) == 1 and h(2,1) == 1) 203 | assert(f(1,2,'a') == 'a' and g(1,2,'a') == 1 and h(1,2,'a') == 1) 204 | assert(f(1,2,'a') 205 | ~= -- force SETLINE before nil 206 | nil, "") 207 | assert(f(1,2,'a') == 'a' and g(1,2,'a') == 1 and h(1,2,'a') == 1) 208 | assert(f(1,2,nil,1,'x') == 'x' and g(1,2,nil,1,'x') == 1 and 209 | h(1,2,nil,1,'x') == 1) 210 | assert(f(1,2,nil,nil,'x') == nil and g(1,2,nil,nil,'x') == 0 and 211 | h(1,2,nil,nil,'x') == 0) 212 | assert(f(1,2,nil,1,nil) == nil and g(1,2,nil,1,nil) == 0 and 213 | h(1,2,nil,1,nil) == 0) 214 | 215 | assert(1 and 2<3 == true and 2<3 and 'a'<'b' == true) 216 | x = 2<3 and not 3; assert(x==false) 217 | x = 2<1 or (2>1 and 'a'); assert(x=='a') 218 | 219 | 220 | do 221 | local a; if nil then a=1; else a=2; end; -- this nil comes as PUSHNIL 2 222 | assert(a==2) 223 | end 224 | 225 | function F(a) 226 | assert(debug.getinfo(1, "n").name == 'F') 227 | return a,2,3 228 | end 229 | 230 | a,b = F(1)~=nil; assert(a == true and b == nil); 231 | a,b = F(nil)==nil; assert(a == true and b == nil) 232 | 233 | ---------------------------------------------------------------- 234 | ------------------------------------------------------------------ 235 | 236 | -- sometimes will be 0, sometimes will not... 237 | _ENV.GLOB1 = math.floor(os.time()) % 2 238 | 239 | -- basic expressions with their respective values 240 | local basiccases = { 241 | {"nil", nil}, 242 | {"false", false}, 243 | {"true", true}, 244 | {"10", 10}, 245 | {"(0==_ENV.GLOB1)", 0 == _ENV.GLOB1}, 246 | } 247 | 248 | print('testing short-circuit optimizations (' .. _ENV.GLOB1 .. ')') 249 | 250 | 251 | -- operators with their respective values 252 | local binops = { 253 | {" and ", function (a,b) if not a then return a else return b end end}, 254 | {" or ", function (a,b) if a then return a else return b end end}, 255 | } 256 | 257 | local cases = {} 258 | 259 | -- creates all combinations of '(cases[i] op cases[n-i])' plus 260 | -- 'not(cases[i] op cases[n-i])' (syntax + value) 261 | local function createcases (n) 262 | local res = {} 263 | for i = 1, n - 1 do 264 | for _, v1 in ipairs(cases[i]) do 265 | for _, v2 in ipairs(cases[n - i]) do 266 | for _, op in ipairs(binops) do 267 | local t = { 268 | "(" .. v1[1] .. op[1] .. v2[1] .. ")", 269 | op[2](v1[2], v2[2]) 270 | } 271 | res[#res + 1] = t 272 | res[#res + 1] = {"not" .. t[1], not t[2]} 273 | end 274 | end 275 | end 276 | end 277 | return res 278 | end 279 | 280 | -- do not do too many combinations for soft tests 281 | local level = _soft and 3 or 4 282 | 283 | cases[1] = basiccases 284 | for i = 2, level do cases[i] = createcases(i) end 285 | print("+") 286 | 287 | local prog = [[if %s then IX = true end; return %s]] 288 | 289 | local i = 0 290 | for n = 1, level do 291 | for _, v in pairs(cases[n]) do 292 | local s = v[1] 293 | local p = load(string.format(prog, s, s), "") 294 | IX = false 295 | assert(p() == v[2] and IX == not not v[2]) 296 | i = i + 1 297 | if i % 60000 == 0 then print('+') end 298 | end 299 | end 300 | ------------------------------------------------------------------ 301 | 302 | -- testing some syntax errors (chosen through 'gcov') 303 | checkload("for x do", "expected") 304 | checkload("x:call", "expected") 305 | 306 | if not _soft then 307 | -- control structure too long 308 | local s = string.rep("a = a + 1\n", 2^18) 309 | s = "while true do " .. s .. "end" 310 | checkload(s, "too long") 311 | end 312 | 313 | print'OK' 314 | -------------------------------------------------------------------------------- /test/lua-5.3.4-tests/events.lua: -------------------------------------------------------------------------------- 1 | -- $Id: events.lua,v 1.45 2016/12/21 19:23:02 roberto Exp $ 2 | -- See Copyright Notice in file all.lua 3 | 4 | print('testing metatables') 5 | 6 | local debug = require'debug' 7 | 8 | X = 20; B = 30 9 | 10 | _ENV = setmetatable({}, {__index=_G}) 11 | 12 | collectgarbage() 13 | 14 | X = X+10 15 | assert(X == 30 and _G.X == 20) 16 | B = false 17 | assert(B == false) 18 | B = nil 19 | assert(B == 30) 20 | 21 | assert(getmetatable{} == nil) 22 | assert(getmetatable(4) == nil) 23 | assert(getmetatable(nil) == nil) 24 | a={name = "NAME"}; setmetatable(a, {__metatable = "xuxu", 25 | __tostring=function(x) return x.name end}) 26 | assert(getmetatable(a) == "xuxu") 27 | assert(tostring(a) == "NAME") 28 | -- cannot change a protected metatable 29 | assert(pcall(setmetatable, a, {}) == false) 30 | a.name = "gororoba" 31 | assert(tostring(a) == "gororoba") 32 | 33 | local a, t = {10,20,30; x="10", y="20"}, {} 34 | assert(setmetatable(a,t) == a) 35 | assert(getmetatable(a) == t) 36 | assert(setmetatable(a,nil) == a) 37 | assert(getmetatable(a) == nil) 38 | assert(setmetatable(a,t) == a) 39 | 40 | 41 | function f (t, i, e) 42 | assert(not e) 43 | local p = rawget(t, "parent") 44 | return (p and p[i]+3), "dummy return" 45 | end 46 | 47 | t.__index = f 48 | 49 | a.parent = {z=25, x=12, [4] = 24} 50 | assert(a[1] == 10 and a.z == 28 and a[4] == 27 and a.x == "10") 51 | 52 | collectgarbage() 53 | 54 | a = setmetatable({}, t) 55 | function f(t, i, v) rawset(t, i, v-3) end 56 | setmetatable(t, t) -- causes a bug in 5.1 ! 57 | t.__newindex = f 58 | a[1] = 30; a.x = "101"; a[5] = 200 59 | assert(a[1] == 27 and a.x == 98 and a[5] == 197) 60 | 61 | do -- bug in Lua 5.3.2 62 | local mt = {} 63 | mt.__newindex = mt 64 | local t = setmetatable({}, mt) 65 | t[1] = 10 -- will segfault on some machines 66 | assert(mt[1] == 10) 67 | end 68 | 69 | 70 | local c = {} 71 | a = setmetatable({}, t) 72 | t.__newindex = c 73 | a[1] = 10; a[2] = 20; a[3] = 90 74 | assert(c[1] == 10 and c[2] == 20 and c[3] == 90) 75 | 76 | 77 | do 78 | local a; 79 | a = setmetatable({}, {__index = setmetatable({}, 80 | {__index = setmetatable({}, 81 | {__index = function (_,n) return a[n-3]+4, "lixo" end})})}) 82 | a[0] = 20 83 | for i=0,10 do 84 | assert(a[i*3] == 20 + i*4) 85 | end 86 | end 87 | 88 | 89 | do -- newindex 90 | local foi 91 | local a = {} 92 | for i=1,10 do a[i] = 0; a['a'..i] = 0; end 93 | setmetatable(a, {__newindex = function (t,k,v) foi=true; rawset(t,k,v) end}) 94 | foi = false; a[1]=0; assert(not foi) 95 | foi = false; a['a1']=0; assert(not foi) 96 | foi = false; a['a11']=0; assert(foi) 97 | foi = false; a[11]=0; assert(foi) 98 | foi = false; a[1]=nil; assert(not foi) 99 | foi = false; a[1]=nil; assert(foi) 100 | end 101 | 102 | 103 | setmetatable(t, nil) 104 | function f (t, ...) return t, {...} end 105 | t.__call = f 106 | 107 | do 108 | local x,y = a(table.unpack{'a', 1}) 109 | assert(x==a and y[1]=='a' and y[2]==1 and y[3]==nil) 110 | x,y = a() 111 | assert(x==a and y[1]==nil) 112 | end 113 | 114 | 115 | local b = setmetatable({}, t) 116 | setmetatable(b,t) 117 | 118 | function f(op) 119 | return function (...) cap = {[0] = op, ...} ; return (...) end 120 | end 121 | t.__add = f("add") 122 | t.__sub = f("sub") 123 | t.__mul = f("mul") 124 | t.__div = f("div") 125 | t.__idiv = f("idiv") 126 | t.__mod = f("mod") 127 | t.__unm = f("unm") 128 | t.__pow = f("pow") 129 | t.__len = f("len") 130 | t.__band = f("band") 131 | t.__bor = f("bor") 132 | t.__bxor = f("bxor") 133 | t.__shl = f("shl") 134 | t.__shr = f("shr") 135 | t.__bnot = f("bnot") 136 | 137 | assert(b+5 == b) 138 | assert(cap[0] == "add" and cap[1] == b and cap[2] == 5 and cap[3]==nil) 139 | assert(b+'5' == b) 140 | assert(cap[0] == "add" and cap[1] == b and cap[2] == '5' and cap[3]==nil) 141 | assert(5+b == 5) 142 | assert(cap[0] == "add" and cap[1] == 5 and cap[2] == b and cap[3]==nil) 143 | assert('5'+b == '5') 144 | assert(cap[0] == "add" and cap[1] == '5' and cap[2] == b and cap[3]==nil) 145 | b=b-3; assert(getmetatable(b) == t) 146 | assert(5-a == 5) 147 | assert(cap[0] == "sub" and cap[1] == 5 and cap[2] == a and cap[3]==nil) 148 | assert('5'-a == '5') 149 | assert(cap[0] == "sub" and cap[1] == '5' and cap[2] == a and cap[3]==nil) 150 | assert(a*a == a) 151 | assert(cap[0] == "mul" and cap[1] == a and cap[2] == a and cap[3]==nil) 152 | assert(a/0 == a) 153 | assert(cap[0] == "div" and cap[1] == a and cap[2] == 0 and cap[3]==nil) 154 | assert(a%2 == a) 155 | assert(cap[0] == "mod" and cap[1] == a and cap[2] == 2 and cap[3]==nil) 156 | assert(a // (1/0) == a) 157 | assert(cap[0] == "idiv" and cap[1] == a and cap[2] == 1/0 and cap[3]==nil) 158 | assert(a & "hi" == a) 159 | assert(cap[0] == "band" and cap[1] == a and cap[2] == "hi" and cap[3]==nil) 160 | assert(a | "hi" == a) 161 | assert(cap[0] == "bor" and cap[1] == a and cap[2] == "hi" and cap[3]==nil) 162 | assert("hi" ~ a == "hi") 163 | assert(cap[0] == "bxor" and cap[1] == "hi" and cap[2] == a and cap[3]==nil) 164 | assert(-a == a) 165 | assert(cap[0] == "unm" and cap[1] == a) 166 | assert(a^4 == a) 167 | assert(cap[0] == "pow" and cap[1] == a and cap[2] == 4 and cap[3]==nil) 168 | assert(a^'4' == a) 169 | assert(cap[0] == "pow" and cap[1] == a and cap[2] == '4' and cap[3]==nil) 170 | assert(4^a == 4) 171 | assert(cap[0] == "pow" and cap[1] == 4 and cap[2] == a and cap[3]==nil) 172 | assert('4'^a == '4') 173 | assert(cap[0] == "pow" and cap[1] == '4' and cap[2] == a and cap[3]==nil) 174 | assert(#a == a) 175 | assert(cap[0] == "len" and cap[1] == a) 176 | assert(~a == a) 177 | assert(cap[0] == "bnot" and cap[1] == a) 178 | assert(a << 3 == a) 179 | assert(cap[0] == "shl" and cap[1] == a and cap[2] == 3) 180 | assert(1.5 >> a == 1.5) 181 | assert(cap[0] == "shr" and cap[1] == 1.5 and cap[2] == a) 182 | 183 | 184 | -- test for rawlen 185 | t = setmetatable({1,2,3}, {__len = function () return 10 end}) 186 | assert(#t == 10 and rawlen(t) == 3) 187 | assert(rawlen"abc" == 3) 188 | assert(not pcall(rawlen, io.stdin)) 189 | assert(not pcall(rawlen, 34)) 190 | assert(not pcall(rawlen)) 191 | 192 | -- rawlen for long strings 193 | assert(rawlen(string.rep('a', 1000)) == 1000) 194 | 195 | 196 | t = {} 197 | t.__lt = function (a,b,c) 198 | collectgarbage() 199 | assert(c == nil) 200 | if type(a) == 'table' then a = a.x end 201 | if type(b) == 'table' then b = b.x end 202 | return aOp(1)) and not(Op(1)>Op(2)) and (Op(2)>Op(1))) 215 | assert(not(Op('a')>Op('a')) and not(Op('a')>Op('b')) and (Op('b')>Op('a'))) 216 | assert((Op(1)>=Op(1)) and not(Op(1)>=Op(2)) and (Op(2)>=Op(1))) 217 | assert((1 >= Op(1)) and not(1 >= Op(2)) and (Op(2) >= 1)) 218 | assert((Op('a')>=Op('a')) and not(Op('a')>=Op('b')) and (Op('b')>=Op('a'))) 219 | assert(('a' >= Op('a')) and not(Op('a') >= 'b') and (Op('b') >= Op('a'))) 220 | end 221 | 222 | test() 223 | 224 | t.__le = function (a,b,c) 225 | assert(c == nil) 226 | if type(a) == 'table' then a = a.x end 227 | if type(b) == 'table' then b = b.x end 228 | return a<=b, "dummy" 229 | end 230 | 231 | test() -- retest comparisons, now using both `lt' and `le' 232 | 233 | 234 | -- test `partial order' 235 | 236 | local function rawSet(x) 237 | local y = {} 238 | for _,k in pairs(x) do y[k] = 1 end 239 | return y 240 | end 241 | 242 | local function Set(x) 243 | return setmetatable(rawSet(x), t) 244 | end 245 | 246 | t.__lt = function (a,b) 247 | for k in pairs(a) do 248 | if not b[k] then return false end 249 | b[k] = nil 250 | end 251 | return next(b) ~= nil 252 | end 253 | 254 | t.__le = nil 255 | 256 | assert(Set{1,2,3} < Set{1,2,3,4}) 257 | assert(not(Set{1,2,3,4} < Set{1,2,3,4})) 258 | assert((Set{1,2,3,4} <= Set{1,2,3,4})) 259 | assert((Set{1,2,3,4} >= Set{1,2,3,4})) 260 | assert((Set{1,3} <= Set{3,5})) -- wrong!! model needs a `le' method ;-) 261 | 262 | t.__le = function (a,b) 263 | for k in pairs(a) do 264 | if not b[k] then return false end 265 | end 266 | return true 267 | end 268 | 269 | assert(not (Set{1,3} <= Set{3,5})) -- now its OK! 270 | assert(not(Set{1,3} <= Set{3,5})) 271 | assert(not(Set{1,3} >= Set{3,5})) 272 | 273 | t.__eq = function (a,b) 274 | for k in pairs(a) do 275 | if not b[k] then return false end 276 | b[k] = nil 277 | end 278 | return next(b) == nil 279 | end 280 | 281 | local s = Set{1,3,5} 282 | assert(s == Set{3,5,1}) 283 | assert(not rawequal(s, Set{3,5,1})) 284 | assert(rawequal(s, s)) 285 | assert(Set{1,3,5,1} == rawSet{3,5,1}) 286 | assert(rawSet{1,3,5,1} == Set{3,5,1}) 287 | assert(Set{1,3,5} ~= Set{3,5,1,6}) 288 | 289 | -- '__eq' is not used for table accesses 290 | t[Set{1,3,5}] = 1 291 | assert(t[Set{1,3,5}] == nil) 292 | 293 | 294 | if not T then 295 | (Message or print)('\n >>> testC not active: skipping tests for \z 296 | userdata equality <<<\n') 297 | else 298 | local u1 = T.newuserdata(0) 299 | local u2 = T.newuserdata(0) 300 | local u3 = T.newuserdata(0) 301 | assert(u1 ~= u2 and u1 ~= u3) 302 | debug.setuservalue(u1, 1); 303 | debug.setuservalue(u2, 2); 304 | debug.setuservalue(u3, 1); 305 | debug.setmetatable(u1, {__eq = function (a, b) 306 | return debug.getuservalue(a) == debug.getuservalue(b) 307 | end}) 308 | debug.setmetatable(u2, {__eq = function (a, b) 309 | return true 310 | end}) 311 | assert(u1 == u3 and u3 == u1 and u1 ~= u2) 312 | assert(u2 == u1 and u2 == u3 and u3 == u2) 313 | assert(u2 ~= {}) -- different types cannot be equal 314 | end 315 | 316 | 317 | t.__concat = function (a,b,c) 318 | assert(c == nil) 319 | if type(a) == 'table' then a = a.val end 320 | if type(b) == 'table' then b = b.val end 321 | if A then return a..b 322 | else 323 | return setmetatable({val=a..b}, t) 324 | end 325 | end 326 | 327 | c = {val="c"}; setmetatable(c, t) 328 | d = {val="d"}; setmetatable(d, t) 329 | 330 | A = true 331 | assert(c..d == 'cd') 332 | assert(0 .."a".."b"..c..d.."e".."f"..(5+3).."g" == "0abcdef8g") 333 | 334 | A = false 335 | assert((c..d..c..d).val == 'cdcd') 336 | x = c..d 337 | assert(getmetatable(x) == t and x.val == 'cd') 338 | x = 0 .."a".."b"..c..d.."e".."f".."g" 339 | assert(x.val == "0abcdefg") 340 | 341 | 342 | -- concat metamethod x numbers (bug in 5.1.1) 343 | c = {} 344 | local x 345 | setmetatable(c, {__concat = function (a,b) 346 | assert(type(a) == "number" and b == c or type(b) == "number" and a == c) 347 | return c 348 | end}) 349 | assert(c..5 == c and 5 .. c == c) 350 | assert(4 .. c .. 5 == c and 4 .. 5 .. 6 .. 7 .. c == c) 351 | 352 | 353 | -- test comparison compatibilities 354 | local t1, t2, c, d 355 | t1 = {}; c = {}; setmetatable(c, t1) 356 | d = {} 357 | t1.__eq = function () return true end 358 | t1.__lt = function () return true end 359 | setmetatable(d, t1) 360 | assert(c == d and c < d and not(d <= c)) 361 | t2 = {} 362 | t2.__eq = t1.__eq 363 | t2.__lt = t1.__lt 364 | setmetatable(d, t2) 365 | assert(c == d and c < d and not(d <= c)) 366 | 367 | 368 | 369 | -- test for several levels of calls 370 | local i 371 | local tt = { 372 | __call = function (t, ...) 373 | i = i+1 374 | if t.f then return t.f(...) 375 | else return {...} 376 | end 377 | end 378 | } 379 | 380 | local a = setmetatable({}, tt) 381 | local b = setmetatable({f=a}, tt) 382 | local c = setmetatable({f=b}, tt) 383 | 384 | i = 0 385 | x = c(3,4,5) 386 | assert(i == 3 and x[1] == 3 and x[3] == 5) 387 | 388 | 389 | assert(_G.X == 20) 390 | 391 | print'+' 392 | 393 | local _g = _G 394 | _ENV = setmetatable({}, {__index=function (_,k) return _g[k] end}) 395 | 396 | 397 | a = {} 398 | rawset(a, "x", 1, 2, 3) 399 | assert(a.x == 1 and rawget(a, "x", 3) == 1) 400 | 401 | print '+' 402 | 403 | -- testing metatables for basic types 404 | mt = {__index = function (a,b) return a+b end, 405 | __len = function (x) return math.floor(x) end} 406 | debug.setmetatable(10, mt) 407 | assert(getmetatable(-2) == mt) 408 | assert((10)[3] == 13) 409 | assert((10)["3"] == 13) 410 | assert(#3.45 == 3) 411 | debug.setmetatable(23, nil) 412 | assert(getmetatable(-2) == nil) 413 | 414 | debug.setmetatable(true, mt) 415 | assert(getmetatable(false) == mt) 416 | mt.__index = function (a,b) return a or b end 417 | assert((true)[false] == true) 418 | assert((false)[false] == false) 419 | debug.setmetatable(false, nil) 420 | assert(getmetatable(true) == nil) 421 | 422 | debug.setmetatable(nil, mt) 423 | assert(getmetatable(nil) == mt) 424 | mt.__add = function (a,b) return (a or 0) + (b or 0) end 425 | assert(10 + nil == 10) 426 | assert(nil + 23 == 23) 427 | assert(nil + nil == 0) 428 | debug.setmetatable(nil, nil) 429 | assert(getmetatable(nil) == nil) 430 | 431 | debug.setmetatable(nil, {}) 432 | 433 | 434 | -- loops in delegation 435 | a = {}; setmetatable(a, a); a.__index = a; a.__newindex = a 436 | assert(not pcall(function (a,b) return a[b] end, a, 10)) 437 | assert(not pcall(function (a,b,c) a[b] = c end, a, 10, true)) 438 | 439 | -- bug in 5.1 440 | T, K, V = nil 441 | grandparent = {} 442 | grandparent.__newindex = function(t,k,v) T=t; K=k; V=v end 443 | 444 | parent = {} 445 | parent.__newindex = parent 446 | setmetatable(parent, grandparent) 447 | 448 | child = setmetatable({}, parent) 449 | child.foo = 10 --> CRASH (on some machines) 450 | assert(T == parent and K == "foo" and V == 10) 451 | 452 | print 'OK' 453 | 454 | return 12 455 | 456 | 457 | -------------------------------------------------------------------------------- /test/lua-5.3.4-tests/files.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trixnz/lua-fmt/3cbb57c38b12b849711286dda4f43b62e09f806d/test/lua-5.3.4-tests/files.lua -------------------------------------------------------------------------------- /test/lua-5.3.4-tests/goto.lua: -------------------------------------------------------------------------------- 1 | -- $Id: goto.lua,v 1.13 2016/11/07 13:11:28 roberto Exp $ 2 | -- See Copyright Notice in file all.lua 3 | 4 | collectgarbage() 5 | 6 | local function errmsg (code, m) 7 | local st, msg = load(code) 8 | assert(not st and string.find(msg, m)) 9 | end 10 | 11 | -- cannot see label inside block 12 | errmsg([[ goto l1; do ::l1:: end ]], "label 'l1'") 13 | errmsg([[ do ::l1:: end goto l1; ]], "label 'l1'") 14 | 15 | -- repeated label 16 | errmsg([[ ::l1:: ::l1:: ]], "label 'l1'") 17 | 18 | 19 | -- undefined label 20 | errmsg([[ goto l1; local aa ::l1:: ::l2:: print(3) ]], "local 'aa'") 21 | 22 | -- jumping over variable definition 23 | errmsg([[ 24 | do local bb, cc; goto l1; end 25 | local aa 26 | ::l1:: print(3) 27 | ]], "local 'aa'") 28 | 29 | -- jumping into a block 30 | errmsg([[ do ::l1:: end goto l1 ]], "label 'l1'") 31 | errmsg([[ goto l1 do ::l1:: end ]], "label 'l1'") 32 | 33 | -- cannot continue a repeat-until with variables 34 | errmsg([[ 35 | repeat 36 | if x then goto cont end 37 | local xuxu = 10 38 | ::cont:: 39 | until xuxu < x 40 | ]], "local 'xuxu'") 41 | 42 | -- simple gotos 43 | local x 44 | do 45 | local y = 12 46 | goto l1 47 | ::l2:: x = x + 1; goto l3 48 | ::l1:: x = y; goto l2 49 | end 50 | ::l3:: ::l3_1:: assert(x == 13) 51 | 52 | 53 | -- long labels 54 | do 55 | local prog = [[ 56 | do 57 | local a = 1 58 | goto l%sa; a = a + 1 59 | ::l%sa:: a = a + 10 60 | goto l%sb; a = a + 2 61 | ::l%sb:: a = a + 20 62 | return a 63 | end 64 | ]] 65 | local label = string.rep("0123456789", 40) 66 | prog = string.format(prog, label, label, label, label) 67 | assert(assert(load(prog))() == 31) 68 | end 69 | 70 | -- goto to correct label when nested 71 | do goto l3; ::l3:: end -- does not loop jumping to previous label 'l3' 72 | 73 | -- ok to jump over local dec. to end of block 74 | do 75 | goto l1 76 | local a = 23 77 | x = a 78 | ::l1::; 79 | end 80 | 81 | while true do 82 | goto l4 83 | goto l1 -- ok to jump over local dec. to end of block 84 | goto l1 -- multiple uses of same label 85 | local x = 45 86 | ::l1:: ;;; 87 | end 88 | ::l4:: assert(x == 13) 89 | 90 | if print then 91 | goto l1 -- ok to jump over local dec. to end of block 92 | error("should not be here") 93 | goto l2 -- ok to jump over local dec. to end of block 94 | local x 95 | ::l1:: ; ::l2:: ;; 96 | else end 97 | 98 | -- to repeat a label in a different function is OK 99 | local function foo () 100 | local a = {} 101 | goto l3 102 | ::l1:: a[#a + 1] = 1; goto l2; 103 | ::l2:: a[#a + 1] = 2; goto l5; 104 | ::l3:: 105 | ::l3a:: a[#a + 1] = 3; goto l1; 106 | ::l4:: a[#a + 1] = 4; goto l6; 107 | ::l5:: a[#a + 1] = 5; goto l4; 108 | ::l6:: assert(a[1] == 3 and a[2] == 1 and a[3] == 2 and 109 | a[4] == 5 and a[5] == 4) 110 | if not a[6] then a[6] = true; goto l3a end -- do it twice 111 | end 112 | 113 | ::l6:: foo() 114 | 115 | 116 | do -- bug in 5.2 -> 5.3.2 117 | local x 118 | ::L1:: 119 | local y -- cannot join this SETNIL with previous one 120 | assert(y == nil) 121 | y = true 122 | if x == nil then 123 | x = 1 124 | goto L1 125 | else 126 | x = x + 1 127 | end 128 | assert(x == 2 and y == true) 129 | end 130 | 131 | -------------------------------------------------------------------------------- 132 | -- testing closing of upvalues 133 | 134 | local debug = require 'debug' 135 | 136 | local function foo () 137 | local t = {} 138 | do 139 | local i = 1 140 | local a, b, c, d 141 | t[1] = function () return a, b, c, d end 142 | ::l1:: 143 | local b 144 | do 145 | local c 146 | t[#t + 1] = function () return a, b, c, d end -- t[2], t[4], t[6] 147 | if i > 2 then goto l2 end 148 | do 149 | local d 150 | t[#t + 1] = function () return a, b, c, d end -- t[3], t[5] 151 | i = i + 1 152 | local a 153 | goto l1 154 | end 155 | end 156 | end 157 | ::l2:: return t 158 | end 159 | 160 | local a = foo() 161 | assert(#a == 6) 162 | 163 | -- all functions share same 'a' 164 | for i = 2, 6 do 165 | assert(debug.upvalueid(a[1], 1) == debug.upvalueid(a[i], 1)) 166 | end 167 | 168 | -- 'b' and 'c' are shared among some of them 169 | for i = 2, 6 do 170 | -- only a[1] uses external 'b'/'b' 171 | assert(debug.upvalueid(a[1], 2) ~= debug.upvalueid(a[i], 2)) 172 | assert(debug.upvalueid(a[1], 3) ~= debug.upvalueid(a[i], 3)) 173 | end 174 | 175 | for i = 3, 5, 2 do 176 | -- inner functions share 'b'/'c' with previous ones 177 | assert(debug.upvalueid(a[i], 2) == debug.upvalueid(a[i - 1], 2)) 178 | assert(debug.upvalueid(a[i], 3) == debug.upvalueid(a[i - 1], 3)) 179 | -- but not with next ones 180 | assert(debug.upvalueid(a[i], 2) ~= debug.upvalueid(a[i + 1], 2)) 181 | assert(debug.upvalueid(a[i], 3) ~= debug.upvalueid(a[i + 1], 3)) 182 | end 183 | 184 | -- only external 'd' is shared 185 | for i = 2, 6, 2 do 186 | assert(debug.upvalueid(a[1], 4) == debug.upvalueid(a[i], 4)) 187 | end 188 | 189 | -- internal 'd's are all different 190 | for i = 3, 5, 2 do 191 | for j = 1, 6 do 192 | assert((debug.upvalueid(a[i], 4) == debug.upvalueid(a[j], 4)) 193 | == (i == j)) 194 | end 195 | end 196 | 197 | -------------------------------------------------------------------------------- 198 | -- testing if x goto optimizations 199 | 200 | local function testG (a) 201 | if a == 1 then 202 | goto l1 203 | error("should never be here!") 204 | elseif a == 2 then goto l2 205 | elseif a == 3 then goto l3 206 | elseif a == 4 then 207 | goto l1 -- go to inside the block 208 | error("should never be here!") 209 | ::l1:: a = a + 1 -- must go to 'if' end 210 | else 211 | goto l4 212 | ::l4a:: a = a * 2; goto l4b 213 | error("should never be here!") 214 | ::l4:: goto l4a 215 | error("should never be here!") 216 | ::l4b:: 217 | end 218 | do return a end 219 | ::l2:: do return "2" end 220 | ::l3:: do return "3" end 221 | ::l1:: return "1" 222 | end 223 | 224 | assert(testG(1) == "1") 225 | assert(testG(2) == "2") 226 | assert(testG(3) == "3") 227 | assert(testG(4) == 5) 228 | assert(testG(5) == 10) 229 | -------------------------------------------------------------------------------- 230 | 231 | 232 | print'OK' 233 | -------------------------------------------------------------------------------- /test/lua-5.3.4-tests/literals.lua: -------------------------------------------------------------------------------- 1 | -- $Id: literals.lua,v 1.36 2016/11/07 13:11:28 roberto Exp $ 2 | -- See Copyright Notice in file all.lua 3 | 4 | print('testing scanner') 5 | 6 | local debug = require "debug" 7 | 8 | 9 | local function dostring (x) return assert(load(x), "")() end 10 | 11 | dostring("x \v\f = \t\r 'a\0a' \v\f\f") 12 | assert(x == 'a\0a' and string.len(x) == 3) 13 | 14 | -- escape sequences 15 | assert('\n\"\'\\' == [[ 16 | 17 | "'\]]) 18 | 19 | assert(string.find("\a\b\f\n\r\t\v", "^%c%c%c%c%c%c%c$")) 20 | 21 | -- assume ASCII just for tests: 22 | assert("\09912" == 'c12') 23 | assert("\99ab" == 'cab') 24 | assert("\099" == '\99') 25 | assert("\099\n" == 'c\10') 26 | assert('\0\0\0alo' == '\0' .. '\0\0' .. 'alo') 27 | 28 | assert(010 .. 020 .. -030 == "1020-30") 29 | 30 | -- hexadecimal escapes 31 | assert("\x00\x05\x10\x1f\x3C\xfF\xe8" == "\0\5\16\31\60\255\232") 32 | 33 | local function lexstring (x, y, n) 34 | local f = assert(load('return ' .. x .. 35 | ', require"debug".getinfo(1).currentline', '')) 36 | local s, l = f() 37 | assert(s == y and l == n) 38 | end 39 | 40 | lexstring("'abc\\z \n efg'", "abcefg", 2) 41 | lexstring("'abc\\z \n\n\n'", "abc", 4) 42 | lexstring("'\\z \n\t\f\v\n'", "", 3) 43 | lexstring("[[\nalo\nalo\n\n]]", "alo\nalo\n\n", 5) 44 | lexstring("[[\nalo\ralo\n\n]]", "alo\nalo\n\n", 5) 45 | lexstring("[[\nalo\ralo\r\n]]", "alo\nalo\n", 4) 46 | lexstring("[[\ralo\n\ralo\r\n]]", "alo\nalo\n", 4) 47 | lexstring("[[alo]\n]alo]]", "alo]\n]alo", 2) 48 | 49 | assert("abc\z 50 | def\z 51 | ghi\z 52 | " == 'abcdefghi') 53 | 54 | 55 | -- UTF-8 sequences 56 | --assert("\u{0}\u{00000000}\x00\0" == string.char(0, 0, 0, 0)) 57 | 58 | -- limits for 1-byte sequences 59 | --assert("\u{0}\u{7F}" == "\x00\z\x7F") 60 | 61 | -- limits for 2-byte sequences 62 | assert("\u{80}\u{7FF}" == "\xC2\x80\z\xDF\xBF") 63 | 64 | -- limits for 3-byte sequences 65 | assert("\u{800}\u{FFFF}" == "\xE0\xA0\x80\z\xEF\xBF\xBF") 66 | 67 | -- limits for 4-byte sequences 68 | assert("\u{10000}\u{10FFFF}" == "\xF0\x90\x80\x80\z\xF4\x8F\xBF\xBF") 69 | 70 | 71 | -- Error in escape sequences 72 | local function lexerror (s, err) 73 | local st, msg = load('return ' .. s, '') 74 | if err ~= '' then err = err .. "'" end 75 | assert(not st and string.find(msg, "near .-" .. err)) 76 | end 77 | 78 | lexerror([["abc\x"]], [[\x"]]) 79 | lexerror([["abc\x]], [[\x]]) 80 | lexerror([["\x]], [[\x]]) 81 | lexerror([["\x5"]], [[\x5"]]) 82 | lexerror([["\x5]], [[\x5]]) 83 | lexerror([["\xr"]], [[\xr]]) 84 | lexerror([["\xr]], [[\xr]]) 85 | lexerror([["\x.]], [[\x.]]) 86 | lexerror([["\x8%"]], [[\x8%%]]) 87 | lexerror([["\xAG]], [[\xAG]]) 88 | lexerror([["\g"]], [[\g]]) 89 | lexerror([["\g]], [[\g]]) 90 | lexerror([["\."]], [[\%.]]) 91 | 92 | lexerror([["\999"]], [[\999"]]) 93 | lexerror([["xyz\300"]], [[\300"]]) 94 | lexerror([[" \256"]], [[\256"]]) 95 | 96 | -- errors in UTF-8 sequences 97 | lexerror([["abc\u{110000}"]], [[abc\u{110000]]) -- too large 98 | lexerror([["abc\u11r"]], [[abc\u1]]) -- missing '{' 99 | lexerror([["abc\u"]], [[abc\u"]]) -- missing '{' 100 | lexerror([["abc\u{11r"]], [[abc\u{11r]]) -- missing '}' 101 | lexerror([["abc\u{11"]], [[abc\u{11"]]) -- missing '}' 102 | lexerror([["abc\u{11]], [[abc\u{11]]) -- missing '}' 103 | lexerror([["abc\u{r"]], [[abc\u{r]]) -- no digits 104 | 105 | -- unfinished strings 106 | lexerror("[=[alo]]", "") 107 | lexerror("[=[alo]=", "") 108 | lexerror("[=[alo]", "") 109 | lexerror("'alo", "") 110 | lexerror("'alo \\z \n\n", "") 111 | lexerror("'alo \\z", "") 112 | lexerror([['alo \98]], "") 113 | 114 | -- valid characters in variable names 115 | for i = 0, 255 do 116 | local s = string.char(i) 117 | assert(not string.find(s, "[a-zA-Z_]") == not load(s .. "=1", "")) 118 | assert(not string.find(s, "[a-zA-Z_0-9]") == 119 | not load("a" .. s .. "1 = 1", "")) 120 | end 121 | 122 | 123 | -- long variable names 124 | 125 | var1 = string.rep('a', 15000) .. '1' 126 | var2 = string.rep('a', 15000) .. '2' 127 | prog = string.format([[ 128 | %s = 5 129 | %s = %s + 1 130 | return function () return %s - %s end 131 | ]], var1, var2, var1, var1, var2) 132 | local f = dostring(prog) 133 | assert(_G[var1] == 5 and _G[var2] == 6 and f() == -1) 134 | var1, var2, f = nil 135 | print('+') 136 | 137 | -- escapes -- 138 | assert("\n\t" == [[ 139 | 140 | ]]) 141 | assert([[ 142 | 143 | $debug]] == "\n $debug") 144 | assert([[ [ ]] ~= [[ ] ]]) 145 | -- long strings -- 146 | b = "001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789" 147 | assert(string.len(b) == 960) 148 | prog = [=[ 149 | print('+') 150 | 151 | a1 = [["this is a 'string' with several 'quotes'"]] 152 | a2 = "'quotes'" 153 | 154 | assert(string.find(a1, a2) == 34) 155 | print('+') 156 | 157 | a1 = [==[temp = [[an arbitrary value]]; ]==] 158 | assert(load(a1))() 159 | assert(temp == 'an arbitrary value') 160 | -- long strings -- 161 | b = "001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789" 162 | assert(string.len(b) == 960) 163 | print('+') 164 | 165 | a = [[00123456789012345678901234567890123456789123456789012345678901234567890123456789 166 | 00123456789012345678901234567890123456789123456789012345678901234567890123456789 167 | 00123456789012345678901234567890123456789123456789012345678901234567890123456789 168 | 00123456789012345678901234567890123456789123456789012345678901234567890123456789 169 | 00123456789012345678901234567890123456789123456789012345678901234567890123456789 170 | 00123456789012345678901234567890123456789123456789012345678901234567890123456789 171 | 00123456789012345678901234567890123456789123456789012345678901234567890123456789 172 | 00123456789012345678901234567890123456789123456789012345678901234567890123456789 173 | 00123456789012345678901234567890123456789123456789012345678901234567890123456789 174 | 00123456789012345678901234567890123456789123456789012345678901234567890123456789 175 | 00123456789012345678901234567890123456789123456789012345678901234567890123456789 176 | 00123456789012345678901234567890123456789123456789012345678901234567890123456789 177 | 00123456789012345678901234567890123456789123456789012345678901234567890123456789 178 | 00123456789012345678901234567890123456789123456789012345678901234567890123456789 179 | 00123456789012345678901234567890123456789123456789012345678901234567890123456789 180 | 00123456789012345678901234567890123456789123456789012345678901234567890123456789 181 | 00123456789012345678901234567890123456789123456789012345678901234567890123456789 182 | 00123456789012345678901234567890123456789123456789012345678901234567890123456789 183 | 00123456789012345678901234567890123456789123456789012345678901234567890123456789 184 | 00123456789012345678901234567890123456789123456789012345678901234567890123456789 185 | 00123456789012345678901234567890123456789123456789012345678901234567890123456789 186 | 00123456789012345678901234567890123456789123456789012345678901234567890123456789 187 | 00123456789012345678901234567890123456789123456789012345678901234567890123456789 188 | ]] 189 | assert(string.len(a) == 1863) 190 | assert(string.sub(a, 1, 40) == string.sub(b, 1, 40)) 191 | x = 1 192 | ]=] 193 | 194 | print('+') 195 | x = nil 196 | dostring(prog) 197 | assert(x) 198 | 199 | prog = nil 200 | a = nil 201 | b = nil 202 | 203 | 204 | -- testing line ends 205 | prog = [[ 206 | a = 1 -- a comment 207 | b = 2 208 | 209 | 210 | x = [=[ 211 | hi 212 | ]=] 213 | y = "\ 214 | hello\r\n\ 215 | " 216 | return require"debug".getinfo(1).currentline 217 | ]] 218 | 219 | for _, n in pairs{"\n", "\r", "\n\r", "\r\n"} do 220 | local prog, nn = string.gsub(prog, "\n", n) 221 | assert(dostring(prog) == nn) 222 | assert(_G.x == "hi\n" and _G.y == "\nhello\r\n\n") 223 | end 224 | 225 | 226 | -- testing comments and strings with long brackets 227 | a = [==[]=]==] 228 | assert(a == "]=") 229 | 230 | a = [==[[===[[=[]]=][====[]]===]===]==] 231 | assert(a == "[===[[=[]]=][====[]]===]===") 232 | 233 | a = [====[[===[[=[]]=][====[]]===]===]====] 234 | assert(a == "[===[[=[]]=][====[]]===]===") 235 | 236 | a = [=[]]]]]]]]]=] 237 | assert(a == "]]]]]]]]") 238 | 239 | 240 | --[===[ 241 | x y z [==[ blu foo 242 | ]== 243 | ] 244 | ]=]==] 245 | error error]=]===] 246 | 247 | -- generate all strings of four of these chars 248 | local x = {"=", "[", "]", "\n"} 249 | local len = 4 250 | local function gen (c, n) 251 | if n==0 then coroutine.yield(c) 252 | else 253 | for _, a in pairs(x) do 254 | gen(c..a, n-1) 255 | end 256 | end 257 | end 258 | 259 | for s in coroutine.wrap(function () gen("", len) end) do 260 | assert(s == load("return [====[\n"..s.."]====]", "")()) 261 | end 262 | 263 | 264 | -- testing decimal point locale 265 | if os.setlocale("pt_BR") or os.setlocale("ptb") then 266 | assert(tonumber("3,4") == 3.4 and tonumber"3.4" == 3.4) 267 | assert(tonumber(" -.4 ") == -0.4) 268 | assert(tonumber(" +0x.41 ") == 0X0.41) 269 | assert(not load("a = (3,4)")) 270 | assert(assert(load("return 3.4"))() == 3.4) 271 | assert(assert(load("return .4,3"))() == .4) 272 | assert(assert(load("return 4."))() == 4.) 273 | assert(assert(load("return 4.+.5"))() == 4.5) 274 | 275 | assert(" 0x.1 " + " 0x,1" + "-0X.1\t" == 0x0.1) 276 | 277 | assert(tonumber"inf" == nil and tonumber"NAN" == nil) 278 | 279 | assert(assert(load(string.format("return %q", 4.51)))() == 4.51) 280 | 281 | local a,b = load("return 4.5.") 282 | assert(string.find(b, "'4%.5%.'")) 283 | 284 | assert(os.setlocale("C")) 285 | else 286 | (Message or print)( 287 | '\n >>> pt_BR locale not available: skipping decimal point tests <<<\n') 288 | end 289 | 290 | 291 | -- testing %q x line ends 292 | local s = "a string with \r and \n and \r\n and \n\r" 293 | local c = string.format("return %q", s) 294 | assert(assert(load(c))() == s) 295 | 296 | -- testing errors 297 | assert(not load"a = 'non-ending string") 298 | assert(not load"a = 'non-ending string\n'") 299 | assert(not load"a = '\\345'") 300 | assert(not load"a = [=x]") 301 | 302 | print('OK') 303 | -------------------------------------------------------------------------------- /test/lua-5.3.4-tests/locals.lua: -------------------------------------------------------------------------------- 1 | -- $Id: locals.lua,v 1.37 2016/11/07 13:11:28 roberto Exp $ 2 | -- See Copyright Notice in file all.lua 3 | 4 | print('testing local variables and environments') 5 | 6 | local debug = require"debug" 7 | 8 | 9 | -- bug in 5.1: 10 | 11 | local function f(x) x = nil; return x end 12 | assert(f(10) == nil) 13 | 14 | local function f() local x; return x end 15 | assert(f(10) == nil) 16 | 17 | local function f(x) x = nil; local y; return x, y end 18 | assert(f(10) == nil and select(2, f(20)) == nil) 19 | 20 | do 21 | local i = 10 22 | do local i = 100; assert(i==100) end 23 | do local i = 1000; assert(i==1000) end 24 | assert(i == 10) 25 | if i ~= 10 then 26 | local i = 20 27 | else 28 | local i = 30 29 | assert(i == 30) 30 | end 31 | end 32 | 33 | 34 | 35 | f = nil 36 | 37 | local f 38 | x = 1 39 | 40 | a = nil 41 | load('local a = {}')() 42 | assert(a == nil) 43 | 44 | function f (a) 45 | local _1, _2, _3, _4, _5 46 | local _6, _7, _8, _9, _10 47 | local x = 3 48 | local b = a 49 | local c,d = a,b 50 | if (d == b) then 51 | local x = 'q' 52 | x = b 53 | assert(x == 2) 54 | else 55 | assert(nil) 56 | end 57 | assert(x == 3) 58 | local f = 10 59 | end 60 | 61 | local b=10 62 | local a; repeat local b; a,b=1,2; assert(a+1==b); until a+b==3 63 | 64 | 65 | assert(x == 1) 66 | 67 | f(2) 68 | assert(type(f) == 'function') 69 | 70 | 71 | local function getenv (f) 72 | local a,b = debug.getupvalue(f, 1) 73 | assert(a == '_ENV') 74 | return b 75 | end 76 | 77 | -- test for global table of loaded chunks 78 | assert(getenv(load"a=3") == _G) 79 | local c = {}; local f = load("a = 3", nil, nil, c) 80 | assert(getenv(f) == c) 81 | assert(c.a == nil) 82 | f() 83 | assert(c.a == 3) 84 | 85 | -- old test for limits for special instructions (now just a generic test) 86 | do 87 | local i = 2 88 | local p = 4 -- p == 2^i 89 | repeat 90 | for j=-3,3 do 91 | assert(load(string.format([[local a=%s; 92 | a=a+%s; 93 | assert(a ==2^%s)]], j, p-j, i), '')) () 94 | assert(load(string.format([[local a=%s; 95 | a=a-%s; 96 | assert(a==-2^%s)]], -j, p-j, i), '')) () 97 | assert(load(string.format([[local a,b=0,%s; 98 | a=b-%s; 99 | assert(a==-2^%s)]], -j, p-j, i), '')) () 100 | end 101 | p = 2 * p; i = i + 1 102 | until p <= 0 103 | end 104 | 105 | print'+' 106 | 107 | 108 | if rawget(_G, "querytab") then 109 | -- testing clearing of dead elements from tables 110 | collectgarbage("stop") -- stop GC 111 | local a = {[{}] = 4, [3] = 0, alo = 1, 112 | a1234567890123456789012345678901234567890 = 10} 113 | 114 | local t = querytab(a) 115 | 116 | for k,_ in pairs(a) do a[k] = nil end 117 | collectgarbage() -- restore GC and collect dead fiels in `a' 118 | for i=0,t-1 do 119 | local k = querytab(a, i) 120 | assert(k == nil or type(k) == 'number' or k == 'alo') 121 | end 122 | end 123 | 124 | 125 | -- testing lexical environments 126 | 127 | assert(_ENV == _G) 128 | 129 | do 130 | local dummy 131 | local _ENV = (function (...) return ... end)(_G, dummy) -- { 132 | 133 | do local _ENV = {assert=assert}; assert(true) end 134 | mt = {_G = _G} 135 | local foo,x 136 | A = false -- "declare" A 137 | do local _ENV = mt 138 | function foo (x) 139 | A = x 140 | do local _ENV = _G; A = 1000 end 141 | return function (x) return A .. x end 142 | end 143 | end 144 | assert(getenv(foo) == mt) 145 | x = foo('hi'); assert(mt.A == 'hi' and A == 1000) 146 | assert(x('*') == mt.A .. '*') 147 | 148 | do local _ENV = {assert=assert, A=10}; 149 | do local _ENV = {assert=assert, A=20}; 150 | assert(A==20);x=A 151 | end 152 | assert(A==10 and x==20) 153 | end 154 | assert(x==20) 155 | 156 | 157 | print('OK') 158 | 159 | return 5,f 160 | 161 | end -- } 162 | 163 | -------------------------------------------------------------------------------- /test/lua-5.3.4-tests/main.lua: -------------------------------------------------------------------------------- 1 | # testing special comment on first line 2 | -- $Id: main.lua,v 1.65 2016/11/07 13:11:28 roberto Exp $ 3 | -- See Copyright Notice in file all.lua 4 | 5 | -- most (all?) tests here assume a reasonable "Unix-like" shell 6 | if _port then return end 7 | 8 | -- use only "double quotes" inside shell scripts (better change to 9 | -- run on Windows) 10 | 11 | 12 | print ("testing stand-alone interpreter") 13 | 14 | assert(os.execute()) -- machine has a system command 15 | 16 | local arg = arg or _ARG 17 | 18 | local prog = os.tmpname() 19 | local otherprog = os.tmpname() 20 | local out = os.tmpname() 21 | 22 | local progname 23 | do 24 | local i = 0 25 | while arg[i] do i=i-1 end 26 | progname = arg[i+1] 27 | end 28 | print("progname: "..progname) 29 | 30 | local prepfile = function (s, p) 31 | p = p or prog 32 | io.output(p) 33 | io.write(s) 34 | assert(io.close()) 35 | end 36 | 37 | local function getoutput () 38 | io.input(out) 39 | local t = io.read("a") 40 | io.input():close() 41 | assert(os.remove(out)) 42 | return t 43 | end 44 | 45 | local function checkprogout (s) 46 | local t = getoutput() 47 | for line in string.gmatch(s, ".-\n") do 48 | assert(string.find(t, line, 1, true)) 49 | end 50 | end 51 | 52 | local function checkout (s) 53 | local t = getoutput() 54 | if s ~= t then print(string.format("'%s' - '%s'\n", s, t)) end 55 | assert(s == t) 56 | return t 57 | end 58 | 59 | 60 | local function RUN (p, ...) 61 | p = string.gsub(p, "lua", '"'..progname..'"', 1) 62 | local s = string.format(p, ...) 63 | assert(os.execute(s)) 64 | end 65 | 66 | local function NoRun (msg, p, ...) 67 | p = string.gsub(p, "lua", '"'..progname..'"', 1) 68 | local s = string.format(p, ...) 69 | s = string.format("%s 2> %s", s, out) -- will send error to 'out' 70 | assert(not os.execute(s)) 71 | assert(string.find(getoutput(), msg, 1, true)) -- check error message 72 | end 73 | 74 | RUN('lua -v') 75 | 76 | print(string.format("(temporary program file used in these tests: %s)", prog)) 77 | 78 | -- running stdin as a file 79 | prepfile"" 80 | RUN('lua - < %s > %s', prog, out) 81 | checkout("") 82 | 83 | prepfile[[ 84 | print( 85 | 1, a 86 | ) 87 | ]] 88 | RUN('lua - < %s > %s', prog, out) 89 | checkout("1\tnil\n") 90 | 91 | RUN('echo "print(10)\nprint(2)\n" | lua > %s', out) 92 | checkout("10\n2\n") 93 | 94 | 95 | -- test option '-' 96 | RUN('echo "print(arg[1])" | lua - -h > %s', out) 97 | checkout("-h\n") 98 | 99 | -- test environment variables used by Lua 100 | 101 | prepfile("print(package.path)") 102 | 103 | -- test LUA_PATH 104 | RUN('env LUA_INIT= LUA_PATH=x lua %s > %s', prog, out) 105 | checkout("x\n") 106 | 107 | -- test LUA_PATH_version 108 | RUN('env LUA_INIT= LUA_PATH_5_3=y LUA_PATH=x lua %s > %s', prog, out) 109 | checkout("y\n") 110 | 111 | -- test LUA_CPATH 112 | prepfile("print(package.cpath)") 113 | RUN('env LUA_INIT= LUA_CPATH=xuxu lua %s > %s', prog, out) 114 | checkout("xuxu\n") 115 | 116 | -- test LUA_CPATH_version 117 | RUN('env LUA_INIT= LUA_CPATH_5_3=yacc LUA_CPATH=x lua %s > %s', prog, out) 118 | checkout("yacc\n") 119 | 120 | -- test LUA_INIT (and its access to 'arg' table) 121 | prepfile("print(X)") 122 | RUN('env LUA_INIT="X=tonumber(arg[1])" lua %s 3.2 > %s', prog, out) 123 | checkout("3.2\n") 124 | 125 | -- test LUA_INIT_version 126 | prepfile("print(X)") 127 | RUN('env LUA_INIT_5_3="X=10" LUA_INIT="X=3" lua %s > %s', prog, out) 128 | checkout("10\n") 129 | 130 | -- test LUA_INIT for files 131 | prepfile("x = x or 10; print(x); x = x + 1") 132 | RUN('env LUA_INIT="@%s" lua %s > %s', prog, prog, out) 133 | checkout("10\n11\n") 134 | 135 | -- test errors in LUA_INIT 136 | NoRun('LUA_INIT:1: msg', 'env LUA_INIT="error(\'msg\')" lua') 137 | 138 | -- test option '-E' 139 | local defaultpath, defaultCpath 140 | 141 | do 142 | prepfile("print(package.path, package.cpath)") 143 | RUN('env LUA_INIT="error(10)" LUA_PATH=xxx LUA_CPATH=xxx lua -E %s > %s', 144 | prog, out) 145 | local out = getoutput() 146 | defaultpath = string.match(out, "^(.-)\t") 147 | defaultCpath = string.match(out, "\t(.-)$") 148 | end 149 | 150 | -- paths did not changed 151 | assert(not string.find(defaultpath, "xxx") and 152 | string.find(defaultpath, "lua") and 153 | not string.find(defaultCpath, "xxx") and 154 | string.find(defaultCpath, "lua")) 155 | 156 | 157 | -- test replacement of ';;' to default path 158 | local function convert (p) 159 | prepfile("print(package.path)") 160 | RUN('env LUA_PATH="%s" lua %s > %s', p, prog, out) 161 | local expected = getoutput() 162 | expected = string.sub(expected, 1, -2) -- cut final end of line 163 | assert(string.gsub(p, ";;", ";"..defaultpath..";") == expected) 164 | end 165 | 166 | convert(";") 167 | convert(";;") 168 | convert(";;;") 169 | convert(";;;;") 170 | convert(";;;;;") 171 | convert(";;a;;;bc") 172 | 173 | 174 | -- test -l over multiple libraries 175 | prepfile("print(1); a=2; return {x=15}") 176 | prepfile(("print(a); print(_G['%s'].x)"):format(prog), otherprog) 177 | RUN('env LUA_PATH="?;;" lua -l %s -l%s -lstring -l io %s > %s', prog, otherprog, otherprog, out) 178 | checkout("1\n2\n15\n2\n15\n") 179 | 180 | -- test 'arg' table 181 | local a = [[ 182 | assert(#arg == 3 and arg[1] == 'a' and 183 | arg[2] == 'b' and arg[3] == 'c') 184 | assert(arg[-1] == '--' and arg[-2] == "-e " and arg[-3] == '%s') 185 | assert(arg[4] == nil and arg[-4] == nil) 186 | local a, b, c = ... 187 | assert(... == 'a' and a == 'a' and b == 'b' and c == 'c') 188 | ]] 189 | a = string.format(a, progname) 190 | prepfile(a) 191 | RUN('lua "-e " -- %s a b c', prog) -- "-e " runs an empty command 192 | 193 | -- test 'arg' availability in libraries 194 | prepfile"assert(arg)" 195 | prepfile("assert(arg)", otherprog) 196 | RUN('env LUA_PATH="?;;" lua -l%s - < %s', prog, otherprog) 197 | 198 | -- test messing up the 'arg' table 199 | RUN('echo "print(...)" | lua -e "arg[1] = 100" - > %s', out) 200 | checkout("100\n") 201 | NoRun("'arg' is not a table", 'echo "" | lua -e "arg = 1" -') 202 | 203 | -- test error in 'print' 204 | RUN('echo 10 | lua -e "print=nil" -i > /dev/null 2> %s', out) 205 | assert(string.find(getoutput(), "error calling 'print'")) 206 | 207 | -- test 'debug.debug' 208 | RUN('echo "io.stderr:write(1000)\ncont" | lua -e "require\'debug\'.debug()" 2> %s', out) 209 | checkout("lua_debug> 1000lua_debug> ") 210 | 211 | -- test many arguments 212 | prepfile[[print(({...})[30])]] 213 | RUN('lua %s %s > %s', prog, string.rep(" a", 30), out) 214 | checkout("a\n") 215 | 216 | RUN([[lua "-eprint(1)" -ea=3 -e "print(a)" > %s]], out) 217 | checkout("1\n3\n") 218 | 219 | -- test iteractive mode 220 | prepfile[[ 221 | (6*2-6) -- === 222 | a = 223 | 10 224 | print(a) 225 | a]] 226 | RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i < %s > %s]], prog, out) 227 | checkprogout("6\n10\n10\n\n") 228 | 229 | prepfile("a = [[b\nc\nd\ne]]\n=a") 230 | RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i < %s > %s]], prog, out) 231 | checkprogout("b\nc\nd\ne\n\n") 232 | 233 | prompt = "alo" 234 | prepfile[[ -- 235 | a = 2 236 | ]] 237 | RUN([[lua "-e_PROMPT='%s'" -i < %s > %s]], prompt, prog, out) 238 | local t = getoutput() 239 | assert(string.find(t, prompt .. ".*" .. prompt .. ".*" .. prompt)) 240 | 241 | -- test for error objects 242 | prepfile[[ 243 | debug = require "debug" 244 | m = {x=0} 245 | setmetatable(m, {__tostring = function(x) 246 | return tostring(debug.getinfo(4).currentline + x.x) 247 | end}) 248 | error(m) 249 | ]] 250 | NoRun(progname .. ": 6\n", [[lua %s]], prog) 251 | 252 | prepfile("error{}") 253 | NoRun("error object is a table value", [[lua %s]], prog) 254 | 255 | 256 | -- chunk broken in many lines 257 | s = [=[ -- 258 | function f ( x ) 259 | local a = [[ 260 | xuxu 261 | ]] 262 | local b = "\ 263 | xuxu\n" 264 | if x == 11 then return 1 + 12 , 2 + 20 end --[[ test multiple returns ]] 265 | return x + 1 266 | --\\ 267 | end 268 | return( f( 100 ) ) 269 | assert( a == b ) 270 | do return f( 11 ) end ]=] 271 | s = string.gsub(s, ' ', '\n\n') -- change all spaces for newlines 272 | prepfile(s) 273 | RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i < %s > %s]], prog, out) 274 | checkprogout("101\n13\t22\n\n") 275 | 276 | prepfile[[#comment in 1st line without \n at the end]] 277 | RUN('lua %s', prog) 278 | 279 | prepfile[[#test line number when file starts with comment line 280 | debug = require"debug" 281 | print(debug.getinfo(1).currentline) 282 | ]] 283 | RUN('lua %s > %s', prog, out) 284 | checkprogout('3') 285 | 286 | -- close Lua with an open file 287 | prepfile(string.format([[io.output(%q); io.write('alo')]], out)) 288 | RUN('lua %s', prog) 289 | checkout('alo') 290 | 291 | -- bug in 5.2 beta (extra \0 after version line) 292 | RUN([[lua -v -e"print'hello'" > %s]], out) 293 | t = getoutput() 294 | assert(string.find(t, "PUC%-Rio\nhello")) 295 | 296 | 297 | -- testing os.exit 298 | prepfile("os.exit(nil, true)") 299 | RUN('lua %s', prog) 300 | prepfile("os.exit(0, true)") 301 | RUN('lua %s', prog) 302 | prepfile("os.exit(true, true)") 303 | RUN('lua %s', prog) 304 | prepfile("os.exit(1, true)") 305 | NoRun("", "lua %s", prog) -- no message 306 | prepfile("os.exit(false, true)") 307 | NoRun("", "lua %s", prog) -- no message 308 | 309 | -- remove temporary files 310 | assert(os.remove(prog)) 311 | assert(os.remove(otherprog)) 312 | assert(not os.remove(out)) 313 | 314 | -- invalid options 315 | NoRun("unrecognized option '-h'", "lua -h") 316 | NoRun("unrecognized option '---'", "lua ---") 317 | NoRun("unrecognized option '-Ex'", "lua -Ex") 318 | NoRun("unrecognized option '-vv'", "lua -vv") 319 | NoRun("unrecognized option '-iv'", "lua -iv") 320 | NoRun("'-e' needs argument", "lua -e") 321 | NoRun("syntax error", "lua -e a") 322 | NoRun("'-l' needs argument", "lua -l") 323 | 324 | 325 | if T then -- auxiliary library? 326 | print("testing 'not enough memory' to create a state") 327 | NoRun("not enough memory", "env MEMLIMIT=100 lua") 328 | end 329 | print('+') 330 | 331 | print('testing Ctrl C') 332 | do 333 | -- interrupt a script 334 | local function kill (pid) 335 | return os.execute(string.format('kill -INT %d 2> /dev/null', pid)) 336 | end 337 | 338 | -- function to run a script in background, returning its output file 339 | -- descriptor and its pid 340 | local function runback (luaprg) 341 | -- shell script to run 'luaprg' in background and echo its pid 342 | local shellprg = string.format('%s -e "%s" & echo $!', progname, luaprg) 343 | local f = io.popen(shellprg, "r") -- run shell script 344 | local pid = f:read() -- get pid for Lua script 345 | print("(if test fails now, it may leave a Lua script running in \z 346 | background, pid " .. pid .. ")") 347 | return f, pid 348 | end 349 | 350 | -- Lua script that runs protected infinite loop and then prints '42' 351 | local f, pid = runback[[ 352 | pcall(function () print(12); while true do end end); print(42)]] 353 | -- wait until script is inside 'pcall' 354 | assert(f:read() == "12") 355 | kill(pid) -- send INT signal to Lua script 356 | -- check that 'pcall' captured the exception and script continued running 357 | assert(f:read() == "42") -- expected output 358 | assert(f:close()) 359 | print("done") 360 | 361 | -- Lua script in a long unbreakable search 362 | local f, pid = runback[[ 363 | print(15); string.find(string.rep('a', 100000), '.*b')]] 364 | -- wait (so script can reach the loop) 365 | assert(f:read() == "15") 366 | assert(os.execute("sleep 1")) 367 | -- must send at least two INT signals to stop this Lua script 368 | local n = 100 369 | for i = 0, 100 do -- keep sending signals 370 | if not kill(pid) then -- until it fails 371 | n = i -- number of non-failed kills 372 | break 373 | end 374 | end 375 | assert(f:close()) 376 | assert(n >= 2) 377 | print(string.format("done (with %d kills)", n)) 378 | 379 | end 380 | 381 | print("OK") 382 | -------------------------------------------------------------------------------- /test/lua-5.3.4-tests/out.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trixnz/lua-fmt/3cbb57c38b12b849711286dda4f43b62e09f806d/test/lua-5.3.4-tests/out.lua -------------------------------------------------------------------------------- /test/lua-5.3.4-tests/pm.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trixnz/lua-fmt/3cbb57c38b12b849711286dda4f43b62e09f806d/test/lua-5.3.4-tests/pm.lua -------------------------------------------------------------------------------- /test/lua-5.3.4-tests/sort.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trixnz/lua-fmt/3cbb57c38b12b849711286dda4f43b62e09f806d/test/lua-5.3.4-tests/sort.lua -------------------------------------------------------------------------------- /test/lua-5.3.4-tests/strings.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trixnz/lua-fmt/3cbb57c38b12b849711286dda4f43b62e09f806d/test/lua-5.3.4-tests/strings.lua -------------------------------------------------------------------------------- /test/lua-5.3.4-tests/tpack.lua: -------------------------------------------------------------------------------- 1 | -- $Id: tpack.lua,v 1.13 2016/11/07 13:11:28 roberto Exp $ 2 | -- See Copyright Notice in file all.lua 3 | 4 | local pack = string.pack 5 | local packsize = string.packsize 6 | local unpack = string.unpack 7 | 8 | print "testing pack/unpack" 9 | 10 | -- maximum size for integers 11 | local NB = 16 12 | 13 | local sizeshort = packsize("h") 14 | local sizeint = packsize("i") 15 | local sizelong = packsize("l") 16 | local sizesize_t = packsize("T") 17 | local sizeLI = packsize("j") 18 | local sizefloat = packsize("f") 19 | local sizedouble = packsize("d") 20 | local sizenumber = packsize("n") 21 | local little = (pack("i2", 1) == "\1\0") 22 | local align = packsize("!xXi16") 23 | 24 | assert(1 <= sizeshort and sizeshort <= sizeint and sizeint <= sizelong and 25 | sizefloat <= sizedouble) 26 | 27 | print("platform:") 28 | print(string.format( 29 | "\tshort %d, int %d, long %d, size_t %d, float %d, double %d,\n\z 30 | \tlua Integer %d, lua Number %d", 31 | sizeshort, sizeint, sizelong, sizesize_t, sizefloat, sizedouble, 32 | sizeLI, sizenumber)) 33 | print("\t" .. (little and "little" or "big") .. " endian") 34 | print("\talignment: " .. align) 35 | 36 | 37 | -- check errors in arguments 38 | function checkerror (msg, f, ...) 39 | local status, err = pcall(f, ...) 40 | -- print(status, err, msg) 41 | assert(not status and string.find(err, msg)) 42 | end 43 | 44 | -- minimum behavior for integer formats 45 | assert(unpack("B", pack("B", 0xff)) == 0xff) 46 | assert(unpack("b", pack("b", 0x7f)) == 0x7f) 47 | assert(unpack("b", pack("b", -0x80)) == -0x80) 48 | 49 | assert(unpack("H", pack("H", 0xffff)) == 0xffff) 50 | assert(unpack("h", pack("h", 0x7fff)) == 0x7fff) 51 | assert(unpack("h", pack("h", -0x8000)) == -0x8000) 52 | 53 | assert(unpack("L", pack("L", 0xffffffff)) == 0xffffffff) 54 | assert(unpack("l", pack("l", 0x7fffffff)) == 0x7fffffff) 55 | assert(unpack("l", pack("l", -0x80000000)) == -0x80000000) 56 | 57 | 58 | for i = 1, NB do 59 | -- small numbers with signal extension ("\xFF...") 60 | local s = string.rep("\xff", i) 61 | assert(pack("i" .. i, -1) == s) 62 | assert(packsize("i" .. i) == #s) 63 | assert(unpack("i" .. i, s) == -1) 64 | 65 | -- small unsigned number ("\0...\xAA") 66 | s = "\xAA" .. string.rep("\0", i - 1) 67 | assert(pack("I" .. i, 0xAA) == s:reverse()) 70 | assert(unpack(">I" .. i, s:reverse()) == 0xAA) 71 | end 72 | 73 | do 74 | local lnum = 0x13121110090807060504030201 75 | local s = pack("i" .. i, ("\xFF"):rep(i - sizeLI) .. s:reverse()) == -lnum) 86 | assert(unpack("i" .. i, "\1" .. ("\x00"):rep(i - 1)) 91 | end 92 | end 93 | 94 | for i = 1, sizeLI do 95 | local lstr = "\1\2\3\4\5\6\7\8\9\10\11\12\13" 96 | local lnum = 0x13121110090807060504030201 97 | local n = lnum & (~(-1 << (i * 8))) 98 | local s = string.sub(lstr, 1, i) 99 | assert(pack("i" .. i, n) == s:reverse()) 101 | assert(unpack(">i" .. i, s:reverse()) == n) 102 | end 103 | 104 | -- sign extension 105 | do 106 | local u = 0xf0 107 | for i = 1, sizeLI - 1 do 108 | assert(unpack("I"..i, "\xf0"..("\xff"):rep(i - 1)) == u) 110 | u = u * 256 + 0xff 111 | end 112 | end 113 | 114 | -- mixed endianness 115 | do 116 | assert(pack(">i2 i2", "\10\0\0\20") 118 | assert(a == 10 and b == 20) 119 | assert(pack("=i4", 2001) == pack("i4", 2001)) 120 | end 121 | 122 | print("testing invalid formats") 123 | 124 | checkerror("out of limits", pack, "i0", 0) 125 | checkerror("out of limits", pack, "i" .. NB + 1, 0) 126 | checkerror("out of limits", pack, "!" .. NB + 1, 0) 127 | checkerror("%(17%) out of limits %[1,16%]", pack, "Xi" .. NB + 1) 128 | checkerror("invalid format option 'r'", pack, "i3r", 0) 129 | checkerror("16%-byte integer", unpack, "i16", string.rep('\3', 16)) 130 | checkerror("not power of 2", pack, "!4i3", 0); 131 | checkerror("missing size", pack, "c", "") 132 | checkerror("variable%-length format", packsize, "s") 133 | checkerror("variable%-length format", packsize, "z") 134 | 135 | -- overflow in option size (error will be in digit after limit) 136 | checkerror("invalid format", packsize, "c1" .. string.rep("0", 40)) 137 | 138 | if packsize("i") == 4 then 139 | -- result would be 2^31 (2^3 repetitions of 2^28 strings) 140 | local s = string.rep("c268435456", 2^3) 141 | checkerror("too large", packsize, s) 142 | -- one less is OK 143 | s = string.rep("c268435456", 2^3 - 1) .. "c268435455" 144 | assert(packsize(s) == 0x7fffffff) 145 | end 146 | 147 | -- overflow in packing 148 | for i = 1, sizeLI - 1 do 149 | local umax = (1 << (i * 8)) - 1 150 | local max = umax >> 1 151 | local min = ~max 152 | checkerror("overflow", pack, "I" .. i, umax + 1) 155 | 156 | checkerror("overflow", pack, ">i" .. i, umax) 157 | checkerror("overflow", pack, ">i" .. i, max + 1) 158 | checkerror("overflow", pack, "i" .. i, pack(">i" .. i, max)) == max) 161 | assert(unpack("I" .. i, pack(">I" .. i, umax)) == umax) 163 | end 164 | 165 | -- Lua integer size 166 | assert(unpack(">j", pack(">j", math.maxinteger)) == math.maxinteger) 167 | assert(unpack("f", 24)) 174 | end 175 | 176 | print "testing pack/unpack of floating-point numbers" 177 | 178 | for _, n in ipairs{0, -1.1, 1.9, 1/0, -1/0, 1e20, -1e20, 0.1, 2000.7} do 179 | assert(unpack("n", pack("n", n)) == n) 180 | assert(unpack("n", pack(">n", n)) == n) 182 | assert(pack("f", n):reverse()) 183 | assert(pack(">d", n) == pack("f", pack(">f", n)) == n) 190 | assert(unpack("d", pack(">d", n)) == n) 192 | end 193 | 194 | print "testing pack/unpack of strings" 195 | do 196 | local s = string.rep("abc", 1000) 197 | assert(pack("zB", s, 247) == s .. "\0\xF7") 198 | local s1, b = unpack("zB", s .. "\0\xF9") 199 | assert(b == 249 and s1 == s) 200 | s1 = pack("s", s) 201 | assert(unpack("s", s1) == s) 202 | 203 | checkerror("does not fit", pack, "s1", s) 204 | 205 | checkerror("contains zeros", pack, "z", "alo\0"); 206 | 207 | for i = 2, NB do 208 | local s1 = pack("s" .. i, s) 209 | assert(unpack("s" .. i, s1) == s and #s1 == #s + i) 210 | end 211 | end 212 | 213 | do 214 | local x = pack("s", "alo") 215 | checkerror("too short", unpack, "s", x:sub(1, -2)) 216 | checkerror("too short", unpack, "c5", "abcd") 217 | checkerror("out of limits", pack, "s100", "alo") 218 | end 219 | 220 | do 221 | assert(pack("c0", "") == "") 222 | assert(packsize("c0") == 0) 223 | assert(unpack("c0", "") == "") 224 | assert(pack("!4 c6", "abcdef") == "abcdef") 227 | assert(pack("c3", "123") == "123") 228 | assert(pack("c0", "") == "") 229 | assert(pack("c8", "123456") == "123456\0\0") 230 | assert(pack("c88", "") == string.rep("\0", 88)) 231 | assert(pack("c188", "ab") == "ab" .. string.rep("\0", 188 - 2)) 232 | local a, b, c = unpack("!4 z c3", "abcdefghi\0xyz") 233 | assert(a == "abcdefghi" and b == "xyz" and c == 14) 234 | checkerror("longer than", pack, "c3", "1234") 235 | end 236 | 237 | 238 | -- testing multiple types and sequence 239 | do 240 | local x = pack("!8 b Xh i4 i8 c1 Xi8", -12, 100, 200, "\xEC") 251 | assert(#x == packsize(">!8 b Xh i4 i8 c1 Xi8")) 252 | assert(x == "\xf4" .. "\0\0\0" .. 253 | "\0\0\0\100" .. 254 | "\0\0\0\0\0\0\0\xC8" .. 255 | "\xEC" .. "\0\0\0\0\0\0\0") 256 | local a, b, c, d, pos = unpack(">!8 c1 Xh i4 i8 b Xi8 XI XH", x) 257 | assert(a == "\xF4" and b == 100 and c == 200 and d == -20 and (pos - 1) == #x) 258 | 259 | x = pack(">!4 c3 c4 c2 z i4 c5 c2 Xi4", 260 | "abc", "abcd", "xz", "hello", 5, "world", "xy") 261 | assert(x == "abcabcdxzhello\0\0\0\0\0\5worldxy\0") 262 | local a, b, c, d, e, f, g, pos = unpack(">!4 c3 c4 c2 z i4 c5 c2 Xh Xi4", x) 263 | assert(a == "abc" and b == "abcd" and c == "xz" and d == "hello" and 264 | e == 5 and f == "world" and g == "xy" and (pos - 1) % 4 == 0) 265 | 266 | x = pack(" b b Xd b Xb x", 1, 2, 3) 267 | assert(packsize(" b b Xd b Xb x") == 4) 268 | assert(x == "\1\2\3\0") 269 | a, b, c, pos = unpack("bbXdb", x) 270 | assert(a == 1 and b == 2 and c == 3 and pos == #x) 271 | 272 | -- only alignment 273 | assert(packsize("!8 xXi8") == 8) 274 | local pos = unpack("!8 xXi8", "0123456701234567"); assert(pos == 9) 275 | assert(packsize("!8 xXi2") == 2) 276 | local pos = unpack("!8 xXi2", "0123456701234567"); assert(pos == 3) 277 | assert(packsize("!2 xXi2") == 2) 278 | local pos = unpack("!2 xXi2", "0123456701234567"); assert(pos == 3) 279 | assert(packsize("!2 xXi8") == 2) 280 | local pos = unpack("!2 xXi8", "0123456701234567"); assert(pos == 3) 281 | assert(packsize("!16 xXi16") == 16) 282 | local pos = unpack("!16 xXi16", "0123456701234567"); assert(pos == 17) 283 | 284 | checkerror("invalid next option", pack, "X") 285 | checkerror("invalid next option", unpack, "XXi", "") 286 | checkerror("invalid next option", unpack, "X i", "") 287 | checkerror("invalid next option", pack, "Xc1") 288 | end 289 | 290 | do -- testing initial position 291 | local x = pack("i4i4i4i4", 1, 2, 3, 4) 292 | for pos = 1, 16, 4 do 293 | local i, p = unpack("i4", x, pos) 294 | assert(i == pos//4 + 1 and p == pos + 4) 295 | end 296 | 297 | -- with alignment 298 | for pos = 0, 12 do -- will always round position to power of 2 299 | local i, p = unpack("!4 i4", x, pos + 1) 300 | assert(i == (pos + 3)//4 + 1 and p == i*4 + 1) 301 | end 302 | 303 | -- negative indices 304 | local i, p = unpack("!4 i4", x, -4) 305 | assert(i == 4 and p == 17) 306 | local i, p = unpack("!4 i4", x, -7) 307 | assert(i == 4 and p == 17) 308 | local i, p = unpack("!4 i4", x, -#x) 309 | assert(i == 1 and p == 5) 310 | 311 | -- limits 312 | for i = 1, #x + 1 do 313 | assert(unpack("c0", x, i) == "") 314 | end 315 | checkerror("out of string", unpack, "c0", x, 0) 316 | checkerror("out of string", unpack, "c0", x, #x + 2) 317 | checkerror("out of string", unpack, "c0", x, -(#x + 1)) 318 | 319 | end 320 | 321 | print "OK" 322 | 323 | -------------------------------------------------------------------------------- /test/lua-5.3.4-tests/utf8.lua: -------------------------------------------------------------------------------- 1 | -- $Id: utf8.lua,v 1.12 2016/11/07 13:11:28 roberto Exp $ 2 | -- See Copyright Notice in file all.lua 3 | 4 | print "testing UTF-8 library" 5 | 6 | local utf8 = require'utf8' 7 | 8 | 9 | local function checkerror (msg, f, ...) 10 | local s, err = pcall(f, ...) 11 | assert(not s and string.find(err, msg)) 12 | end 13 | 14 | 15 | local function len (s) 16 | return #string.gsub(s, "[\x80-\xBF]", "") 17 | end 18 | 19 | 20 | local justone = "^" .. utf8.charpattern .. "$" 21 | 22 | -- 't' is the list of codepoints of 's' 23 | local function checksyntax (s, t) 24 | local ts = {"return '"} 25 | for i = 1, #t do ts[i + 1] = string.format("\\u{%x}", t[i]) end 26 | ts[#t + 2] = "'" 27 | ts = table.concat(ts) 28 | assert(assert(load(ts))() == s) 29 | end 30 | 31 | assert(utf8.offset("alo", 5) == nil) 32 | assert(utf8.offset("alo", -4) == nil) 33 | 34 | -- 't' is the list of codepoints of 's' 35 | local function check (s, t) 36 | local l = utf8.len(s) 37 | assert(#t == l and len(s) == l) 38 | assert(utf8.char(table.unpack(t)) == s) 39 | 40 | assert(utf8.offset(s, 0) == 1) 41 | 42 | checksyntax(s, t) 43 | 44 | local t1 = {utf8.codepoint(s, 1, -1)} 45 | assert(#t == #t1) 46 | for i = 1, #t do assert(t[i] == t1[i]) end 47 | 48 | for i = 1, l do 49 | local pi = utf8.offset(s, i) -- position of i-th char 50 | local pi1 = utf8.offset(s, 2, pi) -- position of next char 51 | assert(string.find(string.sub(s, pi, pi1 - 1), justone)) 52 | assert(utf8.offset(s, -1, pi1) == pi) 53 | assert(utf8.offset(s, i - l - 1) == pi) 54 | assert(pi1 - pi == #utf8.char(utf8.codepoint(s, pi))) 55 | for j = pi, pi1 - 1 do 56 | assert(utf8.offset(s, 0, j) == pi) 57 | end 58 | for j = pi + 1, pi1 - 1 do 59 | assert(not utf8.len(s, j)) 60 | end 61 | assert(utf8.len(s, pi, pi) == 1) 62 | assert(utf8.len(s, pi, pi1 - 1) == 1) 63 | assert(utf8.len(s, pi) == l - i + 1) 64 | assert(utf8.len(s, pi1) == l - i) 65 | assert(utf8.len(s, 1, pi) == i) 66 | end 67 | 68 | local i = 0 69 | for p, c in utf8.codes(s) do 70 | i = i + 1 71 | assert(c == t[i] and p == utf8.offset(s, i)) 72 | assert(utf8.codepoint(s, p) == c) 73 | end 74 | assert(i == #t) 75 | 76 | i = 0 77 | for p, c in utf8.codes(s) do 78 | i = i + 1 79 | assert(c == t[i] and p == utf8.offset(s, i)) 80 | end 81 | assert(i == #t) 82 | 83 | i = 0 84 | for c in string.gmatch(s, utf8.charpattern) do 85 | i = i + 1 86 | assert(c == utf8.char(t[i])) 87 | end 88 | assert(i == #t) 89 | 90 | for i = 1, l do 91 | assert(utf8.offset(s, i) == utf8.offset(s, i - l - 1, #s + 1)) 92 | end 93 | 94 | end 95 | 96 | 97 | do -- error indication in utf8.len 98 | local function check (s, p) 99 | local a, b = utf8.len(s) 100 | assert(not a and b == p) 101 | end 102 | check("abc\xE3def", 4) 103 | check("汉字\x80", #("汉字") + 1) 104 | check("\xF4\x9F\xBF", 1) 105 | check("\xF4\x9F\xBF\xBF", 1) 106 | end 107 | 108 | -- error in utf8.codes 109 | checkerror("invalid UTF%-8 code", 110 | function () 111 | local s = "ab\xff" 112 | for c in utf8.codes(s) do assert(c) end 113 | end) 114 | 115 | 116 | -- error in initial position for offset 117 | checkerror("position out of range", utf8.offset, "abc", 1, 5) 118 | checkerror("position out of range", utf8.offset, "abc", 1, -4) 119 | checkerror("position out of range", utf8.offset, "", 1, 2) 120 | checkerror("position out of range", utf8.offset, "", 1, -1) 121 | checkerror("continuation byte", utf8.offset, "𦧺", 1, 2) 122 | checkerror("continuation byte", utf8.offset, "𦧺", 1, 2) 123 | checkerror("continuation byte", utf8.offset, "\x80", 1) 124 | 125 | 126 | 127 | local s = "hello World" 128 | local t = {string.byte(s, 1, -1)} 129 | for i = 1, utf8.len(s) do assert(t[i] == string.byte(s, i)) end 130 | check(s, t) 131 | 132 | check("汉字/漢字", {27721, 23383, 47, 28450, 23383,}) 133 | 134 | do 135 | local s = "áéí\128" 136 | local t = {utf8.codepoint(s,1,#s - 1)} 137 | assert(#t == 3 and t[1] == 225 and t[2] == 233 and t[3] == 237) 138 | checkerror("invalid UTF%-8 code", utf8.codepoint, s, 1, #s) 139 | checkerror("out of range", utf8.codepoint, s, #s + 1) 140 | t = {utf8.codepoint(s, 4, 3)} 141 | assert(#t == 0) 142 | checkerror("out of range", utf8.codepoint, s, -(#s + 1), 1) 143 | checkerror("out of range", utf8.codepoint, s, 1, #s + 1) 144 | end 145 | 146 | assert(utf8.char() == "") 147 | assert(utf8.char(97, 98, 99) == "abc") 148 | 149 | assert(utf8.codepoint(utf8.char(0x10FFFF)) == 0x10FFFF) 150 | 151 | checkerror("value out of range", utf8.char, 0x10FFFF + 1) 152 | 153 | local function invalid (s) 154 | checkerror("invalid UTF%-8 code", utf8.codepoint, s) 155 | assert(not utf8.len(s)) 156 | end 157 | 158 | -- UTF-8 representation for 0x11ffff (value out of valid range) 159 | invalid("\xF4\x9F\xBF\xBF") 160 | 161 | -- overlong sequences 162 | invalid("\xC0\x80") -- zero 163 | invalid("\xC1\xBF") -- 0x7F (should be coded in 1 byte) 164 | invalid("\xE0\x9F\xBF") -- 0x7FF (should be coded in 2 bytes) 165 | invalid("\xF0\x8F\xBF\xBF") -- 0xFFFF (should be coded in 3 bytes) 166 | 167 | 168 | -- invalid bytes 169 | invalid("\x80") -- continuation byte 170 | invalid("\xBF") -- continuation byte 171 | invalid("\xFE") -- invalid byte 172 | invalid("\xFF") -- invalid byte 173 | 174 | 175 | -- empty string 176 | check("", {}) 177 | 178 | -- minimum and maximum values for each sequence size 179 | s = "\0 \x7F\z 180 | \xC2\x80 \xDF\xBF\z 181 | \xE0\xA0\x80 \xEF\xBF\xBF\z 182 | \xF0\x90\x80\x80 \xF4\x8F\xBF\xBF" 183 | s = string.gsub(s, " ", "") 184 | check(s, {0,0x7F, 0x80,0x7FF, 0x800,0xFFFF, 0x10000,0x10FFFF}) 185 | 186 | x = "日本語a-4\0éó" 187 | check(x, {26085, 26412, 35486, 97, 45, 52, 0, 233, 243}) 188 | 189 | 190 | -- Supplementary Characters 191 | check("𣲷𠜎𠱓𡁻𠵼ab𠺢", 192 | {0x23CB7, 0x2070E, 0x20C53, 0x2107B, 0x20D7C, 0x61, 0x62, 0x20EA2,}) 193 | 194 | check("𨳊𩶘𦧺𨳒𥄫𤓓\xF4\x8F\xBF\xBF", 195 | {0x28CCA, 0x29D98, 0x269FA, 0x28CD2, 0x2512B, 0x244D3, 0x10ffff}) 196 | 197 | 198 | local i = 0 199 | for p, c in string.gmatch(x, "()(" .. utf8.charpattern .. ")") do 200 | i = i + 1 201 | assert(utf8.offset(x, i) == p) 202 | assert(utf8.len(x, p) == utf8.len(x) - i + 1) 203 | assert(utf8.len(c) == 1) 204 | for j = 1, #c - 1 do 205 | assert(utf8.offset(x, 0, p + j - 1) == p) 206 | end 207 | end 208 | 209 | print'ok' 210 | 211 | -------------------------------------------------------------------------------- /test/lua-5.3.4-tests/vararg.lua: -------------------------------------------------------------------------------- 1 | -- $Id: vararg.lua,v 1.25 2016/11/07 13:11:28 roberto Exp $ 2 | -- See Copyright Notice in file all.lua 3 | 4 | print('testing vararg') 5 | 6 | function f(a, ...) 7 | local arg = {n = select('#', ...), ...} 8 | for i=1,arg.n do assert(a[i]==arg[i]) end 9 | return arg.n 10 | end 11 | 12 | function c12 (...) 13 | assert(arg == _G.arg) -- no local 'arg' 14 | local x = {...}; x.n = #x 15 | local res = (x.n==2 and x[1] == 1 and x[2] == 2) 16 | if res then res = 55 end 17 | return res, 2 18 | end 19 | 20 | function vararg (...) return {n = select('#', ...), ...} end 21 | 22 | local call = function (f, args) return f(table.unpack(args, 1, args.n)) end 23 | 24 | assert(f() == 0) 25 | assert(f({1,2,3}, 1, 2, 3) == 3) 26 | assert(f({"alo", nil, 45, f, nil}, "alo", nil, 45, f, nil) == 5) 27 | 28 | assert(c12(1,2)==55) 29 | a,b = assert(call(c12, {1,2})) 30 | assert(a == 55 and b == 2) 31 | a = call(c12, {1,2;n=2}) 32 | assert(a == 55 and b == 2) 33 | a = call(c12, {1,2;n=1}) 34 | assert(not a) 35 | assert(c12(1,2,3) == false) 36 | local a = vararg(call(next, {_G,nil;n=2})) 37 | local b,c = next(_G) 38 | assert(a[1] == b and a[2] == c and a.n == 2) 39 | a = vararg(call(call, {c12, {1,2}})) 40 | assert(a.n == 2 and a[1] == 55 and a[2] == 2) 41 | a = call(print, {'+'}) 42 | assert(a == nil) 43 | 44 | local t = {1, 10} 45 | function t:f (...) local arg = {...}; return self[...]+#arg end 46 | assert(t:f(1,4) == 3 and t:f(2) == 11) 47 | print('+') 48 | 49 | lim = 20 50 | local i, a = 1, {} 51 | while i <= lim do a[i] = i+0.3; i=i+1 end 52 | 53 | function f(a, b, c, d, ...) 54 | local more = {...} 55 | assert(a == 1.3 and more[1] == 5.3 and 56 | more[lim-4] == lim+0.3 and not more[lim-3]) 57 | end 58 | 59 | function g(a,b,c) 60 | assert(a == 1.3 and b == 2.3 and c == 3.3) 61 | end 62 | 63 | call(f, a) 64 | call(g, a) 65 | 66 | a = {} 67 | i = 1 68 | while i <= lim do a[i] = i; i=i+1 end 69 | assert(call(math.max, a) == lim) 70 | 71 | print("+") 72 | 73 | 74 | -- new-style varargs 75 | 76 | function oneless (a, ...) return ... end 77 | 78 | function f (n, a, ...) 79 | local b 80 | assert(arg == _G.arg) -- no local 'arg' 81 | if n == 0 then 82 | local b, c, d = ... 83 | return a, b, c, d, oneless(oneless(oneless(...))) 84 | else 85 | n, b, a = n-1, ..., a 86 | assert(b == ...) 87 | return f(n, a, ...) 88 | end 89 | end 90 | 91 | a,b,c,d,e = assert(f(10,5,4,3,2,1)) 92 | assert(a==5 and b==4 and c==3 and d==2 and e==1) 93 | 94 | a,b,c,d,e = f(4) 95 | assert(a==nil and b==nil and c==nil and d==nil and e==nil) 96 | 97 | 98 | -- varargs for main chunks 99 | f = load[[ return {...} ]] 100 | x = f(2,3) 101 | assert(x[1] == 2 and x[2] == 3 and x[3] == nil) 102 | 103 | 104 | f = load[[ 105 | local x = {...} 106 | for i=1,select('#', ...) do assert(x[i] == select(i, ...)) end 107 | assert(x[select('#', ...)+1] == nil) 108 | return true 109 | ]] 110 | 111 | assert(f("a", "b", nil, {}, assert)) 112 | assert(f()) 113 | 114 | a = {select(3, table.unpack{10,20,30,40})} 115 | assert(#a == 2 and a[1] == 30 and a[2] == 40) 116 | a = {select(1)} 117 | assert(next(a) == nil) 118 | a = {select(-1, 3, 5, 7)} 119 | assert(a[1] == 7 and a[2] == nil) 120 | a = {select(-2, 3, 5, 7)} 121 | assert(a[1] == 5 and a[2] == 7 and a[3] == nil) 122 | pcall(select, 10000) 123 | pcall(select, -10000) 124 | 125 | 126 | -- bug in 5.2.2 127 | 128 | function f(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, 129 | p11, p12, p13, p14, p15, p16, p17, p18, p19, p20, 130 | p21, p22, p23, p24, p25, p26, p27, p28, p29, p30, 131 | p31, p32, p33, p34, p35, p36, p37, p38, p39, p40, 132 | p41, p42, p43, p44, p45, p46, p48, p49, p50, ...) 133 | local a1,a2,a3,a4,a5,a6,a7 134 | local a8,a9,a10,a11,a12,a13,a14 135 | end 136 | 137 | -- assertion fail here 138 | f() 139 | 140 | 141 | print('OK') 142 | 143 | -------------------------------------------------------------------------------- /test/lua-5.3.4-tests/verybig.lua: -------------------------------------------------------------------------------- 1 | -- $Id: verybig.lua,v 1.25 2016/11/07 13:11:28 roberto Exp $ 2 | -- See Copyright Notice in file all.lua 3 | 4 | print "testing RK" 5 | 6 | -- testing opcodes with RK arguments larger than K limit 7 | local function foo () 8 | local dummy = { 9 | -- fill first 256 entries in table of constants 10 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 11 | 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 12 | 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 13 | 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 14 | 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 15 | 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 16 | 97, 98, 99, 100, 101, 102, 103, 104, 17 | 105, 106, 107, 108, 109, 110, 111, 112, 18 | 113, 114, 115, 116, 117, 118, 119, 120, 19 | 121, 122, 123, 124, 125, 126, 127, 128, 20 | 129, 130, 131, 132, 133, 134, 135, 136, 21 | 137, 138, 139, 140, 141, 142, 143, 144, 22 | 145, 146, 147, 148, 149, 150, 151, 152, 23 | 153, 154, 155, 156, 157, 158, 159, 160, 24 | 161, 162, 163, 164, 165, 166, 167, 168, 25 | 169, 170, 171, 172, 173, 174, 175, 176, 26 | 177, 178, 179, 180, 181, 182, 183, 184, 27 | 185, 186, 187, 188, 189, 190, 191, 192, 28 | 193, 194, 195, 196, 197, 198, 199, 200, 29 | 201, 202, 203, 204, 205, 206, 207, 208, 30 | 209, 210, 211, 212, 213, 214, 215, 216, 31 | 217, 218, 219, 220, 221, 222, 223, 224, 32 | 225, 226, 227, 228, 229, 230, 231, 232, 33 | 233, 234, 235, 236, 237, 238, 239, 240, 34 | 241, 242, 243, 244, 245, 246, 247, 248, 35 | 249, 250, 251, 252, 253, 254, 255, 256, 36 | } 37 | assert(24.5 + 0.6 == 25.1) 38 | local t = {foo = function (self, x) return x + self.x end, x = 10} 39 | t.t = t 40 | assert(t:foo(1.5) == 11.5) 41 | assert(t.t:foo(0.5) == 10.5) -- bug in 5.2 alpha 42 | assert(24.3 == 24.3) 43 | assert((function () return t.x end)() == 10) 44 | end 45 | 46 | 47 | foo() 48 | foo = nil 49 | 50 | if _soft then return 10 end 51 | 52 | print "testing large programs (>64k)" 53 | 54 | -- template to create a very big test file 55 | prog = [[$ 56 | 57 | local a,b 58 | 59 | b = {$1$ 60 | b30009 = 65534, 61 | b30010 = 65535, 62 | b30011 = 65536, 63 | b30012 = 65537, 64 | b30013 = 16777214, 65 | b30014 = 16777215, 66 | b30015 = 16777216, 67 | b30016 = 16777217, 68 | b30017 = 0x7fffff, 69 | b30018 = -0x7fffff, 70 | b30019 = 0x1ffffff, 71 | b30020 = -0x1ffffd, 72 | b30021 = -65534, 73 | b30022 = -65535, 74 | b30023 = -65536, 75 | b30024 = -0xffffff, 76 | b30025 = 15012.5, 77 | $2$ 78 | }; 79 | 80 | assert(b.a50008 == 25004 and b["a11"] == -5.5) 81 | assert(b.a33007 == -16503.5 and b.a50009 == -25004.5) 82 | assert(b["b"..30024] == -0xffffff) 83 | 84 | function b:xxx (a,b) return a+b end 85 | assert(b:xxx(10, 12) == 22) -- pushself with non-constant index 86 | b.xxx = nil 87 | 88 | s = 0; n=0 89 | for a,b in pairs(b) do s=s+b; n=n+1 end 90 | -- with 32-bit floats, exact value of 's' depends on summation order 91 | assert(81800000.0 < s and s < 81860000 and n == 70001) 92 | 93 | a = nil; b = nil 94 | print'+' 95 | 96 | function f(x) b=x end 97 | 98 | a = f{$3$} or 10 99 | 100 | assert(a==10) 101 | assert(b[1] == "a10" and b[2] == 5 and b[#b-1] == "a50009") 102 | 103 | 104 | function xxxx (x) return b[x] end 105 | 106 | assert(xxxx(3) == "a11") 107 | 108 | a = nil; b=nil 109 | xxxx = nil 110 | 111 | return 10 112 | 113 | ]] 114 | 115 | -- functions to fill in the $n$ 116 | 117 | local function sig (x) 118 | return (x % 2 == 0) and '' or '-' 119 | end 120 | 121 | F = { 122 | function () -- $1$ 123 | for i=10,50009 do 124 | io.write('a', i, ' = ', sig(i), 5+((i-10)/2), ',\n') 125 | end 126 | end, 127 | 128 | function () -- $2$ 129 | for i=30026,50009 do 130 | io.write('b', i, ' = ', sig(i), 15013+((i-30026)/2), ',\n') 131 | end 132 | end, 133 | 134 | function () -- $3$ 135 | for i=10,50009 do 136 | io.write('"a', i, '", ', sig(i), 5+((i-10)/2), ',\n') 137 | end 138 | end, 139 | } 140 | 141 | file = os.tmpname() 142 | io.output(file) 143 | for s in string.gmatch(prog, "$([^$]+)") do 144 | local n = tonumber(s) 145 | if not n then io.write(s) else F[n]() end 146 | end 147 | io.close() 148 | result = dofile(file) 149 | assert(os.remove(file)) 150 | print'OK' 151 | return result 152 | 153 | -------------------------------------------------------------------------------- /test/lua-5.3.4.test.ts: -------------------------------------------------------------------------------- 1 | import { formatText } from '../src/index'; 2 | import { readFileContents, runLuaCode } from './util'; 3 | 4 | import * as path from 'path'; 5 | import * as luaparse from 'luaparse'; 6 | 7 | function readLuaTest(name: string) { 8 | const testPath = path.join(__dirname, 'lua-5.3.4-tests', name); 9 | 10 | return readFileContents(testPath); 11 | } 12 | 13 | function parseLua(text: string) { 14 | return luaparse.parse(text, { 15 | luaVersion: '5.3' 16 | }); 17 | } 18 | 19 | function generateLuaTest(name: string) { 20 | it(name + ' can still pass tests after being formatted', async () => { 21 | const bootstrap = '\ 22 | _soft = true \ 23 | _port = true \ 24 | _nomsg = true\n'; 25 | 26 | const result = await readLuaTest(name) 27 | .then(contents => bootstrap + contents) 28 | .then(contents => formatText(contents)) 29 | .then(formatted => runLuaCode(formatted)); 30 | 31 | return expect(result).toBe(true); 32 | }); 33 | 34 | it(name + ' can still be parsed after being formatted', async () => { 35 | const result = await readLuaTest(name) 36 | .then(contents => parseLua(contents)); 37 | 38 | return expect(result).not.toBeNull(); 39 | }); 40 | } 41 | 42 | describe('Lua 5.3.4 standalone tests', () => { 43 | generateLuaTest('bitwise.lua'); 44 | generateLuaTest('api.lua'); 45 | generateLuaTest('attrib.lua'); 46 | generateLuaTest('big.lua'); 47 | generateLuaTest('bitwise.lua'); 48 | generateLuaTest('calls.lua'); 49 | generateLuaTest('closure.lua'); 50 | generateLuaTest('code.lua'); 51 | generateLuaTest('constructs.lua'); 52 | // Incompatible: Relies on line numbers 53 | // generateLuaTest('coroutine.lua'); 54 | // Incompatible: Relies on line numbers 55 | // generateLuaTest('db.lua'); 56 | // generateLuaTest('errors.lua'); 57 | generateLuaTest('events.lua'); 58 | // generateLuaTest('files.lua'); 59 | generateLuaTest('gc.lua'); 60 | generateLuaTest('goto.lua'); 61 | generateLuaTest('literals.lua'); 62 | generateLuaTest('locals.lua'); 63 | // generateLuaTest('main.lua'); 64 | generateLuaTest('math.lua'); 65 | generateLuaTest('nextvar.lua'); 66 | // Fails: encoding error? 67 | // generateLuaTest('pm.lua'); 68 | generateLuaTest('sort.lua'); 69 | generateLuaTest('strings.lua'); 70 | generateLuaTest('tpack.lua'); 71 | generateLuaTest('utf8.lua'); 72 | generateLuaTest('vararg.lua'); 73 | generateLuaTest('verybig.lua'); 74 | }); 75 | -------------------------------------------------------------------------------- /test/quotes/__snapshots__/quotes.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`keep_quotemark.lua 1`] = ` 4 | "-- Typical case with {quotemark: 'single' } 5 | print('this will be converted to single quotes') 6 | 7 | -- But keep original quotemark if the alternative quotemark is in the string. 8 | local filename = \\"It's Fred's friend's hamster's file\\" 9 | print(\\"'%s'\\", filename:gsub(\\"'\\", \\"'\\\\\\\\''\\")) 10 | " 11 | `; 12 | -------------------------------------------------------------------------------- /test/quotes/keep_quotemark.lua: -------------------------------------------------------------------------------- 1 | -- Typical case with {quotemark: 'single' } 2 | print("this will be converted to single quotes") 3 | 4 | -- But keep original quotemark if the alternative quotemark is in the string. 5 | local filename = "It's Fred's friend's hamster's file" 6 | print("'%s'", filename:gsub("'","'\\''")) 7 | -------------------------------------------------------------------------------- /test/quotes/quotes.test.ts: -------------------------------------------------------------------------------- 1 | import { runTest } from '../util'; 2 | 3 | runTest(__dirname, { quotemark: 'single' }); 4 | -------------------------------------------------------------------------------- /test/shebang/__snapshots__/shebang.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`keep_shebang.lua 1`] = ` 4 | "#!/usr/bin/env lua 5 | 6 | print(\\"Hello, World\\") 7 | " 8 | `; 9 | -------------------------------------------------------------------------------- /test/shebang/keep_shebang.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env lua 2 | 3 | print('Hello, World') 4 | -------------------------------------------------------------------------------- /test/shebang/shebang.test.ts: -------------------------------------------------------------------------------- 1 | import { runTest } from '../util'; 2 | 3 | runTest(__dirname); 4 | -------------------------------------------------------------------------------- /test/util.ts: -------------------------------------------------------------------------------- 1 | import { spawn } from 'child_process'; 2 | import { readFile, readFileSync, readdirSync } from 'fs'; 3 | import * as path from 'path'; 4 | 5 | import { formatText } from '../src/index'; 6 | import { UserOptions } from '../src/options'; 7 | 8 | export function runLuaCode(code: string): Promise { 9 | return new Promise((resolve, reject) => { 10 | const process = spawn('lua53', ['-']); 11 | try { 12 | process.stdin.write(code, 'utf-8'); 13 | process.stdin.end(); 14 | } catch (e) { 15 | reject(e); 16 | } 17 | 18 | process.stderr.on('data', (data: Buffer) => { 19 | const str = data.toString(); 20 | 21 | return reject(new Error(str)); 22 | }); 23 | 24 | process.on('close', exitCode => { 25 | if (exitCode === 0) { 26 | resolve(true); 27 | } 28 | }); 29 | 30 | process.on('error', err => { 31 | reject(err); 32 | }); 33 | }); 34 | } 35 | 36 | export function readFileContents(path: string) { 37 | return new Promise((resolve, reject) => { 38 | readFile(path, 'utf-8', (err, data) => { 39 | if (err) { 40 | return reject(err); 41 | } 42 | 43 | return resolve(data); 44 | }); 45 | }); 46 | } 47 | 48 | export function runTest(dirName: string, userOptions?: UserOptions) { 49 | test(path.basename(dirName), () => { 50 | readdirSync(dirName).forEach(fileName => { 51 | if (!fileName.endsWith('.lua')) { 52 | return; 53 | } 54 | 55 | const filePath = path.join(dirName, fileName); 56 | const text = readFileSync(filePath, 'utf-8'); 57 | const formatted = formatText(text, userOptions); 58 | 59 | expect(formatted).toMatchSnapshot(fileName); 60 | }); 61 | }); 62 | } 63 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "moduleResolution": "node", 5 | "target": "es6", 6 | "outDir": "dist", 7 | "typeRoots": [ 8 | "./node_modules/@types", 9 | "./typings/modules" 10 | ], 11 | "sourceMap": true, 12 | "declaration": true, 13 | "allowJs": false, 14 | "allowSyntheticDefaultImports": false, 15 | "allowUnreachableCode": false, 16 | "allowUnusedLabels": false, 17 | "alwaysStrict": true, 18 | "experimentalDecorators": true, 19 | "forceConsistentCasingInFileNames": true, 20 | "noEmitOnError": true, 21 | "noFallthroughCasesInSwitch": true, 22 | "noImplicitAny": true, 23 | "noImplicitReturns": true, 24 | "noImplicitThis": true, 25 | "noUnusedLocals": true, 26 | "noUnusedParameters": true, 27 | "removeComments": true, 28 | "skipDefaultLibCheck": true, 29 | "skipLibCheck": true, 30 | "strictNullChecks": true, 31 | "stripInternal": true, 32 | "suppressImplicitAnyIndexErrors": true 33 | }, 34 | "include": [ 35 | "src/**/*.ts", 36 | "bin/**/*.ts" 37 | ], 38 | "exclude": [ 39 | "node_modules", 40 | ".vscode-test" 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "adjacent-overload-signatures": true, 4 | "callable-types": true, 5 | "class-name": true, 6 | "comment-format": [ 7 | true, 8 | "check-space" 9 | ], 10 | "curly": true, 11 | "eofline": true, 12 | "forin": true, 13 | "indent": [ 14 | true, 15 | "spaces" 16 | ], 17 | "interface-over-type-literal": true, 18 | "label-position": true, 19 | "linebreak-style": [ 20 | true, 21 | "LF" 22 | ], 23 | "max-line-length": [ 24 | true, 25 | 120 26 | ], 27 | "member-access": [ 28 | true, 29 | "check-accessor", 30 | "check-constructor" 31 | ], 32 | "new-parens": true, 33 | "no-angle-bracket-type-assertion": true, 34 | "no-arg": true, 35 | "no-bitwise": true, 36 | "no-conditional-assignment": true, 37 | "no-consecutive-blank-lines": [ 38 | true, 39 | 2 40 | ], 41 | "no-construct": true, 42 | "no-default-export": true, 43 | "no-duplicate-variable": true, 44 | "no-eval": true, 45 | "no-inferrable-types": [ 46 | false 47 | ], 48 | "no-internal-module": true, 49 | "no-invalid-this": true, 50 | "no-mergeable-namespace": true, 51 | "no-namespace": [ 52 | true, 53 | "allow-declarations" 54 | ], 55 | "no-parameter-properties": true, 56 | "no-shadowed-variable": true, 57 | "no-string-literal": true, 58 | "no-string-throw": true, 59 | "no-switch-case-fall-through": true, 60 | "no-trailing-whitespace": true, 61 | "no-unsafe-finally": true, 62 | "no-unused-expression": true, 63 | "no-unused-new": true, 64 | "no-var-keyword": true, 65 | 66 | "object-literal-key-quotes": [ 67 | true, 68 | "as-needed" 69 | ], 70 | "object-literal-shorthand": true, 71 | "one-line": [ 72 | true, 73 | "check-open-brace", 74 | "check-whitespace" 75 | ], 76 | "one-variable-per-declaration": [ 77 | true 78 | ], 79 | "only-arrow-functions": [ 80 | true, 81 | "allow-declarations" 82 | ], 83 | "prefer-const": true, 84 | "prefer-for-of": true, 85 | "quotemark": [ 86 | true, 87 | "single", 88 | "jsx-double" 89 | ], 90 | "semicolon": [ 91 | true, 92 | "always" 93 | ], 94 | "triple-equals": [ 95 | true, 96 | "allow-null-check" 97 | ], 98 | "typedef": [ 99 | true, 100 | "parameter" 101 | ], 102 | "use-isnan": true, 103 | "typedef-whitespace": [ 104 | true, 105 | { 106 | "call-signature": "nospace", 107 | "index-signature": "nospace", 108 | "parameter": "nospace", 109 | "property-declaration": "nospace", 110 | "variable-declaration": "nospace" 111 | } 112 | ], 113 | "trailing-comma": [ 114 | true, 115 | { 116 | "multiline": "never", 117 | "singleline": "never" 118 | } 119 | ], 120 | "variable-name": [ 121 | true, 122 | "check-format", 123 | "allow-leading-underscore", 124 | "ban-keywords" 125 | ], 126 | "whitespace": [ 127 | true, 128 | "check-branch", 129 | "check-decl", 130 | "check-operator", 131 | "check-separator", 132 | "check-type" 133 | ] 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /typings/index.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /typings/modules/luaparse/index.d.ts: -------------------------------------------------------------------------------- 1 | /* luaparse by: https://github.com/oxyc */ 2 | /* typing definition by: https://github.com/hydroper */ 3 | declare module 'luaparse' { 4 | interface NodeAdditional { 5 | type: string; 6 | loc: MarkerLocations; 7 | range: [number, number]; 8 | } 9 | 10 | interface ExpAdditional extends NodeAdditional { 11 | inParens?: boolean; 12 | } 13 | 14 | export type Expression = CallExpression | StringCallExpression | TableCallExpression | 15 | FunctionDeclaration | Identifier | IndexExpression | MemberExpression | 16 | TableConstructorExpression | BooleanLiteral | NumericLiteral | StringLiteral | 17 | VarargLiteral | NilLiteral | BinaryExpression | LogicalExpression | UnaryExpression; 18 | 19 | export type Statement = LabelStatement | BreakStatement | GotoStatement | 20 | ReturnStatement | IfStatement | IfClause | ElseifClause | ElseClause | WhileStatement | 21 | DoStatement | RepeatStatement | LocalStatement | AssignmentStatement | CallStatement | 22 | FunctionDeclaration | ForNumericStatement | ForGenericStatement; 23 | 24 | type Node = Chunk | Expression | Statement | TableKey | TableKeyString | TableValue | Comment; 25 | 26 | export interface LabelStatement extends NodeAdditional { 27 | readonly type: "LabelStatement"; 28 | readonly label: Identifier; 29 | } 30 | 31 | export interface BreakStatement extends NodeAdditional { 32 | readonly type: "BreakStatement"; 33 | } 34 | 35 | export interface GotoStatement extends NodeAdditional { 36 | readonly type: "GotoStatement"; 37 | readonly label: Identifier; 38 | } 39 | export interface ReturnStatement extends NodeAdditional { 40 | readonly type: "ReturnStatement"; 41 | readonly arguments: Expression[]; 42 | } 43 | export interface IfStatement extends NodeAdditional { 44 | readonly type: "IfStatement"; 45 | readonly clauses: (IfClause | ElseifClause | ElseClause)[]; 46 | } 47 | export interface IfClause extends NodeAdditional { 48 | readonly type: "IfClause"; 49 | readonly condition: Expression; 50 | readonly body: Statement[]; 51 | } 52 | export interface ElseifClause extends NodeAdditional { 53 | readonly type: "ElseifClause"; 54 | readonly condition: Expression; 55 | readonly body: Statement[]; 56 | } 57 | export interface ElseClause extends NodeAdditional { 58 | readonly type: "ElseClause"; 59 | readonly body: Statement[]; 60 | } 61 | export interface WhileStatement extends NodeAdditional { 62 | readonly type: "WhileStatement"; 63 | readonly condition: Expression; 64 | readonly body: Statement[]; 65 | } 66 | export interface DoStatement extends NodeAdditional { 67 | readonly type: "DoStatement"; 68 | readonly body: Statement[]; 69 | } 70 | export interface RepeatStatement extends NodeAdditional { 71 | readonly type: "RepeatStatement"; 72 | readonly condition: Expression; 73 | readonly body: Statement[]; 74 | } 75 | export interface LocalStatement extends NodeAdditional { 76 | readonly type: "LocalStatement"; 77 | readonly variables: Identifier[]; 78 | readonly init: (Expression | null)[]; 79 | } 80 | export interface AssignmentStatement extends NodeAdditional { 81 | readonly type: "AssignmentStatement"; 82 | readonly variables: (Identifier | IndexExpression | MemberExpression)[]; 83 | readonly init: (Expression | null)[]; 84 | } 85 | export interface CallStatement extends NodeAdditional { 86 | readonly type: "CallStatement"; 87 | readonly expression: Expression; 88 | } 89 | export interface FunctionDeclaration extends ExpAdditional { 90 | readonly type: "FunctionDeclaration"; 91 | readonly identifier: Identifier | MemberExpression | null; 92 | readonly isLocal: boolean; 93 | readonly parameters: (Identifier | VarargLiteral)[]; 94 | readonly body: Statement[]; 95 | } 96 | export interface ForNumericStatement extends NodeAdditional { 97 | readonly type: "ForNumericStatement"; 98 | readonly variable: Identifier; 99 | readonly start: Expression; 100 | readonly end: Expression; 101 | readonly step: Expression; 102 | readonly body: Statement[]; 103 | } 104 | export interface ForGenericStatement extends NodeAdditional { 105 | readonly type: "ForGenericStatement"; 106 | readonly variables: Identifier[]; 107 | readonly iterators: Expression[]; 108 | readonly body: Statement[]; 109 | } 110 | export interface Chunk extends ExpAdditional { 111 | readonly type: "Chunk"; 112 | readonly body: Statement[]; 113 | readonly comments: Comment[]; 114 | readonly globals?: Expression[]; 115 | } 116 | export interface Identifier extends ExpAdditional { 117 | readonly type: "Identifier"; 118 | readonly name: string; 119 | readonly isLocal?: boolean 120 | } 121 | export interface BooleanLiteral extends ExpAdditional { 122 | readonly type: "BooleanLiteral"; 123 | readonly raw: string; 124 | readonly value: boolean; 125 | } 126 | export interface NilLiteral extends ExpAdditional { 127 | readonly type: "NilLiteral"; 128 | readonly raw: string; 129 | readonly value: null; 130 | } 131 | export interface NumericLiteral extends ExpAdditional { 132 | readonly type: "NumericLiteral"; 133 | readonly raw: string; 134 | readonly value: number; 135 | } 136 | export interface StringLiteral extends ExpAdditional { 137 | readonly type: "StringLiteral"; 138 | readonly raw: string; 139 | readonly value: string; 140 | } 141 | export interface VarargLiteral extends ExpAdditional { 142 | readonly type: "VarargLiteral"; 143 | readonly raw: string; 144 | readonly value: string; 145 | } 146 | export interface TableKey extends NodeAdditional { 147 | readonly type: "TableKey"; 148 | readonly key: Expression; 149 | readonly value: Expression; 150 | } 151 | export interface TableKeyString extends NodeAdditional { 152 | readonly type: "TableKeyString"; 153 | readonly key: Identifier; 154 | readonly value: Expression; 155 | } 156 | export interface TableValue extends NodeAdditional { 157 | readonly type: "TableValue"; 158 | readonly value: Expression; 159 | } 160 | export interface TableConstructorExpression extends ExpAdditional { 161 | readonly type: "TableConstructorExpression"; 162 | readonly fields: (TableKey | TableKeyString | TableValue)[]; 163 | } 164 | export interface BinaryExpression extends ExpAdditional { 165 | readonly type: "BinaryExpression"; 166 | readonly operator: string; 167 | readonly left: Expression; 168 | readonly right: Expression; 169 | } 170 | export interface LogicalExpression extends ExpAdditional { 171 | readonly type: "LogicalExpression"; 172 | readonly operator: string; 173 | readonly left: Expression; 174 | readonly right: Expression; 175 | } 176 | export interface UnaryExpression extends ExpAdditional { 177 | readonly type: "UnaryExpression"; 178 | readonly operator: string; 179 | readonly argument: Expression; 180 | } 181 | export interface MemberExpression extends ExpAdditional { 182 | readonly type: "MemberExpression"; 183 | readonly indexer: string; 184 | readonly identifier: Identifier; 185 | readonly base: Expression; 186 | } 187 | export interface IndexExpression extends ExpAdditional { 188 | readonly type: "IndexExpression"; 189 | readonly base: Expression; 190 | readonly index: Expression; 191 | } 192 | export interface CallExpression extends ExpAdditional { 193 | readonly type: "CallExpression"; 194 | readonly base: Expression; 195 | readonly arguments: Expression[]; 196 | } 197 | export interface TableCallExpression extends ExpAdditional { 198 | readonly type: "TableCallExpression"; 199 | readonly base: Expression; 200 | readonly arguments: TableCallExpression; 201 | } 202 | export interface StringCallExpression extends ExpAdditional { 203 | readonly type: "StringCallExpression"; 204 | readonly base: Expression; 205 | readonly argument: StringLiteral; 206 | } 207 | export interface Comment extends NodeAdditional { 208 | readonly type: "Comment"; 209 | readonly raw: string; 210 | readonly value: string; 211 | } 212 | interface MarkerLocation { 213 | line: number; 214 | column: number; 215 | } 216 | interface MarkerLocations { 217 | start: MarkerLocation; 218 | end: MarkerLocation; 219 | } 220 | export module Tokens { 221 | export type EOF = 1; 222 | export type StringLiteral = 2; 223 | export type Identifier = 8; 224 | export type NumericLiteral = 16; 225 | export type Punctuator = 32; 226 | export type BooleanLiteral = 64; 227 | export type NilLiteral = 128; 228 | export type VarargLiteral = 256; 229 | } 230 | export interface Token { 231 | //readonly type: Tokens.EOF | Tokens.StringLiteral | Tokens.Identifier | Tokens.NumericLiteral | 232 | // Tokens.Punctuator | Tokens.BooleanLiteral | Tokens.NilLiteral | Tokens.VarargLiteral; 233 | readonly type: number; 234 | readonly value: string; 235 | readonly line: number; 236 | readonly lineStart: number; 237 | readonly loc?: MarkerLocations; 238 | readonly range: [number, number]; 239 | } 240 | export const defaultOptions: Options; 241 | export const version: string; 242 | 243 | export const ast: { [name: string]: any }; 244 | 245 | export function end(code: string): Chunk; 246 | export function lex(): Token; 247 | export function parse(code: Options | string, options?: Options | null): Chunk; 248 | export function write(code: string): void; 249 | 250 | interface Options { 251 | wait?: boolean; 252 | comments?: boolean; 253 | scope?: boolean; 254 | locations?: boolean; 255 | ranges?: boolean; 256 | onCreateNode?: (node: Node) => void | null; 257 | onCreateScope?: Function | null; 258 | onDestroyScope?: Function | null; 259 | //luaVersion?: '5.1' | '5.2' | '5.3'; 260 | luaVersion?: string; 261 | } 262 | } 263 | --------------------------------------------------------------------------------